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
9ce995f6
Commit
9ce995f6
authored
Apr 15, 2016
by
Yegor
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
[driver] refactor API to finder objects (#3365)
parent
a91bc0ba
Changes
11
Hide whitespace changes
Inline
Side-by-side
Showing
11 changed files
with
176 additions
and
213 deletions
+176
-213
scroll_perf_test.dart
...nchmarks/complex_layout/test_driver/scroll_perf_test.dart
+1
-1
scroll_perf_test.dart
examples/material_gallery/test_driver/scroll_perf_test.dart
+4
-4
scroll_perf_test.dart
examples/stocks/test_driver/scroll_perf_test.dart
+1
-1
flutter_driver.dart
packages/flutter_driver/lib/flutter_driver.dart
+4
-2
driver.dart
packages/flutter_driver/lib/src/driver.dart
+42
-28
extension.dart
packages/flutter_driver/lib/src/extension.dart
+35
-60
find.dart
packages/flutter_driver/lib/src/find.dart
+67
-27
gesture.dart
packages/flutter_driver/lib/src/gesture.dart
+6
-5
message.dart
packages/flutter_driver/lib/src/message.dart
+0
-57
flutter_driver_test.dart
packages/flutter_driver/test/flutter_driver_test.dart
+13
-25
main_test.dart.tmpl
packages/flutter_tools/templates/driver/main_test.dart.tmpl
+3
-3
No files found.
dev/benchmarks/complex_layout/test_driver/scroll_perf_test.dart
View file @
9ce995f6
...
...
@@ -22,7 +22,7 @@ void main() {
test
(
'measure'
,
()
async
{
Timeline
timeline
=
await
driver
.
traceAction
(()
async
{
// Find the scrollable stock list
ObjectRef
stockList
=
await
driver
.
findB
yValueKey
(
'main-scroll'
);
SerializableFinder
stockList
=
find
.
b
yValueKey
(
'main-scroll'
);
expect
(
stockList
,
isNotNull
);
// Scroll down
...
...
examples/material_gallery/test_driver/scroll_perf_test.dart
View file @
9ce995f6
...
...
@@ -22,12 +22,12 @@ void main() {
test
(
'measure'
,
()
async
{
Timeline
timeline
=
await
driver
.
traceAction
(()
async
{
// Find the scrollable stock list
ObjectRef
stockList
=
await
driver
.
findB
yValueKey
(
'Gallery List'
);
SerializableFinder
stockList
=
find
.
b
yValueKey
(
'Gallery List'
);
expect
(
stockList
,
isNotNull
);
await
driver
.
tap
(
await
driver
.
findByT
ext
(
'Demos'
));
await
driver
.
tap
(
await
driver
.
findByT
ext
(
'Components'
));
await
driver
.
tap
(
await
driver
.
findByT
ext
(
'Style'
));
await
driver
.
tap
(
find
.
t
ext
(
'Demos'
));
await
driver
.
tap
(
find
.
t
ext
(
'Components'
));
await
driver
.
tap
(
find
.
t
ext
(
'Style'
));
// TODO(eseidel): These are very artifical scrolls, we should use better
// https://github.com/flutter/flutter/issues/3316
...
...
examples/stocks/test_driver/scroll_perf_test.dart
View file @
9ce995f6
...
...
@@ -23,7 +23,7 @@ void main() {
test
(
'measure'
,
()
async
{
Timeline
timeline
=
await
driver
.
traceAction
(()
async
{
// Find the scrollable stock list
ObjectRef
stockList
=
await
driver
.
findB
yValueKey
(
'stock-list'
);
SerializableFinder
stockList
=
find
.
b
yValueKey
(
'stock-list'
);
expect
(
stockList
,
isNotNull
);
// Scroll down
...
...
packages/flutter_driver/lib/flutter_driver.dart
View file @
9ce995f6
...
...
@@ -12,6 +12,9 @@
library
flutter_driver
;
export
'src/driver.dart'
show
find
,
CommonFinders
,
EvaluatorFunction
,
FlutterDriver
;
export
'src/error.dart'
show
...
...
@@ -21,7 +24,7 @@ export 'src/error.dart' show
flutterDriverLog
;
export
'src/find.dart'
show
ObjectRef
,
SerializableFinder
,
GetTextResult
;
export
'src/health.dart'
show
...
...
@@ -31,7 +34,6 @@ export 'src/health.dart' show
export
'src/message.dart'
show
Message
,
Command
,
ObjectRef
,
CommandWithTarget
,
Result
;
...
...
packages/flutter_driver/lib/src/driver.dart
View file @
9ce995f6
...
...
@@ -20,6 +20,14 @@ import 'timeline.dart';
final
Logger
_log
=
new
Logger
(
'FlutterDriver'
);
/// A convenient accessor to frequently used finders.
///
/// Examples:
///
/// driver.tap(find.byText('Save'));
/// driver.scroll(find.byValueKey(42));
const
CommonFinders
find
=
const
CommonFinders
.
_
();
/// Computes a value.
///
/// If computation is asynchronous, the function may return a [Future].
...
...
@@ -162,14 +170,15 @@ class FlutterDriver {
Future
<
Map
<
String
,
dynamic
>>
_sendCommand
(
Command
command
)
async
{
Map
<
String
,
String
>
parameters
=
<
String
,
String
>{
'command'
:
command
.
kind
}
..
addAll
(
command
.
serialize
());
return
_appIsolate
.
invokeExtension
(
_kFlutterExtensionMethod
,
parameters
)
.
then
((
Map
<
String
,
dynamic
>
result
)
=>
result
,
onError:
(
dynamic
error
,
dynamic
stackTrace
)
{
throw
new
DriverError
(
'Failed to fulfill
${command.runtimeType}
due to remote error'
,
error
,
stackTrace
);
});
try
{
return
await
_appIsolate
.
invokeExtension
(
_kFlutterExtensionMethod
,
parameters
);
}
catch
(
error
,
stackTrace
)
{
throw
new
DriverError
(
'Failed to fulfill
${command.runtimeType}
due to remote error'
,
error
,
stackTrace
);
}
}
/// Checks the status of the Flutter Driver extension.
...
...
@@ -177,23 +186,14 @@ class FlutterDriver {
return
Health
.
fromJson
(
await
_sendCommand
(
new
GetHealth
()));
}
/// Finds the UI element with the given [key].
Future
<
ObjectRef
>
findByValueKey
(
dynamic
key
)
async
{
return
ObjectRef
.
fromJson
(
await
_sendCommand
(
new
Find
(
new
ByValueKey
(
key
))));
}
/// Finds the UI element for the tooltip with the given [message].
Future
<
ObjectRef
>
findByTooltipMessage
(
String
message
)
async
{
return
ObjectRef
.
fromJson
(
await
_sendCommand
(
new
Find
(
new
ByTooltipMessage
(
message
))));
}
/// Finds the text element with the given [text].
Future
<
ObjectRef
>
findByText
(
String
text
)
async
{
return
ObjectRef
.
fromJson
(
await
_sendCommand
(
new
Find
(
new
ByText
(
text
))));
/// Taps at the center of the widget located by [finder].
Future
<
Null
>
tap
(
SerializableFinder
finder
)
async
{
return
await
_sendCommand
(
new
Tap
(
finder
)).
then
((
Map
<
String
,
dynamic
>
_
)
=>
null
);
}
Future
<
Null
>
tap
(
ObjectRef
ref
)
async
{
return
await
_sendCommand
(
new
Tap
(
ref
)).
then
((
Map
<
String
,
dynamic
>
_
)
=>
null
);
/// Whether at least one widget identified by [finder] exists on the UI.
Future
<
bool
>
exists
(
SerializableFinder
finder
)
async
{
return
await
_sendCommand
(
new
Exists
(
finder
)).
then
((
Map
<
String
,
dynamic
>
_
)
=>
null
);
}
/// Tell the driver to perform a scrolling action.
...
...
@@ -209,13 +209,13 @@ class FlutterDriver {
///
/// The move events are generated at a given [frequency] in Hz (or events per
/// second). It defaults to 60Hz.
Future
<
Null
>
scroll
(
ObjectRef
ref
,
double
dx
,
double
dy
,
Duration
duration
,
{
int
frequency:
60
})
async
{
return
await
_sendCommand
(
new
Scroll
(
ref
,
dx
,
dy
,
duration
,
frequency
)).
then
((
Map
<
String
,
dynamic
>
_
)
=>
null
);
Future
<
Null
>
scroll
(
SerializableFinder
finder
,
double
dx
,
double
dy
,
Duration
duration
,
{
int
frequency:
60
})
async
{
return
await
_sendCommand
(
new
Scroll
(
finder
,
dx
,
dy
,
duration
,
frequency
)).
then
((
Map
<
String
,
dynamic
>
_
)
=>
null
);
}
Future
<
String
>
getText
(
ObjectRef
ref
)
async
{
GetTextResult
result
=
GetTextResult
.
fromJson
(
await
_sendCommand
(
new
GetText
(
ref
)));
return
result
.
text
;
/// Returns the text in the `Text` widget located by [finder].
Future
<
String
>
getText
(
SerializableFinder
finder
)
async
{
return
GetTextResult
.
fromJson
(
await
_sendCommand
(
new
GetText
(
finder
)))
.
text
;
}
/// Starts recording performance traces.
...
...
@@ -358,3 +358,17 @@ Future<VMServiceClientConnection> _waitAndConnect(String url) async {
return
attemptConnection
();
}
/// Provides convenient accessors to frequently used finders.
class
CommonFinders
{
const
CommonFinders
.
_
();
/// Finds [Text] widgets containing string equal to [text].
SerializableFinder
text
(
String
text
)
=>
new
ByText
(
text
);
/// Finds widgets by [key].
SerializableFinder
byValueKey
(
dynamic
key
)
=>
new
ByValueKey
(
key
);
/// Finds widgets with a tooltip with the given [message].
SerializableFinder
byTooltip
(
String
message
)
=>
new
ByTooltipMessage
(
message
);
}
packages/flutter_driver/lib/src/extension.dart
View file @
9ce995f6
...
...
@@ -47,34 +47,39 @@ typedef Future<Result> CommandHandlerCallback(Command c);
/// Deserializes JSON map to a command object.
typedef
Command
CommandDeserializerCallback
(
Map
<
String
,
String
>
params
);
/// Runs the finder and returns the [Element] found, or `null`.
typedef
Future
<
Element
>
FinderCallback
(
SerializableFinder
finder
);
class
FlutterDriverExtension
{
static
final
Logger
_log
=
new
Logger
(
'FlutterDriverExtension'
);
FlutterDriverExtension
()
{
_commandHandlers
=
{
_commandHandlers
=
<
String
,
CommandHandlerCallback
>
{
'get_health'
:
getHealth
,
'find'
:
find
,
'tap'
:
tap
,
'get_text'
:
getText
,
'scroll'
:
scroll
,
};
_commandDeserializers
=
{
_commandDeserializers
=
<
String
,
CommandDeserializerCallback
>
{
'get_health'
:
GetHealth
.
deserialize
,
'find'
:
Find
.
deserialize
,
'tap'
:
Tap
.
deserialize
,
'get_text'
:
GetText
.
deserialize
,
'scroll'
:
Scroll
.
deserialize
,
};
_finders
=
<
String
,
FinderCallback
>{
'ByValueKey'
:
_findByValueKey
,
'ByTooltipMessage'
:
_findByTooltipMessage
,
'ByText'
:
_findByText
,
};
}
final
Instrumentation
prober
=
new
Instrumentation
();
Map
<
String
,
CommandHandlerCallback
>
_commandHandlers
=
<
String
,
CommandHandlerCallback
>{};
Map
<
String
,
CommandDeserializerCallback
>
_commandDeserializers
=
<
String
,
CommandDeserializerCallback
>{};
Map
<
String
,
CommandHandlerCallback
>
_commandHandlers
;
Map
<
String
,
CommandDeserializerCallback
>
_commandDeserializers
;
Map
<
String
,
FinderCallback
>
_finders
;
Future
<
ServiceExtensionResponse
>
call
(
Map
<
String
,
String
>
params
)
async
{
try
{
...
...
@@ -107,36 +112,18 @@ class FlutterDriverExtension {
Future
<
Health
>
getHealth
(
GetHealth
command
)
async
=>
new
Health
(
HealthStatus
.
ok
);
Future
<
ObjectRef
>
find
(
Find
command
)
async
{
SearchSpecification
searchSpec
=
command
.
searchSpec
;
switch
(
searchSpec
.
runtimeType
)
{
case
ByValueKey:
return
findByValueKey
(
searchSpec
);
case
ByTooltipMessage:
return
findByTooltipMessage
(
searchSpec
);
case
ByText:
return
findByText
(
searchSpec
);
}
throw
new
DriverError
(
'Unsupported search specification type
${searchSpec.runtimeType}
'
);
}
/// Runs object [locator] repeatedly until it returns a non-`null` value.
///
/// [descriptionGetter] describes the object to be waited for. It is used in
/// the warning printed should timeout happen.
Future
<
ObjectRef
>
_waitForObject
(
String
descriptionGetter
(),
Object
locator
())
async
{
Object
object
=
await
retry
(
locator
,
_kDefaultTimeout
,
_kDefaultPauseBetweenRetries
,
predicate:
(
Object
object
)
{
/// Runs object [finder] repeatedly until it finds an [Element].
Future
<
Element
>
_waitForElement
(
String
descriptionGetter
(),
Element
locator
())
{
return
retry
(
locator
,
_kDefaultTimeout
,
_kDefaultPauseBetweenRetries
,
predicate:
(
dynamic
object
)
{
return
object
!=
null
;
}).
catchError
((
Object
error
,
Object
stackTrace
)
{
_log
.
warning
(
'Timed out waiting for
${descriptionGetter()}
'
);
return
null
;
});
ObjectRef
elemRef
=
object
!=
null
?
new
ObjectRef
(
_registerObject
(
object
))
:
new
ObjectRef
.
notFound
();
return
new
Future
<
ObjectRef
>.
value
(
elemRef
);
}
Future
<
ObjectRef
>
findByValueKey
(
ByValueKey
byKey
)
async
{
return
_waitFor
Objec
t
(
Future
<
Element
>
_
findByValueKey
(
ByValueKey
byKey
)
async
{
return
_waitFor
Elemen
t
(
()
=>
'element with key "
${byKey.keyValue}
" of type
${byKey.keyValueType}
'
,
()
{
return
prober
.
findElementByKey
(
new
ValueKey
<
dynamic
>(
byKey
.
keyValue
));
...
...
@@ -144,8 +131,8 @@ class FlutterDriverExtension {
);
}
Future
<
ObjectRef
>
findByTooltipMessage
(
ByTooltipMessage
byTooltipMessage
)
async
{
return
_waitFor
Objec
t
(
Future
<
Element
>
_
findByTooltipMessage
(
ByTooltipMessage
byTooltipMessage
)
async
{
return
_waitFor
Elemen
t
(
()
=>
'tooltip with message "
${byTooltipMessage.text}
" on it'
,
()
{
return
prober
.
findElement
((
Element
element
)
{
...
...
@@ -160,22 +147,31 @@ class FlutterDriverExtension {
);
}
Future
<
ObjectRef
>
findByText
(
ByText
byText
)
async
{
return
await
_waitFor
Objec
t
(
Future
<
Element
>
_
findByText
(
ByText
byText
)
async
{
return
await
_waitFor
Elemen
t
(
()
=>
'text "
${byText.text}
"'
,
()
{
return
prober
.
findText
(
byText
.
text
);
});
}
Future
<
Element
>
_runFinder
(
SerializableFinder
finder
)
{
FinderCallback
cb
=
_finders
[
finder
.
finderType
];
if
(
cb
==
null
)
throw
'Unsupported finder type:
${finder.finderType}
'
;
return
cb
(
finder
);
}
Future
<
TapResult
>
tap
(
Tap
command
)
async
{
Element
target
=
await
_
dereferenceOrDie
(
command
.
targetRef
);
Element
target
=
await
_
runFinder
(
command
.
finder
);
prober
.
tap
(
target
);
return
new
TapResult
();
}
Future
<
ScrollResult
>
scroll
(
Scroll
command
)
async
{
Element
target
=
await
_
dereferenceOrDie
(
command
.
targetRef
);
Element
target
=
await
_
runFinder
(
command
.
finder
);
final
int
totalMoves
=
command
.
duration
.
inMicroseconds
*
command
.
frequency
~/
Duration
.
MICROSECONDS_PER_SECOND
;
Offset
delta
=
new
Offset
(
command
.
dx
,
command
.
dy
)
/
totalMoves
.
toDouble
();
Duration
pause
=
command
.
duration
~/
totalMoves
;
...
...
@@ -198,30 +194,9 @@ class FlutterDriverExtension {
}
Future
<
GetTextResult
>
getText
(
GetText
command
)
async
{
Element
target
=
await
_
dereferenceOrDie
(
command
.
targetRef
);
Element
target
=
await
_
runFinder
(
command
.
finder
);
// TODO(yjbanov): support more ways to read text
Text
text
=
target
.
widget
;
return
new
GetTextResult
(
text
.
data
);
}
int
_refCounter
=
1
;
final
Map
<
String
,
Object
>
_objectRefs
=
<
String
,
Object
>{};
String
_registerObject
(
Object
obj
)
{
if
(
obj
==
null
)
throw
new
ArgumentError
(
'Cannot register null object'
);
String
refKey
=
'
${_refCounter++}
'
;
_objectRefs
[
refKey
]
=
obj
;
return
refKey
;
}
dynamic
_dereference
(
String
reference
)
=>
_objectRefs
[
reference
];
Future
<
dynamic
>
_dereferenceOrDie
(
String
reference
)
{
Element
object
=
_dereference
(
reference
);
if
(
object
==
null
)
return
new
Future
<
String
>.
error
(
'Object reference not found (
$reference
).'
);
return
new
Future
<
Element
>.
value
(
object
);
}
}
packages/flutter_driver/lib/src/find.dart
View file @
9ce995f6
...
...
@@ -11,46 +11,86 @@ DriverError _createInvalidKeyValueTypeError(String invalidType) {
return
new
DriverError
(
'Unsupported key value type
$invalidType
. Flutter Driver only supports
${_supportedKeyValueTypes.join(", ")}
'
);
}
/// Command to find an element.
class
Find
extends
Command
{
/// A command aimed at an object to be located by [finder].
///
/// Implementations must provide a concrete [kind]. If additional data is
/// required beyond the [finder] the implementation may override [serialize]
/// and add more keys to the returned map.
abstract
class
CommandWithTarget
extends
Command
{
CommandWithTarget
(
this
.
finder
)
{
if
(
finder
==
null
)
throw
new
DriverError
(
'
${this.runtimeType}
target cannot be null'
);
}
/// Locates the object or objects targeted by this command.
final
SerializableFinder
finder
;
/// This method is meant to be overridden if data in addition to [finder]
/// is serialized to JSON.
///
/// Example:
///
/// Map<String, String> toJson() => super.toJson()..addAll({
/// 'foo': this.foo,
/// });
@override
final
String
kind
=
'find'
;
Map
<
String
,
String
>
serialize
()
=>
finder
.
serialize
();
}
/// Checks if the widget identified by the given finder exists.
class
Exists
extends
CommandWithTarget
{
@override
final
String
kind
=
'exists'
;
Find
(
this
.
searchSpec
);
Exists
(
SerializableFinder
finder
)
:
super
(
finder
);
final
SearchSpecification
searchSpec
;
static
Exists
deserialize
(
Map
<
String
,
String
>
json
)
{
return
new
Exists
(
SerializableFinder
.
deserialize
(
json
));
}
@override
Map
<
String
,
String
>
serialize
()
=>
searchSpec
.
serialize
();
Map
<
String
,
String
>
serialize
()
=>
super
.
serialize
();
}
static
Find
deserialize
(
Map
<
String
,
String
>
json
)
{
return
new
Find
(
SearchSpecification
.
deserialize
(
json
));
class
ExistsResult
extends
Result
{
ExistsResult
(
this
.
exists
);
static
ExistsResult
fromJson
(
Map
<
String
,
dynamic
>
json
)
{
return
new
ExistsResult
(
json
[
'exists'
]);
}
/// Whether the widget was found on the UI or not.
final
bool
exists
;
@override
Map
<
String
,
dynamic
>
toJson
()
=>
{
'exists'
:
exists
,
};
}
/// Describes how to the driver should search for elements.
abstract
class
Se
archSpecification
{
String
get
searchSpec
Type
;
abstract
class
Se
rializableFinder
{
String
get
finder
Type
;
static
Se
archSpecification
deserialize
(
Map
<
String
,
String
>
json
)
{
String
searchSpecType
=
json
[
'searchSpec
Type'
];
switch
(
searchSpec
Type
)
{
static
Se
rializableFinder
deserialize
(
Map
<
String
,
String
>
json
)
{
String
finderType
=
json
[
'finder
Type'
];
switch
(
finder
Type
)
{
case
'ByValueKey'
:
return
ByValueKey
.
deserialize
(
json
);
case
'ByTooltipMessage'
:
return
ByTooltipMessage
.
deserialize
(
json
);
case
'ByText'
:
return
ByText
.
deserialize
(
json
);
}
throw
new
DriverError
(
'Unsupported search specification type
$
searchSpec
Type
'
);
throw
new
DriverError
(
'Unsupported search specification type
$
finder
Type
'
);
}
Map
<
String
,
String
>
serialize
()
=>
{
'
searchSpecType'
:
searchSpec
Type
,
'
finderType'
:
finder
Type
,
};
}
///
Tells [Find] to search
by tooltip text.
class
ByTooltipMessage
extends
Se
archSpecification
{
///
Finds widgets
by tooltip text.
class
ByTooltipMessage
extends
Se
rializableFinder
{
@override
final
String
searchSpec
Type
=
'ByTooltipMessage'
;
final
String
finder
Type
=
'ByTooltipMessage'
;
ByTooltipMessage
(
this
.
text
);
...
...
@@ -67,10 +107,10 @@ class ByTooltipMessage extends SearchSpecification {
}
}
///
Tells [Find] to search for `Text` widget by tex
t.
class
ByText
extends
Se
archSpecification
{
///
Finds widgets by [text] inside a `Text` widge
t.
class
ByText
extends
Se
rializableFinder
{
@override
final
String
searchSpec
Type
=
'ByText'
;
final
String
finder
Type
=
'ByText'
;
ByText
(
this
.
text
);
...
...
@@ -86,10 +126,10 @@ class ByText extends SearchSpecification {
}
}
///
Tells [Find] to search
by `ValueKey`.
class
ByValueKey
extends
Se
archSpecification
{
///
Finds widgets
by `ValueKey`.
class
ByValueKey
extends
Se
rializableFinder
{
@override
final
String
searchSpec
Type
=
'ByValueKey'
;
final
String
finder
Type
=
'ByValueKey'
;
ByValueKey
(
dynamic
keyValue
)
:
this
.
keyValue
=
keyValue
,
...
...
@@ -132,14 +172,14 @@ class ByValueKey extends SearchSpecification {
/// Command to read the text from a given element.
class
GetText
extends
CommandWithTarget
{
/// [
targetRef] identifies
an element that contains a piece of text.
GetText
(
ObjectRef
targetRef
)
:
super
(
targetRef
);
/// [
finder] looks for
an element that contains a piece of text.
GetText
(
SerializableFinder
finder
)
:
super
(
finder
);
@override
final
String
kind
=
'get_text'
;
static
GetText
deserialize
(
Map
<
String
,
String
>
json
)
{
return
new
GetText
(
new
ObjectRef
(
json
[
'targetRef'
]
));
return
new
GetText
(
SerializableFinder
.
deserialize
(
json
));
}
@override
...
...
packages/flutter_driver/lib/src/gesture.dart
View file @
9ce995f6
...
...
@@ -3,15 +3,16 @@
// found in the LICENSE file.
import
'message.dart'
;
import
'find.dart'
;
class
Tap
extends
CommandWithTarget
{
@override
final
String
kind
=
'tap'
;
Tap
(
ObjectRef
targetRef
)
:
super
(
targetRef
);
Tap
(
SerializableFinder
finder
)
:
super
(
finder
);
static
Tap
deserialize
(
Map
<
String
,
String
>
json
)
{
return
new
Tap
(
new
ObjectRef
(
json
[
'targetRef'
]
));
return
new
Tap
(
SerializableFinder
.
deserialize
(
json
));
}
@override
...
...
@@ -34,16 +35,16 @@ class Scroll extends CommandWithTarget {
final
String
kind
=
'scroll'
;
Scroll
(
ObjectRef
targetRef
,
SerializableFinder
finder
,
this
.
dx
,
this
.
dy
,
this
.
duration
,
this
.
frequency
)
:
super
(
targetRef
);
)
:
super
(
finder
);
static
Scroll
deserialize
(
Map
<
String
,
dynamic
>
json
)
{
return
new
Scroll
(
new
ObjectRef
(
json
[
'targetRef'
]
),
SerializableFinder
.
deserialize
(
json
),
double
.
parse
(
json
[
'dx'
]),
double
.
parse
(
json
[
'dy'
]),
new
Duration
(
microseconds:
int
.
parse
(
json
[
'duration'
])),
...
...
packages/flutter_driver/lib/src/message.dart
View file @
9ce995f6
...
...
@@ -2,8 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import
'error.dart'
;
/// An object sent from the Flutter Driver to a Flutter application to instruct
/// the application to perform a task.
abstract
class
Command
{
...
...
@@ -20,58 +18,3 @@ abstract class Result { // ignore: one_member_abstracts
/// Serializes this message to a JSON map.
Map
<
String
,
dynamic
>
toJson
();
}
/// A serializable reference to an object that lives in the application isolate.
class
ObjectRef
extends
Result
{
ObjectRef
(
this
.
objectReferenceKey
);
ObjectRef
.
notFound
()
:
this
(
null
);
static
ObjectRef
fromJson
(
Map
<
String
,
dynamic
>
json
)
{
return
json
[
'objectReferenceKey'
]
!=
null
?
new
ObjectRef
(
json
[
'objectReferenceKey'
])
:
null
;
}
/// Identifier used to dereference an object.
///
/// This value is generated by the application-side isolate. Flutter driver
/// tests should not generate these keys.
final
String
objectReferenceKey
;
@override
Map
<
String
,
dynamic
>
toJson
()
=>
{
'objectReferenceKey'
:
objectReferenceKey
,
};
}
/// A command aimed at an object represented by [targetRef].
///
/// Implementations must provide a concrete [kind]. If additional data is
/// required beyond the [targetRef] the implementation may override [serialize]
/// and add more keys to the returned map.
abstract
class
CommandWithTarget
extends
Command
{
CommandWithTarget
(
ObjectRef
ref
)
:
this
.
targetRef
=
ref
?.
objectReferenceKey
{
if
(
ref
==
null
)
throw
new
DriverError
(
'
${this.runtimeType}
target cannot be null'
);
if
(
ref
.
objectReferenceKey
==
null
)
throw
new
DriverError
(
'
${this.runtimeType}
target reference cannot be null'
);
}
/// Refers to the object targeted by this command.
final
String
targetRef
;
/// This method is meant to be overridden if data in addition to [targetRef]
/// is serialized to JSON.
///
/// Example:
///
/// Map<String, String> toJson() => super.toJson()..addAll({
/// 'foo': this.foo,
/// });
@override
Map
<
String
,
String
>
serialize
()
=>
<
String
,
String
>{
'targetRef'
:
targetRef
,
};
}
packages/flutter_driver/test/flutter_driver_test.dart
View file @
9ce995f6
...
...
@@ -7,7 +7,6 @@ import 'dart:async';
import
'package:flutter_driver/src/driver.dart'
;
import
'package:flutter_driver/src/error.dart'
;
import
'package:flutter_driver/src/health.dart'
;
import
'package:flutter_driver/src/message.dart'
;
import
'package:flutter_driver/src/timeline.dart'
;
import
'package:json_rpc_2/json_rpc_2.dart'
as
rpc
;
import
'package:mockito/mockito.dart'
;
...
...
@@ -120,27 +119,23 @@ void main() {
await
driver
.
close
();
});
group
(
'
find
ByValueKey'
,
()
{
group
(
'ByValueKey'
,
()
{
test
(
'restricts value types'
,
()
async
{
expect
(
driver
.
findB
yValueKey
(
null
),
expect
(
()
=>
find
.
b
yValueKey
(
null
),
throwsA
(
new
isInstanceOf
<
DriverError
>()));
});
test
(
'finds by ValueKey'
,
()
async
{
when
(
mockIsolate
.
invokeExtension
(
any
,
any
)).
thenAnswer
((
Invocation
i
)
{
expect
(
i
.
positionalArguments
[
1
],
{
'command'
:
'
find
'
,
'
searchSpec
Type'
:
'ByValueKey'
,
'command'
:
'
tap
'
,
'
finder
Type'
:
'ByValueKey'
,
'keyValueString'
:
'foo'
,
'keyValueType'
:
'String'
});
return
new
Future
<
Map
<
String
,
dynamic
>>.
value
(<
String
,
dynamic
>{
'objectReferenceKey'
:
'123'
,
});
return
new
Future
<
Null
>.
value
();
});
ObjectRef
result
=
await
driver
.
findByValueKey
(
'foo'
);
expect
(
result
,
isNotNull
);
expect
(
result
.
objectReferenceKey
,
'123'
);
await
driver
.
tap
(
find
.
byValueKey
(
'foo'
));
});
});
...
...
@@ -149,20 +144,16 @@ void main() {
expect
(
driver
.
tap
(
null
),
throwsA
(
new
isInstanceOf
<
DriverError
>()));
});
test
(
'requires a valid target reference'
,
()
async
{
expect
(
driver
.
tap
(
new
ObjectRef
.
notFound
()),
throwsA
(
new
isInstanceOf
<
DriverError
>()));
});
test
(
'sends the tap command'
,
()
async
{
when
(
mockIsolate
.
invokeExtension
(
any
,
any
)).
thenAnswer
((
Invocation
i
)
{
expect
(
i
.
positionalArguments
[
1
],
<
String
,
dynamic
>{
'command'
:
'tap'
,
'targetRef'
:
'123'
'finderType'
:
'ByText'
,
'text'
:
'foo'
,
});
return
new
Future
<
Map
<
String
,
dynamic
>>.
value
();
});
await
driver
.
tap
(
new
ObjectRef
(
'123
'
));
await
driver
.
tap
(
find
.
text
(
'foo
'
));
});
});
...
...
@@ -171,22 +162,19 @@ void main() {
expect
(
driver
.
getText
(
null
),
throwsA
(
new
isInstanceOf
<
DriverError
>()));
});
test
(
'requires a valid target reference'
,
()
async
{
expect
(
driver
.
getText
(
new
ObjectRef
.
notFound
()),
throwsA
(
new
isInstanceOf
<
DriverError
>()));
});
test
(
'sends the getText command'
,
()
async
{
when
(
mockIsolate
.
invokeExtension
(
any
,
any
)).
thenAnswer
((
Invocation
i
)
{
expect
(
i
.
positionalArguments
[
1
],
<
String
,
dynamic
>{
'command'
:
'get_text'
,
'targetRef'
:
'123'
'finderType'
:
'ByValueKey'
,
'keyValueString'
:
'123'
,
'keyValueType'
:
'int'
});
return
new
Future
<
Map
<
String
,
dynamic
>>.
value
({
'text'
:
'hello'
});
});
String
result
=
await
driver
.
getText
(
new
ObjectRef
(
'123'
));
String
result
=
await
driver
.
getText
(
find
.
byValueKey
(
123
));
expect
(
result
,
'hello'
);
});
});
...
...
packages/flutter_tools/templates/driver/main_test.dart.tmpl
View file @
9ce995f6
...
...
@@ -23,14 +23,14 @@ void main() {
test('tap on the floating action button; verify counter', () async {
// Find floating action button (fab) to tap on
ObjectRef fab = await driver.findByTooltipMessage
('Increment');
expect(
fab, isNotNull
);
SerializableFinder fab = find.byTooltip
('Increment');
expect(
await driver.exists(fab), isTrue
);
// Tap on the fab
await driver.tap(fab);
// Wait for text to change to the desired value
expect(await driver.
findByText('Button tapped 1 time.'), isNotNull
);
expect(await driver.
exists(find.text('Button tapped 1 time.')), 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