Properly report load errors caused by browsers.

Previously, all errors were getting reported as part of the first suite
loaded in a given browser, and future suites were timing out. Now one
error is reported per suite.

R=kevmoo@google.com

Review URL: https://codereview.chromium.org//1224423002 .
diff --git a/CHANGELOG.md b/CHANGELOG.md
index e790b21..531ae7a 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,7 @@
+## 0.12.3+6
+
+* Properly report load errors caused by failing to start browsers.
+
 ## 0.12.3+5
 
 * Fix a crash when skipping tests because their platforms don't match.
diff --git a/lib/src/runner/browser/server.dart b/lib/src/runner/browser/server.dart
index 8c9bcf9..0740990 100644
--- a/lib/src/runner/browser/server.dart
+++ b/lib/src/runner/browser/server.dart
@@ -8,6 +8,7 @@
 import 'dart:convert';
 import 'dart:io';
 
+import 'package:async/async.dart';
 import 'package:http_multi_server/http_multi_server.dart';
 import 'package:path/path.dart' as p;
 import 'package:pool/pool.dart';
@@ -134,10 +135,12 @@
   final _browsers = new Map<TestPlatform, Browser>();
 
   /// A map from browser identifiers to futures that will complete to the
-  /// [BrowserManager]s for those browsers.
+  /// [BrowserManager]s for those browsers, or the errors that occurred when
+  /// trying to load those managers.
   ///
   /// This should only be accessed through [_browserManagerFor].
-  final _browserManagers = new Map<TestPlatform, Future<BrowserManager>>();
+  final _browserManagers =
+      new Map<TestPlatform, Future<Result<BrowserManager>>>();
 
   /// A map from test suite paths to Futures that will complete once those
   /// suites are finished compiling.
@@ -408,13 +411,16 @@
   /// If no browser manager is running yet, starts one.
   Future<BrowserManager> _browserManagerFor(TestPlatform platform) {
     var manager = _browserManagers[platform];
-    if (manager != null) return manager;
+    if (manager != null) return Result.release(manager);
 
     var completer = new Completer();
 
-    // Swallow errors, since they're already being surfaced through the return
-    // value and [browser.onError].
-    _browserManagers[platform] = completer.future.catchError((_) {});
+    // Capture errors and release them later to avoid Zone issues. This call to
+    // [_browserManagerFor] is running in a different [LoadSuite] than future
+    // calls, which means they're also running in different error zones so
+    // errors can't be freely passed between them. Storing the error or value as
+    // an explicit [Result] fixes that.
+    _browserManagers[platform] = Result.capture(completer.future);
     var path = _webSocketHandler.create(webSocketHandler((webSocket) {
       completer.complete(new BrowserManager(platform, webSocket));
     }));