Skip to content

Commit f45ac37

Browse files
committed
1 parent 8f87b9e commit f45ac37

16 files changed

+520
-118
lines changed

CHANGELOG.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,12 @@
11
### 0.12.0-beta.8
22

3+
* Add support for configuring timeouts on a test, group, and suite basis. Test
4+
and group timeouts are configured with the `timeout` named argument; suites
5+
are configured using the `@Timeout` annotation. See [the README][timeout] for
6+
more information.
7+
8+
[timeout]: https://github.com/dart-lang/test/blob/master/README.md#timeouts
9+
310
* Add a `--version` flag.
411

512
### 0.12.0-beta.7

README.md

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -278,6 +278,49 @@ void main() {
278278

279279
[expectAsync]: http://www.dartdocs.org/documentation/test/latest/index.html#test/test@id_expectAsync
280280

281+
## Configuring Tests
282+
283+
### Timeouts
284+
285+
By default, tests will time out after 30 seconds of inactivity. However, this
286+
can be configured on a per-test, -group, or -suite basis. To change the timeout
287+
for a test suite, put a `@Timeout` annotation at the top of the file:
288+
289+
```dart
290+
@Timeout(new Duration(seconds: 45))
291+
292+
import "package:test/test.dart";
293+
294+
void main() {
295+
// ...
296+
}
297+
```
298+
299+
In addition to setting an absolute timeout, you can set the timeout relative to
300+
the default using `@Timeout.factor`. For example, `@Timeout.factor(1.5)` will
301+
set the timeout to one and a half times as long as the default—45 seconds.
302+
303+
Timeouts can be set for tests and groups using the `timeout` parameter. This
304+
parameter takes a `Timeout` object just like the annotation. For example:
305+
306+
```dart
307+
import "package:test/test.dart";
308+
309+
void main() {
310+
group("slow tests", () {
311+
// ...
312+
313+
test("even slower test", () {
314+
// ...
315+
}, timeout: new Timeout.factor(2))
316+
}, timeout: new Timeout(new Duration(minutes: 1)));
317+
}
318+
```
319+
320+
Nested timeouts apply in order from outermost to innermost. That means that
321+
"even slower test" will take two minutes to time out, since it multiplies the
322+
group's timeout by 2.
323+
281324
## Testing With `barback`
282325

283326
Packages using the `barback` transformer system may need to test code that's

lib/pub_serve.dart

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,8 @@ import "${p.url.basename(id.path)}" as test;
3535
3636
void main(_, Map message) {
3737
var sendPort = message['reply'];
38-
IsolateListener.start(sendPort, () => test.main);
38+
var metadata = new Metadata.deserialize(message['metadata']);
39+
IsolateListener.start(sendPort, metadata, () => test.main);
3940
}
4041
'''));
4142

lib/src/backend/invoker.dart

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,9 @@ class Invoker {
6767
/// The test being run.
6868
LocalTest get _test => liveTest.test as LocalTest;
6969

70+
/// The test metadata merged with the suite metadata.
71+
final Metadata metadata;
72+
7073
/// Note that this is meaningless once [_onCompleteCompleter] is complete.
7174
var _outstandingCallbacks = 0;
7275

@@ -84,7 +87,8 @@ class Invoker {
8487
return Zone.current[#test.invoker];
8588
}
8689

87-
Invoker._(Suite suite, LocalTest test) {
90+
Invoker._(Suite suite, LocalTest test)
91+
: metadata = suite.metadata.merge(test.metadata) {
8892
_controller = new LiveTestController(suite, test, _onRun, () {
8993
_closed = true;
9094
});
@@ -158,7 +162,7 @@ class Invoker {
158162
// TODO(nweiz): Make the timeout configurable.
159163
// TODO(nweiz): Reset this timer whenever the user's code interacts with
160164
// the library.
161-
var timeout = _test.metadata.timeout.apply(new Duration(seconds: 30));
165+
var timeout = metadata.timeout.apply(new Duration(seconds: 30));
162166
var timer = new Timer(timeout, () {
163167
if (liveTest.isComplete) return;
164168
handleError(

lib/src/backend/metadata.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ class Metadata {
2323
/// [testOn] defaults to [PlatformSelector.all].
2424
Metadata({PlatformSelector testOn, Timeout timeout})
2525
: testOn = testOn == null ? PlatformSelector.all : testOn,
26-
timeout = timeout == null ? new Timeout.factor(1) : timeout;
26+
timeout = timeout == null ? const Timeout.factor(1) : timeout;
2727

2828
/// Creates a new Metadata, but with fields parsed from strings where
2929
/// applicable.

lib/src/runner/browser/browser_manager.dart

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,11 @@ class BrowserManager {
3838
///
3939
/// [url] should be an HTML page with a reference to the JS-compiled test
4040
/// suite. [path] is the path of the original test suite file, which is used
41-
/// for reporting.
42-
Future<Suite> loadSuite(String path, Uri url) {
41+
/// for reporting. [metadata] is the parsed metadata for the test suite.
42+
Future<Suite> loadSuite(String path, Uri url, Metadata metadata) {
43+
url = url.replace(
44+
fragment: Uri.encodeFull(JSON.encode(metadata.serialize())));
45+
4346
var suiteChannel = _channel.virtualChannel();
4447
_channel.sink.add({
4548
"command": "loadSuite",
@@ -66,10 +69,10 @@ class BrowserManager {
6669
}
6770

6871
return new Suite(response["tests"].map((test) {
69-
var metadata = new Metadata.deserialize(test['metadata']);
72+
var testMetadata = new Metadata.deserialize(test['metadata']);
7073
var testChannel = suiteChannel.virtualChannel(test['channel']);
71-
return new IframeTest(test['name'], metadata, testChannel);
72-
}), path: path);
74+
return new IframeTest(test['name'], testMetadata, testChannel);
75+
}), metadata: metadata, path: path);
7376
});
7477
}
7578
}

lib/src/runner/browser/iframe_listener.dart

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,11 @@
55
library test.runner.browser.iframe_listener;
66

77
import 'dart:async';
8-
import 'dart:html';
8+
import 'dart:convert';
9+
import 'dart:html' hide Metadata;
910

1011
import '../../backend/declarer.dart';
12+
import '../../backend/metadata.dart';
1113
import '../../backend/suite.dart';
1214
import '../../backend/test.dart';
1315
import '../../util/multi_channel.dart';
@@ -63,7 +65,13 @@ class IframeListener {
6365
return;
6466
}
6567

66-
new IframeListener._(new Suite(declarer.tests))._listen(channel);
68+
var url = Uri.parse(window.location.href);
69+
var metadata = url.hasFragment
70+
? new Metadata.deserialize(JSON.decode(Uri.decodeFull(url.fragment)))
71+
: new Metadata();
72+
73+
new IframeListener._(new Suite(declarer.tests, metadata: metadata))
74+
._listen(channel);
6775
}
6876

6977
/// Constructs a [MultiChannel] wrapping the `postMessage` communication with

lib/src/runner/browser/server.dart

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import 'package:shelf/shelf_io.dart' as shelf_io;
1515
import 'package:shelf_static/shelf_static.dart';
1616
import 'package:shelf_web_socket/shelf_web_socket.dart';
1717

18+
import '../../backend/metadata.dart';
1819
import '../../backend/suite.dart';
1920
import '../../backend/test_platform.dart';
2021
import '../../util/io.dart';
@@ -223,7 +224,8 @@ void main() {
223224
///
224225
/// This will start a browser to load the suite if one isn't already running.
225226
/// Throws an [ArgumentError] if [browser] isn't a browser platform.
226-
Future<Suite> loadSuite(String path, TestPlatform browser) {
227+
Future<Suite> loadSuite(String path, TestPlatform browser,
228+
Metadata metadata) {
227229
if (!browser.isBrowser) {
228230
throw new ArgumentError("$browser is not a browser.");
229231
}
@@ -249,7 +251,7 @@ void main() {
249251
// TODO(nweiz): Don't start the browser until all the suites are compiled.
250252
return _browserManagerFor(browser).then((browserManager) {
251253
if (_closed) return null;
252-
return browserManager.loadSuite(path, suiteUrl);
254+
return browserManager.loadSuite(path, suiteUrl, metadata);
253255
}).then((suite) {
254256
if (_closed) return null;
255257
if (suite != null) return suite.change(platform: browser.name);

lib/src/runner/loader.dart

Lines changed: 25 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -135,35 +135,41 @@ class Loader {
135135
'When using "pub serve", all test files must be in test/.');
136136
}
137137

138-
if (platform.isBrowser) return _loadBrowserFile(path, platform);
139-
assert(platform == TestPlatform.vm);
140-
return _loadVmFile(path);
138+
if (platform == TestPlatform.vm) return _loadVmFile(path, metadata);
139+
assert(platform.isBrowser);
140+
return _loadBrowserFile(path, platform, metadata);
141141
}).then((suite) {
142142
if (suite == null) return;
143143

144-
controller.add(suite
145-
.change(metadata: metadata).filter(platform, os: currentOS));
144+
controller.add(suite.filter(platform, os: currentOS));
146145
}).catchError(controller.addError);
147146
}).then((_) => controller.close());
148147

149148
return controller.stream;
150149
}
151150

152-
/// Load the test suite at [path] in a browser.
153-
Future<Suite> _loadBrowserFile(String path, TestPlatform platform) =>
151+
/// Load the test suite at [path] in [platform].
152+
///
153+
/// [metadata] is the suite-level metadata for the test.
154+
Future<Suite> _loadBrowserFile(String path, TestPlatform platform,
155+
Metadata metadata) =>
154156
_browserServer.then((browserServer) =>
155-
browserServer.loadSuite(path, platform));
157+
browserServer.loadSuite(path, platform, metadata));
156158

157159
/// Load the test suite at [path] in VM isolate.
158-
Future<Suite> _loadVmFile(String path) {
160+
///
161+
/// [metadata] is the suite-level metadata for the test.
162+
Future<Suite> _loadVmFile(String path, Metadata metadata) {
159163
var receivePort = new ReceivePort();
160164

161165
return new Future.sync(() {
162166
if (_pubServeUrl != null) {
163167
var url = _pubServeUrl.resolve(
164168
p.relative(path, from: 'test') + '.vm_test.dart');
165-
return Isolate.spawnUri(url, [], {'reply': receivePort.sendPort})
166-
.then((isolate) => new IsolateWrapper(isolate, () {}))
169+
return Isolate.spawnUri(url, [], {
170+
'reply': receivePort.sendPort,
171+
'metadata': metadata.serialize()
172+
}).then((isolate) => new IsolateWrapper(isolate, () {}))
167173
.catchError((error, stackTrace) {
168174
if (error is! IsolateSpawnException) throw error;
169175

@@ -181,16 +187,19 @@ class Loader {
181187
});
182188
} else {
183189
return runInIsolate('''
190+
import "package:test/src/backend/metadata.dart";
184191
import "package:test/src/runner/vm/isolate_listener.dart";
185192
186193
import "${p.toUri(p.absolute(path))}" as test;
187194
188195
void main(_, Map message) {
189196
var sendPort = message['reply'];
190-
IsolateListener.start(sendPort, () => test.main);
197+
var metadata = new Metadata.deserialize(message['metadata']);
198+
IsolateListener.start(sendPort, metadata, () => test.main);
191199
}
192200
''', {
193-
'reply': receivePort.sendPort
201+
'reply': receivePort.sendPort,
202+
'metadata': metadata.serialize()
194203
}, packageRoot: _packageRoot);
195204
}
196205
}).catchError((error, stackTrace) {
@@ -211,9 +220,9 @@ void main(_, Map message) {
211220
}
212221

213222
return new Suite(response["tests"].map((test) {
214-
var metadata = new Metadata.deserialize(test['metadata']);
215-
return new IsolateTest(test['name'], metadata, test['sendPort']);
216-
}), path: path, platform: "VM");
223+
var testMetadata = new Metadata.deserialize(test['metadata']);
224+
return new IsolateTest(test['name'], testMetadata, test['sendPort']);
225+
}), metadata: metadata, path: path, platform: "VM");
217226
});
218227
}
219228

0 commit comments

Comments
 (0)