blob: ce38df6355c66116a09000f9a059a61aae0d2548 [file] [log] [blame]
// 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.
import 'dart:async';
import 'package:test/src/backend/group.dart';
import 'package:test/src/backend/invoker.dart';
import 'package:test/src/backend/suite.dart';
import 'package:test/src/backend/test.dart';
import 'package:test/src/frontend/timeout.dart';
import 'package:test/test.dart';
import '../utils.dart';
Suite _suite;
void main() {
setUp(() {
_suite = new Suite(new Group.root([]));
});
group(".test()", () {
test("declares a test with a description and body", () async {
var bodyRun = false;
var tests = declare(() {
test("description", () {
bodyRun = true;
});
});
expect(tests, hasLength(1));
expect(tests.single.name, equals("description"));
await _runTest(tests[0]);
expect(bodyRun, isTrue);
});
test("declares a test with an object as the description", () async {
var tests = declare(() {
test(Object, () {
});
});
expect(tests.single.name, equals("Object"));
});
test("declares multiple tests", () {
var tests = declare(() {
test("description 1", () {});
test("description 2", () {});
test("description 3", () {});
});
expect(tests, hasLength(3));
expect(tests[0].name, equals("description 1"));
expect(tests[1].name, equals("description 2"));
expect(tests[2].name, equals("description 3"));
});
});
group(".setUp()", () {
test("is run before all tests", () async {
var setUpRun = false;
var tests = declare(() {
setUp(() => setUpRun = true);
test("description 1", expectAsync0(() {
expect(setUpRun, isTrue);
setUpRun = false;
}, max: 1));
test("description 2", expectAsync0(() {
expect(setUpRun, isTrue);
setUpRun = false;
}, max: 1));
});
await _runTest(tests[0]);
await _runTest(tests[1]);
});
test("can return a Future", () {
var setUpRun = false;
var tests = declare(() {
setUp(() {
return new Future(() => setUpRun = true);
});
test("description", expectAsync0(() {
expect(setUpRun, isTrue);
}, max: 1));
});
return _runTest(tests.single);
});
test("runs in call order within a group", () async {
var firstSetUpRun = false;
var secondSetUpRun = false;
var thirdSetUpRun = false;
var tests = declare(() {
setUp(expectAsync0(() async {
expect(secondSetUpRun, isFalse);
expect(thirdSetUpRun, isFalse);
firstSetUpRun = true;
}));
setUp(expectAsync0(() async {
expect(firstSetUpRun, isTrue);
expect(thirdSetUpRun, isFalse);
secondSetUpRun = true;
}));
setUp(expectAsync0(() async {
expect(firstSetUpRun, isTrue);
expect(secondSetUpRun, isTrue);
thirdSetUpRun = true;
}));
test("description", expectAsync0(() {
expect(firstSetUpRun, isTrue);
expect(secondSetUpRun, isTrue);
expect(thirdSetUpRun, isTrue);
}));
});
await _runTest(tests.single);
});
});
group(".tearDown()", () {
test("is run after all tests", () async {
var tearDownRun;
var tests = declare(() {
setUp(() => tearDownRun = false);
tearDown(() => tearDownRun = true);
test("description 1", expectAsync0(() {
expect(tearDownRun, isFalse);
}, max: 1));
test("description 2", expectAsync0(() {
expect(tearDownRun, isFalse);
}, max: 1));
});
await _runTest(tests[0]);
expect(tearDownRun, isTrue);
await _runTest(tests[1]);
expect(tearDownRun, isTrue);
});
test("is run after an out-of-band failure", () async {
var tearDownRun;
var tests = declare(() {
setUp(() => tearDownRun = false);
tearDown(() => tearDownRun = true);
test("description 1", expectAsync0(() {
Invoker.current.addOutstandingCallback();
new Future(() => throw new TestFailure("oh no"));
}, max: 1));
});
await _runTest(tests.single, shouldFail: true);
expect(tearDownRun, isTrue);
});
test("can return a Future", () async {
var tearDownRun = false;
var tests = declare(() {
tearDown(() {
return new Future(() => tearDownRun = true);
});
test("description", expectAsync0(() {
expect(tearDownRun, isFalse);
}, max: 1));
});
await _runTest(tests.single);
expect(tearDownRun, isTrue);
});
test("isn't run until there are no outstanding callbacks", () async {
var outstandingCallbackRemoved = false;
var outstandingCallbackRemovedBeforeTeardown = false;
var tests = declare(() {
tearDown(() {
outstandingCallbackRemovedBeforeTeardown = outstandingCallbackRemoved;
});
test("description", () {
Invoker.current.addOutstandingCallback();
pumpEventQueue().then((_) {
outstandingCallbackRemoved = true;
Invoker.current.removeOutstandingCallback();
});
});
});
await _runTest(tests.single);
expect(outstandingCallbackRemovedBeforeTeardown, isTrue);
});
test("doesn't complete until there are no outstanding callbacks", () async {
var outstandingCallbackRemoved = false;
var tests = declare(() {
tearDown(() {
Invoker.current.addOutstandingCallback();
pumpEventQueue().then((_) {
outstandingCallbackRemoved = true;
Invoker.current.removeOutstandingCallback();
});
});
test("description", () {});
});
await _runTest(tests.single);
expect(outstandingCallbackRemoved, isTrue);
});
test("runs in reverse call order within a group", () async {
var firstTearDownRun = false;
var secondTearDownRun = false;
var thirdTearDownRun = false;
var tests = declare(() {
tearDown(expectAsync0(() async {
expect(secondTearDownRun, isTrue);
expect(thirdTearDownRun, isTrue);
firstTearDownRun = true;
}));
tearDown(expectAsync0(() async {
expect(firstTearDownRun, isFalse);
expect(thirdTearDownRun, isTrue);
secondTearDownRun = true;
}));
tearDown(expectAsync0(() async {
expect(firstTearDownRun, isFalse);
expect(secondTearDownRun, isFalse);
thirdTearDownRun = true;
}));
test("description", expectAsync0(() {
expect(firstTearDownRun, isFalse);
expect(secondTearDownRun, isFalse);
expect(thirdTearDownRun, isFalse);
}, max: 1));
});
await _runTest(tests.single);
});
test("runs further tearDowns in a group even if one fails", () async {
var tests = declare(() {
tearDown(expectAsync0(() {}));
tearDown(() async {
throw 'error';
});
test("description", expectAsync0(() {}));
});
await _runTest(tests.single, shouldFail: true);
});
});
group("in a group,", () {
test("tests inherit the group's description", () {
var entries = declare(() {
group("group", () {
test("description", () {});
});
});
expect(entries, hasLength(1));
var testGroup = entries.single as Group;
expect(testGroup.name, equals("group"));
expect(testGroup.entries, hasLength(1));
expect(testGroup.entries.single, new isInstanceOf<Test>());
expect(testGroup.entries.single.name, "group description");
});
test("tests inherit the group's description when it's not a string", () {
var entries = declare(() {
group(Object, () {
test("description", () {});
});
});
expect(entries, hasLength(1));
var testGroup = entries.single as Group;
expect(testGroup.name, equals("Object"));
expect(testGroup.entries, hasLength(1));
expect(testGroup.entries.single, new isInstanceOf<Test>());
expect(testGroup.entries.single.name, "Object description");
});
test("a test's timeout factor is applied to the group's", () {
var entries = declare(() {
group("group", () {
test("test", () {},
timeout: new Timeout.factor(3));
}, timeout: new Timeout.factor(2));
});
expect(entries, hasLength(1));
var testGroup = entries.single as Group;
expect(testGroup.metadata.timeout.scaleFactor, equals(2));
expect(testGroup.entries, hasLength(1));
expect(testGroup.entries.single, new isInstanceOf<Test>());
expect(testGroup.entries.single.metadata.timeout.scaleFactor,
equals(6));
});
test("a test's timeout factor is applied to the group's duration", () {
var entries = declare(() {
group("group", () {
test("test", () {},
timeout: new Timeout.factor(2));
}, timeout: new Timeout(new Duration(seconds: 10)));
});
expect(entries, hasLength(1));
var testGroup = entries.single as Group;
expect(testGroup.metadata.timeout.duration,
equals(new Duration(seconds: 10)));
expect(testGroup.entries, hasLength(1));
expect(testGroup.entries.single, new isInstanceOf<Test>());
expect(testGroup.entries.single.metadata.timeout.duration,
equals(new Duration(seconds: 20)));
});
test("a test's timeout duration is applied over the group's", () {
var entries = declare(() {
group("group", () {
test("test", () {},
timeout: new Timeout(new Duration(seconds: 15)));
}, timeout: new Timeout(new Duration(seconds: 10)));
});
expect(entries, hasLength(1));
var testGroup = entries.single as Group;
expect(testGroup.metadata.timeout.duration,
equals(new Duration(seconds: 10)));
expect(testGroup.entries, hasLength(1));
expect(testGroup.entries.single, new isInstanceOf<Test>());
expect(testGroup.entries.single.metadata.timeout.duration,
equals(new Duration(seconds: 15)));
});
test("disallows asynchronous groups", () async {
declare(() {
expect(() => group("group", () async {}), throwsArgumentError);
});
});
group(".setUp()", () {
test("is scoped to the group", () async {
var setUpRun = false;
var entries = declare(() {
group("group", () {
setUp(() => setUpRun = true);
test("description 1", expectAsync0(() {
expect(setUpRun, isTrue);
setUpRun = false;
}, max: 1));
});
test("description 2", expectAsync0(() {
expect(setUpRun, isFalse);
setUpRun = false;
}, max: 1));
});
await _runTest((entries[0] as Group).entries.single);
await _runTest(entries[1]);
});
test("runs from the outside in", () {
var outerSetUpRun = false;
var middleSetUpRun = false;
var innerSetUpRun = false;
var entries = declare(() {
setUp(expectAsync0(() {
expect(middleSetUpRun, isFalse);
expect(innerSetUpRun, isFalse);
outerSetUpRun = true;
}, max: 1));
group("middle", () {
setUp(expectAsync0(() {
expect(outerSetUpRun, isTrue);
expect(innerSetUpRun, isFalse);
middleSetUpRun = true;
}, max: 1));
group("inner", () {
setUp(expectAsync0(() {
expect(outerSetUpRun, isTrue);
expect(middleSetUpRun, isTrue);
innerSetUpRun = true;
}, max: 1));
test("description", expectAsync0(() {
expect(outerSetUpRun, isTrue);
expect(middleSetUpRun, isTrue);
expect(innerSetUpRun, isTrue);
}, max: 1));
});
});
});
var middleGroup = entries.single as Group;
var innerGroup = middleGroup.entries.single as Group;
return _runTest(innerGroup.entries.single);
});
test("handles Futures when chained", () {
var outerSetUpRun = false;
var innerSetUpRun = false;
var entries = declare(() {
setUp(expectAsync0(() {
expect(innerSetUpRun, isFalse);
return new Future(() => outerSetUpRun = true);
}, max: 1));
group("inner", () {
setUp(expectAsync0(() {
expect(outerSetUpRun, isTrue);
return new Future(() => innerSetUpRun = true);
}, max: 1));
test("description", expectAsync0(() {
expect(outerSetUpRun, isTrue);
expect(innerSetUpRun, isTrue);
}, max: 1));
});
});
var innerGroup = entries.single as Group;
return _runTest(innerGroup.entries.single);
});
test("inherits group's tags", () {
var tests = declare(() {
group("outer", () {
group("inner", () {
test("with tags", () {}, tags: "d");
}, tags: ["b", "c"]);
}, tags: "a");
});
var outerGroup = tests.single as Group;
var innerGroup = outerGroup.entries.single as Group;
var testWithTags = innerGroup.entries.single;
expect(outerGroup.metadata.tags, unorderedEquals(["a"]));
expect(innerGroup.metadata.tags, unorderedEquals(["a", "b", "c"]));
expect(testWithTags.metadata.tags,
unorderedEquals(["a", "b", "c", "d"]));
});
test("throws on invalid tags", () {
expect(() {
declare(() {
group("a", () {}, tags: 1);
});
}, throwsArgumentError);
});
});
group(".tearDown()", () {
test("is scoped to the group", () async {
var tearDownRun;
var entries = declare(() {
setUp(() => tearDownRun = false);
group("group", () {
tearDown(() => tearDownRun = true);
test("description 1", expectAsync0(() {
expect(tearDownRun, isFalse);
}, max: 1));
});
test("description 2", expectAsync0(() {
expect(tearDownRun, isFalse);
}, max: 1));
});
var testGroup = entries[0] as Group;
await _runTest(testGroup.entries.single);
expect(tearDownRun, isTrue);
await _runTest(entries[1]);
expect(tearDownRun, isFalse);
});
test("runs from the inside out", () async {
var innerTearDownRun = false;
var middleTearDownRun = false;
var outerTearDownRun = false;
var entries = declare(() {
tearDown(expectAsync0(() {
expect(innerTearDownRun, isTrue);
expect(middleTearDownRun, isTrue);
outerTearDownRun = true;
}, max: 1));
group("middle", () {
tearDown(expectAsync0(() {
expect(innerTearDownRun, isTrue);
expect(outerTearDownRun, isFalse);
middleTearDownRun = true;
}, max: 1));
group("inner", () {
tearDown(expectAsync0(() {
expect(outerTearDownRun, isFalse);
expect(middleTearDownRun, isFalse);
innerTearDownRun = true;
}, max: 1));
test("description", expectAsync0(() {
expect(outerTearDownRun, isFalse);
expect(middleTearDownRun, isFalse);
expect(innerTearDownRun, isFalse);
}, max: 1));
});
});
});
var middleGroup = entries.single as Group;
var innerGroup = middleGroup.entries.single as Group;
await _runTest(innerGroup.entries.single);
expect(innerTearDownRun, isTrue);
expect(middleTearDownRun, isTrue);
expect(outerTearDownRun, isTrue);
});
test("handles Futures when chained", () async {
var outerTearDownRun = false;
var innerTearDownRun = false;
var entries = declare(() {
tearDown(expectAsync0(() {
expect(innerTearDownRun, isTrue);
return new Future(() => outerTearDownRun = true);
}, max: 1));
group("inner", () {
tearDown(expectAsync0(() {
expect(outerTearDownRun, isFalse);
return new Future(() => innerTearDownRun = true);
}, max: 1));
test("description", expectAsync0(() {
expect(outerTearDownRun, isFalse);
expect(innerTearDownRun, isFalse);
}, max: 1));
});
});
var innerGroup = entries.single as Group;
await _runTest(innerGroup.entries.single);
expect(innerTearDownRun, isTrue);
expect(outerTearDownRun, isTrue);
});
test("runs outer callbacks even when inner ones fail", () async {
var outerTearDownRun = false;
var entries = declare(() {
tearDown(() {
return new Future(() => outerTearDownRun = true);
});
group("inner", () {
tearDown(() {
throw 'inner error';
});
test("description", expectAsync0(() {
expect(outerTearDownRun, isFalse);
}, max: 1));
});
});
var innerGroup = entries.single as Group;
await _runTest(innerGroup.entries.single, shouldFail: true);
expect(outerTearDownRun, isTrue);
});
});
});
}
/// Runs [test].
///
/// This automatically sets up an `onError` listener to ensure that the test
/// doesn't throw any invisible exceptions.
Future _runTest(Test test, {bool shouldFail: false}) {
var liveTest = test.load(_suite);
liveTest.onError.listen(shouldFail
? expectAsync1((_) {})
: (error) => registerException(error.error, error.stackTrace));
return liveTest.run();
}