| Index: lib/src/runner/engine.dart
|
| diff --git a/lib/src/runner/engine.dart b/lib/src/runner/engine.dart
|
| index 6bd51bfe726bfa0d875b6575a35ecce311629110..ed88544469073593e889b37943542cd38def2047 100644
|
| --- a/lib/src/runner/engine.dart
|
| +++ b/lib/src/runner/engine.dart
|
| @@ -215,18 +215,35 @@ class Engine {
|
| return;
|
| }
|
|
|
| - for (var entry in group.entries) {
|
| - if (_closed) return;
|
| + var setUpAllSucceeded = true;
|
| + if (group.setUpAll != null) {
|
| + var liveTest = group.setUpAll.load(suite);
|
| + await _runLiveTest(liveTest, countSuccess: false);
|
| + setUpAllSucceeded = liveTest.state.result == Result.success;
|
| + }
|
|
|
| - if (entry is Group) {
|
| - await _runGroup(suite, entry);
|
| - } else if (entry.metadata.skip) {
|
| - await _runLiveTest(_skippedTest(suite, entry));
|
| - } else {
|
| - var test = entry as Test;
|
| - await _runLiveTest(test.load(suite));
|
| + if (!_closed && setUpAllSucceeded) {
|
| + for (var entry in group.entries) {
|
| + if (_closed) return;
|
| +
|
| + if (entry is Group) {
|
| + await _runGroup(suite, entry);
|
| + } else if (entry.metadata.skip) {
|
| + await _runLiveTest(_skippedTest(suite, entry));
|
| + } else {
|
| + var test = entry as Test;
|
| + await _runLiveTest(test.load(suite));
|
| + }
|
| }
|
| }
|
| +
|
| + // Even if we're closed or setUpAll failed, we want to run all the teardowns
|
| + // to ensure that any state is properly cleaned up.
|
| + if (group.tearDownAll != null) {
|
| + var liveTest = group.tearDownAll.load(suite);
|
| + await _runLiveTest(liveTest, countSuccess: false);
|
| + if (_closed) await liveTest.close();
|
| + }
|
| }
|
|
|
| /// Returns a dummy [LiveTest] for a test or group marked as "skip".
|
| @@ -244,7 +261,10 @@ class Engine {
|
| }
|
|
|
| /// Runs [liveTest].
|
| - Future _runLiveTest(LiveTest liveTest) async {
|
| + ///
|
| + /// If [countSuccess] is `true` (the default), the test is put into [passed]
|
| + /// if it succeeds. Otherwise, it's removed from [liveTests] entirely.
|
| + Future _runLiveTest(LiveTest liveTest, {bool countSuccess: true}) async {
|
| _liveTests.add(liveTest);
|
| _active.add(liveTest);
|
|
|
| @@ -270,8 +290,10 @@ class Engine {
|
| _failed.add(liveTest);
|
| } else if (liveTest.test.metadata.skip) {
|
| _skipped.add(liveTest);
|
| - } else {
|
| + } else if (countSuccess) {
|
| _passed.add(liveTest);
|
| + } else {
|
| + _liveTests.remove(liveTest);
|
| }
|
| });
|
|
|
| @@ -342,15 +364,19 @@ class Engine {
|
| /// the engine indicates that no more output should be emitted.
|
| Future close() async {
|
| _closed = true;
|
| - if (_closedBeforeDone == null) _closedBeforeDone = true;
|
| + if (_closedBeforeDone != null) _closedBeforeDone = true;
|
| _suiteController.close();
|
|
|
| // Close the running tests first so that we're sure to wait for them to
|
| // finish before we close their suites and cause them to become unloaded.
|
| var allLiveTests = liveTests.toSet()..addAll(_activeLoadTests);
|
| - await Future.wait(allLiveTests.map((liveTest) => liveTest.close()));
|
| -
|
| - var allSuites = allLiveTests.map((liveTest) => liveTest.suite).toSet();
|
| - await Future.wait(allSuites.map((suite) => suite.close()));
|
| + var futures = allLiveTests.map((liveTest) => liveTest.close()).toList();
|
| +
|
| + // Closing the load pool will close the test suites as soon as their tests
|
| + // are done. For browser suites this is effectively immediate since their
|
| + // tests shut down as soon as they're closed, but for VM suites we may need
|
| + // to wait for tearDowns or tearDownAlls to run.
|
| + futures.add(_loadPool.close());
|
| + await Future.wait(futures, eagerError: true);
|
| }
|
| }
|
|
|