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
b37c3be0
Unverified
Commit
b37c3be0
authored
May 10, 2019
by
Michael Goderbauer
Committed by
GitHub
May 10, 2019
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add ancestor and descendant finders to Driver (#32410)
parent
70514385
Changes
5
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
355 additions
and
0 deletions
+355
-0
find.dart
packages/flutter_driver/lib/src/common/find.dart
+116
-0
driver.dart
packages/flutter_driver/lib/src/driver/driver.dart
+22
-0
extension.dart
packages/flutter_driver/lib/src/extension/extension.dart
+18
-0
extension_test.dart
packages/flutter_driver/test/src/extension_test.dart
+116
-0
find_test.dart
packages/flutter_driver/test/src/find_test.dart
+83
-0
No files found.
packages/flutter_driver/lib/src/common/find.dart
View file @
b37c3be0
...
...
@@ -148,6 +148,8 @@ abstract class SerializableFinder {
case
'BySemanticsLabel'
:
return
BySemanticsLabel
.
deserialize
(
json
);
case
'ByText'
:
return
ByText
.
deserialize
(
json
);
case
'PageBack'
:
return
const
PageBack
();
case
'Descendant'
:
return
Descendant
.
deserialize
(
json
);
case
'Ancestor'
:
return
Ancestor
.
deserialize
(
json
);
}
throw
DriverError
(
'Unsupported search specification type
$finderType
'
);
}
...
...
@@ -317,6 +319,120 @@ class PageBack extends SerializableFinder {
String
get
finderType
=>
'PageBack'
;
}
/// A Flutter Driver finder that finds a descendant of [of] that matches
/// [matching].
///
/// If the `matchRoot` argument is true, then the widget specified by [of] will
/// be considered for a match. The argument defaults to false.
class
Descendant
extends
SerializableFinder
{
/// Creates a descendant finder.
const
Descendant
({
@required
this
.
of
,
@required
this
.
matching
,
this
.
matchRoot
=
false
,
});
/// The finder specifying the widget of which the descendant is to be found.
final
SerializableFinder
of
;
/// Only a descendant of [of] matching this finder will be found.
final
SerializableFinder
matching
;
/// Whether the widget matching [of] will be considered for a match.
final
bool
matchRoot
;
@override
String
get
finderType
=>
'Descendant'
;
@override
Map
<
String
,
String
>
serialize
()
{
return
super
.
serialize
()
..
addAll
(
of
.
serialize
().
map
((
String
key
,
String
value
)
=>
MapEntry
<
String
,
String
>(
'of_
$key
'
,
value
)))
..
addAll
(
matching
.
serialize
().
map
((
String
key
,
String
value
)
=>
MapEntry
<
String
,
String
>(
'matching_
$key
'
,
value
)))
..
addAll
(<
String
,
String
>{
'matchRoot'
:
matchRoot
?
'true'
:
'false'
,
});
}
/// Deserializes the finder from JSON generated by [serialize].
static
Descendant
deserialize
(
Map
<
String
,
String
>
json
)
{
final
Map
<
String
,
String
>
of
=
<
String
,
String
>{};
final
Map
<
String
,
String
>
matching
=
<
String
,
String
>{};
final
Map
<
String
,
String
>
other
=
<
String
,
String
>{};
for
(
String
key
in
json
.
keys
)
{
if
(
key
.
startsWith
(
'of_'
))
{
of
[
key
.
substring
(
'of_'
.
length
)]
=
json
[
key
];
}
else
if
(
key
.
startsWith
(
'matching_'
))
{
matching
[
key
.
substring
(
'matching_'
.
length
)]
=
json
[
key
];
}
else
{
other
[
key
]
=
json
[
key
];
}
}
return
Descendant
(
of:
SerializableFinder
.
deserialize
(
of
),
matching:
SerializableFinder
.
deserialize
(
matching
),
matchRoot:
other
[
'matchRoot'
]
==
'true'
,
);
}
}
/// A Flutter Driver finder that finds an ancestor of [of] that matches
/// [matching].
///
/// If the `matchRoot` argument is true, then the widget specified by [of] will
/// be considered for a match. The argument defaults to false.
class
Ancestor
extends
SerializableFinder
{
/// Creates an ancestor finder.
const
Ancestor
({
@required
this
.
of
,
@required
this
.
matching
,
this
.
matchRoot
=
false
,
});
/// The finder specifying the widget of which the ancestor is to be found.
final
SerializableFinder
of
;
/// Only an ancestor of [of] matching this finder will be found.
final
SerializableFinder
matching
;
/// Whether the widget matching [of] will be considered for a match.
final
bool
matchRoot
;
@override
String
get
finderType
=>
'Ancestor'
;
@override
Map
<
String
,
String
>
serialize
()
{
return
super
.
serialize
()
..
addAll
(
of
.
serialize
().
map
((
String
key
,
String
value
)
=>
MapEntry
<
String
,
String
>(
'of_
$key
'
,
value
)))
..
addAll
(
matching
.
serialize
().
map
((
String
key
,
String
value
)
=>
MapEntry
<
String
,
String
>(
'matching_
$key
'
,
value
)))
..
addAll
(<
String
,
String
>{
'matchRoot'
:
matchRoot
?
'true'
:
'false'
,
});
}
/// Deserializes the finder from JSON generated by [serialize].
static
Ancestor
deserialize
(
Map
<
String
,
String
>
json
)
{
final
Map
<
String
,
String
>
of
=
<
String
,
String
>{};
final
Map
<
String
,
String
>
matching
=
<
String
,
String
>{};
final
Map
<
String
,
String
>
other
=
<
String
,
String
>{};
for
(
String
key
in
json
.
keys
)
{
if
(
key
.
startsWith
(
'of_'
))
{
of
[
key
.
substring
(
'of_'
.
length
)]
=
json
[
key
];
}
else
if
(
key
.
startsWith
(
'matching_'
))
{
matching
[
key
.
substring
(
'matching_'
.
length
)]
=
json
[
key
];
}
else
{
other
[
key
]
=
json
[
key
];
}
}
return
Ancestor
(
of:
SerializableFinder
.
deserialize
(
of
),
matching:
SerializableFinder
.
deserialize
(
matching
),
matchRoot:
other
[
'matchRoot'
]
==
'true'
,
);
}
}
/// A Flutter driver command that retrieves a semantics id using a specified finder.
///
/// This command requires assertions to be enabled on the device.
...
...
packages/flutter_driver/lib/src/driver/driver.dart
View file @
b37c3be0
...
...
@@ -1017,6 +1017,28 @@ class CommonFinders {
/// Finds the back button on a Material or Cupertino page's scaffold.
SerializableFinder
pageBack
()
=>
const
PageBack
();
/// Finds the widget that is an ancestor 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.
SerializableFinder
ancestor
({
@required
SerializableFinder
of
,
@required
SerializableFinder
matching
,
bool
matchRoot
=
false
,
})
=>
Ancestor
(
of:
of
,
matching:
matching
,
matchRoot:
matchRoot
);
/// 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.
SerializableFinder
descendant
({
@required
SerializableFinder
of
,
@required
SerializableFinder
matching
,
bool
matchRoot
=
false
,
})
=>
Descendant
(
of:
of
,
matching:
matching
,
matchRoot:
matchRoot
);
}
/// An immutable 2D floating-point offset used by Flutter Driver.
...
...
packages/flutter_driver/lib/src/extension/extension.dart
View file @
b37c3be0
...
...
@@ -142,6 +142,8 @@ class FlutterDriverExtension {
'ByValueKey'
:
(
SerializableFinder
finder
)
=>
_createByValueKeyFinder
(
finder
),
'ByType'
:
(
SerializableFinder
finder
)
=>
_createByTypeFinder
(
finder
),
'PageBack'
:
(
SerializableFinder
finder
)
=>
_createPageBackFinder
(),
'Ancestor'
:
(
SerializableFinder
finder
)
=>
_createAncestorFinder
(
finder
),
'Descendant'
:
(
SerializableFinder
finder
)
=>
_createDescendantFinder
(
finder
),
});
}
...
...
@@ -310,6 +312,22 @@ class FlutterDriverExtension {
},
description:
'Material or Cupertino back button'
);
}
Finder
_createAncestorFinder
(
Ancestor
arguments
)
{
return
find
.
ancestor
(
of:
_createFinder
(
arguments
.
of
),
matching:
_createFinder
(
arguments
.
matching
),
matchRoot:
arguments
.
matchRoot
,
);
}
Finder
_createDescendantFinder
(
Descendant
arguments
)
{
return
find
.
descendant
(
of:
_createFinder
(
arguments
.
of
),
matching:
_createFinder
(
arguments
.
matching
),
matchRoot:
arguments
.
matchRoot
,
);
}
Finder
_createFinder
(
SerializableFinder
finder
)
{
final
FinderConstructor
constructor
=
_finders
[
finder
.
finderType
];
...
...
packages/flutter_driver/test/src/extension_test.dart
View file @
b37c3be0
...
...
@@ -2,12 +2,15 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import
'package:flutter/material.dart'
;
import
'package:flutter/rendering.dart'
;
import
'package:flutter/scheduler.dart'
;
import
'package:flutter/widgets.dart'
;
import
'package:flutter_driver/flutter_driver.dart'
;
import
'package:flutter_driver/src/common/find.dart'
;
import
'package:flutter_driver/src/common/geometry.dart'
;
import
'package:flutter_driver/src/common/request_data.dart'
;
import
'package:flutter_driver/src/common/text.dart'
;
import
'package:flutter_driver/src/extension/extension.dart'
;
import
'package:flutter_test/flutter_test.dart'
;
...
...
@@ -151,4 +154,117 @@ void main() {
expect
(
await
getOffset
(
OffsetType
.
bottomRight
),
const
Offset
(
40
+
100.0
,
30
+
120.0
));
expect
(
await
getOffset
(
OffsetType
.
center
),
const
Offset
(
40
+
(
100
/
2
),
30
+
(
120
/
2
)));
});
testWidgets
(
'descendant finder'
,
(
WidgetTester
tester
)
async
{
flutterDriverLog
.
listen
((
LogRecord
_
)
{});
// Silence logging.
final
FlutterDriverExtension
extension
=
FlutterDriverExtension
((
String
arg
)
async
=>
''
,
true
);
Future
<
String
>
getDescendantText
({
String
of
,
bool
matchRoot
=
false
})
async
{
final
Map
<
String
,
Object
>
arguments
=
GetText
(
Descendant
(
of:
ByValueKey
(
of
),
matching:
ByValueKey
(
'text2'
),
matchRoot:
matchRoot
,
),
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
(
of:
'column'
),
'Hello2'
);
expect
(
await
getDescendantText
(
of:
'column'
,
matchRoot:
true
),
'Hello2'
);
expect
(
await
getDescendantText
(
of:
'text2'
,
matchRoot:
true
),
'Hello2'
);
// Find nothing
Future
<
String
>
result
=
getDescendantText
(
of:
'text1'
,
matchRoot:
true
);
await
tester
.
pump
(
const
Duration
(
seconds:
2
));
expect
(
await
result
,
null
);
result
=
getDescendantText
(
of:
'text2'
);
await
tester
.
pump
(
const
Duration
(
seconds:
2
));
expect
(
await
result
,
null
);
});
testWidgets
(
'ancestor finder'
,
(
WidgetTester
tester
)
async
{
flutterDriverLog
.
listen
((
LogRecord
_
)
{});
// Silence logging.
final
FlutterDriverExtension
extension
=
FlutterDriverExtension
((
String
arg
)
async
=>
''
,
true
);
Future
<
Offset
>
getAncestorTopLeft
({
String
of
,
String
matching
,
bool
matchRoot
=
false
})
async
{
final
Map
<
String
,
Object
>
arguments
=
GetOffset
(
Ancestor
(
of:
ByValueKey
(
of
),
matching:
ByValueKey
(
matching
),
matchRoot:
matchRoot
,
),
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
(
key:
const
ValueKey
<
String
>(
'parent'
),
height:
100
,
width:
100
,
child:
Center
(
child:
Row
(
children:
<
Widget
>[
Container
(
key:
const
ValueKey
<
String
>(
'leftchild'
),
width:
25
,
height:
25
,
),
Container
(
key:
const
ValueKey
<
String
>(
'righttchild'
),
width:
25
,
height:
25
,
),
],
),
),
)
),
)
);
expect
(
await
getAncestorTopLeft
(
of:
'leftchild'
,
matching:
'parent'
),
const
Offset
((
800
-
100
)
/
2
,
(
600
-
100
)
/
2
),
);
expect
(
await
getAncestorTopLeft
(
of:
'leftchild'
,
matching:
'parent'
,
matchRoot:
true
),
const
Offset
((
800
-
100
)
/
2
,
(
600
-
100
)
/
2
),
);
expect
(
await
getAncestorTopLeft
(
of:
'parent'
,
matching:
'parent'
,
matchRoot:
true
),
const
Offset
((
800
-
100
)
/
2
,
(
600
-
100
)
/
2
),
);
// Find nothing
Future
<
Offset
>
result
=
getAncestorTopLeft
(
of:
'leftchild'
,
matching:
'leftchild'
);
await
tester
.
pump
(
const
Duration
(
seconds:
2
));
expect
(
await
result
,
null
);
result
=
getAncestorTopLeft
(
of:
'leftchild'
,
matching:
'righttchild'
);
await
tester
.
pump
(
const
Duration
(
seconds:
2
));
expect
(
await
result
,
null
);
});
}
packages/flutter_driver/test/src/find_test.dart
0 → 100644
View file @
b37c3be0
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import
'package:flutter_driver/src/common/find.dart'
;
import
'../common.dart'
;
void
main
(
)
{
test
(
'Ancestor finder serialize'
,
()
{
const
SerializableFinder
of
=
ByType
(
'Text'
);
final
SerializableFinder
matching
=
ByValueKey
(
'hello'
);
final
Ancestor
a
=
Ancestor
(
of:
of
,
matching:
matching
,
matchRoot:
true
,
);
expect
(
a
.
serialize
(),
<
String
,
String
>{
'finderType'
:
'Ancestor'
,
'of_finderType'
:
'ByType'
,
'of_type'
:
'Text'
,
'matching_finderType'
:
'ByValueKey'
,
'matching_keyValueString'
:
'hello'
,
'matching_keyValueType'
:
'String'
,
'matchRoot'
:
'true'
});
});
test
(
'Ancestor finder deserialize'
,
()
{
final
Map
<
String
,
String
>
serialized
=
<
String
,
String
>{
'finderType'
:
'Ancestor'
,
'of_finderType'
:
'ByType'
,
'of_type'
:
'Text'
,
'matching_finderType'
:
'ByValueKey'
,
'matching_keyValueString'
:
'hello'
,
'matching_keyValueType'
:
'String'
,
'matchRoot'
:
'true'
};
final
Ancestor
a
=
Ancestor
.
deserialize
(
serialized
);
expect
(
a
.
of
,
isA
<
ByType
>());
expect
(
a
.
matching
,
isA
<
ByValueKey
>());
expect
(
a
.
matchRoot
,
isTrue
);
});
test
(
'Descendant finder serialize'
,
()
{
const
SerializableFinder
of
=
ByType
(
'Text'
);
final
SerializableFinder
matching
=
ByValueKey
(
'hello'
);
final
Descendant
a
=
Descendant
(
of:
of
,
matching:
matching
,
matchRoot:
true
,
);
expect
(
a
.
serialize
(),
<
String
,
String
>{
'finderType'
:
'Descendant'
,
'of_finderType'
:
'ByType'
,
'of_type'
:
'Text'
,
'matching_finderType'
:
'ByValueKey'
,
'matching_keyValueString'
:
'hello'
,
'matching_keyValueType'
:
'String'
,
'matchRoot'
:
'true'
});
});
test
(
'Descendant finder deserialize'
,
()
{
final
Map
<
String
,
String
>
serialized
=
<
String
,
String
>{
'finderType'
:
'Descendant'
,
'of_finderType'
:
'ByType'
,
'of_type'
:
'Text'
,
'matching_finderType'
:
'ByValueKey'
,
'matching_keyValueString'
:
'hello'
,
'matching_keyValueType'
:
'String'
,
'matchRoot'
:
'true'
};
final
Descendant
a
=
Descendant
.
deserialize
(
serialized
);
expect
(
a
.
of
,
isA
<
ByType
>());
expect
(
a
.
matching
,
isA
<
ByValueKey
>());
expect
(
a
.
matchRoot
,
isTrue
);
});
}
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