add several debugger and runtime methods
diff --git a/analysis_options.yaml b/analysis_options.yaml
index e6d99f9..1aa11af 100644
--- a/analysis_options.yaml
+++ b/analysis_options.yaml
@@ -8,4 +8,8 @@
- avoid_init_to_null
- directives_ordering
- slash_for_doc_comments
+ - prefer_const_constructors
+ - prefer_const_constructors_in_immutables
+ - prefer_const_declarations
+ - prefer_const_literals_to_create_immutables
- prefer_final_fields
diff --git a/changelog.md b/changelog.md
index 27a9bb7..1d831f5 100644
--- a/changelog.md
+++ b/changelog.md
@@ -1,5 +1,12 @@
# webkit_inspection_protocol.dart
+## 0.5.1
+- add `Runtime.evaluate`
+- add `Debugger.setBreakpoint`
+- add `Debugger.removeBreakpoint`
+- add `Debugger.evaluateOnCallFrame`
+- add `Debugger.getPossibleBreakpoints`
+
## 0.5.0+1
- fixed a bug in reading type of `WipScope`
diff --git a/lib/src/console.dart b/lib/src/console.dart
index e54f300..72d9e27 100644
--- a/lib/src/console.dart
+++ b/lib/src/console.dart
@@ -9,13 +9,16 @@
class WipConsole extends WipDomain {
WipConsole(WipConnection connection) : super(connection);
- Future enable() => sendCommand('Console.enable');
- Future disable() => sendCommand('Console.disable');
- Future clearMessages() => sendCommand('Console.clearMessages');
+ Future<WipResponse> enable() => sendCommand('Console.enable');
+
+ Future<WipResponse> disable() => sendCommand('Console.disable');
+
+ Future<WipResponse> clearMessages() => sendCommand('Console.clearMessages');
Stream<ConsoleMessageEvent> get onMessage => eventStream(
'Console.messageAdded',
(WipEvent event) => new ConsoleMessageEvent(event));
+
Stream<ConsoleClearedEvent> get onCleared => eventStream(
'Console.messagesCleared',
(WipEvent event) => new ConsoleClearedEvent(event));
@@ -27,7 +30,9 @@
Map get _message => params['message'] as Map;
String get text => _message['text'] as String;
+
String get level => _message['level'] as String;
+
String get url => _message['url'] as String;
Iterable<WipConsoleCallFrame> getStackTrace() {
@@ -52,8 +57,12 @@
WipConsoleCallFrame.fromMap(this._map);
int get columnNumber => _map['columnNumber'] as int;
+
String get functionName => _map['functionName'] as String;
+
int get lineNumber => _map['lineNumber'] as int;
+
String get scriptId => _map['scriptId'] as String;
+
String get url => _map['url'] as String;
}
diff --git a/lib/src/debugger.dart b/lib/src/debugger.dart
index fa4c428..5f5d5c1 100644
--- a/lib/src/debugger.dart
+++ b/lib/src/debugger.dart
@@ -18,32 +18,140 @@
});
}
- Future enable() => sendCommand('Debugger.enable');
- Future disable() => sendCommand('Debugger.disable');
+ Future<WipResponse> enable() => sendCommand('Debugger.enable');
+
+ Future<WipResponse> disable() => sendCommand('Debugger.disable');
Future<String> getScriptSource(String scriptId) async =>
(await sendCommand('Debugger.getScriptSource',
params: {'scriptId': scriptId}))
.result['scriptSource'] as String;
- Future pause() => sendCommand('Debugger.pause');
- Future resume() => sendCommand('Debugger.resume');
+ Future<WipResponse> pause() => sendCommand('Debugger.pause');
- Future stepInto() => sendCommand('Debugger.stepInto');
- Future stepOut() => sendCommand('Debugger.stepOut');
- Future stepOver() => sendCommand('Debugger.stepOver');
+ Future<WipResponse> resume() => sendCommand('Debugger.resume');
- Future setPauseOnExceptions(PauseState state) =>
- sendCommand('Debugger.setPauseOnExceptions',
- params: {'state': _pauseStateToString(state)});
+ Future<WipResponse> stepInto() => sendCommand('Debugger.stepInto');
+
+ Future<WipResponse> stepOut() => sendCommand('Debugger.stepOut');
+
+ Future<WipResponse> stepOver() => sendCommand('Debugger.stepOver');
+
+ Future<WipResponse> setPauseOnExceptions(PauseState state) {
+ return sendCommand('Debugger.setPauseOnExceptions',
+ params: {'state': _pauseStateToString(state)});
+ }
+
+ /// Sets JavaScript breakpoint at a given location.
+ ///
+ /// - `location`: Location to set breakpoint in
+ /// - `condition`: Expression to use as a breakpoint condition. When
+ /// specified, debugger will only stop on the breakpoint if this expression
+ /// evaluates to true.
+ Future<SetBreakpointResponse> setBreakpoint(
+ WipLocation location, {
+ String condition,
+ }) async {
+ Map<String, dynamic> params = {
+ 'location': location.toJsonMap(),
+ };
+ if (condition != null) {
+ params['condition'] = condition;
+ }
+
+ final WipResponse response =
+ await sendCommand('Debugger.setBreakpoint', params: params);
+
+ if (response.result.containsKey('exceptionDetails')) {
+ throw new ExceptionDetails(
+ response.result['exceptionDetails'] as Map<String, dynamic>);
+ } else {
+ return new SetBreakpointResponse(response.json);
+ }
+ }
+
+ /// Removes JavaScript breakpoint.
+ Future<WipResponse> removeBreakpoint(String breakpointId) {
+ return sendCommand('Debugger.removeBreakpoint',
+ params: {'breakpointId': breakpointId});
+ }
+
+ /// Evaluates expression on a given call frame.
+ ///
+ /// - `callFrameId`: Call frame identifier to evaluate on
+ /// - `expression`: Expression to evaluate
+ /// - `returnByValue`: Whether the result is expected to be a JSON object that
+ /// should be sent by value
+ Future<RemoteObject> evaluateOnCallFrame(
+ String callFrameId,
+ String expression, {
+ bool returnByValue,
+ }) async {
+ Map<String, dynamic> params = {
+ 'callFrameId': callFrameId,
+ 'expression': expression,
+ };
+ if (returnByValue != null) {
+ params['returnByValue'] = returnByValue;
+ }
+
+ final WipResponse response =
+ await sendCommand('Debugger.evaluateOnCallFrame', params: params);
+
+ if (response.result.containsKey('exceptionDetails')) {
+ throw new ExceptionDetails(
+ response.result['exceptionDetails'] as Map<String, dynamic>);
+ } else {
+ return new RemoteObject(
+ response.result['result'] as Map<String, dynamic>);
+ }
+ }
+
+ /// Returns possible locations for breakpoint. scriptId in start and end range
+ /// locations should be the same.
+ ///
+ /// - `start`: Start of range to search possible breakpoint locations in
+ /// - `end`: End of range to search possible breakpoint locations in
+ /// (excluding). When not specified, end of scripts is used as end of range.
+ /// - `restrictToFunction`: Only consider locations which are in the same
+ /// (non-nested) function as start.
+ Future<List<WipBreakLocation>> getPossibleBreakpoints(
+ WipLocation start, {
+ WipLocation end,
+ bool restrictToFunction,
+ }) async {
+ Map<String, dynamic> params = {
+ 'start': start.toJsonMap(),
+ };
+ if (end != null) {
+ params['end'] = end.toJsonMap();
+ }
+ if (restrictToFunction != null) {
+ params['restrictToFunction'] = restrictToFunction;
+ }
+
+ final WipResponse response =
+ await sendCommand('Debugger.getPossibleBreakpoints', params: params);
+
+ if (response.result.containsKey('exceptionDetails')) {
+ throw new ExceptionDetails(
+ response.result['exceptionDetails'] as Map<String, dynamic>);
+ } else {
+ List locations = response.result['locations'];
+ return List.from(locations.map((map) => WipBreakLocation(map)));
+ }
+ }
Stream<DebuggerPausedEvent> get onPaused => eventStream(
'Debugger.paused', (WipEvent event) => new DebuggerPausedEvent(event));
+
Stream<GlobalObjectClearedEvent> get onGlobalObjectCleared => eventStream(
'Debugger.globalObjectCleared',
(WipEvent event) => new GlobalObjectClearedEvent(event));
+
Stream<DebuggerResumedEvent> get onResumed => eventStream(
'Debugger.resumed', (WipEvent event) => new DebuggerResumedEvent(event));
+
Stream<ScriptParsedEvent> get onScriptParsed => eventStream(
'Debugger.scriptParsed',
(WipEvent event) => new ScriptParsedEvent(event));
@@ -72,6 +180,8 @@
ScriptParsedEvent(WipEvent event)
: this.script = new WipScript(event.params),
super(event);
+
+ String toString() => script.toString();
}
class GlobalObjectClearedEvent extends WrappedWipEvent {
@@ -86,6 +196,7 @@
DebuggerPausedEvent(WipEvent event) : super(event);
String get reason => params['reason'] as String;
+
Object get data => params['data'];
Iterable<WipCallFrame> getCallFrames() => (params['callFrames'] as List)
@@ -100,9 +211,12 @@
WipCallFrame(this._map);
String get callFrameId => _map['callFrameId'] as String;
+
String get functionName => _map['functionName'] as String;
+
WipLocation get location =>
new WipLocation(_map['location'] as Map<String, dynamic>);
+
WipRemoteObject get thisObject =>
new WipRemoteObject(_map['this'] as Map<String, dynamic>);
@@ -117,9 +231,24 @@
WipLocation(this._map);
- int get columnNumber => _map['columnNumber'] as int;
- int get lineNumber => _map['lineNumber'] as int;
- String get scriptId => _map['scriptId'] as String;
+ WipLocation.fromValues(String scriptId, int lineNumber, {int columnNumber})
+ : _map = {} {
+ _map['scriptId'] = scriptId;
+ _map['lineNumber'] = lineNumber;
+ if (columnNumber != null) {
+ _map['columnNumber'] = columnNumber;
+ }
+ }
+
+ String get scriptId => _map['scriptId'];
+
+ int get lineNumber => _map['lineNumber'];
+
+ int get columnNumber => _map['columnNumber'];
+
+ Map<String, dynamic> toJsonMap() {
+ return _map;
+ }
String toString() => '[${scriptId}:${lineNumber}:${columnNumber}]';
}
@@ -130,10 +259,15 @@
WipRemoteObject(this._map);
String get className => _map['className'] as String;
+
String get description => _map['description'] as String;
+
String get objectId => _map['objectId'] as String;
+
String get subtype => _map['subtype'] as String;
+
String get type => _map['type'] as String;
+
Object get value => _map['value'];
}
@@ -143,12 +277,19 @@
WipScript(this._map);
String get scriptId => _map['scriptId'] as String;
+
String get url => _map['url'] as String;
+
int get startLine => _map['startLine'] as int;
+
int get startColumn => _map['startColumn'] as int;
+
int get endLine => _map['endLine'] as int;
+
int get endColumn => _map['endColumn'] as int;
+
bool get isContentScript => _map['isContentScript'] as bool;
+
String get sourceMapURL => _map['sourceMapURL'] as String;
String toString() => '[script ${scriptId}: ${url}]';
@@ -168,3 +309,27 @@
WipRemoteObject get object =>
new WipRemoteObject(_map['object'] as Map<String, dynamic>);
}
+
+class WipBreakLocation extends WipLocation {
+ WipBreakLocation(Map<String, dynamic> map) : super(map);
+
+ WipBreakLocation.fromValues(String scriptId, int lineNumber,
+ {int columnNumber, String type})
+ : super.fromValues(scriptId, lineNumber, columnNumber: columnNumber) {
+ if (type != null) {
+ _map['type'] = type;
+ }
+ }
+
+ /// Allowed Values: `debuggerStatement`, `call`, `return`.
+ String get type => _map['type'];
+}
+
+/// The response from [WipDebugger.setBreakpoint].
+class SetBreakpointResponse extends WipResponse {
+ SetBreakpointResponse(Map<String, dynamic> json) : super(json);
+
+ String get breakpointId => result['breakpointId'];
+
+ WipLocation get actualLocation => WipLocation(result['actualLocation']);
+}
diff --git a/lib/src/log.dart b/lib/src/log.dart
index eac0a42..772d453 100644
--- a/lib/src/log.dart
+++ b/lib/src/log.dart
@@ -8,8 +8,9 @@
class WipLog extends WipDomain {
WipLog(WipConnection connection) : super(connection);
- Future enable() => sendCommand('Log.enable');
- Future disable() => sendCommand('Log.disable');
+ Future<WipResponse> enable() => sendCommand('Log.enable');
+
+ Future<WipResponse> disable() => sendCommand('Log.disable');
Stream<LogEntry> get onEntryAdded =>
eventStream('Log.entryAdded', (WipEvent event) => new LogEntry(event));
diff --git a/lib/src/page.dart b/lib/src/page.dart
index e7e03f9..e8bf1e5 100644
--- a/lib/src/page.dart
+++ b/lib/src/page.dart
@@ -8,19 +8,19 @@
class WipPage extends WipDomain {
WipPage(WipConnection connection) : super(connection);
- Future enable() => sendCommand('Page.enable');
- Future disable() => sendCommand('Page.disable');
+ Future<WipResponse> enable() => sendCommand('Page.enable');
- Future navigate(String url) =>
+ Future<WipResponse> disable() => sendCommand('Page.disable');
+
+ Future<WipResponse> navigate(String url) =>
sendCommand('Page.navigate', params: {'url': url});
- Future reload({bool ignoreCache, String scriptToEvaluateOnLoad}) {
+ Future<WipResponse> reload(
+ {bool ignoreCache, String scriptToEvaluateOnLoad}) {
var params = <String, dynamic>{};
-
if (ignoreCache != null) {
params['ignoreCache'] = ignoreCache;
}
-
if (scriptToEvaluateOnLoad != null) {
params['scriptToEvaluateOnLoad'] = scriptToEvaluateOnLoad;
}
diff --git a/lib/src/runtime.dart b/lib/src/runtime.dart
index f223fb9..d93eb03 100644
--- a/lib/src/runtime.dart
+++ b/lib/src/runtime.dart
@@ -9,15 +9,40 @@
class WipRuntime extends WipDomain {
WipRuntime(WipConnection connection) : super(connection);
- Future enable() => sendCommand('Runtime.enable');
+ Future<WipResponse> enable() => sendCommand('Runtime.enable');
- Future disable() => sendCommand('Runtime.disable');
+ Future<WipResponse> disable() => sendCommand('Runtime.disable');
/// Evaluates expression on global object.
- Future<RemoteObject> evaluate(String expression) async {
- final WipResponse response = await sendCommand('Runtime.evaluate', params: {
+ ///
+ /// - `returnByValue`: Whether the result is expected to be a JSON object that
+ /// should be sent by value.
+ /// - `contextId`: Specifies in which execution context to perform evaluation.
+ /// If the parameter is omitted the evaluation will be performed in the
+ /// context of the inspected page.
+ /// - `awaitPromise`: Whether execution should await for resulting value and
+ /// return once awaited promise is resolved.
+ Future<RemoteObject> evaluate(
+ String expression, {
+ bool returnByValue,
+ int contextId,
+ bool awaitPromise,
+ }) async {
+ Map<String, dynamic> params = {
'expression': expression,
- });
+ };
+ if (returnByValue != null) {
+ params['returnByValue'] = returnByValue;
+ }
+ if (contextId != null) {
+ params['contextId'] = contextId;
+ }
+ if (awaitPromise != null) {
+ params['awaitPromise'] = awaitPromise;
+ }
+
+ final WipResponse response =
+ await sendCommand('Runtime.evaluate', params: params);
if (response.result.containsKey('exceptionDetails')) {
throw new ExceptionDetails(
@@ -30,28 +55,37 @@
/// Calls function with given declaration on the given object. Object group of
/// the result is inherited from the target object.
+ ///
+ /// Each element in [arguments] must be either a [RemoteObject] or a primitive
+ /// object (int, String, double, bool).
Future<RemoteObject> callFunctionOn(
String functionDeclaration, {
- String objectId,
- int executionContextId,
List<dynamic> arguments,
+ String objectId,
+ bool returnByValue,
+ int executionContextId,
}) async {
Map<String, dynamic> params = {
'functionDeclaration': functionDeclaration,
};
-
if (objectId != null) {
params['objectId'] = objectId;
}
-
+ if (returnByValue != null) {
+ params['returnByValue'] = returnByValue;
+ }
if (executionContextId != null) {
params['executionContextId'] = executionContextId;
}
-
- if (objectId != null) {
- // Convert to a ist of CallArguments.
+ if (arguments != null) {
+ // Convert to a list of RemoteObjects and primitive values to
+ // CallArguments.
params['arguments'] = arguments.map((dynamic value) {
- return {'value': value};
+ if (value is RemoteObject) {
+ return {'objectId': value.objectId};
+ } else {
+ return {'value': value};
+ }
}).toList();
}
@@ -110,6 +144,8 @@
ExceptionDetails(this._map);
+ Map<String, dynamic> get json => _map;
+
/// Exception id.
int get exceptionId => _map['exceptionId'] as int;
diff --git a/lib/src/target.dart b/lib/src/target.dart
index 7e1577d..5b51382 100644
--- a/lib/src/target.dart
+++ b/lib/src/target.dart
@@ -20,7 +20,7 @@
}
/// Activates (focuses) the target.
- Future activateTarget(String targetId) =>
+ Future<WipResponse> activateTarget(String targetId) =>
sendCommand('Target.activateTarget', params: {'targetId': targetId});
/// Closes the target. If the target is a page that gets closed too.
@@ -41,19 +41,17 @@
/// - binding.onmessage = json => handleMessage(json) - a callback that will
/// be called for the protocol notifications and command responses.
@experimental
- Future<void> exposeDevToolsProtocol(
+ Future<WipResponse> exposeDevToolsProtocol(
String targetId, {
String bindingName,
- }) async {
+ }) {
final Map<String, dynamic> params = {'targetId': targetId};
if (bindingName != null) {
params['bindingName'] = bindingName;
}
- final WipResponse response = await sendCommand(
+ return sendCommand(
'Target.exposeDevToolsProtocol',
params: params,
);
- dynamic foo = await response.result['targetId'];
- print(foo);
}
}
diff --git a/lib/webkit_inspection_protocol.dart b/lib/webkit_inspection_protocol.dart
index 358c951..cfc4257 100644
--- a/lib/webkit_inspection_protocol.dart
+++ b/lib/webkit_inspection_protocol.dart
@@ -69,7 +69,7 @@
rethrow;
}
}
- await new Future.delayed(new Duration(milliseconds: 25));
+ await new Future.delayed(const Duration(milliseconds: 25));
}
}
@@ -244,10 +244,12 @@
}
class WipError {
+ final Map<String, dynamic> json;
+
final int id;
final dynamic error;
- WipError(Map<String, dynamic> json)
+ WipError(this.json)
: id = json['id'] as int,
error = json['error'];
@@ -255,10 +257,12 @@
}
class WipResponse {
+ final Map<String, dynamic> json;
+
final int id;
final Map<String, dynamic> result;
- WipResponse(Map<String, dynamic> json)
+ WipResponse(this.json)
: id = json['id'] as int,
result = json['result'] as Map<String, dynamic>;
@@ -290,12 +294,12 @@
.putIfAbsent(
method,
() => new StreamTransformer.fromHandlers(
- handleData: (WipEvent event, EventSink<T> sink) {
- if (event.method == method) {
- sink.add(transformer(event));
- }
- },
- ).bind(connection.onNotification),
+ handleData: (WipEvent event, EventSink<T> sink) {
+ if (event.method == method) {
+ sink.add(transformer(event));
+ }
+ },
+ ).bind(connection.onNotification),
)
.cast();
}
diff --git a/pubspec.yaml b/pubspec.yaml
index 5676af6..3824d82 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -1,11 +1,7 @@
name: webkit_inspection_protocol
-version: 0.5.0+1
+version: 0.5.1
description: A client for the Chrome DevTools Protocol (previously called the Webkit Inspection Protocol).
-
homepage: https://github.com/google/webkit_inspection_protocol.dart
-authors:
-- Devon Carew <devoncarew@google.com>
-- Marc Fisher <fisherii@google.com>
environment:
sdk: '>=2.0.0 <3.0.0'
diff --git a/test/console_test.dart b/test/console_test.dart
index f0375a9..46c5abf 100644
--- a/test/console_test.dart
+++ b/test/console_test.dart
@@ -19,7 +19,7 @@
Future checkMessages(int expectedCount) async {
// make sure all messages have been delivered
- await new Future.delayed(new Duration(seconds: 1));
+ await new Future.delayed(const Duration(seconds: 1));
expect(events, hasLength(expectedCount));
for (int i = 0; i < expectedCount; i++) {
if (i == 0) {
diff --git a/test/data/debugger_test.html b/test/data/debugger_test.html
new file mode 100644
index 0000000..b40e0cd
--- /dev/null
+++ b/test/data/debugger_test.html
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<html>
+<head lang="en">
+ <meta charset="UTF-8">
+ <title></title>
+</head>
+<body>
+<script language="JavaScript">
+ console.clear();
+ console.log('message 1');
+ console.log('message 2');
+ console.log('message 3');
+</script>
+
+</body>
+</html>
diff --git a/test/debugger_test.dart b/test/debugger_test.dart
new file mode 100644
index 0000000..8c2c265
--- /dev/null
+++ b/test/debugger_test.dart
@@ -0,0 +1,97 @@
+// Copyright 2020 Google. All rights reserved. Use of this source code is
+// governed by a BSD-style license that can be found in the LICENSE file.
+
+@TestOn('vm')
+library wip.debugger_test;
+
+import 'dart:async';
+
+import 'package:test/test.dart';
+import 'package:webkit_inspection_protocol/webkit_inspection_protocol.dart';
+
+import 'test_setup.dart';
+
+void main() {
+ group('WipDebugger', () {
+ WipDebugger debugger;
+ List<StreamSubscription> subs = [];
+
+ setUp(() async {
+ debugger = (await wipConnection).debugger;
+ });
+
+ tearDown(() async {
+ await debugger.disable();
+ debugger = null;
+
+ await closeConnection();
+ subs.forEach((s) => s.cancel());
+ subs.clear();
+ });
+
+ test('gets script events', () async {
+ final controller = StreamController<ScriptParsedEvent>();
+ subs.add(debugger.onScriptParsed.listen(controller.add));
+
+ await debugger.enable();
+ await navigateToPage('debugger_test.html');
+
+ expect(controller.stream.first, isNotNull);
+ });
+
+ test('getScriptSource', () async {
+ final controller = StreamController<ScriptParsedEvent>();
+ subs.add(debugger.onScriptParsed.listen(controller.add));
+
+ await debugger.enable();
+ await navigateToPage('debugger_test.html');
+
+ final event = await controller.stream
+ .firstWhere((event) => event.script.url.endsWith('.html'));
+ expect(event.script.scriptId, isNotEmpty);
+
+ final source = await debugger.getScriptSource(event.script.scriptId);
+ expect(source, isNotEmpty);
+ });
+
+ test('getPossibleBreakpoints', () async {
+ final controller = StreamController<ScriptParsedEvent>();
+ subs.add(debugger.onScriptParsed.listen(controller.add));
+
+ await debugger.enable();
+ await navigateToPage('debugger_test.html');
+
+ final event = await controller.stream
+ .firstWhere((event) => event.script.url.endsWith('.html'));
+ expect(event.script.scriptId, isNotEmpty);
+
+ final script = event.script;
+
+ final result = await debugger
+ .getPossibleBreakpoints(WipLocation.fromValues(script.scriptId, 0));
+ expect(result, isNotEmpty);
+ expect(result.any((bp) => bp.lineNumber == 10), true);
+ });
+
+ test('setBreakpoint / removeBreakpoint', () async {
+ final controller = StreamController<ScriptParsedEvent>();
+ subs.add(debugger.onScriptParsed.listen(controller.add));
+
+ await debugger.enable();
+ await navigateToPage('debugger_test.html');
+
+ final event = await controller.stream
+ .firstWhere((event) => event.script.url.endsWith('.html'));
+ expect(event.script.scriptId, isNotEmpty);
+
+ final script = event.script;
+
+ final bpResult = await debugger
+ .setBreakpoint(WipLocation.fromValues(script.scriptId, 10));
+ expect(bpResult.breakpointId, isNotEmpty);
+
+ final result = await debugger.removeBreakpoint(bpResult.breakpointId);
+ expect(result.result, isEmpty);
+ });
+ });
+}
diff --git a/test/test_setup.dart b/test/test_setup.dart
index 940a5cb..5f478b2 100644
--- a/test/test_setup.dart
+++ b/test/test_setup.dart
@@ -106,7 +106,7 @@
await (await wipConnection)
.page
.navigate((await _testServerUri).resolve(page).toString());
- await new Future.delayed(new Duration(seconds: 1));
+ await new Future.delayed(const Duration(seconds: 1));
return wipConnection;
}