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;
 }