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 |
index a6222bea183ba8e45b7c865c05b58a3443b9a35a..1b1f4c94609676893e86b4616b2a9af547863e8a 100644 |
--- a/lib/src/runner/browser/browser_manager.dart |
+++ b/lib/src/runner/browser/browser_manager.dart |
@@ -11,23 +11,27 @@ import 'package:async/async.dart'; |
import 'package:http_parser/http_parser.dart'; |
import 'package:pool/pool.dart'; |
+import '../../backend/group.dart'; |
import '../../backend/metadata.dart'; |
+import '../../backend/test.dart'; |
import '../../backend/test_platform.dart'; |
import '../../util/multi_channel.dart'; |
+import '../../util/remote_exception.dart'; |
import '../../util/stack_trace_mapper.dart'; |
import '../../utils.dart'; |
import '../application_exception.dart'; |
import '../environment.dart'; |
+import '../load_exception.dart'; |
import '../runner_suite.dart'; |
import 'browser.dart'; |
import 'chrome.dart'; |
import 'content_shell.dart'; |
import 'dartium.dart'; |
import 'firefox.dart'; |
+import 'iframe_test.dart'; |
import 'internet_explorer.dart'; |
import 'phantom_js.dart'; |
import 'safari.dart'; |
-import 'suite.dart'; |
/// A class that manages the connection to a single running browser. |
/// |
@@ -176,16 +180,18 @@ class BrowserManager { |
// prematurely (e.g. via Control-C). |
var suiteVirtualChannel = _channel.virtualChannel(); |
var suiteId = _suiteId++; |
+ var suiteChannel; |
closeIframe() { |
if (_closed) return; |
+ suiteChannel.sink.close(); |
_channel.sink.add({ |
"command": "closeSuite", |
"id": suiteId |
}); |
} |
- return await _pool.withResource(() async { |
+ var response = await _pool.withResource(() { |
_channel.sink.add({ |
"command": "loadSuite", |
"url": url.toString(), |
@@ -193,15 +199,85 @@ class BrowserManager { |
"channel": suiteVirtualChannel.id |
}); |
- try { |
- return await loadBrowserSuite( |
- suiteVirtualChannel, await _environment, path, |
- mapper: mapper, platform: _platform, onClose: () => closeIframe()); |
- } catch (_) { |
- closeIframe(); |
- rethrow; |
- } |
+ // Create a nested MultiChannel because the iframe will be using a channel |
+ // wrapped within the host's channel. |
+ suiteChannel = new MultiChannel( |
+ suiteVirtualChannel.stream, suiteVirtualChannel.sink); |
+ |
+ var completer = new Completer(); |
+ suiteChannel.stream.listen((response) { |
+ if (response["type"] == "print") { |
+ print(response["line"]); |
+ } else { |
+ completer.complete(response); |
+ } |
+ }, onDone: () { |
+ if (!completer.isCompleted) completer.complete(); |
+ }); |
+ |
+ return completer.future.timeout(new Duration(minutes: 1), onTimeout: () { |
+ throw new LoadException( |
+ path, |
+ "Timed out waiting for the test suite to connect on " |
+ "${_platform.name}."); |
+ }); |
}); |
+ |
+ if (response == null) { |
+ closeIframe(); |
+ throw new LoadException( |
+ path, "Connection closed before test suite loaded."); |
+ } |
+ |
+ if (response["type"] == "loadException") { |
+ closeIframe(); |
+ throw new LoadException(path, response["message"]); |
+ } |
+ |
+ if (response["type"] == "error") { |
+ closeIframe(); |
+ var asyncError = RemoteException.deserialize(response["error"]); |
+ await new Future.error( |
+ new LoadException(path, asyncError.error), |
+ asyncError.stackTrace); |
+ } |
+ |
+ return new RunnerSuite( |
+ await _environment, |
+ _deserializeGroup(suiteChannel, mapper, response["root"]), |
+ platform: _platform, |
+ path: path, |
+ onClose: () => closeIframe()); |
+ } |
+ |
+ /// Deserializes [group] into a concrete [Group] class. |
+ Group _deserializeGroup(MultiChannel suiteChannel, |
+ StackTraceMapper mapper, Map group) { |
+ var metadata = new Metadata.deserialize(group['metadata']); |
+ return new Group(group['name'], group['entries'].map((entry) { |
+ if (entry['type'] == 'group') { |
+ return _deserializeGroup(suiteChannel, mapper, entry); |
+ } |
+ |
+ return _deserializeTest(suiteChannel, mapper, entry); |
+ }), |
+ metadata: metadata, |
+ setUpAll: _deserializeTest(suiteChannel, mapper, group['setUpAll']), |
+ tearDownAll: |
+ _deserializeTest(suiteChannel, mapper, group['tearDownAll'])); |
+ } |
+ |
+ /// Deserializes [test] into a concrete [Test] class. |
+ /// |
+ /// Returns `null` if [test] is `null`. |
+ Test _deserializeTest(MultiChannel suiteChannel, StackTraceMapper mapper, |
+ Map test) { |
+ if (test == null) return null; |
+ |
+ var metadata = new Metadata.deserialize(test['metadata']); |
+ var testChannel = suiteChannel.virtualChannel(test['channel']); |
+ return new IframeTest(test['name'], metadata, testChannel, |
+ mapper: mapper); |
} |
/// An implementation of [Environment.displayPause]. |