Index: lib/src/runner/browser/browser_manager.dart |
diff --git a/lib/src/runner/browser/browser_manager.dart b/lib/src/runner/browser/browser_manager.dart |
new file mode 100644 |
index 0000000000000000000000000000000000000000..44851f0b5525e2ad6fb4f1fc129338c0a70471e0 |
--- /dev/null |
+++ b/lib/src/runner/browser/browser_manager.dart |
@@ -0,0 +1,68 @@ |
+// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file |
+// for details. All rights reserved. Use of this source code is governed by a |
+// BSD-style license that can be found in the LICENSE file. |
+ |
+library unittest.runner.browser.browser_manager; |
+ |
+import 'dart:async'; |
+import 'dart:convert'; |
+ |
+import 'package:http_parser/http_parser.dart'; |
+ |
+import '../../backend/suite.dart'; |
+import '../../util/multi_channel.dart'; |
+import '../../util/remote_exception.dart'; |
+import '../../utils.dart'; |
+import '../load_exception.dart'; |
+import 'iframe_test.dart'; |
+ |
+/// A class that manages the connection to a single running browser. |
+/// |
+/// This is in charge of telling the browser which test suites to load and |
+/// converting its responses into [Suite] objects. |
+class BrowserManager { |
+ /// The channel used to communicate with the browser. |
+ /// |
+ /// This is connected to a page running `static/host.dart`. |
+ final MultiChannel _channel; |
+ |
+ /// Creates a new BrowserManager that communicates with a browser over |
+ /// [webSocket]. |
+ BrowserManager(CompatibleWebSocket webSocket) |
+ : _channel = new MultiChannel( |
+ webSocket.map(JSON.decode), |
+ mapSink(webSocket, JSON.encode)); |
+ |
+ /// Tells the browser the load a test suite from the URL [url]. |
+ /// |
+ /// [url] should be an HTML page with a reference to the JS-compiled test |
+ /// suite. [path] is the path of the original test suite file, which is used |
+ /// for reporting. |
+ Future<Suite> loadSuite(String path, Uri url) { |
+ var suiteChannel = _channel.virtualChannel(); |
+ _channel.sink.add({ |
+ "command": "loadSuite", |
+ "url": url.toString(), |
+ "channel": suiteChannel.id |
+ }); |
+ |
+ // Create a nested MultiChannel because the iframe will be using a channel |
+ // wrapped within the host's channel. |
+ suiteChannel = new MultiChannel(suiteChannel.stream, suiteChannel.sink); |
+ return suiteChannel.stream.first.then((response) { |
+ if (response["type"] == "loadException") { |
+ return new Future.error(new LoadException(path, response["message"])); |
+ } else if (response["type"] == "error") { |
+ var asyncError = RemoteException.deserialize(response["error"]); |
+ return new Future.error( |
+ new LoadException(path, asyncError.error), |
+ asyncError.stackTrace); |
+ } |
+ |
+ return new Suite(path, response["tests"].map((test) { |
+ var testChannel = suiteChannel.virtualChannel(test['channel']); |
+ return new IframeTest(test['name'], testChannel); |
+ })); |
+ }); |
+ } |
+} |