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
4373a319
Unverified
Commit
4373a319
authored
5 years ago
by
Michael Goderbauer
Committed by
GitHub
5 years ago
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Reapply "Revert "Propagate textfield character limits to semantics (#40468)" (#40767)
parent
f19f040a
Changes
17
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
17 changed files
with
458 additions
and
25 deletions
+458
-25
main_test.dart
...ests/android_semantics_testing/test_driver/main_test.dart
+10
-2
text_field.dart
packages/flutter/lib/src/material/text_field.dart
+21
-10
custom_paint.dart
packages/flutter/lib/src/rendering/custom_paint.dart
+6
-0
proxy_box.dart
packages/flutter/lib/src/rendering/proxy_box.dart
+32
-0
semantics.dart
packages/flutter/lib/src/semantics/semantics.dart
+132
-2
basic.dart
packages/flutter/lib/src/widgets/basic.dart
+8
-0
text_field_test.dart
packages/flutter/test/material/text_field_test.dart
+62
-0
semantics_test.dart
packages/flutter/test/semantics/semantics_test.dart
+4
-0
semantics_debugger_test.dart
packages/flutter/test/widgets/semantics_debugger_test.dart
+13
-2
semantics_tester.dart
packages/flutter/test/widgets/semantics_tester.dart
+31
-1
find.dart
packages/flutter_driver/lib/src/common/find.dart
+12
-0
driver.dart
packages/flutter_driver/lib/src/driver/driver.dart
+10
-2
extension.dart
packages/flutter_driver/lib/src/extension/extension.dart
+4
-2
extension_test.dart
packages/flutter_driver/test/src/extension_test.dart
+81
-0
find_test.dart
packages/flutter_driver/test/src/find_test.dart
+12
-4
matchers.dart
packages/flutter_test/lib/src/matchers.dart
+16
-0
matchers_test.dart
packages/flutter_test/test/matchers_test.dart
+4
-0
No files found.
dev/integration_tests/android_semantics_testing/test_driver/main_test.dart
View file @
4373a319
...
...
@@ -64,7 +64,11 @@ void main() {
});
test
(
'TextField has correct Android semantics'
,
()
async
{
final
SerializableFinder
normalTextField
=
find
.
byValueKey
(
normalTextFieldKeyValue
);
final
SerializableFinder
normalTextField
=
find
.
descendant
(
of:
find
.
byValueKey
(
normalTextFieldKeyValue
),
matching:
find
.
byType
(
'Semantics'
),
firstMatchOnly:
true
,
);
expect
(
await
getSemantics
(
normalTextField
),
hasAndroidSemantics
(
className:
AndroidClassName
.
editText
,
isEditable:
true
,
...
...
@@ -112,7 +116,11 @@ void main() {
});
test
(
'password TextField has correct Android semantics'
,
()
async
{
final
SerializableFinder
passwordTextField
=
find
.
byValueKey
(
passwordTextFieldKeyValue
);
final
SerializableFinder
passwordTextField
=
find
.
descendant
(
of:
find
.
byValueKey
(
passwordTextFieldKeyValue
),
matching:
find
.
byType
(
'Semantics'
),
firstMatchOnly:
true
,
);
expect
(
await
getSemantics
(
passwordTextField
),
hasAndroidSemantics
(
className:
AndroidClassName
.
editText
,
isEditable:
true
,
...
...
This diff is collapsed.
Click to expand it.
packages/flutter/lib/src/material/text_field.dart
View file @
4373a319
...
...
@@ -753,6 +753,8 @@ class _TextFieldState extends State<TextField> with AutomaticKeepAliveClientMixi
bool
get
_isEnabled
=>
widget
.
enabled
??
widget
.
decoration
?.
enabled
??
true
;
int
get
_currentLength
=>
_effectiveController
.
value
.
text
.
runes
.
length
;
InputDecoration
_getEffectiveDecoration
()
{
final
MaterialLocalizations
localizations
=
MaterialLocalizations
.
of
(
context
);
final
ThemeData
themeData
=
Theme
.
of
(
context
);
...
...
@@ -769,7 +771,7 @@ class _TextFieldState extends State<TextField> with AutomaticKeepAliveClientMixi
// If buildCounter was provided, use it to generate a counter widget.
Widget
counter
;
final
int
currentLength
=
_
effectiveController
.
value
.
text
.
runes
.
l
ength
;
final
int
currentLength
=
_
currentL
ength
;
if
(
effectiveDecoration
.
counter
==
null
&&
effectiveDecoration
.
counterText
==
null
&&
widget
.
buildCounter
!=
null
)
{
...
...
@@ -1099,18 +1101,27 @@ class _TextFieldState extends State<TextField> with AutomaticKeepAliveClientMixi
child:
child
,
);
}
return
Semantics
(
onTap:
()
{
if
(!
_effectiveController
.
selection
.
isValid
)
_effectiveController
.
selection
=
TextSelection
.
collapsed
(
offset:
_effectiveController
.
text
.
length
);
_requestKeyboard
();
},
return
IgnorePointer
(
ignoring:
!
_isEnabled
,
child:
MouseRegion
(
onEnter:
_handleMouseEnter
,
onExit:
_handleMouseExit
,
child:
IgnorePointer
(
ignoring:
!
_isEnabled
,
child:
AnimatedBuilder
(
animation:
controller
,
// changes the _currentLength
builder:
(
BuildContext
context
,
Widget
child
)
{
return
Semantics
(
maxValueLength:
widget
.
maxLengthEnforced
&&
widget
.
maxLength
!=
null
&&
widget
.
maxLength
>
0
?
widget
.
maxLength
:
null
,
currentValueLength:
_currentLength
,
onTap:
()
{
if
(!
_effectiveController
.
selection
.
isValid
)
_effectiveController
.
selection
=
TextSelection
.
collapsed
(
offset:
_effectiveController
.
text
.
length
);
_requestKeyboard
();
},
child:
child
,
);
},
child:
_selectionGestureDetectorBuilder
.
buildGestureDetector
(
behavior:
HitTestBehavior
.
translucent
,
child:
child
,
...
...
This diff is collapsed.
Click to expand it.
packages/flutter/lib/src/rendering/custom_paint.dart
View file @
4373a319
...
...
@@ -864,6 +864,12 @@ class RenderCustomPaint extends RenderProxyBox {
if
(
properties
.
liveRegion
!=
null
)
{
config
.
liveRegion
=
properties
.
liveRegion
;
}
if
(
properties
.
maxValueLength
!=
null
)
{
config
.
maxValueLength
=
properties
.
maxValueLength
;
}
if
(
properties
.
currentValueLength
!=
null
)
{
config
.
currentValueLength
=
properties
.
currentValueLength
;
}
if
(
properties
.
toggled
!=
null
)
{
config
.
isToggled
=
properties
.
toggled
;
}
...
...
This diff is collapsed.
Click to expand it.
packages/flutter/lib/src/rendering/proxy_box.dart
View file @
4373a319
...
...
@@ -3497,6 +3497,8 @@ class RenderSemanticsAnnotations extends RenderProxyBox {
bool
hidden
,
bool
image
,
bool
liveRegion
,
int
maxValueLength
,
int
currentValueLength
,
String
label
,
String
value
,
String
increasedValue
,
...
...
@@ -3544,6 +3546,8 @@ class RenderSemanticsAnnotations extends RenderProxyBox {
_scopesRoute
=
scopesRoute
,
_namesRoute
=
namesRoute
,
_liveRegion
=
liveRegion
,
_maxValueLength
=
maxValueLength
,
_currentValueLength
=
currentValueLength
,
_hidden
=
hidden
,
_image
=
image
,
_onDismiss
=
onDismiss
,
...
...
@@ -3799,6 +3803,28 @@ class RenderSemanticsAnnotations extends RenderProxyBox {
markNeedsSemanticsUpdate
();
}
/// If non-null, sets the [SemanticsNode.maxValueLength] semantic to the given
/// value.
int
get
maxValueLength
=>
_maxValueLength
;
int
_maxValueLength
;
set
maxValueLength
(
int
value
)
{
if
(
_maxValueLength
==
value
)
return
;
_maxValueLength
=
value
;
markNeedsSemanticsUpdate
();
}
/// If non-null, sets the [SemanticsNode.currentValueLength] semantic to the
/// given value.
int
get
currentValueLength
=>
_currentValueLength
;
int
_currentValueLength
;
set
currentValueLength
(
int
value
)
{
if
(
_currentValueLength
==
value
)
return
;
_currentValueLength
=
value
;
markNeedsSemanticsUpdate
();
}
/// If non-null, sets the [SemanticsNode.isToggled] semantic to the given
/// value.
bool
get
toggled
=>
_toggled
;
...
...
@@ -4370,6 +4396,12 @@ class RenderSemanticsAnnotations extends RenderProxyBox {
config
.
namesRoute
=
namesRoute
;
if
(
liveRegion
!=
null
)
config
.
liveRegion
=
liveRegion
;
if
(
maxValueLength
!=
null
)
{
config
.
maxValueLength
=
maxValueLength
;
}
if
(
currentValueLength
!=
null
)
{
config
.
currentValueLength
=
currentValueLength
;
}
if
(
textDirection
!=
null
)
config
.
textDirection
=
textDirection
;
if
(
sortKey
!=
null
)
...
...
This diff is collapsed.
Click to expand it.
packages/flutter/lib/src/semantics/semantics.dart
View file @
4373a319
This diff is collapsed.
Click to expand it.
packages/flutter/lib/src/widgets/basic.dart
View file @
4373a319
...
...
@@ -6196,6 +6196,8 @@ class Semantics extends SingleChildRenderObjectWidget {
bool
hidden
,
bool
image
,
bool
liveRegion
,
int
maxValueLength
,
int
currentValueLength
,
String
label
,
String
value
,
String
increasedValue
,
...
...
@@ -6247,6 +6249,8 @@ class Semantics extends SingleChildRenderObjectWidget {
hidden:
hidden
,
image:
image
,
liveRegion:
liveRegion
,
maxValueLength:
maxValueLength
,
currentValueLength:
currentValueLength
,
label:
label
,
value:
value
,
increasedValue:
increasedValue
,
...
...
@@ -6350,6 +6354,8 @@ class Semantics extends SingleChildRenderObjectWidget {
readOnly:
properties
.
readOnly
,
focused:
properties
.
focused
,
liveRegion:
properties
.
liveRegion
,
maxValueLength:
properties
.
maxValueLength
,
currentValueLength:
properties
.
currentValueLength
,
inMutuallyExclusiveGroup:
properties
.
inMutuallyExclusiveGroup
,
obscured:
properties
.
obscured
,
multiline:
properties
.
multiline
,
...
...
@@ -6422,6 +6428,8 @@ class Semantics extends SingleChildRenderObjectWidget {
..
hidden
=
properties
.
hidden
..
image
=
properties
.
image
..
liveRegion
=
properties
.
liveRegion
..
maxValueLength
=
properties
.
maxValueLength
..
currentValueLength
=
properties
.
currentValueLength
..
label
=
properties
.
label
..
value
=
properties
.
value
..
increasedValue
=
properties
.
increasedValue
...
...
This diff is collapsed.
Click to expand it.
packages/flutter/test/material/text_field_test.dart
View file @
4373a319
...
...
@@ -3367,6 +3367,68 @@ void main() {
semantics
.
dispose
();
});
testWidgets
(
'Disabled text field does not have tap action'
,
(
WidgetTester
tester
)
async
{
final
SemanticsTester
semantics
=
SemanticsTester
(
tester
);
await
tester
.
pumpWidget
(
const
MaterialApp
(
home:
Material
(
child:
Center
(
child:
TextField
(
maxLength:
10
,
enabled:
false
,
),
),
),
),
);
expect
(
semantics
,
isNot
(
includesNodeWith
(
actions:
<
SemanticsAction
>[
SemanticsAction
.
tap
])));
semantics
.
dispose
();
});
testWidgets
(
'currentValueLength/maxValueLength are in the tree'
,
(
WidgetTester
tester
)
async
{
final
SemanticsTester
semantics
=
SemanticsTester
(
tester
);
final
TextEditingController
controller
=
TextEditingController
();
await
tester
.
pumpWidget
(
MaterialApp
(
home:
Material
(
child:
Center
(
child:
TextField
(
controller:
controller
,
maxLength:
10
,
),
),
),
),
);
expect
(
semantics
,
includesNodeWith
(
flags:
<
SemanticsFlag
>[
SemanticsFlag
.
isTextField
],
maxValueLength:
10
,
currentValueLength:
0
,
));
await
tester
.
showKeyboard
(
find
.
byType
(
TextField
));
const
String
testValue
=
'123'
;
tester
.
testTextInput
.
updateEditingValue
(
const
TextEditingValue
(
text:
testValue
,
selection:
TextSelection
.
collapsed
(
offset:
3
),
composing:
TextRange
(
start:
0
,
end:
testValue
.
length
),
));
await
tester
.
pump
();
expect
(
semantics
,
includesNodeWith
(
flags:
<
SemanticsFlag
>[
SemanticsFlag
.
isTextField
,
SemanticsFlag
.
isFocused
],
maxValueLength:
10
,
currentValueLength:
3
,
));
semantics
.
dispose
();
});
testWidgets
(
'Read only TextField identifies as read only text field in semantics'
,
(
WidgetTester
tester
)
async
{
final
SemanticsTester
semantics
=
SemanticsTester
(
tester
);
...
...
This diff is collapsed.
Click to expand it.
packages/flutter/test/semantics/semantics_test.dart
View file @
4373a319
...
...
@@ -447,6 +447,8 @@ void main() {
' textDirection: null
\n
'
' sortKey: null
\n
'
' platformViewId: null
\n
'
' maxValueLength: null
\n
'
' currentValueLength: null
\n
'
' scrollChildren: null
\n
'
' scrollIndex: null
\n
'
' scrollExtentMin: null
\n
'
...
...
@@ -543,6 +545,8 @@ void main() {
' textDirection: null
\n
'
' sortKey: null
\n
'
' platformViewId: null
\n
'
' maxValueLength: null
\n
'
' currentValueLength: null
\n
'
' scrollChildren: null
\n
'
' scrollIndex: null
\n
'
' scrollExtentMin: null
\n
'
...
...
This diff is collapsed.
Click to expand it.
packages/flutter/test/widgets/semantics_debugger_test.dart
View file @
4373a319
...
...
@@ -452,8 +452,11 @@ void main() {
),
);
final
dynamic
semanticsDebuggerPainter
=
_getSemanticsDebuggerPainter
(
debuggerKey:
debugger
,
tester:
tester
);
final
RenderObject
renderTextfield
=
tester
.
renderObject
(
find
.
descendant
(
of:
find
.
byKey
(
textField
),
matching:
find
.
byType
(
Semantics
)).
first
);
expect
(
_getMessageShownInSemanticsDebugger
(
widgetKey:
textField
,
debuggerKey:
debugger
,
tester:
tester
),
semanticsDebuggerPainter
.
getMessage
(
renderTextfield
.
debugSemantics
),
'textfield'
,
);
});
...
...
@@ -463,6 +466,14 @@ String _getMessageShownInSemanticsDebugger({
@required
Key
widgetKey
,
@required
Key
debuggerKey
,
@required
WidgetTester
tester
,
})
{
final
dynamic
semanticsDebuggerPainter
=
_getSemanticsDebuggerPainter
(
debuggerKey:
debuggerKey
,
tester:
tester
);
return
semanticsDebuggerPainter
.
getMessage
(
tester
.
renderObject
(
find
.
byKey
(
widgetKey
)).
debugSemantics
);
}
dynamic
_getSemanticsDebuggerPainter
(
{
@required
Key
debuggerKey
,
@required
WidgetTester
tester
,
})
{
final
CustomPaint
customPaint
=
tester
.
widgetList
(
find
.
descendant
(
of:
find
.
byKey
(
debuggerKey
),
...
...
@@ -470,5 +481,5 @@ String _getMessageShownInSemanticsDebugger({
)).
first
;
final
dynamic
semanticsDebuggerPainter
=
customPaint
.
foregroundPainter
;
expect
(
semanticsDebuggerPainter
.
runtimeType
.
toString
(),
'_SemanticsDebuggerPainter'
);
return
semanticsDebuggerPainter
.
getMessage
(
tester
.
renderObject
(
find
.
byKey
(
widgetKey
)).
debugSemantics
)
;
return
semanticsDebuggerPainter
;
}
This diff is collapsed.
Click to expand it.
packages/flutter/test/widgets/semantics_tester.dart
View file @
4373a319
...
...
@@ -442,6 +442,8 @@ class SemanticsTester {
double
scrollPosition
,
double
scrollExtentMax
,
double
scrollExtentMin
,
int
currentValueLength
,
int
maxValueLength
,
SemanticsNode
ancestor
,
})
{
bool
checkNode
(
SemanticsNode
node
)
{
...
...
@@ -471,6 +473,12 @@ class SemanticsTester {
return
false
;
if
(
scrollExtentMin
!=
null
&&
!
nearEqual
(
node
.
scrollExtentMin
,
scrollExtentMin
,
0.1
))
return
false
;
if
(
currentValueLength
!=
null
&&
node
.
currentValueLength
!=
currentValueLength
)
{
return
false
;
}
if
(
maxValueLength
!=
null
&&
node
.
maxValueLength
!=
maxValueLength
)
{
return
false
;
}
return
true
;
}
...
...
@@ -713,7 +721,19 @@ class _IncludesNodeWith extends Matcher {
this
.
scrollPosition
,
this
.
scrollExtentMax
,
this
.
scrollExtentMin
,
})
:
assert
(
label
!=
null
||
value
!=
null
||
actions
!=
null
||
flags
!=
null
||
scrollPosition
!=
null
||
scrollExtentMax
!=
null
||
scrollExtentMin
!=
null
);
this
.
maxValueLength
,
this
.
currentValueLength
,
})
:
assert
(
label
!=
null
||
value
!=
null
||
actions
!=
null
||
flags
!=
null
||
scrollPosition
!=
null
||
scrollExtentMax
!=
null
||
scrollExtentMin
!=
null
||
maxValueLength
!=
null
||
currentValueLength
!=
null
);
final
String
label
;
final
String
value
;
...
...
@@ -724,6 +744,8 @@ class _IncludesNodeWith extends Matcher {
final
double
scrollPosition
;
final
double
scrollExtentMax
;
final
double
scrollExtentMin
;
final
int
currentValueLength
;
final
int
maxValueLength
;
@override
bool
matches
(
covariant
SemanticsTester
item
,
Map
<
dynamic
,
dynamic
>
matchState
)
{
...
...
@@ -737,6 +759,8 @@ class _IncludesNodeWith extends Matcher {
scrollPosition:
scrollPosition
,
scrollExtentMax:
scrollExtentMax
,
scrollExtentMin:
scrollExtentMin
,
currentValueLength:
currentValueLength
,
maxValueLength:
maxValueLength
,
).
isNotEmpty
;
}
...
...
@@ -761,6 +785,8 @@ class _IncludesNodeWith extends Matcher {
if
(
scrollPosition
!=
null
)
'scrollPosition "
$scrollPosition
"'
,
if
(
scrollExtentMax
!=
null
)
'scrollExtentMax "
$scrollExtentMax
"'
,
if
(
scrollExtentMin
!=
null
)
'scrollExtentMin "
$scrollExtentMin
"'
,
if
(
currentValueLength
!=
null
)
'currentValueLength "
$currentValueLength
"'
,
if
(
maxValueLength
!=
null
)
'maxValueLength "
$maxValueLength
"'
,
];
return
strings
.
join
(
', '
);
}
...
...
@@ -780,6 +806,8 @@ Matcher includesNodeWith({
double
scrollPosition
,
double
scrollExtentMax
,
double
scrollExtentMin
,
int
maxValueLength
,
int
currentValueLength
,
})
{
return
_IncludesNodeWith
(
label:
label
,
...
...
@@ -791,5 +819,7 @@ Matcher includesNodeWith({
scrollPosition:
scrollPosition
,
scrollExtentMax:
scrollExtentMax
,
scrollExtentMin:
scrollExtentMin
,
maxValueLength:
maxValueLength
,
currentValueLength:
currentValueLength
,
);
}
This diff is collapsed.
Click to expand it.
packages/flutter_driver/lib/src/common/find.dart
View file @
4373a319
...
...
@@ -317,6 +317,7 @@ class Descendant extends SerializableFinder {
@required
this
.
of
,
@required
this
.
matching
,
this
.
matchRoot
=
false
,
this
.
firstMatchOnly
=
false
,
});
/// The finder specifying the widget of which the descendant is to be found.
...
...
@@ -328,6 +329,9 @@ class Descendant extends SerializableFinder {
/// Whether the widget matching [of] will be considered for a match.
final
bool
matchRoot
;
/// If true then only the first descendant matching `matching` will be returned.
final
bool
firstMatchOnly
;
@override
String
get
finderType
=>
'Descendant'
;
...
...
@@ -338,6 +342,7 @@ class Descendant extends SerializableFinder {
..
addAll
(
matching
.
serialize
().
map
((
String
key
,
String
value
)
=>
MapEntry
<
String
,
String
>(
'matching_
$key
'
,
value
)))
..
addAll
(<
String
,
String
>{
'matchRoot'
:
matchRoot
?
'true'
:
'false'
,
'firstMatchOnly'
:
firstMatchOnly
?
'true'
:
'false'
,
});
}
...
...
@@ -359,6 +364,7 @@ class Descendant extends SerializableFinder {
of:
SerializableFinder
.
deserialize
(
of
),
matching:
SerializableFinder
.
deserialize
(
matching
),
matchRoot:
other
[
'matchRoot'
]
==
'true'
,
firstMatchOnly:
other
[
'firstMatchOnly'
]
==
'true'
,
);
}
}
...
...
@@ -374,6 +380,7 @@ class Ancestor extends SerializableFinder {
@required
this
.
of
,
@required
this
.
matching
,
this
.
matchRoot
=
false
,
this
.
firstMatchOnly
=
false
,
});
/// The finder specifying the widget of which the ancestor is to be found.
...
...
@@ -385,6 +392,9 @@ class Ancestor extends SerializableFinder {
/// Whether the widget matching [of] will be considered for a match.
final
bool
matchRoot
;
/// If true then only the first ancestor matching `matching` will be returned.
final
bool
firstMatchOnly
;
@override
String
get
finderType
=>
'Ancestor'
;
...
...
@@ -395,6 +405,7 @@ class Ancestor extends SerializableFinder {
..
addAll
(
matching
.
serialize
().
map
((
String
key
,
String
value
)
=>
MapEntry
<
String
,
String
>(
'matching_
$key
'
,
value
)))
..
addAll
(<
String
,
String
>{
'matchRoot'
:
matchRoot
?
'true'
:
'false'
,
'firstMatchOnly'
:
firstMatchOnly
?
'true'
:
'false'
,
});
}
...
...
@@ -416,6 +427,7 @@ class Ancestor extends SerializableFinder {
of:
SerializableFinder
.
deserialize
(
of
),
matching:
SerializableFinder
.
deserialize
(
matching
),
matchRoot:
other
[
'matchRoot'
]
==
'true'
,
firstMatchOnly:
other
[
'firstMatchOnly'
]
==
'true'
,
);
}
}
...
...
This diff is collapsed.
Click to expand it.
packages/flutter_driver/lib/src/driver/driver.dart
View file @
4373a319
...
...
@@ -1199,22 +1199,30 @@ class CommonFinders {
///
/// If the `matchRoot` argument is true then the widget specified by `of` will
/// be considered for a match. The argument defaults to false.
///
/// If `firstMatchOnly` is true then only the first ancestor matching
/// `matching` will be returned. Defaults to false.
SerializableFinder
ancestor
({
@required
SerializableFinder
of
,
@required
SerializableFinder
matching
,
bool
matchRoot
=
false
,
})
=>
Ancestor
(
of:
of
,
matching:
matching
,
matchRoot:
matchRoot
);
bool
firstMatchOnly
=
false
,
})
=>
Ancestor
(
of:
of
,
matching:
matching
,
matchRoot:
matchRoot
,
firstMatchOnly:
firstMatchOnly
);
/// Finds the widget that is an descendant of the `of` parameter and that
/// matches the `matching` parameter.
///
/// If the `matchRoot` argument is true then the widget specified by `of` will
/// be considered for a match. The argument defaults to false.
///
/// If `firstMatchOnly` is true then only the first descendant matching
/// `matching` will be returned. Defaults to false.
SerializableFinder
descendant
({
@required
SerializableFinder
of
,
@required
SerializableFinder
matching
,
bool
matchRoot
=
false
,
})
=>
Descendant
(
of:
of
,
matching:
matching
,
matchRoot:
matchRoot
);
bool
firstMatchOnly
=
false
,
})
=>
Descendant
(
of:
of
,
matching:
matching
,
matchRoot:
matchRoot
,
firstMatchOnly:
firstMatchOnly
);
}
/// An immutable 2D floating-point offset used by Flutter Driver.
...
...
This diff is collapsed.
Click to expand it.
packages/flutter_driver/lib/src/extension/extension.dart
View file @
4373a319
...
...
@@ -335,19 +335,21 @@ class FlutterDriverExtension {
}
Finder
_createAncestorFinder
(
Ancestor
arguments
)
{
return
find
.
ancestor
(
final
Finder
finder
=
find
.
ancestor
(
of:
_createFinder
(
arguments
.
of
),
matching:
_createFinder
(
arguments
.
matching
),
matchRoot:
arguments
.
matchRoot
,
);
return
arguments
.
firstMatchOnly
?
finder
.
first
:
finder
;
}
Finder
_createDescendantFinder
(
Descendant
arguments
)
{
return
find
.
descendant
(
final
Finder
finder
=
find
.
descendant
(
of:
_createFinder
(
arguments
.
of
),
matching:
_createFinder
(
arguments
.
matching
),
matchRoot:
arguments
.
matchRoot
,
);
return
arguments
.
firstMatchOnly
?
finder
.
first
:
finder
;
}
Finder
_createFinder
(
SerializableFinder
finder
)
{
...
...
This diff is collapsed.
Click to expand it.
packages/flutter_driver/test/src/extension_test.dart
View file @
4373a319
...
...
@@ -573,6 +573,39 @@ void main() {
expect
(
await
result
,
null
);
});
testWidgets
(
'descendant finder firstMatchOnly'
,
(
WidgetTester
tester
)
async
{
flutterDriverLog
.
listen
((
LogRecord
_
)
{});
// Silence logging.
final
FlutterDriverExtension
extension
=
FlutterDriverExtension
((
String
arg
)
async
=>
''
,
true
);
Future
<
String
>
getDescendantText
()
async
{
final
Map
<
String
,
Object
>
arguments
=
GetText
(
Descendant
(
of:
ByValueKey
(
'column'
),
matching:
const
ByType
(
'Text'
),
firstMatchOnly:
true
,
),
timeout:
const
Duration
(
seconds:
1
)).
serialize
();
final
Map
<
String
,
dynamic
>
result
=
await
extension
.
call
(
arguments
);
if
(
result
[
'isError'
])
{
return
null
;
}
return
GetTextResult
.
fromJson
(
result
[
'response'
]).
text
;
}
await
tester
.
pumpWidget
(
MaterialApp
(
home:
Column
(
key:
const
ValueKey
<
String
>(
'column'
),
children:
const
<
Widget
>[
Text
(
'Hello1'
,
key:
ValueKey
<
String
>(
'text1'
)),
Text
(
'Hello2'
,
key:
ValueKey
<
String
>(
'text2'
)),
Text
(
'Hello3'
,
key:
ValueKey
<
String
>(
'text3'
)),
],
),
),
);
expect
(
await
getDescendantText
(),
'Hello1'
);
});
testWidgets
(
'ancestor finder'
,
(
WidgetTester
tester
)
async
{
flutterDriverLog
.
listen
((
LogRecord
_
)
{});
// Silence logging.
final
FlutterDriverExtension
extension
=
FlutterDriverExtension
((
String
arg
)
async
=>
''
,
true
);
...
...
@@ -642,6 +675,54 @@ void main() {
expect
(
await
result
,
null
);
});
testWidgets
(
'ancestor finder firstMatchOnly'
,
(
WidgetTester
tester
)
async
{
flutterDriverLog
.
listen
((
LogRecord
_
)
{});
// Silence logging.
final
FlutterDriverExtension
extension
=
FlutterDriverExtension
((
String
arg
)
async
=>
''
,
true
);
Future
<
Offset
>
getAncestorTopLeft
()
async
{
final
Map
<
String
,
Object
>
arguments
=
GetOffset
(
Ancestor
(
of:
ByValueKey
(
'leaf'
),
matching:
const
ByType
(
'Container'
),
firstMatchOnly:
true
,
),
OffsetType
.
topLeft
,
timeout:
const
Duration
(
seconds:
1
)).
serialize
();
final
Map
<
String
,
dynamic
>
response
=
await
extension
.
call
(
arguments
);
if
(
response
[
'isError'
])
{
return
null
;
}
final
GetOffsetResult
result
=
GetOffsetResult
.
fromJson
(
response
[
'response'
]);
return
Offset
(
result
.
dx
,
result
.
dy
);
}
await
tester
.
pumpWidget
(
MaterialApp
(
home:
Center
(
child:
Container
(
height:
200
,
width:
200
,
child:
Center
(
child:
Container
(
height:
100
,
width:
100
,
child:
Center
(
child:
Container
(
key:
const
ValueKey
<
String
>(
'leaf'
),
height:
50
,
width:
50
,
),
),
),
),
),
),
),
);
expect
(
await
getAncestorTopLeft
(),
const
Offset
((
800
-
100
)
/
2
,
(
600
-
100
)
/
2
),
);
});
testWidgets
(
'GetDiagnosticsTree'
,
(
WidgetTester
tester
)
async
{
final
FlutterDriverExtension
extension
=
FlutterDriverExtension
((
String
arg
)
async
=>
''
,
true
);
...
...
This diff is collapsed.
Click to expand it.
packages/flutter_driver/test/src/find_test.dart
View file @
4373a319
...
...
@@ -15,6 +15,7 @@ void main() {
of:
of
,
matching:
matching
,
matchRoot:
true
,
firstMatchOnly:
true
,
);
expect
(
a
.
serialize
(),
<
String
,
String
>{
'finderType'
:
'Ancestor'
,
...
...
@@ -23,7 +24,8 @@ void main() {
'matching_finderType'
:
'ByValueKey'
,
'matching_keyValueString'
:
'hello'
,
'matching_keyValueType'
:
'String'
,
'matchRoot'
:
'true'
'matchRoot'
:
'true'
,
'firstMatchOnly'
:
'true'
,
});
});
...
...
@@ -35,13 +37,15 @@ void main() {
'matching_finderType'
:
'ByValueKey'
,
'matching_keyValueString'
:
'hello'
,
'matching_keyValueType'
:
'String'
,
'matchRoot'
:
'true'
'matchRoot'
:
'true'
,
'firstMatchOnly'
:
'true'
,
};
final
Ancestor
a
=
Ancestor
.
deserialize
(
serialized
);
expect
(
a
.
of
,
isA
<
ByType
>());
expect
(
a
.
matching
,
isA
<
ByValueKey
>());
expect
(
a
.
matchRoot
,
isTrue
);
expect
(
a
.
firstMatchOnly
,
isTrue
);
});
test
(
'Descendant finder serialize'
,
()
{
...
...
@@ -52,6 +56,7 @@ void main() {
of:
of
,
matching:
matching
,
matchRoot:
true
,
firstMatchOnly:
true
,
);
expect
(
a
.
serialize
(),
<
String
,
String
>{
'finderType'
:
'Descendant'
,
...
...
@@ -60,7 +65,8 @@ void main() {
'matching_finderType'
:
'ByValueKey'
,
'matching_keyValueString'
:
'hello'
,
'matching_keyValueType'
:
'String'
,
'matchRoot'
:
'true'
'matchRoot'
:
'true'
,
'firstMatchOnly'
:
'true'
,
});
});
...
...
@@ -72,12 +78,14 @@ void main() {
'matching_finderType'
:
'ByValueKey'
,
'matching_keyValueString'
:
'hello'
,
'matching_keyValueType'
:
'String'
,
'matchRoot'
:
'true'
'matchRoot'
:
'true'
,
'firstMatchOnly'
:
'true'
,
};
final
Descendant
a
=
Descendant
.
deserialize
(
serialized
);
expect
(
a
.
of
,
isA
<
ByType
>());
expect
(
a
.
matching
,
isA
<
ByValueKey
>());
expect
(
a
.
matchRoot
,
isTrue
);
expect
(
a
.
firstMatchOnly
,
isTrue
);
});
}
This diff is collapsed.
Click to expand it.
packages/flutter_test/lib/src/matchers.dart
View file @
4373a319
...
...
@@ -433,6 +433,8 @@ Matcher matchesSemantics({
double
elevation
,
double
thickness
,
int
platformViewId
,
int
maxValueLength
,
int
currentValueLength
,
// Flags //
bool
hasCheckedState
=
false
,
bool
isChecked
=
false
,
...
...
@@ -552,6 +554,8 @@ Matcher matchesSemantics({
platformViewId:
platformViewId
,
customActions:
customActions
,
hintOverrides:
hintOverrides
,
currentValueLength:
currentValueLength
,
maxValueLength:
maxValueLength
,
children:
children
,
);
}
...
...
@@ -1745,6 +1749,8 @@ class _MatchesSemanticsData extends Matcher {
this
.
elevation
,
this
.
thickness
,
this
.
platformViewId
,
this
.
maxValueLength
,
this
.
currentValueLength
,
this
.
customActions
,
this
.
hintOverrides
,
this
.
children
,
...
...
@@ -1765,6 +1771,8 @@ class _MatchesSemanticsData extends Matcher {
final
double
elevation
;
final
double
thickness
;
final
int
platformViewId
;
final
int
maxValueLength
;
final
int
currentValueLength
;
final
List
<
Matcher
>
children
;
@override
...
...
@@ -1796,6 +1804,10 @@ class _MatchesSemanticsData extends Matcher {
description
.
add
(
' with thickness:
$thickness
'
);
if
(
platformViewId
!=
null
)
description
.
add
(
' with platformViewId:
$platformViewId
'
);
if
(
maxValueLength
!=
null
)
description
.
add
(
' with maxValueLength:
$maxValueLength
'
);
if
(
currentValueLength
!=
null
)
description
.
add
(
' with currentValueLength:
$currentValueLength
'
);
if
(
customActions
!=
null
)
description
.
add
(
' with custom actions:
$customActions
'
);
if
(
hintOverrides
!=
null
)
...
...
@@ -1838,6 +1850,10 @@ class _MatchesSemanticsData extends Matcher {
return
failWithDescription
(
matchState
,
'thickness was:
${data.thickness}
'
);
if
(
platformViewId
!=
null
&&
platformViewId
!=
data
.
platformViewId
)
return
failWithDescription
(
matchState
,
'platformViewId was:
${data.platformViewId}
'
);
if
(
currentValueLength
!=
null
&&
currentValueLength
!=
data
.
currentValueLength
)
return
failWithDescription
(
matchState
,
'currentValueLength was:
${data.currentValueLength}
'
);
if
(
maxValueLength
!=
null
&&
maxValueLength
!=
data
.
maxValueLength
)
return
failWithDescription
(
matchState
,
'maxValueLength was:
${data.maxValueLength}
'
);
if
(
actions
!=
null
)
{
int
actionBits
=
0
;
for
(
SemanticsAction
action
in
actions
)
...
...
This diff is collapsed.
Click to expand it.
packages/flutter_test/test/matchers_test.dart
View file @
4373a319
...
...
@@ -525,6 +525,8 @@ void main() {
scrollExtentMin:
null
,
platformViewId:
105
,
customSemanticsActionIds:
<
int
>[
CustomSemanticsAction
.
getIdentifier
(
action
)],
currentValueLength:
10
,
maxValueLength:
15
,
);
final
_FakeSemanticsNode
node
=
_FakeSemanticsNode
();
node
.
data
=
data
;
...
...
@@ -535,6 +537,8 @@ void main() {
elevation:
3.0
,
thickness:
4.0
,
platformViewId:
105
,
currentValueLength:
10
,
maxValueLength:
15
,
/* Flags */
hasCheckedState:
true
,
isChecked:
true
,
...
...
This diff is collapsed.
Click to expand it.
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