Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Sign in
Toggle navigation
F
Front-End
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
abdullh.alsoleman
Front-End
Commits
4f4c7816
Unverified
Commit
4f4c7816
authored
Mar 14, 2022
by
Valentin Marquis
Committed by
GitHub
Mar 14, 2022
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Fix/text containing finder work with rich texts (#99682)
parent
2f73173c
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
154 additions
and
34 deletions
+154
-34
finders.dart
packages/flutter_test/lib/src/finders.dart
+76
-34
finders_test.dart
packages/flutter_test/test/finders_test.dart
+78
-0
No files found.
packages/flutter_test/lib/src/finders.dart
View file @
4f4c7816
...
...
@@ -65,8 +65,20 @@ class CommonFinders {
);
}
/// Finds [Text] and [EditableText] widgets which contain the given
/// `pattern` argument.
/// Finds [Text] and [EditableText], and optionally [RichText] widgets
/// which contain the given `pattern` argument.
///
/// If `findRichText` is false, all standalone [RichText] widgets are
/// ignored and `pattern` is matched with [Text.data] or [Text.textSpan].
/// If `findRichText` is true, [RichText] widgets (and therefore also
/// [Text] and [Text.rich] widgets) are matched by comparing the
/// [InlineSpan.toPlainText] with the given `pattern`.
///
/// For [EditableText] widgets, the `pattern` is always compared to the currentt
/// value of the [EditableText.controller].
///
/// If the `skipOffstage` argument is true (the default), then this skips
/// nodes that are [Offstage] or that are from inactive [Route]s.
///
/// ## Sample code
///
...
...
@@ -75,9 +87,27 @@ class CommonFinders {
/// expect(find.textContain(RegExp(r'(\w+)')), findsOneWidget);
/// ```
///
/// If the `skipOffstage` argument is true (the default), then this skips
/// nodes that are [Offstage] or that are from inactive [Route]s.
Finder
textContaining
(
Pattern
pattern
,
{
bool
skipOffstage
=
true
})
=>
_TextContainingFinder
(
pattern
,
skipOffstage:
skipOffstage
);
/// This will match [Text], [Text.rich], and [EditableText] widgets that
/// contain the given pattern : 'Back' or RegExp(r'(\w+)').
///
/// ```dart
/// expect(find.textContain('Close', findRichText: true), findsOneWidget);
/// expect(find.textContain(RegExp(r'(\w+)'), findRichText: true), findsOneWidget);
/// ```
///
/// This will match [Text], [Text.rich], [EditableText], as well as standalone
/// [RichText] widgets that contain the given pattern : 'Close' or RegExp(r'(\w+)').
Finder
textContaining
(
Pattern
pattern
,
{
bool
findRichText
=
false
,
bool
skipOffstage
=
true
,
})
{
return
_TextContainingFinder
(
pattern
,
findRichText:
findRichText
,
skipOffstage:
skipOffstage
);
}
/// Looks for widgets that contain a [Text] descendant with `text`
/// in it.
...
...
@@ -634,15 +664,12 @@ abstract class MatchFinder extends Finder {
}
}
class
_TextFinder
extends
MatchFinder
{
_TextFinder
(
this
.
text
,
{
abstract
class
_MatchTextFinder
extends
MatchFinder
{
_MatchTextFinder
({
this
.
findRichText
=
false
,
bool
skipOffstage
=
true
,
})
:
super
(
skipOffstage:
skipOffstage
);
final
String
text
;
/// Whether standalone [RichText] widgets should be found or not.
///
/// Defaults to `false`.
...
...
@@ -656,17 +683,18 @@ class _TextFinder extends MatchFinder {
/// In either case, [EditableText] widgets will also be matched.
final
bool
findRichText
;
@override
String
get
description
=>
'text "
$text
"'
;
bool
matchesText
(
String
textToMatch
);
@override
bool
matches
(
Element
candidate
)
{
final
Widget
widget
=
candidate
.
widget
;
if
(
widget
is
EditableText
)
if
(
widget
is
EditableText
)
{
return
_matchesEditableText
(
widget
);
}
if
(!
findRichText
)
if
(!
findRichText
)
{
return
_matchesNonRichText
(
widget
);
}
// It would be sufficient to always use _matchesRichText if we wanted to
// match both standalone RichText widgets as well as Text widgets. However,
// the find.text() finder used to always ignore standalone RichText widgets,
...
...
@@ -676,29 +704,52 @@ class _TextFinder extends MatchFinder {
}
bool
_matchesRichText
(
Widget
widget
)
{
if
(
widget
is
RichText
)
return
widget
.
text
.
toPlainText
()
==
text
;
if
(
widget
is
RichText
)
{
return
matchesText
(
widget
.
text
.
toPlainText
());
}
return
false
;
}
bool
_matchesNonRichText
(
Widget
widget
)
{
if
(
widget
is
Text
)
{
if
(
widget
.
data
!=
null
)
return
widget
.
data
==
text
;
if
(
widget
.
data
!=
null
)
{
return
matchesText
(
widget
.
data
!);
}
assert
(
widget
.
textSpan
!=
null
);
return
widget
.
textSpan
!.
toPlainText
()
==
text
;
return
matchesText
(
widget
.
textSpan
!.
toPlainText
())
;
}
return
false
;
}
bool
_matchesEditableText
(
EditableText
widget
)
{
return
widget
.
controller
.
text
==
text
;
return
matchesText
(
widget
.
controller
.
text
)
;
}
}
class
_TextContainingFinder
extends
MatchFinder
{
_TextContainingFinder
(
this
.
pattern
,
{
bool
skipOffstage
=
true
})
:
super
(
skipOffstage:
skipOffstage
);
class
_TextFinder
extends
_MatchTextFinder
{
_TextFinder
(
this
.
text
,
{
bool
findRichText
=
false
,
bool
skipOffstage
=
true
,
})
:
super
(
findRichText:
findRichText
,
skipOffstage:
skipOffstage
);
final
String
text
;
@override
String
get
description
=>
'text "
$text
"'
;
@override
bool
matchesText
(
String
textToMatch
)
{
return
textToMatch
==
text
;
}
}
class
_TextContainingFinder
extends
_MatchTextFinder
{
_TextContainingFinder
(
this
.
pattern
,
{
bool
findRichText
=
false
,
bool
skipOffstage
=
true
,
})
:
super
(
findRichText:
findRichText
,
skipOffstage:
skipOffstage
);
final
Pattern
pattern
;
...
...
@@ -706,17 +757,8 @@ class _TextContainingFinder extends MatchFinder {
String
get
description
=>
'text containing
$pattern
'
;
@override
bool
matches
(
Element
candidate
)
{
final
Widget
widget
=
candidate
.
widget
;
if
(
widget
is
Text
)
{
if
(
widget
.
data
!=
null
)
return
widget
.
data
!.
contains
(
pattern
);
assert
(
widget
.
textSpan
!=
null
);
return
widget
.
textSpan
!.
toPlainText
().
contains
(
pattern
);
}
else
if
(
widget
is
EditableText
)
{
return
widget
.
controller
.
text
.
contains
(
pattern
);
}
return
false
;
bool
matchesText
(
String
textToMatch
)
{
return
textToMatch
.
contains
(
pattern
);
}
}
...
...
packages/flutter_test/test/finders_test.dart
View file @
4f4c7816
...
...
@@ -166,6 +166,84 @@ void main() {
expect
(
find
.
textContaining
(
RegExp
(
r'test'
)),
findsOneWidget
);
expect
(
find
.
textContaining
(
'test'
),
findsOneWidget
);
});
group
(
'findRichText'
,
()
{
testWidgets
(
'finds RichText widgets when enabled'
,
(
WidgetTester
tester
)
async
{
await
tester
.
pumpWidget
(
_boilerplate
(
RichText
(
text:
const
TextSpan
(
text:
't'
,
children:
<
TextSpan
>[
TextSpan
(
text:
'est'
),
],
),
)));
expect
(
find
.
textContaining
(
'te'
,
findRichText:
true
),
findsOneWidget
);
});
testWidgets
(
'finds Text widgets once when enabled'
,
(
WidgetTester
tester
)
async
{
await
tester
.
pumpWidget
(
_boilerplate
(
const
Text
(
'test2'
)));
expect
(
find
.
textContaining
(
'tes'
,
findRichText:
true
),
findsOneWidget
);
});
testWidgets
(
'does not find RichText widgets when disabled'
,
(
WidgetTester
tester
)
async
{
await
tester
.
pumpWidget
(
_boilerplate
(
RichText
(
text:
const
TextSpan
(
text:
't'
,
children:
<
TextSpan
>[
TextSpan
(
text:
'est'
),
],
),
)));
expect
(
find
.
textContaining
(
'te'
),
findsNothing
);
});
testWidgets
(
'does not find Text and RichText separated by semantics widgets twice'
,
(
WidgetTester
tester
)
async
{
// If rich: true found both Text and RichText, this would find two widgets.
await
tester
.
pumpWidget
(
_boilerplate
(
const
Text
(
'test'
,
semanticsLabel:
'foo'
),
));
expect
(
find
.
textContaining
(
'tes'
),
findsOneWidget
);
});
testWidgets
(
'finds Text.rich widgets when enabled'
,
(
WidgetTester
tester
)
async
{
await
tester
.
pumpWidget
(
_boilerplate
(
const
Text
.
rich
(
TextSpan
(
text:
't'
,
children:
<
TextSpan
>[
TextSpan
(
text:
'est'
),
TextSpan
(
text:
'3'
),
],
),
)));
expect
(
find
.
textContaining
(
't3'
,
findRichText:
true
),
findsOneWidget
);
});
testWidgets
(
'finds Text.rich widgets when disabled'
,
(
WidgetTester
tester
)
async
{
await
tester
.
pumpWidget
(
_boilerplate
(
const
Text
.
rich
(
TextSpan
(
text:
't'
,
children:
<
TextSpan
>[
TextSpan
(
text:
'est'
),
TextSpan
(
text:
'3'
),
],
),
)));
expect
(
find
.
textContaining
(
't3'
),
findsOneWidget
);
});
});
});
group
(
'semantics'
,
()
{
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment