1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
// Copyright 2016 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 'error.dart';
import 'message.dart';
const List<Type> _supportedKeyValueTypes = const <Type>[String, int];
DriverError _createInvalidKeyValueTypeError(String invalidType) {
return new DriverError('Unsupported key value type $invalidType. Flutter Driver only supports ${_supportedKeyValueTypes.join(", ")}');
}
/// 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
Map<String, String> serialize() => finder.serialize();
}
/// Waits until [finder] can locate the target.
class WaitFor extends CommandWithTarget {
@override
final String kind = 'waitFor';
WaitFor(SerializableFinder finder, {this.timeout})
: super(finder);
final Duration timeout;
static WaitFor deserialize(Map<String, String> json) {
Duration timeout = json['timeout'] != null
? new Duration(milliseconds: int.parse(json['timeout']))
: null;
return new WaitFor(SerializableFinder.deserialize(json), timeout: timeout);
}
@override
Map<String, String> serialize() {
Map<String, String> json = super.serialize();
if (timeout != null) {
json['timeout'] = '${timeout.inMilliseconds}';
}
return json;
}
}
class WaitForResult extends Result {
WaitForResult();
static WaitForResult fromJson(Map<String, dynamic> json) {
return new WaitForResult();
}
@override
Map<String, dynamic> toJson() => <String, dynamic>{};
}
/// Describes how to the driver should search for elements.
abstract class SerializableFinder {
String get finderType;
static SerializableFinder deserialize(Map<String, String> json) {
String finderType = json['finderType'];
switch(finderType) {
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 $finderType');
}
Map<String, String> serialize() => <String, String>{
'finderType': finderType,
};
}
/// Finds widgets by tooltip text.
class ByTooltipMessage extends SerializableFinder {
@override
final String finderType = 'ByTooltipMessage';
ByTooltipMessage(this.text);
/// Tooltip message text.
final String text;
@override
Map<String, String> serialize() => super.serialize()..addAll(<String, String>{
'text': text,
});
static ByTooltipMessage deserialize(Map<String, String> json) {
return new ByTooltipMessage(json['text']);
}
}
/// Finds widgets by [text] inside a `Text` widget.
class ByText extends SerializableFinder {
@override
final String finderType = 'ByText';
ByText(this.text);
final String text;
@override
Map<String, String> serialize() => super.serialize()..addAll(<String, String>{
'text': text,
});
static ByText deserialize(Map<String, String> json) {
return new ByText(json['text']);
}
}
/// Finds widgets by `ValueKey`.
class ByValueKey extends SerializableFinder {
@override
final String finderType = 'ByValueKey';
ByValueKey(dynamic keyValue)
: this.keyValue = keyValue,
this.keyValueString = '$keyValue',
this.keyValueType = '${keyValue.runtimeType}' {
if (!_supportedKeyValueTypes.contains(keyValue.runtimeType))
throw _createInvalidKeyValueTypeError('$keyValue.runtimeType');
}
/// The true value of the key.
final dynamic keyValue;
/// Stringified value of the key (we can only send strings to the VM service)
final String keyValueString;
/// The type name of the key.
///
/// May be one of "String", "int". The list of supported types may change.
final String keyValueType;
@override
Map<String, String> serialize() => super.serialize()..addAll(<String, String>{
'keyValueString': keyValueString,
'keyValueType': keyValueType,
});
static ByValueKey deserialize(Map<String, String> json) {
String keyValueString = json['keyValueString'];
String keyValueType = json['keyValueType'];
switch(keyValueType) {
case 'int':
return new ByValueKey(int.parse(keyValueString));
case 'String':
return new ByValueKey(keyValueString);
default:
throw _createInvalidKeyValueTypeError(keyValueType);
}
}
}
/// Command to read the text from a given element.
class GetText extends CommandWithTarget {
/// [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(SerializableFinder.deserialize(json));
}
@override
Map<String, String> serialize() => super.serialize();
}
class GetTextResult extends Result {
GetTextResult(this.text);
final String text;
static GetTextResult fromJson(Map<String, dynamic> json) {
return new GetTextResult(json['text']);
}
@override
Map<String, dynamic> toJson() => <String, String>{
'text': text,
};
}