100% doc coverage in package:flutter_driver (#6738)
This commit is contained in:
parent
64609588f4
commit
0cd69826f5
@ -6,6 +6,7 @@ import 'dart:async';
|
|||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
import 'package:json_rpc_2/json_rpc_2.dart' as rpc;
|
import 'package:json_rpc_2/json_rpc_2.dart' as rpc;
|
||||||
|
import 'package:meta/meta.dart';
|
||||||
import 'package:vm_service_client/vm_service_client.dart';
|
import 'package:vm_service_client/vm_service_client.dart';
|
||||||
import 'package:web_socket_channel/io.dart';
|
import 'package:web_socket_channel/io.dart';
|
||||||
|
|
||||||
@ -17,8 +18,34 @@ import 'input.dart';
|
|||||||
import 'message.dart';
|
import 'message.dart';
|
||||||
import 'timeline.dart';
|
import 'timeline.dart';
|
||||||
|
|
||||||
|
/// Timeline stream identifier.
|
||||||
enum TimelineStream {
|
enum TimelineStream {
|
||||||
all, api, compiler, dart, debugger, embedder, gc, isolate, vm
|
/// A meta-identifier that instructs the Dart VM to record all streams.
|
||||||
|
all,
|
||||||
|
|
||||||
|
/// Marks events related to calls made via Dart's C API.
|
||||||
|
api,
|
||||||
|
|
||||||
|
/// Marks events from the Dart VM's JIT compiler.
|
||||||
|
compiler,
|
||||||
|
|
||||||
|
/// Marks events emitted using the `dart:developer` API.
|
||||||
|
dart,
|
||||||
|
|
||||||
|
/// Marks events from the Dart VM debugger.
|
||||||
|
debugger,
|
||||||
|
|
||||||
|
/// Marks events emitted using the `dart_tools_api.h` C API.
|
||||||
|
embedder,
|
||||||
|
|
||||||
|
/// Marks events from the garbage collector.
|
||||||
|
gc,
|
||||||
|
|
||||||
|
/// Marks events related to message passing between Dart isolates.
|
||||||
|
isolate,
|
||||||
|
|
||||||
|
/// Marks internal VM events.
|
||||||
|
vm,
|
||||||
}
|
}
|
||||||
|
|
||||||
const List<TimelineStream> _defaultStreams = const <TimelineStream>[TimelineStream.all];
|
const List<TimelineStream> _defaultStreams = const <TimelineStream>[TimelineStream.all];
|
||||||
@ -62,6 +89,9 @@ typedef dynamic EvaluatorFunction();
|
|||||||
|
|
||||||
/// Drives a Flutter Application running in another process.
|
/// Drives a Flutter Application running in another process.
|
||||||
class FlutterDriver {
|
class FlutterDriver {
|
||||||
|
/// Creates a driver that uses a connection provided by the given
|
||||||
|
/// [_serviceClient], [_peer] and [_appIsolate].
|
||||||
|
@visibleForTesting
|
||||||
FlutterDriver.connectedTo(this._serviceClient, this._peer, this._appIsolate);
|
FlutterDriver.connectedTo(this._serviceClient, this._peer, this._appIsolate);
|
||||||
|
|
||||||
static const String _kFlutterExtensionMethod = 'ext.flutter.driver';
|
static const String _kFlutterExtensionMethod = 'ext.flutter.driver';
|
||||||
@ -316,6 +346,9 @@ class FlutterDriver {
|
|||||||
///
|
///
|
||||||
/// This is merely a convenience wrapper on top of [startTracing] and
|
/// This is merely a convenience wrapper on top of [startTracing] and
|
||||||
/// [stopTracingAndDownloadTimeline].
|
/// [stopTracingAndDownloadTimeline].
|
||||||
|
///
|
||||||
|
/// [streams] limits the recorded timeline event streams to only the ones
|
||||||
|
/// listed. By default, all streams are recorded.
|
||||||
Future<Timeline> traceAction(Future<dynamic> action(), { List<TimelineStream> streams: _defaultStreams }) async {
|
Future<Timeline> traceAction(Future<dynamic> action(), { List<TimelineStream> streams: _defaultStreams }) async {
|
||||||
await startTracing(streams: streams);
|
await startTracing(streams: streams);
|
||||||
await action();
|
await action();
|
||||||
@ -334,6 +367,7 @@ class FlutterDriver {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Encapsulates connection information to an instance of a Flutter application.
|
/// Encapsulates connection information to an instance of a Flutter application.
|
||||||
|
@visibleForTesting
|
||||||
class VMServiceClientConnection {
|
class VMServiceClientConnection {
|
||||||
/// Use this for structured access to the VM service's public APIs.
|
/// Use this for structured access to the VM service's public APIs.
|
||||||
final VMServiceClient client;
|
final VMServiceClient client;
|
||||||
@ -344,6 +378,7 @@ class VMServiceClientConnection {
|
|||||||
/// caution.
|
/// caution.
|
||||||
final rpc.Peer peer;
|
final rpc.Peer peer;
|
||||||
|
|
||||||
|
/// Creates an instance of this class given a [client] and a [peer].
|
||||||
VMServiceClientConnection(this.client, this.peer);
|
VMServiceClientConnection(this.client, this.peer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7,12 +7,17 @@ import 'dart:io' show stderr;
|
|||||||
|
|
||||||
/// Standard error thrown by Flutter Driver API.
|
/// Standard error thrown by Flutter Driver API.
|
||||||
class DriverError extends Error {
|
class DriverError extends Error {
|
||||||
|
/// Create an error with a [message] and (optionally) the [originalError] and
|
||||||
|
/// [originalStackTrace] that caused it.
|
||||||
DriverError(this.message, [this.originalError, this.originalStackTrace]);
|
DriverError(this.message, [this.originalError, this.originalStackTrace]);
|
||||||
|
|
||||||
/// Human-readable error message.
|
/// Human-readable error message.
|
||||||
final String message;
|
final String message;
|
||||||
|
|
||||||
|
/// The error object that was caught and wrapped by this error object.
|
||||||
final dynamic originalError;
|
final dynamic originalError;
|
||||||
|
|
||||||
|
/// The stack trace that was caught and wrapped by this error object.
|
||||||
final dynamic originalStackTrace;
|
final dynamic originalStackTrace;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -47,44 +52,99 @@ void _log(LogLevel level, String loggerName, Object message) {
|
|||||||
final Stream<LogRecord> flutterDriverLog = _logger.stream;
|
final Stream<LogRecord> flutterDriverLog = _logger.stream;
|
||||||
|
|
||||||
/// Severity of a log entry.
|
/// Severity of a log entry.
|
||||||
enum LogLevel { trace, info, warning, error, critical }
|
enum LogLevel {
|
||||||
|
/// Messages used to supplement the higher-level messages with more details.
|
||||||
|
///
|
||||||
|
/// This will likely produce a lot of output.
|
||||||
|
trace,
|
||||||
|
|
||||||
|
/// Informational messages that do not indicate a problem.
|
||||||
|
info,
|
||||||
|
|
||||||
|
/// A potential problem.
|
||||||
|
warning,
|
||||||
|
|
||||||
|
/// A certain problem but the program will attempt to continue.
|
||||||
|
error,
|
||||||
|
|
||||||
|
/// A critical problem; the program will attempt to quit immediately.
|
||||||
|
critical,
|
||||||
|
}
|
||||||
|
|
||||||
/// A log entry.
|
/// A log entry.
|
||||||
class LogRecord {
|
class LogRecord {
|
||||||
const LogRecord._(this.level, this.loggerName, this.message);
|
const LogRecord._(this.level, this.loggerName, this.message);
|
||||||
|
|
||||||
|
/// The severity of the log record.
|
||||||
final LogLevel level;
|
final LogLevel level;
|
||||||
|
|
||||||
|
/// The name of the logger that logged the message.
|
||||||
final String loggerName;
|
final String loggerName;
|
||||||
|
|
||||||
|
/// The log message.
|
||||||
|
///
|
||||||
|
/// The message should be a normal and complete sentence ending with a period.
|
||||||
|
/// It is OK to omit the subject in the message to imply [loggerName]. It is
|
||||||
|
/// also OK to omit article, such as "the" and "a".
|
||||||
|
///
|
||||||
|
/// Example: if [loggerName] is "FlutterDriver" and [message] is "Failed to
|
||||||
|
/// connect to application." then this log record means that FlutterDriver
|
||||||
|
/// failed to connect to the application.
|
||||||
final String message;
|
final String message;
|
||||||
|
|
||||||
|
/// Short description of the log level.
|
||||||
|
///
|
||||||
|
/// It is meant to be read by humans. There's no guarantee that this value is
|
||||||
|
/// stable enough to be parsed by machines.
|
||||||
String get levelDescription => level.toString().split(".").last;
|
String get levelDescription => level.toString().split(".").last;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String toString() => '[${levelDescription.padRight(5)}] $loggerName: $message';
|
String toString() => '[${levelDescription.padRight(5)}] $loggerName: $message';
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Package-private; users should use other public logging libraries.
|
/// Logger used internally by Flutter Driver to avoid mandating any specific
|
||||||
|
/// logging library.
|
||||||
|
///
|
||||||
|
/// By default the output from this logger is printed to [stderr]. However, a
|
||||||
|
/// subscriber to the [flutterDriverLog] stream may redirect the log records
|
||||||
|
/// elsewhere, including other logging API. The logger stops sending messages to
|
||||||
|
/// [stderr] upon first subscriber.
|
||||||
|
///
|
||||||
|
/// This class is package-private. Flutter users should use other public logging
|
||||||
|
/// libraries.
|
||||||
class Logger {
|
class Logger {
|
||||||
|
/// Creates a new logger.
|
||||||
Logger(this.name);
|
Logger(this.name);
|
||||||
|
|
||||||
|
/// Identifies the part of the system that emits message into this object.
|
||||||
|
///
|
||||||
|
/// It is common for [name] to be used as an implicit subject of an action
|
||||||
|
/// described in a log message. For example, if you emit message "failed" and
|
||||||
|
/// [name] is "FlutterDriver", the meaning of the message should be understood
|
||||||
|
/// as "FlutterDriver failed". See also [LogRecord.message].
|
||||||
final String name;
|
final String name;
|
||||||
|
|
||||||
|
/// Emits a [LogLevel.trace] record into `this` logger.
|
||||||
void trace(Object message) {
|
void trace(Object message) {
|
||||||
_log(LogLevel.trace, name, message);
|
_log(LogLevel.trace, name, message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Emits a [LogLevel.info] record into `this` logger.
|
||||||
void info(Object message) {
|
void info(Object message) {
|
||||||
_log(LogLevel.info, name, message);
|
_log(LogLevel.info, name, message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Emits a [LogLevel.warning] record into `this` logger.
|
||||||
void warning(Object message) {
|
void warning(Object message) {
|
||||||
_log(LogLevel.warning, name, message);
|
_log(LogLevel.warning, name, message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Emits a [LogLevel.error] record into `this` logger.
|
||||||
void error(Object message) {
|
void error(Object message) {
|
||||||
_log(LogLevel.error, name, message);
|
_log(LogLevel.error, name, message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Emits a [LogLevel.critical] record into `this` logger.
|
||||||
void critical(Object message) {
|
void critical(Object message) {
|
||||||
_log(LogLevel.critical, name, message);
|
_log(LogLevel.critical, name, message);
|
||||||
}
|
}
|
||||||
|
@ -25,7 +25,7 @@ class _DriverBinding extends WidgetsFlutterBinding { // TODO(ianh): refactor so
|
|||||||
@override
|
@override
|
||||||
void initServiceExtensions() {
|
void initServiceExtensions() {
|
||||||
super.initServiceExtensions();
|
super.initServiceExtensions();
|
||||||
FlutterDriverExtension extension = new FlutterDriverExtension();
|
_FlutterDriverExtension extension = new _FlutterDriverExtension._();
|
||||||
registerServiceExtension(
|
registerServiceExtension(
|
||||||
name: _extensionMethodName,
|
name: _extensionMethodName,
|
||||||
callback: extension.call
|
callback: extension.call
|
||||||
@ -55,10 +55,10 @@ typedef Command CommandDeserializerCallback(Map<String, String> params);
|
|||||||
/// Runs the finder and returns the [Element] found, or `null`.
|
/// Runs the finder and returns the [Element] found, or `null`.
|
||||||
typedef Finder FinderConstructor(SerializableFinder finder);
|
typedef Finder FinderConstructor(SerializableFinder finder);
|
||||||
|
|
||||||
class FlutterDriverExtension {
|
class _FlutterDriverExtension {
|
||||||
static final Logger _log = new Logger('FlutterDriverExtension');
|
static final Logger _log = new Logger('FlutterDriverExtension');
|
||||||
|
|
||||||
FlutterDriverExtension() {
|
_FlutterDriverExtension._() {
|
||||||
_commandHandlers.addAll(<String, CommandHandlerCallback>{
|
_commandHandlers.addAll(<String, CommandHandlerCallback>{
|
||||||
'get_health': _getHealth,
|
'get_health': _getHealth,
|
||||||
'tap': _tap,
|
'tap': _tap,
|
||||||
@ -88,11 +88,21 @@ class FlutterDriverExtension {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
final WidgetController prober = new WidgetController(WidgetsBinding.instance);
|
final WidgetController _prober = new WidgetController(WidgetsBinding.instance);
|
||||||
final Map<String, CommandHandlerCallback> _commandHandlers = <String, CommandHandlerCallback>{};
|
final Map<String, CommandHandlerCallback> _commandHandlers = <String, CommandHandlerCallback>{};
|
||||||
final Map<String, CommandDeserializerCallback> _commandDeserializers = <String, CommandDeserializerCallback>{};
|
final Map<String, CommandDeserializerCallback> _commandDeserializers = <String, CommandDeserializerCallback>{};
|
||||||
final Map<String, FinderConstructor> _finders = <String, FinderConstructor>{};
|
final Map<String, FinderConstructor> _finders = <String, FinderConstructor>{};
|
||||||
|
|
||||||
|
/// Processes a driver command configured by [params] and returns a result
|
||||||
|
/// as an arbitrary JSON object.
|
||||||
|
///
|
||||||
|
/// [params] must contain key "command" whose value is a string that
|
||||||
|
/// identifies the kind of the command and its corresponding
|
||||||
|
/// [CommandDeserializerCallback]. Other keys and values are specific to the
|
||||||
|
/// concrete implementation of [Command] and [CommandDeserializerCallback].
|
||||||
|
///
|
||||||
|
/// The returned JSON is command specific. Generally the caller deserializes
|
||||||
|
/// the result into a subclass of [Result], but that's not strictly required.
|
||||||
Future<Map<String, dynamic>> call(Map<String, String> params) async {
|
Future<Map<String, dynamic>> call(Map<String, String> params) async {
|
||||||
try {
|
try {
|
||||||
String commandKind = params['command'];
|
String commandKind = params['command'];
|
||||||
@ -181,7 +191,7 @@ class FlutterDriverExtension {
|
|||||||
|
|
||||||
Future<TapResult> _tap(Command command) async {
|
Future<TapResult> _tap(Command command) async {
|
||||||
Tap tapCommand = command;
|
Tap tapCommand = command;
|
||||||
await prober.tap(await _waitForElement(_createFinder(tapCommand.finder)));
|
await _prober.tap(await _waitForElement(_createFinder(tapCommand.finder)));
|
||||||
return new TapResult();
|
return new TapResult();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -199,20 +209,20 @@ class FlutterDriverExtension {
|
|||||||
final int totalMoves = scrollCommand.duration.inMicroseconds * scrollCommand.frequency ~/ Duration.MICROSECONDS_PER_SECOND;
|
final int totalMoves = scrollCommand.duration.inMicroseconds * scrollCommand.frequency ~/ Duration.MICROSECONDS_PER_SECOND;
|
||||||
Offset delta = new Offset(scrollCommand.dx, scrollCommand.dy) / totalMoves.toDouble();
|
Offset delta = new Offset(scrollCommand.dx, scrollCommand.dy) / totalMoves.toDouble();
|
||||||
Duration pause = scrollCommand.duration ~/ totalMoves;
|
Duration pause = scrollCommand.duration ~/ totalMoves;
|
||||||
Point startLocation = prober.getCenter(target);
|
Point startLocation = _prober.getCenter(target);
|
||||||
Point currentLocation = startLocation;
|
Point currentLocation = startLocation;
|
||||||
TestPointer pointer = new TestPointer(1);
|
TestPointer pointer = new TestPointer(1);
|
||||||
HitTestResult hitTest = new HitTestResult();
|
HitTestResult hitTest = new HitTestResult();
|
||||||
|
|
||||||
prober.binding.hitTest(hitTest, startLocation);
|
_prober.binding.hitTest(hitTest, startLocation);
|
||||||
prober.binding.dispatchEvent(pointer.down(startLocation), hitTest);
|
_prober.binding.dispatchEvent(pointer.down(startLocation), hitTest);
|
||||||
await new Future<Null>.value(); // so that down and move don't happen in the same microtask
|
await new Future<Null>.value(); // so that down and move don't happen in the same microtask
|
||||||
for (int moves = 0; moves < totalMoves; moves++) {
|
for (int moves = 0; moves < totalMoves; moves++) {
|
||||||
currentLocation = currentLocation + delta;
|
currentLocation = currentLocation + delta;
|
||||||
prober.binding.dispatchEvent(pointer.move(currentLocation), hitTest);
|
_prober.binding.dispatchEvent(pointer.move(currentLocation), hitTest);
|
||||||
await new Future<Null>.delayed(pause);
|
await new Future<Null>.delayed(pause);
|
||||||
}
|
}
|
||||||
prober.binding.dispatchEvent(pointer.up(), hitTest);
|
_prober.binding.dispatchEvent(pointer.up(), hitTest);
|
||||||
|
|
||||||
return new ScrollResult();
|
return new ScrollResult();
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,8 @@
|
|||||||
// Use of this source code is governed by a BSD-style license that can be
|
// Use of this source code is governed by a BSD-style license that can be
|
||||||
// found in the LICENSE file.
|
// found in the LICENSE file.
|
||||||
|
|
||||||
|
import 'package:meta/meta.dart';
|
||||||
|
|
||||||
import 'error.dart';
|
import 'error.dart';
|
||||||
import 'message.dart';
|
import 'message.dart';
|
||||||
|
|
||||||
@ -17,6 +19,7 @@ DriverError _createInvalidKeyValueTypeError(String invalidType) {
|
|||||||
/// required beyond the [finder] the implementation may override [serialize]
|
/// required beyond the [finder] the implementation may override [serialize]
|
||||||
/// and add more keys to the returned map.
|
/// and add more keys to the returned map.
|
||||||
abstract class CommandWithTarget extends Command {
|
abstract class CommandWithTarget extends Command {
|
||||||
|
/// Constructs this command given a [finder].
|
||||||
CommandWithTarget(this.finder) {
|
CommandWithTarget(this.finder) {
|
||||||
if (finder == null)
|
if (finder == null)
|
||||||
throw new DriverError('${this.runtimeType} target cannot be null');
|
throw new DriverError('${this.runtimeType} target cannot be null');
|
||||||
@ -42,11 +45,20 @@ class WaitFor extends CommandWithTarget {
|
|||||||
@override
|
@override
|
||||||
final String kind = 'waitFor';
|
final String kind = 'waitFor';
|
||||||
|
|
||||||
|
/// Creates a command that waits for the widget identified by [finder] to
|
||||||
|
/// appear within the [timeout] amount of time.
|
||||||
|
///
|
||||||
|
/// If [timeout] is not specified the command times out after 5 seconds.
|
||||||
WaitFor(SerializableFinder finder, {this.timeout})
|
WaitFor(SerializableFinder finder, {this.timeout})
|
||||||
: super(finder);
|
: super(finder);
|
||||||
|
|
||||||
|
/// The maximum amount of time to wait for the [finder] to locate the desired
|
||||||
|
/// widgets before timing out the command.
|
||||||
|
///
|
||||||
|
/// Defaults to 5 seconds.
|
||||||
final Duration timeout;
|
final Duration timeout;
|
||||||
|
|
||||||
|
/// Deserializes the command from JSON generated by [serialize].
|
||||||
static WaitFor deserialize(Map<String, String> json) {
|
static WaitFor deserialize(Map<String, String> json) {
|
||||||
Duration timeout = json['timeout'] != null
|
Duration timeout = json['timeout'] != null
|
||||||
? new Duration(milliseconds: int.parse(json['timeout']))
|
? new Duration(milliseconds: int.parse(json['timeout']))
|
||||||
@ -66,9 +78,9 @@ class WaitFor extends CommandWithTarget {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The result of a [WaitFor] command.
|
||||||
class WaitForResult extends Result {
|
class WaitForResult extends Result {
|
||||||
WaitForResult();
|
/// Deserializes the result from JSON.
|
||||||
|
|
||||||
static WaitForResult fromJson(Map<String, dynamic> json) {
|
static WaitForResult fromJson(Map<String, dynamic> json) {
|
||||||
return new WaitForResult();
|
return new WaitForResult();
|
||||||
}
|
}
|
||||||
@ -79,8 +91,10 @@ class WaitForResult extends Result {
|
|||||||
|
|
||||||
/// Describes how to the driver should search for elements.
|
/// Describes how to the driver should search for elements.
|
||||||
abstract class SerializableFinder {
|
abstract class SerializableFinder {
|
||||||
|
/// Identifies the type of finder to be used by the driver extension.
|
||||||
String get finderType;
|
String get finderType;
|
||||||
|
|
||||||
|
/// Deserializes a finder from JSON generated by [serialize].
|
||||||
static SerializableFinder deserialize(Map<String, String> json) {
|
static SerializableFinder deserialize(Map<String, String> json) {
|
||||||
String finderType = json['finderType'];
|
String finderType = json['finderType'];
|
||||||
switch(finderType) {
|
switch(finderType) {
|
||||||
@ -91,6 +105,11 @@ abstract class SerializableFinder {
|
|||||||
throw new DriverError('Unsupported search specification type $finderType');
|
throw new DriverError('Unsupported search specification type $finderType');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Serializes common fields to JSON.
|
||||||
|
///
|
||||||
|
/// Methods that override [serialize] are expected to call `super.serialize`
|
||||||
|
/// and add more fields to the returned [Map].
|
||||||
|
@mustCallSuper
|
||||||
Map<String, String> serialize() => <String, String>{
|
Map<String, String> serialize() => <String, String>{
|
||||||
'finderType': finderType,
|
'finderType': finderType,
|
||||||
};
|
};
|
||||||
@ -101,6 +120,7 @@ class ByTooltipMessage extends SerializableFinder {
|
|||||||
@override
|
@override
|
||||||
final String finderType = 'ByTooltipMessage';
|
final String finderType = 'ByTooltipMessage';
|
||||||
|
|
||||||
|
/// Creates a tooltip finder given the tooltip's message [text].
|
||||||
ByTooltipMessage(this.text);
|
ByTooltipMessage(this.text);
|
||||||
|
|
||||||
/// Tooltip message text.
|
/// Tooltip message text.
|
||||||
@ -111,6 +131,7 @@ class ByTooltipMessage extends SerializableFinder {
|
|||||||
'text': text,
|
'text': text,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
/// Deserializes the finder from JSON generated by [serialize].
|
||||||
static ByTooltipMessage deserialize(Map<String, String> json) {
|
static ByTooltipMessage deserialize(Map<String, String> json) {
|
||||||
return new ByTooltipMessage(json['text']);
|
return new ByTooltipMessage(json['text']);
|
||||||
}
|
}
|
||||||
@ -121,8 +142,10 @@ class ByText extends SerializableFinder {
|
|||||||
@override
|
@override
|
||||||
final String finderType = 'ByText';
|
final String finderType = 'ByText';
|
||||||
|
|
||||||
|
/// Creates a text finder given the text.
|
||||||
ByText(this.text);
|
ByText(this.text);
|
||||||
|
|
||||||
|
/// The text that appears inside the `Text` widget.
|
||||||
final String text;
|
final String text;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -130,6 +153,7 @@ class ByText extends SerializableFinder {
|
|||||||
'text': text,
|
'text': text,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
/// Deserializes the finder from JSON generated by [serialize].
|
||||||
static ByText deserialize(Map<String, String> json) {
|
static ByText deserialize(Map<String, String> json) {
|
||||||
return new ByText(json['text']);
|
return new ByText(json['text']);
|
||||||
}
|
}
|
||||||
@ -140,6 +164,7 @@ class ByValueKey extends SerializableFinder {
|
|||||||
@override
|
@override
|
||||||
final String finderType = 'ByValueKey';
|
final String finderType = 'ByValueKey';
|
||||||
|
|
||||||
|
/// Creates a finder given the key value.
|
||||||
ByValueKey(dynamic keyValue)
|
ByValueKey(dynamic keyValue)
|
||||||
: this.keyValue = keyValue,
|
: this.keyValue = keyValue,
|
||||||
this.keyValueString = '$keyValue',
|
this.keyValueString = '$keyValue',
|
||||||
@ -165,6 +190,7 @@ class ByValueKey extends SerializableFinder {
|
|||||||
'keyValueType': keyValueType,
|
'keyValueType': keyValueType,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
/// Deserializes the finder from JSON generated by [serialize].
|
||||||
static ByValueKey deserialize(Map<String, String> json) {
|
static ByValueKey deserialize(Map<String, String> json) {
|
||||||
String keyValueString = json['keyValueString'];
|
String keyValueString = json['keyValueString'];
|
||||||
String keyValueType = json['keyValueType'];
|
String keyValueType = json['keyValueType'];
|
||||||
@ -187,6 +213,7 @@ class GetText extends CommandWithTarget {
|
|||||||
@override
|
@override
|
||||||
final String kind = 'get_text';
|
final String kind = 'get_text';
|
||||||
|
|
||||||
|
/// Deserializes the command from JSON generated by [serialize].
|
||||||
static GetText deserialize(Map<String, String> json) {
|
static GetText deserialize(Map<String, String> json) {
|
||||||
return new GetText(SerializableFinder.deserialize(json));
|
return new GetText(SerializableFinder.deserialize(json));
|
||||||
}
|
}
|
||||||
@ -195,11 +222,15 @@ class GetText extends CommandWithTarget {
|
|||||||
Map<String, String> serialize() => super.serialize();
|
Map<String, String> serialize() => super.serialize();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The result of the [GetText] command.
|
||||||
class GetTextResult extends Result {
|
class GetTextResult extends Result {
|
||||||
|
/// Creates a result with the given [text].
|
||||||
GetTextResult(this.text);
|
GetTextResult(this.text);
|
||||||
|
|
||||||
|
/// The text extracted by the [GetText] command.
|
||||||
final String text;
|
final String text;
|
||||||
|
|
||||||
|
/// Deserializes the result from JSON.
|
||||||
static GetTextResult fromJson(Map<String, dynamic> json) {
|
static GetTextResult fromJson(Map<String, dynamic> json) {
|
||||||
return new GetTextResult(json['text']);
|
return new GetTextResult(json['text']);
|
||||||
}
|
}
|
||||||
|
@ -5,12 +5,15 @@
|
|||||||
import 'message.dart';
|
import 'message.dart';
|
||||||
import 'find.dart';
|
import 'find.dart';
|
||||||
|
|
||||||
|
/// Taps on a target widget located by [finder].
|
||||||
class Tap extends CommandWithTarget {
|
class Tap extends CommandWithTarget {
|
||||||
@override
|
@override
|
||||||
final String kind = 'tap';
|
final String kind = 'tap';
|
||||||
|
|
||||||
|
/// Creates a tap command to tap on a widget located by [finder].
|
||||||
Tap(SerializableFinder finder) : super(finder);
|
Tap(SerializableFinder finder) : super(finder);
|
||||||
|
|
||||||
|
/// Deserializes this command from JSON generated by [serialize].
|
||||||
static Tap deserialize(Map<String, String> json) {
|
static Tap deserialize(Map<String, String> json) {
|
||||||
return new Tap(SerializableFinder.deserialize(json));
|
return new Tap(SerializableFinder.deserialize(json));
|
||||||
}
|
}
|
||||||
@ -19,7 +22,9 @@ class Tap extends CommandWithTarget {
|
|||||||
Map<String, String> serialize() => super.serialize();
|
Map<String, String> serialize() => super.serialize();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The result of a [Tap] command.
|
||||||
class TapResult extends Result {
|
class TapResult extends Result {
|
||||||
|
/// Deserializes this result from JSON.
|
||||||
static TapResult fromJson(Map<String, dynamic> json) {
|
static TapResult fromJson(Map<String, dynamic> json) {
|
||||||
return new TapResult();
|
return new TapResult();
|
||||||
}
|
}
|
||||||
@ -34,6 +39,8 @@ class Scroll extends CommandWithTarget {
|
|||||||
@override
|
@override
|
||||||
final String kind = 'scroll';
|
final String kind = 'scroll';
|
||||||
|
|
||||||
|
/// Creates a scroll command that will attempt to scroll a scrollable view by
|
||||||
|
/// dragging a widget located by the given [finder].
|
||||||
Scroll(
|
Scroll(
|
||||||
SerializableFinder finder,
|
SerializableFinder finder,
|
||||||
this.dx,
|
this.dx,
|
||||||
@ -42,6 +49,7 @@ class Scroll extends CommandWithTarget {
|
|||||||
this.frequency
|
this.frequency
|
||||||
) : super(finder);
|
) : super(finder);
|
||||||
|
|
||||||
|
/// Deserializes this command from JSON generated by [serialize].
|
||||||
static Scroll deserialize(Map<String, dynamic> json) {
|
static Scroll deserialize(Map<String, dynamic> json) {
|
||||||
return new Scroll(
|
return new Scroll(
|
||||||
SerializableFinder.deserialize(json),
|
SerializableFinder.deserialize(json),
|
||||||
@ -73,20 +81,9 @@ class Scroll extends CommandWithTarget {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Command the driver to ensure that the element represented by [finder]
|
/// The result of a [Scroll] command.
|
||||||
/// has been scrolled completely into view.
|
|
||||||
class ScrollIntoView extends CommandWithTarget {
|
|
||||||
@override
|
|
||||||
final String kind = 'scrollIntoView';
|
|
||||||
|
|
||||||
ScrollIntoView(SerializableFinder finder) : super(finder);
|
|
||||||
|
|
||||||
static ScrollIntoView deserialize(Map<String, dynamic> json) {
|
|
||||||
return new ScrollIntoView(SerializableFinder.deserialize(json));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class ScrollResult extends Result {
|
class ScrollResult extends Result {
|
||||||
|
/// Deserializes this result from JSON.
|
||||||
static ScrollResult fromJson(Map<String, dynamic> json) {
|
static ScrollResult fromJson(Map<String, dynamic> json) {
|
||||||
return new ScrollResult();
|
return new ScrollResult();
|
||||||
}
|
}
|
||||||
@ -94,3 +91,24 @@ class ScrollResult extends Result {
|
|||||||
@override
|
@override
|
||||||
Map<String, dynamic> toJson() => <String, dynamic>{};
|
Map<String, dynamic> toJson() => <String, dynamic>{};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Command the driver to ensure that the element represented by [finder]
|
||||||
|
/// has been scrolled completely into view.
|
||||||
|
class ScrollIntoView extends CommandWithTarget {
|
||||||
|
@override
|
||||||
|
final String kind = 'scrollIntoView';
|
||||||
|
|
||||||
|
/// Creates this command given a [finder] used to locate the widget to be
|
||||||
|
/// scrolled into view.
|
||||||
|
ScrollIntoView(SerializableFinder finder) : super(finder);
|
||||||
|
|
||||||
|
/// Deserializes this command from JSON generated by [serialize].
|
||||||
|
static ScrollIntoView deserialize(Map<String, dynamic> json) {
|
||||||
|
return new ScrollIntoView(SerializableFinder.deserialize(json));
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is here just to be clear that this command isn't adding any extra
|
||||||
|
// fields.
|
||||||
|
@override
|
||||||
|
Map<String, String> serialize() => super.serialize();
|
||||||
|
}
|
||||||
|
@ -10,6 +10,7 @@ class GetHealth implements Command {
|
|||||||
@override
|
@override
|
||||||
final String kind = 'get_health';
|
final String kind = 'get_health';
|
||||||
|
|
||||||
|
/// Deserializes the command from JSON generated by [serialize].
|
||||||
static GetHealth deserialize(Map<String, String> json) => new GetHealth();
|
static GetHealth deserialize(Map<String, String> json) => new GetHealth();
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -30,10 +31,12 @@ final EnumIndex<HealthStatus> _healthStatusIndex =
|
|||||||
|
|
||||||
/// Application health status.
|
/// Application health status.
|
||||||
class Health extends Result {
|
class Health extends Result {
|
||||||
|
/// Creates a [Health] object with the given [status].
|
||||||
Health(this.status) {
|
Health(this.status) {
|
||||||
assert(status != null);
|
assert(status != null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Deserializes the result from JSON.
|
||||||
static Health fromJson(Map<String, dynamic> json) {
|
static Health fromJson(Map<String, dynamic> json) {
|
||||||
return new Health(_healthStatusIndex.lookupBySimpleName(json['status']));
|
return new Health(_healthStatusIndex.lookupBySimpleName(json['status']));
|
||||||
}
|
}
|
||||||
|
@ -5,14 +5,21 @@
|
|||||||
import 'message.dart';
|
import 'message.dart';
|
||||||
import 'find.dart';
|
import 'find.dart';
|
||||||
|
|
||||||
|
/// Sets [text] in a text input widget.
|
||||||
class SetInputText extends CommandWithTarget {
|
class SetInputText extends CommandWithTarget {
|
||||||
@override
|
@override
|
||||||
final String kind = 'setInputText';
|
final String kind = 'setInputText';
|
||||||
|
|
||||||
|
/// Creates a command.
|
||||||
|
///
|
||||||
|
/// [finder] identifies the text input widget. [text] is the string that is
|
||||||
|
/// set as the value of the text input.
|
||||||
SetInputText(SerializableFinder finder, this.text) : super(finder);
|
SetInputText(SerializableFinder finder, this.text) : super(finder);
|
||||||
|
|
||||||
|
/// The value of the text input to set.
|
||||||
final String text;
|
final String text;
|
||||||
|
|
||||||
|
/// Deserializes this command from JSON generated by [serialize].
|
||||||
static SetInputText deserialize(Map<String, dynamic> json) {
|
static SetInputText deserialize(Map<String, dynamic> json) {
|
||||||
String text = json['text'];
|
String text = json['text'];
|
||||||
return new SetInputText(SerializableFinder.deserialize(json), text);
|
return new SetInputText(SerializableFinder.deserialize(json), text);
|
||||||
@ -26,7 +33,9 @@ class SetInputText extends CommandWithTarget {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The result of a [SetInputText] command.
|
||||||
class SetInputTextResult extends Result {
|
class SetInputTextResult extends Result {
|
||||||
|
/// Deserializes this result from JSON.
|
||||||
static SetInputTextResult fromJson(Map<String, dynamic> json) {
|
static SetInputTextResult fromJson(Map<String, dynamic> json) {
|
||||||
return new SetInputTextResult();
|
return new SetInputTextResult();
|
||||||
}
|
}
|
||||||
@ -35,22 +44,32 @@ class SetInputTextResult extends Result {
|
|||||||
Map<String, dynamic> toJson() => <String, dynamic>{};
|
Map<String, dynamic> toJson() => <String, dynamic>{};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Submits text entered in a text input widget.
|
||||||
|
///
|
||||||
|
/// The definition of submitting input text can be found
|
||||||
|
/// [here](https://docs.flutter.io/flutter/material/Input/onSubmitted.html).
|
||||||
class SubmitInputText extends CommandWithTarget {
|
class SubmitInputText extends CommandWithTarget {
|
||||||
@override
|
@override
|
||||||
final String kind = 'submitInputText';
|
final String kind = 'submitInputText';
|
||||||
|
|
||||||
|
/// Create a command that submits text on input widget identified by [finder].
|
||||||
SubmitInputText(SerializableFinder finder) : super(finder);
|
SubmitInputText(SerializableFinder finder) : super(finder);
|
||||||
|
|
||||||
|
/// Deserializes this command from JSON generated by [serialize].
|
||||||
static SubmitInputText deserialize(Map<String, dynamic> json) {
|
static SubmitInputText deserialize(Map<String, dynamic> json) {
|
||||||
return new SubmitInputText(SerializableFinder.deserialize(json));
|
return new SubmitInputText(SerializableFinder.deserialize(json));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The result of a [SubmitInputText] command.
|
||||||
class SubmitInputTextResult extends Result {
|
class SubmitInputTextResult extends Result {
|
||||||
|
/// Creates a result with [text] as the submitted value.
|
||||||
SubmitInputTextResult(this.text);
|
SubmitInputTextResult(this.text);
|
||||||
|
|
||||||
|
/// The submitted value.
|
||||||
final String text;
|
final String text;
|
||||||
|
|
||||||
|
/// Deserializes this result from JSON.
|
||||||
static SubmitInputTextResult fromJson(Map<String, dynamic> json) {
|
static SubmitInputTextResult fromJson(Map<String, dynamic> json) {
|
||||||
return new SubmitInputTextResult(json['text']);
|
return new SubmitInputTextResult(json['text']);
|
||||||
}
|
}
|
||||||
|
@ -3,12 +3,13 @@
|
|||||||
// found in the LICENSE file.
|
// found in the LICENSE file.
|
||||||
|
|
||||||
/// Timeline data recorded by the Flutter runtime.
|
/// Timeline data recorded by the Flutter runtime.
|
||||||
///
|
|
||||||
/// The data is in the `chrome://tracing` format. It can be saved to a file
|
|
||||||
/// and loaded in Chrome for visual inspection.
|
|
||||||
///
|
|
||||||
/// See https://docs.google.com/document/d/1CvAClvFfyA5R-PhYUmn5OOQtYMH4h6I0nSsKchNAySU/preview
|
|
||||||
class Timeline {
|
class Timeline {
|
||||||
|
/// Creates a timeline given JSON-encoded timeline data.
|
||||||
|
///
|
||||||
|
/// [json] is in the `chrome://tracing` format. It can be saved to a file
|
||||||
|
/// and loaded in Chrome for visual inspection.
|
||||||
|
///
|
||||||
|
/// See https://docs.google.com/document/d/1CvAClvFfyA5R-PhYUmn5OOQtYMH4h6I0nSsKchNAySU/preview
|
||||||
factory Timeline.fromJson(Map<String, dynamic> json) {
|
factory Timeline.fromJson(Map<String, dynamic> json) {
|
||||||
return new Timeline._(json, _parseEvents(json));
|
return new Timeline._(json, _parseEvents(json));
|
||||||
}
|
}
|
||||||
@ -24,6 +25,7 @@ class Timeline {
|
|||||||
|
|
||||||
/// A single timeline event.
|
/// A single timeline event.
|
||||||
class TimelineEvent {
|
class TimelineEvent {
|
||||||
|
/// Creates a timeline event given JSON-encoded event data.
|
||||||
factory TimelineEvent(Map<String, dynamic> json) {
|
factory TimelineEvent(Map<String, dynamic> json) {
|
||||||
return new TimelineEvent._(
|
return new TimelineEvent._(
|
||||||
json,
|
json,
|
||||||
|
@ -19,8 +19,9 @@ final JsonEncoder _prettyEncoder = new JsonEncoder.withIndent(' ');
|
|||||||
/// phase. Anything past that is in the danger of missing the frame as 60FPS.
|
/// phase. Anything past that is in the danger of missing the frame as 60FPS.
|
||||||
const Duration kBuildBudget = const Duration(milliseconds: 8);
|
const Duration kBuildBudget = const Duration(milliseconds: 8);
|
||||||
|
|
||||||
/// Extracts statistics from the event loop timeline.
|
/// Extracts statistics from a [Timeline].
|
||||||
class TimelineSummary {
|
class TimelineSummary {
|
||||||
|
/// Creates a timeline summary given a full timeline object.
|
||||||
TimelineSummary.summarize(this._timeline);
|
TimelineSummary.summarize(this._timeline);
|
||||||
|
|
||||||
final Timeline _timeline;
|
final Timeline _timeline;
|
||||||
@ -142,6 +143,7 @@ class TimedEvent {
|
|||||||
/// The duration of the event.
|
/// The duration of the event.
|
||||||
final Duration duration;
|
final Duration duration;
|
||||||
|
|
||||||
|
/// Creates a timed event given begin and end timestamps in microseconds.
|
||||||
TimedEvent(int beginTimeMicros, int endTimeMicros)
|
TimedEvent(int beginTimeMicros, int endTimeMicros)
|
||||||
: this.beginTimeMicros = beginTimeMicros,
|
: this.beginTimeMicros = beginTimeMicros,
|
||||||
this.endTimeMicros = endTimeMicros,
|
this.endTimeMicros = endTimeMicros,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user