Skip to content
This repository was archived by the owner on Feb 22, 2023. It is now read-only.

Commit 0f41cff

Browse files
author
nturgut
committed
taking the webdriver specific actions to another file
1 parent 6d85adc commit 0f41cff

File tree

6 files changed

+252
-173
lines changed

6 files changed

+252
-173
lines changed

packages/integration_test/example/test_driver/example_integration_web_extended.dart

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import 'package:integration_test_example/main.dart' as app;
1515
void main() {
1616
final IntegrationTestWidgetsFlutterBinding binding =
1717
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
18+
1819
testWidgets('verify text', (WidgetTester tester) async {
1920
// Build our app and trigger a frame.
2021
app.main();
@@ -33,6 +34,6 @@ void main() {
3334
findsOneWidget,
3435
);
3536

36-
await binding.takeScreenshot('platform');
37+
await binding.driverCommandManager.takeScreenshot('platform_name');
3738
});
3839
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
// Copyright 2019 The Chromium Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
5+
import 'common.dart';
6+
7+
/// The dart:io implementation of [driverCommandManager].
8+
///
9+
/// See also:
10+
///
11+
/// * [_driver_commands_web.dart], which has the dart:html implementation
12+
DriverCommandManager get driverCommandManager => null;
Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
// Copyright 2019 The Chromium Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
5+
import 'dart:async';
6+
7+
import 'package:flutter_test/flutter_test.dart';
8+
9+
import 'common.dart';
10+
11+
/// Manager for sending [WebDriverAction]s to driver side.
12+
///
13+
/// See: [WebDriverCommandManager].
14+
DriverCommandManager get driverCommandManager =>
15+
_singletonWebDriverCommandManager;
16+
17+
/// WebDriverCommandManager singleton.
18+
final WebDriverCommandManager _singletonWebDriverCommandManager =
19+
WebDriverCommandManager();
20+
21+
/// Enables Web Driver commands for `integration_tests`.
22+
///
23+
/// Manages communication between `integration_tests` and the `driver_tests`.
24+
///
25+
/// Tests can execute an Web Driver actions such as `screenshot` using browsers'
26+
/// WebDriver APIs.
27+
///
28+
/// See: https://www.w3.org/TR/webdriver/
29+
class WebDriverCommandManager extends DriverCommandManager {
30+
/// Tests will put the action requests from WebDriver to this pipe.
31+
Completer<WebDriverAction> webDriverActionPipe = Completer<WebDriverAction>();
32+
33+
/// Updated when WebDriver completes the request by the test method.
34+
///
35+
/// For example, a test method will ask for a screenshot by calling
36+
/// `takeScreenshot`. When this screenshot is taken [driverActionComplete]
37+
/// will complete.
38+
Completer<bool> driverActionComplete = Completer<bool>();
39+
40+
/// Takes screenshot using WebDriver screenshot command.
41+
///
42+
/// Only works on Web when tests are run via `flutter driver` command.
43+
///
44+
/// See: https://www.w3.org/TR/webdriver/#screen-capture
45+
Future<void> takeScreenshot(String screenshot_name) async {
46+
await _webDriverCommand(WebDriverAction.screenshot(screenshot_name));
47+
}
48+
49+
Future<void> _webDriverCommand(WebDriverAction command) async {
50+
try {
51+
webDriverActionPipe.complete(Future.value(command));
52+
try {
53+
final bool awaitCommand = await driverActionComplete.future;
54+
if (!awaitCommand) {
55+
throw Exception('Web Driver Command failed: ${command.type}');
56+
}
57+
} catch (e) {
58+
throw Exception(
59+
'Web Driver Command failed: ${command.type} with ' 'exception $e');
60+
}
61+
} finally {
62+
// Reset the completer and release the lock.
63+
driverActionComplete = Completer<bool>();
64+
}
65+
}
66+
67+
/// The callback function to response the driver side input.
68+
///
69+
/// Provides a handshake mechanism for executing [WebDriverAction]s on the
70+
/// driver side.
71+
Future<Map<String, dynamic>> callbackWithDriverCommands(
72+
Map<String, String> params, IntegrationTestResults testRunner) async {
73+
final String command = params['command'];
74+
// Test status is added as an exta message.
75+
final String extraMessage = params['message'] ?? '';
76+
Map<String, String> response;
77+
switch (command) {
78+
case 'request_data':
79+
// If not extra message is added continue as normal.
80+
if (extraMessage.isEmpty) {
81+
final bool allTestsPassed = await testRunner.allTestsPassed.future;
82+
response = <String, String>{
83+
'message': allTestsPassed
84+
? Response.allTestsPassed(data: testRunner.reportData).toJson()
85+
: Response.someTestsFailed(
86+
testRunner.failureMethodsDetails,
87+
data: testRunner.reportData,
88+
).toJson(),
89+
};
90+
} else {
91+
// If Test status is `wait_on_webdriver_command` send the first
92+
// command in the `commandPipe` to the tests.
93+
if (extraMessage == '${TestStatus.waitOnWebdriverCommand}') {
94+
final WebDriverAction action = await webDriverActionPipe.future;
95+
switch (action.type) {
96+
case WebDriverActionTypes.screenshot:
97+
final Map<String, dynamic> data = Map.from(action.values);
98+
data.addAll(
99+
WebDriverAction.typeToMap(WebDriverActionTypes.screenshot));
100+
response = <String, String>{
101+
'message': Response.webDriverCommand(data: data).toJson(),
102+
};
103+
break;
104+
case WebDriverActionTypes.noop:
105+
final Map<String, dynamic> data = Map();
106+
data.addAll(
107+
WebDriverAction.typeToMap(WebDriverActionTypes.noop));
108+
response = <String, String>{
109+
'message': Response.webDriverCommand(data: data).toJson(),
110+
};
111+
break;
112+
default:
113+
throw UnimplementedError('$command is not implemented');
114+
}
115+
}
116+
// Tests will send `webdriver_command_complete` status after
117+
// WebDriver completes an action.
118+
else if (extraMessage == '${TestStatus.webdriverCommandComplete}') {
119+
final Map<String, dynamic> data = Map();
120+
data.addAll(WebDriverAction.typeToMap(WebDriverActionTypes.ack));
121+
response = <String, String>{
122+
'message': Response.webDriverCommand(data: data).toJson(),
123+
};
124+
driverActionComplete.complete(Future.value(true));
125+
webDriverActionPipe = Completer<WebDriverAction>();
126+
} else {
127+
throw UnimplementedError('$command is not implemented');
128+
}
129+
}
130+
break;
131+
case 'get_health':
132+
response = <String, String>{'status': 'ok'};
133+
break;
134+
default:
135+
throw UnimplementedError('$command is not implemented');
136+
}
137+
return <String, dynamic>{
138+
'isError': false,
139+
'response': response,
140+
};
141+
}
142+
143+
@override
144+
void cleanup() {
145+
if (!webDriverActionPipe.isCompleted) {
146+
webDriverActionPipe
147+
.complete(Future<WebDriverAction>.value(WebDriverAction.noop()));
148+
}
149+
150+
if (!driverActionComplete.isCompleted) {
151+
driverActionComplete.complete(Future<bool>.value(false));
152+
}
153+
}
154+
}

packages/integration_test/lib/common.dart

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
// Use of this source code is governed by a BSD-style license that can be
33
// found in the LICENSE file.
44

5+
import 'dart:async';
56
import 'dart:convert';
67

78
/// An object sent from integration_test back to the Flutter Driver in response to
@@ -186,3 +187,40 @@ class WebDriverAction {
186187
'web_driver_action': '${type}',
187188
};
188189
}
190+
191+
/// Template methods to implement for any class which manages communication
192+
/// between `integration_tests` and the `driver_tests`.
193+
///
194+
/// See example [WebDriverCommandManager].
195+
abstract class DriverCommandManager {
196+
/// The callback function to response the driver side input which can also
197+
/// send WebDriver command requests such as `screenshot` to driver side.
198+
Future<Map<String, dynamic>> callbackWithDriverCommands(
199+
Map<String, String> params, IntegrationTestResults testRunner);
200+
201+
/// Request to take a screenshot of the application from the driver side.
202+
void takeScreenshot(String screenshot);
203+
204+
/// Cleanup and completers or locks used during the communication.
205+
void cleanup();
206+
}
207+
208+
/// Interface that surfaces test results of integration tests.
209+
///
210+
/// Implemented by [IntegrationTestWidgetsFlutterBinding]s.
211+
///
212+
/// Any class which needs to access the test results but do not want to create
213+
/// a cyclic dependency [IntegrationTestWidgetsFlutterBinding]s can use this
214+
/// interface. Example [WebDriverCommandManager].
215+
abstract class IntegrationTestResults {
216+
/// Stores failure details.
217+
///
218+
/// Failed test method's names used as key.
219+
List<Failure> get failureMethodsDetails;
220+
221+
/// The extra data for the reported result.
222+
Map<String, dynamic> get reportData;
223+
224+
/// Whether all the test methods completed succesfully.
225+
Completer<bool> get allTestsPassed;
226+
}

0 commit comments

Comments
 (0)