mirror of
https://github.com/flutter/flutter
synced 2024-10-13 11:42:54 +00:00
1242 lines
47 KiB
Dart
1242 lines
47 KiB
Dart
// Copyright 2014 The Flutter 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 'dart:async';
|
|
import 'dart:convert';
|
|
|
|
import 'package:flutter_driver/src/common/error.dart';
|
|
import 'package:flutter_driver/src/common/health.dart';
|
|
import 'package:flutter_driver/src/common/layer_tree.dart';
|
|
import 'package:flutter_driver/src/common/wait.dart';
|
|
import 'package:flutter_driver/src/driver/driver.dart';
|
|
import 'package:flutter_driver/src/driver/timeline.dart';
|
|
import 'package:json_rpc_2/json_rpc_2.dart' as rpc;
|
|
import 'package:mockito/mockito.dart';
|
|
import 'package:vm_service_client/vm_service_client.dart';
|
|
import 'package:quiver/testing/async.dart';
|
|
|
|
import 'common.dart';
|
|
|
|
/// Magical timeout value that's different from the default.
|
|
const Duration _kTestTimeout = Duration(milliseconds: 1234);
|
|
const String _kSerializedTestTimeout = '1234';
|
|
const String _kWebScriptPrefix = "window.\$flutterDriver('";
|
|
const String _kWebScriptSuffix = "')";
|
|
|
|
void main() {
|
|
final List<String> log = <String>[];
|
|
driverLog = (String source, String message) {
|
|
log.add('$source: $message');
|
|
};
|
|
|
|
group('VMServiceFlutterDriver.connect', () {
|
|
MockVMServiceClient mockClient;
|
|
MockVM mockVM;
|
|
MockIsolate mockIsolate;
|
|
MockPeer mockPeer;
|
|
MockIsolate otherIsolate;
|
|
|
|
void expectLogContains(String message) {
|
|
expect(log, anyElement(contains(message)));
|
|
}
|
|
|
|
setUp(() {
|
|
log.clear();
|
|
mockClient = MockVMServiceClient();
|
|
mockVM = MockVM();
|
|
mockIsolate = MockIsolate();
|
|
otherIsolate = MockIsolate();
|
|
mockPeer = MockPeer();
|
|
when(mockClient.getVM()).thenAnswer((_) => Future<MockVM>.value(mockVM));
|
|
when(mockClient.onIsolateRunnable).thenAnswer((Invocation invocation) {
|
|
return Stream<VMIsolateRef>.fromIterable(<VMIsolateRef>[otherIsolate]);
|
|
});
|
|
when(mockVM.isolates).thenReturn(<VMRunnableIsolate>[mockIsolate]);
|
|
when(mockIsolate.loadRunnable()).thenAnswer((_) => Future<MockIsolate>.value(mockIsolate));
|
|
when(mockIsolate.load()).thenAnswer((_) => Future<MockIsolate>.value(mockIsolate));
|
|
when(mockIsolate.extensionRpcs).thenReturn(<String>[]);
|
|
when(mockIsolate.onExtensionAdded).thenAnswer((Invocation invocation) {
|
|
return Stream<String>.fromIterable(<String>['ext.flutter.driver']);
|
|
});
|
|
when(mockIsolate.invokeExtension(any, any)).thenAnswer(
|
|
(Invocation invocation) => makeMockResponse(<String, dynamic>{'status': 'ok'}));
|
|
vmServiceConnectFunction = (String url, {Map<String, dynamic> headers}) {
|
|
return Future<VMServiceClientConnection>.value(
|
|
VMServiceClientConnection(mockClient, mockPeer)
|
|
);
|
|
};
|
|
when(otherIsolate.load()).thenAnswer((_) => Future<MockIsolate>.value(otherIsolate));
|
|
when(otherIsolate.resume()).thenAnswer((Invocation invocation) {
|
|
return Future<dynamic>.value(null);
|
|
});
|
|
});
|
|
|
|
tearDown(() async {
|
|
restoreVmServiceConnectFunction();
|
|
});
|
|
|
|
test('connects to isolate paused at start', () async {
|
|
final List<String> connectionLog = <String>[];
|
|
when(mockPeer.sendRequest('streamListen', any)).thenAnswer((Invocation invocation) {
|
|
connectionLog.add('streamListen');
|
|
return null;
|
|
});
|
|
when(mockIsolate.pauseEvent).thenReturn(MockVMPauseStartEvent());
|
|
when(mockIsolate.resume()).thenAnswer((Invocation invocation) {
|
|
connectionLog.add('resume');
|
|
return Future<dynamic>.value(null);
|
|
});
|
|
when(otherIsolate.pauseEvent).thenReturn(MockVMPauseStartEvent());
|
|
when(mockIsolate.onExtensionAdded).thenAnswer((Invocation invocation) {
|
|
connectionLog.add('onExtensionAdded');
|
|
return Stream<String>.fromIterable(<String>['ext.flutter.driver']);
|
|
});
|
|
when(otherIsolate.resume()).thenAnswer((Invocation invocation) {
|
|
connectionLog.add('other-resume');
|
|
return Future<dynamic>.value(null);
|
|
});
|
|
|
|
final FlutterDriver driver = await FlutterDriver.connect(dartVmServiceUrl: '');
|
|
expect(driver, isNotNull);
|
|
expectLogContains('Attempting to resume isolate');
|
|
expect(connectionLog, <String>['streamListen', 'resume', 'other-resume', 'onExtensionAdded']);
|
|
});
|
|
|
|
test('connects to isolate paused mid-flight', () async {
|
|
when(mockIsolate.pauseEvent).thenReturn(MockVMPauseBreakpointEvent());
|
|
when(mockIsolate.resume()).thenAnswer((Invocation invocation) => Future<dynamic>.value(null));
|
|
|
|
final FlutterDriver driver = await FlutterDriver.connect(dartVmServiceUrl: '');
|
|
expect(driver, isNotNull);
|
|
expectLogContains('Attempting to resume isolate');
|
|
});
|
|
|
|
// This test simulates a situation when we believe that the isolate is
|
|
// currently paused, but something else (e.g. a debugger) resumes it before
|
|
// we do. There's no need to fail as we should be able to drive the app
|
|
// just fine.
|
|
test('connects despite losing the race to resume isolate', () async {
|
|
when(mockIsolate.pauseEvent).thenReturn(MockVMPauseBreakpointEvent());
|
|
when(mockIsolate.resume()).thenAnswer((Invocation invocation) {
|
|
// This needs to be wrapped in a closure to not be considered uncaught
|
|
// by package:test
|
|
return Future<dynamic>.error(rpc.RpcException(101, ''));
|
|
});
|
|
|
|
final FlutterDriver driver = await FlutterDriver.connect(dartVmServiceUrl: '');
|
|
expect(driver, isNotNull);
|
|
expectLogContains('Attempted to resume an already resumed isolate');
|
|
});
|
|
|
|
test('connects to unpaused isolate', () async {
|
|
when(mockIsolate.pauseEvent).thenReturn(MockVMResumeEvent());
|
|
final FlutterDriver driver = await FlutterDriver.connect(dartVmServiceUrl: '');
|
|
expect(driver, isNotNull);
|
|
expectLogContains('Isolate is not paused. Assuming application is ready.');
|
|
});
|
|
|
|
test('connects to unpaused when onExtensionAdded does not contain the '
|
|
'driver extension', () async {
|
|
when(mockIsolate.pauseEvent).thenReturn(MockVMResumeEvent());
|
|
when(mockIsolate.extensionRpcs).thenReturn(<String>['ext.flutter.driver']);
|
|
when(mockIsolate.onExtensionAdded).thenAnswer((Invocation invocation) {
|
|
return const Stream<String>.empty();
|
|
});
|
|
final FlutterDriver driver = await FlutterDriver.connect(dartVmServiceUrl: '');
|
|
expect(driver, isNotNull);
|
|
expectLogContains('Isolate is not paused. Assuming application is ready.');
|
|
});
|
|
|
|
test('connects with headers', () async {
|
|
Map<String, dynamic> actualHeaders;
|
|
vmServiceConnectFunction = (String url, {Map<String, dynamic> headers}) {
|
|
actualHeaders = headers;
|
|
return Future<VMServiceClientConnection>.value(
|
|
VMServiceClientConnection(mockClient, mockPeer)
|
|
);
|
|
};
|
|
|
|
final Map<String, String> expectedHeaders = <String, String>{'header-key': 'header-value'};
|
|
final FlutterDriver driver = await FlutterDriver.connect(
|
|
dartVmServiceUrl: '', headers: expectedHeaders);
|
|
expect(driver, isNotNull);
|
|
expect(actualHeaders, equals(expectedHeaders));
|
|
});
|
|
});
|
|
|
|
group('VMServiceFlutterDriver', () {
|
|
MockVMServiceClient mockClient;
|
|
MockPeer mockPeer;
|
|
MockIsolate mockIsolate;
|
|
VMServiceFlutterDriver driver;
|
|
|
|
setUp(() {
|
|
mockClient = MockVMServiceClient();
|
|
mockPeer = MockPeer();
|
|
mockIsolate = MockIsolate();
|
|
when(mockClient.onIsolateRunnable).thenAnswer((Invocation invocation) {
|
|
return Stream<VMIsolateRef>.fromIterable(<VMIsolateRef>[]);
|
|
});
|
|
driver = VMServiceFlutterDriver.connectedTo(mockClient, mockPeer, mockIsolate);
|
|
});
|
|
|
|
test('checks the health of the driver extension', () async {
|
|
when(mockIsolate.invokeExtension(any, any)).thenAnswer(
|
|
(Invocation invocation) => makeMockResponse(<String, dynamic>{'status': 'ok'}));
|
|
final Health result = await driver.checkHealth();
|
|
expect(result.status, HealthStatus.ok);
|
|
});
|
|
|
|
test('closes connection', () async {
|
|
when(mockClient.close()).thenAnswer((Invocation invocation) => Future<dynamic>.value(null));
|
|
await driver.close();
|
|
});
|
|
|
|
group('ByValueKey', () {
|
|
test('restricts value types', () async {
|
|
expect(() => find.byValueKey(null), throwsDriverError);
|
|
});
|
|
|
|
test('finds by ValueKey', () async {
|
|
when(mockIsolate.invokeExtension(any, any)).thenAnswer((Invocation i) {
|
|
expect(i.positionalArguments[1], <String, String>{
|
|
'command': 'tap',
|
|
'timeout': _kSerializedTestTimeout,
|
|
'finderType': 'ByValueKey',
|
|
'keyValueString': 'foo',
|
|
'keyValueType': 'String',
|
|
});
|
|
return makeMockResponse(<String, dynamic>{});
|
|
});
|
|
await driver.tap(find.byValueKey('foo'), timeout: _kTestTimeout);
|
|
});
|
|
});
|
|
|
|
group('BySemanticsLabel', () {
|
|
test('finds by Semantic label using String', () async {
|
|
when(mockIsolate.invokeExtension(any, any)).thenAnswer((Invocation i) {
|
|
expect(i.positionalArguments[1], <String, String>{
|
|
'command': 'tap',
|
|
'timeout': _kSerializedTestTimeout,
|
|
'finderType': 'BySemanticsLabel',
|
|
'label': 'foo',
|
|
});
|
|
return makeMockResponse(<String, dynamic>{});
|
|
});
|
|
await driver.tap(find.bySemanticsLabel('foo'), timeout: _kTestTimeout);
|
|
});
|
|
|
|
test('finds by Semantic label using RegExp', () async {
|
|
when(mockIsolate.invokeExtension(any, any)).thenAnswer((Invocation i) {
|
|
expect(i.positionalArguments[1], <String, String>{
|
|
'command': 'tap',
|
|
'timeout': _kSerializedTestTimeout,
|
|
'finderType': 'BySemanticsLabel',
|
|
'label': '^foo',
|
|
'isRegExp': 'true',
|
|
});
|
|
return makeMockResponse(<String, dynamic>{});
|
|
});
|
|
await driver.tap(find.bySemanticsLabel(RegExp('^foo')), timeout: _kTestTimeout);
|
|
});
|
|
});
|
|
|
|
group('tap', () {
|
|
test('requires a target reference', () async {
|
|
expect(driver.tap(null), throwsDriverError);
|
|
});
|
|
|
|
test('sends the tap command', () async {
|
|
when(mockIsolate.invokeExtension(any, any)).thenAnswer((Invocation i) {
|
|
expect(i.positionalArguments[1], <String, dynamic>{
|
|
'command': 'tap',
|
|
'timeout': _kSerializedTestTimeout,
|
|
'finderType': 'ByText',
|
|
'text': 'foo',
|
|
});
|
|
return makeMockResponse(<String, dynamic>{});
|
|
});
|
|
await driver.tap(find.text('foo'), timeout: _kTestTimeout);
|
|
});
|
|
});
|
|
|
|
group('getText', () {
|
|
test('requires a target reference', () async {
|
|
expect(driver.getText(null), throwsDriverError);
|
|
});
|
|
|
|
test('sends the getText command', () async {
|
|
when(mockIsolate.invokeExtension(any, any)).thenAnswer((Invocation i) {
|
|
expect(i.positionalArguments[1], <String, dynamic>{
|
|
'command': 'get_text',
|
|
'timeout': _kSerializedTestTimeout,
|
|
'finderType': 'ByValueKey',
|
|
'keyValueString': '123',
|
|
'keyValueType': 'int',
|
|
});
|
|
return makeMockResponse(<String, String>{
|
|
'text': 'hello',
|
|
});
|
|
});
|
|
final String result = await driver.getText(find.byValueKey(123), timeout: _kTestTimeout);
|
|
expect(result, 'hello');
|
|
});
|
|
});
|
|
|
|
group('getLayerTree', () {
|
|
test('sends the getLayerTree command', () async {
|
|
when(mockIsolate.invokeExtension(any, any)).thenAnswer((Invocation i) {
|
|
expect(i.positionalArguments[1], <String, dynamic>{
|
|
'command': 'get_layer_tree',
|
|
'timeout': _kSerializedTestTimeout,
|
|
});
|
|
return makeMockResponse(<String, String>{
|
|
'tree': 'hello',
|
|
});
|
|
});
|
|
final LayerTree result = await driver.getLayerTree(timeout: _kTestTimeout);
|
|
final LayerTree referenceTree = LayerTree.fromJson(<String, String>{
|
|
'tree': 'hello',
|
|
});
|
|
expect(result.tree, referenceTree.tree);
|
|
});
|
|
});
|
|
|
|
group('waitFor', () {
|
|
test('requires a target reference', () async {
|
|
expect(driver.waitFor(null), throwsDriverError);
|
|
});
|
|
|
|
test('sends the waitFor command', () async {
|
|
when(mockIsolate.invokeExtension(any, any)).thenAnswer((Invocation i) {
|
|
expect(i.positionalArguments[1], <String, dynamic>{
|
|
'command': 'waitFor',
|
|
'finderType': 'ByTooltipMessage',
|
|
'text': 'foo',
|
|
'timeout': _kSerializedTestTimeout,
|
|
});
|
|
return makeMockResponse(<String, dynamic>{});
|
|
});
|
|
await driver.waitFor(find.byTooltip('foo'), timeout: _kTestTimeout);
|
|
});
|
|
});
|
|
|
|
group('getWidgetDiagnostics', () {
|
|
test('sends the getWidgetDiagnostics command', () async {
|
|
when(mockIsolate.invokeExtension(any, any)).thenAnswer((Invocation i) {
|
|
expect(i.positionalArguments[1], <String, dynamic>{
|
|
'command': 'get_diagnostics_tree',
|
|
'diagnosticsType': 'widget',
|
|
'finderType': 'ByTooltipMessage',
|
|
'text': 'foo',
|
|
'includeProperties': 'true',
|
|
'subtreeDepth': '0',
|
|
'timeout': _kSerializedTestTimeout,
|
|
});
|
|
return makeMockResponse(<String, dynamic>{});
|
|
});
|
|
await driver.getWidgetDiagnostics(find.byTooltip('foo'), timeout: _kTestTimeout);
|
|
});
|
|
});
|
|
|
|
group('getRenderObjectDiagnostics', () {
|
|
test('sends the getRenderObjectDiagnostics command', () async {
|
|
when(mockIsolate.invokeExtension(any, any)).thenAnswer((Invocation i) {
|
|
expect(i.positionalArguments[1], <String, dynamic>{
|
|
'command': 'get_diagnostics_tree',
|
|
'diagnosticsType': 'renderObject',
|
|
'finderType': 'ByTooltipMessage',
|
|
'text': 'foo',
|
|
'includeProperties': 'true',
|
|
'subtreeDepth': '0',
|
|
'timeout': _kSerializedTestTimeout,
|
|
});
|
|
return makeMockResponse(<String, dynamic>{});
|
|
});
|
|
await driver.getRenderObjectDiagnostics(find.byTooltip('foo'), timeout: _kTestTimeout);
|
|
});
|
|
});
|
|
|
|
group('waitForCondition', () {
|
|
test('sends the wait for NoPendingFrameCondition command', () async {
|
|
when(mockIsolate.invokeExtension(any, any)).thenAnswer((Invocation i) {
|
|
expect(i.positionalArguments[1], <String, dynamic>{
|
|
'command': 'waitForCondition',
|
|
'timeout': _kSerializedTestTimeout,
|
|
'conditionName': 'NoPendingFrameCondition',
|
|
});
|
|
return makeMockResponse(<String, dynamic>{});
|
|
});
|
|
await driver.waitForCondition(const NoPendingFrame(), timeout: _kTestTimeout);
|
|
});
|
|
|
|
test('sends the wait for NoPendingPlatformMessages command', () async {
|
|
when(mockIsolate.invokeExtension(any, any)).thenAnswer((Invocation i) {
|
|
expect(i.positionalArguments[1], <String, dynamic>{
|
|
'command': 'waitForCondition',
|
|
'timeout': _kSerializedTestTimeout,
|
|
'conditionName': 'NoPendingPlatformMessagesCondition',
|
|
});
|
|
return makeMockResponse(<String, dynamic>{});
|
|
});
|
|
await driver.waitForCondition(const NoPendingPlatformMessages(), timeout: _kTestTimeout);
|
|
});
|
|
|
|
test('sends the waitForCondition of combined conditions command', () async {
|
|
when(mockIsolate.invokeExtension(any, any)).thenAnswer((Invocation i) {
|
|
expect(i.positionalArguments[1], <String, dynamic>{
|
|
'command': 'waitForCondition',
|
|
'timeout': _kSerializedTestTimeout,
|
|
'conditionName': 'CombinedCondition',
|
|
'conditions': '[{"conditionName":"NoPendingFrameCondition"},{"conditionName":"NoTransientCallbacksCondition"}]',
|
|
});
|
|
return makeMockResponse(<String, dynamic>{});
|
|
});
|
|
const SerializableWaitCondition combinedCondition =
|
|
CombinedCondition(<SerializableWaitCondition>[NoPendingFrame(), NoTransientCallbacks()]);
|
|
await driver.waitForCondition(combinedCondition, timeout: _kTestTimeout);
|
|
});
|
|
});
|
|
|
|
group('waitUntilNoTransientCallbacks', () {
|
|
test('sends the waitUntilNoTransientCallbacks command', () async {
|
|
when(mockIsolate.invokeExtension(any, any)).thenAnswer((Invocation i) {
|
|
expect(i.positionalArguments[1], <String, dynamic>{
|
|
'command': 'waitForCondition',
|
|
'timeout': _kSerializedTestTimeout,
|
|
'conditionName': 'NoTransientCallbacksCondition',
|
|
});
|
|
return makeMockResponse(<String, dynamic>{});
|
|
});
|
|
await driver.waitUntilNoTransientCallbacks(timeout: _kTestTimeout);
|
|
});
|
|
});
|
|
|
|
group('waitUntilFirstFrameRasterized', () {
|
|
test('sends the waitUntilFirstFrameRasterized command', () async {
|
|
when(mockIsolate.invokeExtension(any, any)).thenAnswer((Invocation i) {
|
|
expect(i.positionalArguments[1], <String, dynamic>{
|
|
'command': 'waitForCondition',
|
|
'conditionName': 'FirstFrameRasterizedCondition',
|
|
});
|
|
return makeMockResponse(<String, dynamic>{});
|
|
});
|
|
await driver.waitUntilFirstFrameRasterized();
|
|
});
|
|
});
|
|
|
|
group('getOffset', () {
|
|
test('requires a target reference', () async {
|
|
expect(driver.getCenter(null), throwsDriverError);
|
|
expect(driver.getTopLeft(null), throwsDriverError);
|
|
expect(driver.getTopRight(null), throwsDriverError);
|
|
expect(driver.getBottomLeft(null), throwsDriverError);
|
|
expect(driver.getBottomRight(null), throwsDriverError);
|
|
});
|
|
|
|
test('sends the getCenter command', () async {
|
|
when(mockIsolate.invokeExtension(any, any)).thenAnswer((Invocation i) {
|
|
expect(i.positionalArguments[1], <String, dynamic>{
|
|
'command': 'get_offset',
|
|
'offsetType': 'center',
|
|
'timeout': _kSerializedTestTimeout,
|
|
'finderType': 'ByValueKey',
|
|
'keyValueString': '123',
|
|
'keyValueType': 'int',
|
|
});
|
|
return makeMockResponse(<String, double>{
|
|
'dx': 11,
|
|
'dy': 12,
|
|
});
|
|
});
|
|
final DriverOffset result = await driver.getCenter(find.byValueKey(123), timeout: _kTestTimeout);
|
|
expect(result, const DriverOffset(11, 12));
|
|
});
|
|
|
|
test('sends the getTopLeft command', () async {
|
|
when(mockIsolate.invokeExtension(any, any)).thenAnswer((Invocation i) {
|
|
expect(i.positionalArguments[1], <String, dynamic>{
|
|
'command': 'get_offset',
|
|
'offsetType': 'topLeft',
|
|
'timeout': _kSerializedTestTimeout,
|
|
'finderType': 'ByValueKey',
|
|
'keyValueString': '123',
|
|
'keyValueType': 'int',
|
|
});
|
|
return makeMockResponse(<String, double>{
|
|
'dx': 11,
|
|
'dy': 12,
|
|
});
|
|
});
|
|
final DriverOffset result = await driver.getTopLeft(find.byValueKey(123), timeout: _kTestTimeout);
|
|
expect(result, const DriverOffset(11, 12));
|
|
});
|
|
|
|
test('sends the getTopRight command', () async {
|
|
when(mockIsolate.invokeExtension(any, any)).thenAnswer((Invocation i) {
|
|
expect(i.positionalArguments[1], <String, dynamic>{
|
|
'command': 'get_offset',
|
|
'offsetType': 'topRight',
|
|
'timeout': _kSerializedTestTimeout,
|
|
'finderType': 'ByValueKey',
|
|
'keyValueString': '123',
|
|
'keyValueType': 'int',
|
|
});
|
|
return makeMockResponse(<String, double>{
|
|
'dx': 11,
|
|
'dy': 12,
|
|
});
|
|
});
|
|
final DriverOffset result = await driver.getTopRight(find.byValueKey(123), timeout: _kTestTimeout);
|
|
expect(result, const DriverOffset(11, 12));
|
|
});
|
|
|
|
test('sends the getBottomLeft command', () async {
|
|
when(mockIsolate.invokeExtension(any, any)).thenAnswer((Invocation i) {
|
|
expect(i.positionalArguments[1], <String, dynamic>{
|
|
'command': 'get_offset',
|
|
'offsetType': 'bottomLeft',
|
|
'timeout': _kSerializedTestTimeout,
|
|
'finderType': 'ByValueKey',
|
|
'keyValueString': '123',
|
|
'keyValueType': 'int',
|
|
});
|
|
return makeMockResponse(<String, double>{
|
|
'dx': 11,
|
|
'dy': 12,
|
|
});
|
|
});
|
|
final DriverOffset result = await driver.getBottomLeft(find.byValueKey(123), timeout: _kTestTimeout);
|
|
expect(result, const DriverOffset(11, 12));
|
|
});
|
|
|
|
test('sends the getBottomRight command', () async {
|
|
when(mockIsolate.invokeExtension(any, any)).thenAnswer((Invocation i) {
|
|
expect(i.positionalArguments[1], <String, dynamic>{
|
|
'command': 'get_offset',
|
|
'offsetType': 'bottomRight',
|
|
'timeout': _kSerializedTestTimeout,
|
|
'finderType': 'ByValueKey',
|
|
'keyValueString': '123',
|
|
'keyValueType': 'int',
|
|
});
|
|
return makeMockResponse(<String, double>{
|
|
'dx': 11,
|
|
'dy': 12,
|
|
});
|
|
});
|
|
final DriverOffset result = await driver.getBottomRight(find.byValueKey(123), timeout: _kTestTimeout);
|
|
expect(result, const DriverOffset(11, 12));
|
|
});
|
|
});
|
|
|
|
group('clearTimeline', () {
|
|
test('clears timeline', () async {
|
|
bool clearWasCalled = false;
|
|
when(mockPeer.sendRequest('clearVMTimeline', argThat(equals(<String, dynamic>{}))))
|
|
.thenAnswer((Invocation invocation) async {
|
|
clearWasCalled = true;
|
|
return null;
|
|
});
|
|
await driver.clearTimeline();
|
|
expect(clearWasCalled, isTrue);
|
|
});
|
|
});
|
|
|
|
group('traceAction', () {
|
|
List<String> log;
|
|
|
|
setUp(() async {
|
|
log = <String>[];
|
|
|
|
when(mockPeer.sendRequest('clearVMTimeline', argThat(equals(<String, dynamic>{}))))
|
|
.thenAnswer((Invocation invocation) async {
|
|
log.add('clear');
|
|
return null;
|
|
});
|
|
|
|
when(mockPeer.sendRequest('getVMTimelineMicros'))
|
|
.thenAnswer((Invocation invocation) async {
|
|
log.add('getVMTimelineMicros');
|
|
return <String, Object>{};
|
|
});
|
|
|
|
when(mockPeer.sendRequest('setVMTimelineFlags', argThat(equals(<String, dynamic>{'recordedStreams': '[all]'}))))
|
|
.thenAnswer((Invocation invocation) async {
|
|
log.add('startTracing');
|
|
return null;
|
|
});
|
|
|
|
when(mockPeer.sendRequest('setVMTimelineFlags', argThat(equals(<String, dynamic>{'recordedStreams': '[]'}))))
|
|
.thenAnswer((Invocation invocation) async {
|
|
log.add('stopTracing');
|
|
return null;
|
|
});
|
|
|
|
when(mockPeer.sendRequest('getVMTimeline')).thenAnswer((Invocation invocation) async {
|
|
log.add('download');
|
|
return <String, dynamic>{
|
|
'traceEvents': <dynamic>[
|
|
<String, String>{
|
|
'name': 'test event',
|
|
},
|
|
],
|
|
};
|
|
});
|
|
});
|
|
|
|
test('without clearing timeline', () async {
|
|
final Timeline timeline = await driver.traceAction(() async {
|
|
log.add('action');
|
|
}, retainPriorEvents: true);
|
|
|
|
expect(log, const <String>[
|
|
'startTracing',
|
|
'action',
|
|
'stopTracing',
|
|
'download',
|
|
]);
|
|
expect(timeline.events.single.name, 'test event');
|
|
});
|
|
|
|
test('with clearing timeline', () async {
|
|
final Timeline timeline = await driver.traceAction(() async {
|
|
log.add('action');
|
|
});
|
|
|
|
expect(log, const <String>[
|
|
'clear',
|
|
'getVMTimelineMicros',
|
|
'startTracing',
|
|
'action',
|
|
'getVMTimelineMicros',
|
|
'stopTracing',
|
|
'download',
|
|
]);
|
|
expect(timeline.events.single.name, 'test event');
|
|
});
|
|
|
|
test('with time interval', () async {
|
|
int count = 0;
|
|
when(mockPeer.sendRequest('getVMTimelineMicros'))
|
|
.thenAnswer((Invocation invocation) async {
|
|
log.add('getVMTimelineMicros');
|
|
return <String, Object>{
|
|
if (count++ == 0)
|
|
'timestamp': 0
|
|
else
|
|
'timestamp': 1000001,
|
|
};
|
|
});
|
|
when(mockPeer.sendRequest('getVMTimeline', argThat(equals(<String, dynamic>{
|
|
'timeOriginMicros': 0,
|
|
'timeExtentMicros': 999999
|
|
}))))
|
|
.thenAnswer((Invocation invocation) async {
|
|
log.add('download 1');
|
|
return <String, dynamic>{
|
|
'traceEvents': <dynamic>[
|
|
<String, String>{
|
|
'name': 'test event 1',
|
|
},
|
|
],
|
|
};
|
|
});
|
|
when(mockPeer.sendRequest('getVMTimeline', argThat(equals(<String, dynamic>{
|
|
'timeOriginMicros': 1000000,
|
|
'timeExtentMicros': 999999,
|
|
}))))
|
|
.thenAnswer((Invocation invocation) async {
|
|
log.add('download 2');
|
|
return <String, dynamic>{
|
|
'traceEvents': <dynamic>[
|
|
<String, String>{
|
|
'name': 'test event 2',
|
|
},
|
|
],
|
|
};
|
|
});
|
|
|
|
|
|
final Timeline timeline = await driver.traceAction(() async {
|
|
log.add('action');
|
|
});
|
|
|
|
expect(log, const <String>[
|
|
'clear',
|
|
'getVMTimelineMicros',
|
|
'startTracing',
|
|
'action',
|
|
'getVMTimelineMicros',
|
|
'stopTracing',
|
|
'download 1',
|
|
'download 2',
|
|
]);
|
|
expect(timeline.events.map((TimelineEvent event) => event.name), <String>[
|
|
'test event 1',
|
|
'test event 2',
|
|
]);
|
|
});
|
|
});
|
|
|
|
group('traceAction with timeline streams', () {
|
|
test('specify non-default timeline streams', () async {
|
|
bool actionCalled = false;
|
|
bool startTracingCalled = false;
|
|
bool stopTracingCalled = false;
|
|
|
|
when(mockPeer.sendRequest('getVMTimelineMicros'))
|
|
.thenAnswer((Invocation invocation) async {
|
|
log.add('getVMTimelineMicros');
|
|
return <String, Object>{};
|
|
});
|
|
|
|
when(mockPeer.sendRequest('setVMTimelineFlags', argThat(equals(<String, dynamic>{'recordedStreams': '[Dart, GC, Compiler]'}))))
|
|
.thenAnswer((Invocation invocation) async {
|
|
startTracingCalled = true;
|
|
return null;
|
|
});
|
|
|
|
when(mockPeer.sendRequest('setVMTimelineFlags', argThat(equals(<String, dynamic>{'recordedStreams': '[]'}))))
|
|
.thenAnswer((Invocation invocation) async {
|
|
stopTracingCalled = true;
|
|
return null;
|
|
});
|
|
|
|
when(mockPeer.sendRequest('getVMTimeline')).thenAnswer((Invocation invocation) async {
|
|
return <String, dynamic>{
|
|
'traceEvents': <dynamic>[
|
|
<String, String>{
|
|
'name': 'test event',
|
|
},
|
|
],
|
|
};
|
|
});
|
|
|
|
final Timeline timeline = await driver.traceAction(() async {
|
|
actionCalled = true;
|
|
},
|
|
streams: const <TimelineStream>[
|
|
TimelineStream.dart,
|
|
TimelineStream.gc,
|
|
TimelineStream.compiler,
|
|
],
|
|
retainPriorEvents: true);
|
|
|
|
expect(actionCalled, isTrue);
|
|
expect(startTracingCalled, isTrue);
|
|
expect(stopTracingCalled, isTrue);
|
|
expect(timeline.events.single.name, 'test event');
|
|
});
|
|
});
|
|
|
|
group('sendCommand error conditions', () {
|
|
test('local default timeout', () async {
|
|
log.clear();
|
|
when(mockIsolate.invokeExtension(any, any)).thenAnswer((Invocation i) {
|
|
// completer never completed to trigger timeout
|
|
return Completer<Map<String, dynamic>>().future;
|
|
});
|
|
FakeAsync().run((FakeAsync time) {
|
|
driver.waitFor(find.byTooltip('foo'));
|
|
expect(log, <String>[]);
|
|
time.elapse(kUnusuallyLongTimeout);
|
|
});
|
|
expect(log, <String>['VMServiceFlutterDriver: waitFor message is taking a long time to complete...']);
|
|
});
|
|
|
|
test('local custom timeout', () async {
|
|
log.clear();
|
|
when(mockIsolate.invokeExtension(any, any)).thenAnswer((Invocation i) {
|
|
// completer never completed to trigger timeout
|
|
return Completer<Map<String, dynamic>>().future;
|
|
});
|
|
FakeAsync().run((FakeAsync time) {
|
|
final Duration customTimeout = kUnusuallyLongTimeout - const Duration(seconds: 1);
|
|
driver.waitFor(find.byTooltip('foo'), timeout: customTimeout);
|
|
expect(log, <String>[]);
|
|
time.elapse(customTimeout);
|
|
});
|
|
expect(log, <String>['VMServiceFlutterDriver: waitFor message is taking a long time to complete...']);
|
|
});
|
|
|
|
test('remote error', () async {
|
|
when(mockIsolate.invokeExtension(any, any)).thenAnswer((Invocation i) {
|
|
return makeMockResponse(<String, dynamic>{
|
|
'message': 'This is a failure',
|
|
}, isError: true);
|
|
});
|
|
try {
|
|
await driver.waitFor(find.byTooltip('foo'));
|
|
fail('expected an exception');
|
|
} catch (error) {
|
|
expect(error, isA<DriverError>());
|
|
expect(error.message, 'Error in Flutter application: {message: This is a failure}');
|
|
}
|
|
});
|
|
|
|
test('uncaught remote error', () async {
|
|
when(mockIsolate.invokeExtension(any, any)).thenAnswer((Invocation i) {
|
|
return Future<Map<String, dynamic>>.error(
|
|
rpc.RpcException(9999, 'test error'),
|
|
);
|
|
});
|
|
|
|
expect(driver.waitFor(find.byTooltip('foo')), throwsDriverError);
|
|
});
|
|
});
|
|
|
|
group('VMServiceFlutterDriver Unsupported error', () {
|
|
test('enableAccessibility', () async {
|
|
expect(driver.enableAccessibility(), throwsA(isA<UnsupportedError>()));
|
|
});
|
|
|
|
test('webDriver', () async {
|
|
expect(() => driver.webDriver, throwsA(isA<UnsupportedError>()));
|
|
});
|
|
});
|
|
});
|
|
|
|
group('VMServiceFlutterDriver with custom timeout', () {
|
|
MockVMServiceClient mockClient;
|
|
MockPeer mockPeer;
|
|
MockIsolate mockIsolate;
|
|
VMServiceFlutterDriver driver;
|
|
|
|
setUp(() {
|
|
mockClient = MockVMServiceClient();
|
|
mockPeer = MockPeer();
|
|
mockIsolate = MockIsolate();
|
|
when(mockClient.onIsolateRunnable).thenAnswer((Invocation invocation) {
|
|
return Stream<VMIsolateRef>.fromIterable(<VMIsolateRef>[]);
|
|
});
|
|
driver = VMServiceFlutterDriver.connectedTo(mockClient, mockPeer, mockIsolate);
|
|
});
|
|
|
|
test('GetHealth has no default timeout', () async {
|
|
when(mockIsolate.invokeExtension(any, any)).thenAnswer((Invocation i) {
|
|
expect(i.positionalArguments[1], <String, String>{
|
|
'command': 'get_health',
|
|
});
|
|
return makeMockResponse(<String, dynamic>{'status': 'ok'});
|
|
});
|
|
await driver.checkHealth();
|
|
});
|
|
|
|
test('does not interfere with explicit timeouts', () async {
|
|
when(mockIsolate.invokeExtension(any, any)).thenAnswer((Invocation i) {
|
|
expect(i.positionalArguments[1], <String, String>{
|
|
'command': 'get_health',
|
|
'timeout': _kSerializedTestTimeout,
|
|
});
|
|
return makeMockResponse(<String, dynamic>{'status': 'ok'});
|
|
});
|
|
await driver.checkHealth(timeout: _kTestTimeout);
|
|
});
|
|
});
|
|
|
|
group('WebFlutterDriver', () {
|
|
MockFlutterWebConnection mockConnection;
|
|
WebFlutterDriver driver;
|
|
|
|
setUp(() {
|
|
mockConnection = MockFlutterWebConnection();
|
|
when(mockConnection.supportsTimelineAction).thenReturn(true);
|
|
driver = WebFlutterDriver.connectedTo(mockConnection);
|
|
});
|
|
|
|
test('closes connection', () async {
|
|
when(mockConnection.close()).thenAnswer((Invocation invocation) => Future<dynamic>.value(null));
|
|
await driver.close();
|
|
});
|
|
|
|
group('ByValueKey', () {
|
|
test('restricts value types', () async {
|
|
expect(() => find.byValueKey(null),
|
|
throwsDriverError);
|
|
});
|
|
|
|
test('finds by ValueKey', () async {
|
|
when(mockConnection.sendCommand(any, any)).thenAnswer((Invocation i) async {
|
|
final String script = _checkAndEncode(i.positionalArguments[0]);
|
|
expect(Map<String, String>.from(jsonDecode(script) as Map<String, dynamic>), <String, String>{
|
|
'command': 'tap',
|
|
'timeout': _kSerializedTestTimeout,
|
|
'finderType': 'ByValueKey',
|
|
'keyValueString': 'foo',
|
|
'keyValueType': 'String',
|
|
});
|
|
return jsonEncode(await makeMockResponse(<String, dynamic>{}));
|
|
});
|
|
await driver.tap(find.byValueKey('foo'), timeout: _kTestTimeout);
|
|
});
|
|
});
|
|
|
|
group('BySemanticsLabel', () {
|
|
test('finds by Semantic label using String', () async {
|
|
when(mockConnection.sendCommand(any, any)).thenAnswer((Invocation i) async {
|
|
final String script = _checkAndEncode(i.positionalArguments[0]);
|
|
expect(Map<String, String>.from(jsonDecode(script) as Map<String, dynamic>), <String, String>{
|
|
'command': 'tap',
|
|
'timeout': _kSerializedTestTimeout,
|
|
'finderType': 'BySemanticsLabel',
|
|
'label': 'foo',
|
|
});
|
|
return jsonEncode(await makeMockResponse(<String, dynamic>{}));
|
|
});
|
|
await driver.tap(find.bySemanticsLabel('foo'), timeout: _kTestTimeout);
|
|
});
|
|
|
|
test('finds by Semantic label using RegExp', () async {
|
|
when(mockConnection.sendCommand(any, any)).thenAnswer((Invocation i) async {
|
|
final String script = _checkAndEncode(i.positionalArguments[0]);
|
|
expect(Map<String, String>.from(jsonDecode(script) as Map<String, dynamic>), <String, String>{
|
|
'command': 'tap',
|
|
'timeout': _kSerializedTestTimeout,
|
|
'finderType': 'BySemanticsLabel',
|
|
'label': '^foo',
|
|
'isRegExp': 'true',
|
|
});
|
|
return jsonEncode(await makeMockResponse(<String, dynamic>{}));
|
|
});
|
|
await driver.tap(find.bySemanticsLabel(RegExp('^foo')), timeout: _kTestTimeout);
|
|
});
|
|
});
|
|
|
|
group('tap', () {
|
|
test('requires a target reference', () async {
|
|
expect(driver.tap(null), throwsDriverError);
|
|
});
|
|
|
|
test('sends the tap command', () async {
|
|
when(mockConnection.sendCommand(any, any)).thenAnswer((Invocation i) async {
|
|
final String script = _checkAndEncode(i.positionalArguments[0]);
|
|
expect(Map<String, String>.from(jsonDecode(script) as Map<String, dynamic>), <String, String>{
|
|
'command': 'tap',
|
|
'timeout': _kSerializedTestTimeout,
|
|
'finderType': 'ByText',
|
|
'text': 'foo',
|
|
});
|
|
return jsonEncode(await makeMockResponse(<String, dynamic>{}));
|
|
});
|
|
await driver.tap(find.text('foo'), timeout: _kTestTimeout);
|
|
});
|
|
});
|
|
|
|
group('getText', () {
|
|
test('requires a target reference', () async {
|
|
expect(driver.getText(null), throwsDriverError);
|
|
});
|
|
|
|
test('sends the getText command', () async {
|
|
when(mockConnection.sendCommand(any, any)).thenAnswer((Invocation i) async {
|
|
final String script = _checkAndEncode(i.positionalArguments[0]);
|
|
expect(Map<String, String>.from(jsonDecode(script) as Map<String, dynamic>), <String, String>{
|
|
'command': 'get_text',
|
|
'timeout': _kSerializedTestTimeout,
|
|
'finderType': 'ByValueKey',
|
|
'keyValueString': '123',
|
|
'keyValueType': 'int',
|
|
});
|
|
return jsonEncode(await makeMockResponse(<String, String>{
|
|
'text': 'hello',
|
|
}));
|
|
});
|
|
final String result = await driver.getText(find.byValueKey(123), timeout: _kTestTimeout);
|
|
expect(result, 'hello');
|
|
});
|
|
});
|
|
|
|
group('waitFor', () {
|
|
test('requires a target reference', () async {
|
|
expect(driver.waitFor(null), throwsDriverError);
|
|
});
|
|
|
|
test('sends the waitFor command', () async {
|
|
when(mockConnection.sendCommand(any, any)).thenAnswer((Invocation i) async {
|
|
final String script = _checkAndEncode(i.positionalArguments[0]);
|
|
expect(Map<String, String>.from(jsonDecode(script) as Map<String, dynamic>), <String, String>{
|
|
'command': 'waitFor',
|
|
'finderType': 'ByTooltipMessage',
|
|
'text': 'foo',
|
|
'timeout': _kSerializedTestTimeout,
|
|
});
|
|
return jsonEncode(await makeMockResponse(<String, dynamic>{}));
|
|
});
|
|
await driver.waitFor(find.byTooltip('foo'), timeout: _kTestTimeout);
|
|
});
|
|
});
|
|
|
|
group('waitForCondition', () {
|
|
test('sends the wait for NoPendingFrameCondition command', () async {
|
|
when(mockConnection.sendCommand(any, any)).thenAnswer((Invocation i) async {
|
|
final String script = _checkAndEncode(i.positionalArguments[0]);
|
|
expect(Map<String, String>.from(jsonDecode(script) as Map<String, dynamic>), <String, String>{
|
|
'command': 'waitForCondition',
|
|
'timeout': _kSerializedTestTimeout,
|
|
'conditionName': 'NoPendingFrameCondition',
|
|
});
|
|
return jsonEncode(await makeMockResponse(<String, dynamic>{}));
|
|
});
|
|
await driver.waitForCondition(const NoPendingFrame(), timeout: _kTestTimeout);
|
|
});
|
|
|
|
test('sends the wait for NoPendingPlatformMessages command', () async {
|
|
when(mockConnection.sendCommand(any, any)).thenAnswer((Invocation i) async {
|
|
final String script = _checkAndEncode(i.positionalArguments[0]);
|
|
expect(Map<String, String>.from(jsonDecode(script) as Map<String, dynamic>), <String, String>{
|
|
'command': 'waitForCondition',
|
|
'timeout': _kSerializedTestTimeout,
|
|
'conditionName': 'NoPendingPlatformMessagesCondition',
|
|
});
|
|
return jsonEncode(await makeMockResponse(<String, dynamic>{}));
|
|
});
|
|
await driver.waitForCondition(const NoPendingPlatformMessages(), timeout: _kTestTimeout);
|
|
});
|
|
|
|
test('sends the waitForCondition of combined conditions command', () async {
|
|
when(mockConnection.sendCommand(any, any)).thenAnswer((Invocation i) async {
|
|
final String script = _checkAndEncode(i.positionalArguments[0]);
|
|
expect(Map<String, String>.from(jsonDecode(script) as Map<String, dynamic>), <String, String>{
|
|
'command': 'waitForCondition',
|
|
'timeout': _kSerializedTestTimeout,
|
|
'conditionName': 'CombinedCondition',
|
|
'conditions': '[{"conditionName":"NoPendingFrameCondition"},{"conditionName":"NoTransientCallbacksCondition"}]',
|
|
});
|
|
return jsonEncode(await makeMockResponse(<String, dynamic>{}));
|
|
});
|
|
const SerializableWaitCondition combinedCondition =
|
|
CombinedCondition(<SerializableWaitCondition>[NoPendingFrame(), NoTransientCallbacks()]);
|
|
await driver.waitForCondition(combinedCondition, timeout: _kTestTimeout);
|
|
});
|
|
});
|
|
|
|
group('waitUntilNoTransientCallbacks', () {
|
|
test('sends the waitUntilNoTransientCallbacks command', () async {
|
|
when(mockConnection.sendCommand(any, any)).thenAnswer((Invocation i) async {
|
|
final String script = _checkAndEncode(i.positionalArguments[0]);
|
|
expect(Map<String, String>.from(jsonDecode(script) as Map<String, dynamic>), <String, String>{
|
|
'command': 'waitForCondition',
|
|
'timeout': _kSerializedTestTimeout,
|
|
'conditionName': 'NoTransientCallbacksCondition',
|
|
});
|
|
return jsonEncode(await makeMockResponse(<String, dynamic>{}));
|
|
});
|
|
await driver.waitUntilNoTransientCallbacks(timeout: _kTestTimeout);
|
|
});
|
|
});
|
|
|
|
group('getOffset', () {
|
|
test('requires a target reference', () async {
|
|
expect(driver.getCenter(null), throwsDriverError);
|
|
expect(driver.getTopLeft(null), throwsDriverError);
|
|
expect(driver.getTopRight(null), throwsDriverError);
|
|
expect(driver.getBottomLeft(null), throwsDriverError);
|
|
expect(driver.getBottomRight(null), throwsDriverError);
|
|
});
|
|
|
|
test('sends the getCenter command', () async {
|
|
when(mockConnection.sendCommand(any, any)).thenAnswer((Invocation i) async {
|
|
final String script = _checkAndEncode(i.positionalArguments[0]);
|
|
expect(Map<String, String>.from(jsonDecode(script) as Map<String, dynamic>), <String, String>{
|
|
'command': 'get_offset',
|
|
'offsetType': 'center',
|
|
'timeout': _kSerializedTestTimeout,
|
|
'finderType': 'ByValueKey',
|
|
'keyValueString': '123',
|
|
'keyValueType': 'int',
|
|
});
|
|
return jsonEncode(await makeMockResponse(<String, double>{
|
|
'dx': 11,
|
|
'dy': 12,
|
|
}));
|
|
});
|
|
final DriverOffset result = await driver.getCenter(find.byValueKey(123), timeout: _kTestTimeout);
|
|
expect(result, const DriverOffset(11, 12));
|
|
});
|
|
|
|
test('sends the getTopLeft command', () async {
|
|
when(mockConnection.sendCommand(any, any)).thenAnswer((Invocation i) async {
|
|
final String script = _checkAndEncode(i.positionalArguments[0]);
|
|
expect(Map<String, String>.from(jsonDecode(script) as Map<String, dynamic>), <String, String>{
|
|
'command': 'get_offset',
|
|
'offsetType': 'topLeft',
|
|
'timeout': _kSerializedTestTimeout,
|
|
'finderType': 'ByValueKey',
|
|
'keyValueString': '123',
|
|
'keyValueType': 'int',
|
|
});
|
|
return jsonEncode(await makeMockResponse(<String, double>{
|
|
'dx': 11,
|
|
'dy': 12,
|
|
}));
|
|
});
|
|
final DriverOffset result = await driver.getTopLeft(find.byValueKey(123), timeout: _kTestTimeout);
|
|
expect(result, const DriverOffset(11, 12));
|
|
});
|
|
|
|
test('sends the getTopRight command', () async {
|
|
when(mockConnection.sendCommand(any, any)).thenAnswer((Invocation i) async {
|
|
final String script = _checkAndEncode(i.positionalArguments[0]);
|
|
expect(Map<String, String>.from(jsonDecode(script) as Map<String, dynamic>), <String, String>{
|
|
'command': 'get_offset',
|
|
'offsetType': 'topRight',
|
|
'timeout': _kSerializedTestTimeout,
|
|
'finderType': 'ByValueKey',
|
|
'keyValueString': '123',
|
|
'keyValueType': 'int',
|
|
});
|
|
return jsonEncode(await makeMockResponse(<String, double>{
|
|
'dx': 11,
|
|
'dy': 12,
|
|
}));
|
|
});
|
|
final DriverOffset result = await driver.getTopRight(find.byValueKey(123), timeout: _kTestTimeout);
|
|
expect(result, const DriverOffset(11, 12));
|
|
});
|
|
|
|
test('sends the getBottomLeft command', () async {
|
|
when(mockConnection.sendCommand(any, any)).thenAnswer((Invocation i) async {
|
|
final String script = _checkAndEncode(i.positionalArguments[0]);
|
|
expect(Map<String, String>.from(jsonDecode(script) as Map<String, dynamic>), <String, String>{
|
|
'command': 'get_offset',
|
|
'offsetType': 'bottomLeft',
|
|
'timeout': _kSerializedTestTimeout,
|
|
'finderType': 'ByValueKey',
|
|
'keyValueString': '123',
|
|
'keyValueType': 'int',
|
|
});
|
|
return jsonEncode(await makeMockResponse(<String, double>{
|
|
'dx': 11,
|
|
'dy': 12,
|
|
}));
|
|
});
|
|
final DriverOffset result = await driver.getBottomLeft(find.byValueKey(123), timeout: _kTestTimeout);
|
|
expect(result, const DriverOffset(11, 12));
|
|
});
|
|
|
|
test('sends the getBottomRight command', () async {
|
|
when(mockConnection.sendCommand(any, any)).thenAnswer((Invocation i) async {
|
|
final String script = _checkAndEncode(i.positionalArguments[0]);
|
|
expect(Map<String, String>.from(jsonDecode(script) as Map<String, dynamic>), <String, String>{
|
|
'command': 'get_offset',
|
|
'offsetType': 'bottomRight',
|
|
'timeout': _kSerializedTestTimeout,
|
|
'finderType': 'ByValueKey',
|
|
'keyValueString': '123',
|
|
'keyValueType': 'int',
|
|
});
|
|
return jsonEncode(await makeMockResponse(<String, double>{
|
|
'dx': 11,
|
|
'dy': 12,
|
|
}));
|
|
});
|
|
final DriverOffset result = await driver.getBottomRight(find.byValueKey(123), timeout: _kTestTimeout);
|
|
expect(result, const DriverOffset(11, 12));
|
|
});
|
|
});
|
|
|
|
test('checks the health of the driver extension', () async {
|
|
when(mockConnection.sendCommand(any, any)).thenAnswer((Invocation i) async {
|
|
final String script = _checkAndEncode(i.positionalArguments[0]);
|
|
expect(Map<String, String>.from(jsonDecode(script) as Map<String, dynamic>), <String, String>{
|
|
'command': 'get_health',
|
|
});
|
|
return jsonEncode(await makeMockResponse(<String, dynamic>{'status': 'ok'}));
|
|
});
|
|
await driver.checkHealth();
|
|
});
|
|
|
|
group('WebFlutterDriver Unimplemented/Unsupported error', () {
|
|
test('forceGC', () async {
|
|
expect(driver.forceGC(),
|
|
throwsA(isA<UnimplementedError>()));
|
|
});
|
|
|
|
test('getVmFlags', () async {
|
|
expect(driver.getVmFlags(),
|
|
throwsA(isA<UnimplementedError>()));
|
|
});
|
|
|
|
test('waitUntilFirstFrameRasterized', () async {
|
|
expect(driver.waitUntilFirstFrameRasterized(),
|
|
throwsA(isA<UnimplementedError>()));
|
|
});
|
|
|
|
test('appIsoloate', () async {
|
|
expect(() => driver.appIsolate.invokeExtension('abc', <String, String>{'abc': '123'}),
|
|
throwsA(isA<UnsupportedError>()));
|
|
});
|
|
|
|
test('serviceClient', () async {
|
|
expect(() => driver.serviceClient.getVM(),
|
|
throwsA(isA<UnsupportedError>()));
|
|
});
|
|
});
|
|
});
|
|
|
|
group('WebFlutterDriver with non-chrome browser', () {
|
|
MockFlutterWebConnection mockConnection;
|
|
WebFlutterDriver driver;
|
|
|
|
setUp(() {
|
|
mockConnection = MockFlutterWebConnection();
|
|
when(mockConnection.supportsTimelineAction).thenReturn(false);
|
|
driver = WebFlutterDriver.connectedTo(mockConnection);
|
|
});
|
|
|
|
test('tracing', () async {
|
|
expect(driver.traceAction(() async { return Future<dynamic>.value(); }),
|
|
throwsA(isA<UnsupportedError>()));
|
|
expect(driver.startTracing(),
|
|
throwsA(isA<UnsupportedError>()));
|
|
expect(driver.stopTracingAndDownloadTimeline(),
|
|
throwsA(isA<UnsupportedError>()));
|
|
expect(driver.clearTimeline(),
|
|
throwsA(isA<UnsupportedError>()));
|
|
});
|
|
});
|
|
}
|
|
|
|
/// This function will verify the format of the script
|
|
/// and return the actual script.
|
|
/// script will be in the following format:
|
|
// window.flutterDriver('[actual script]')
|
|
String _checkAndEncode(dynamic script) {
|
|
expect(script, isA<String>());
|
|
expect(script.startsWith(_kWebScriptPrefix), isTrue);
|
|
expect(script.endsWith(_kWebScriptSuffix), isTrue);
|
|
// Strip prefix and suffix
|
|
return script.substring(_kWebScriptPrefix.length, script.length - 2) as String;
|
|
}
|
|
|
|
Future<Map<String, dynamic>> makeMockResponse(
|
|
Map<String, dynamic> response, {
|
|
bool isError = false,
|
|
}) {
|
|
return Future<Map<String, dynamic>>.value(<String, dynamic>{
|
|
'isError': isError,
|
|
'response': response,
|
|
});
|
|
}
|
|
|
|
class MockVMServiceClient extends Mock implements VMServiceClient { }
|
|
|
|
class MockVM extends Mock implements VM { }
|
|
|
|
class MockIsolate extends Mock implements VMRunnableIsolate { }
|
|
|
|
class MockVMPauseStartEvent extends Mock implements VMPauseStartEvent { }
|
|
|
|
class MockVMPauseBreakpointEvent extends Mock implements VMPauseBreakpointEvent { }
|
|
|
|
class MockVMResumeEvent extends Mock implements VMResumeEvent { }
|
|
|
|
class MockFlutterWebConnection extends Mock implements FlutterWebConnection { }
|
|
|
|
class MockPeer extends Mock implements rpc.Peer {
|
|
@override
|
|
bool get isClosed => false;
|
|
}
|