Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions integration_tests/spawn_hybrid/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,7 @@ dependency_overrides:
path: ../../pkgs/test_api
test_core:
path: ../../pkgs/test_core
matcher:
git:
url: https://github.com/dart-lang/matcher.git
ref: 3fc9b3c35c3c0465ebef9158971f8203a4fc9416
4 changes: 4 additions & 0 deletions integration_tests/wasm/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,7 @@ dependency_overrides:
path: ../../pkgs/test_api
test_core:
path: ../../pkgs/test_core
matcher:
git:
url: https://github.com/dart-lang/matcher.git
ref: 3fc9b3c35c3c0465ebef9158971f8203a4fc9416
4 changes: 4 additions & 0 deletions legacy_tests/nnbd_opted_in/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,7 @@ dependency_overrides:
path: ../../pkgs/test_api
test_core:
path: ../../pkgs/test_core
matcher:
git:
url: https://github.com/dart-lang/matcher.git
ref: 3fc9b3c35c3c0465ebef9158971f8203a4fc9416
4 changes: 4 additions & 0 deletions legacy_tests/nnbd_opted_in_with_optout/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,7 @@ dependency_overrides:
path: ../../pkgs/test_api
test_core:
path: ../../pkgs/test_core
matcher:
git:
url: https://github.com/dart-lang/matcher.git
ref: 3fc9b3c35c3c0465ebef9158971f8203a4fc9416
4 changes: 4 additions & 0 deletions legacy_tests/nnbd_opted_out/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,7 @@ dependency_overrides:
path: ../../pkgs/test_api
test_core:
path: ../../pkgs/test_core
matcher:
git:
url: https://github.com/dart-lang/matcher.git
ref: 3fc9b3c35c3c0465ebef9158971f8203a4fc9416
4 changes: 4 additions & 0 deletions legacy_tests/spawn_hybrid_with_optout/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,7 @@ dependency_overrides:
path: ../../pkgs/test_api
test_core:
path: ../../pkgs/test_core
matcher:
git:
url: https://github.com/dart-lang/matcher.git
ref: 3fc9b3c35c3c0465ebef9158971f8203a4fc9416
4 changes: 4 additions & 0 deletions legacy_tests/unit_tests/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,7 @@ dependency_overrides:
path: ../../pkgs/test_api
test_core:
path: ../../pkgs/test_core
matcher:
git:
url: https://github.com/dart-lang/matcher.git
ref: 3fc9b3c35c3c0465ebef9158971f8203a4fc9416
4 changes: 4 additions & 0 deletions pkgs/checks/pubspec_overrides.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,7 @@ dependency_overrides:
path: ../test_core
test:
path: ../test
matcher:
git:
url: https://github.com/dart-lang/matcher.git
ref: 3b48930a01f678e2921cea16563af67460e6f765
225 changes: 3 additions & 222 deletions pkgs/test/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,12 +35,12 @@

## Writing Tests

Tests are specified using the top-level [`test()`] function, and test assertions
are made using [`expect()`]:
Tests are specified using the top-level [`test()`] function.
Test asserts can be made using [`expect` from `package:matcher`][expect]

[`test()`]: https://pub.dev/documentation/test_core/latest/test_core.scaffolding/test.html

[`expect()`]: https://pub.dev/documentation/test_api/latest/expect/expect.html
[expect]: https://pub.dev/documentation/matcher/latest/expect/expect.html

```dart
import 'package:test/test.dart';
Expand Down Expand Up @@ -91,42 +91,6 @@ void main() {
}
```

Any matchers from the [`matcher`] package can be used with `expect()` to do
complex validations:

[`matcher`]: https://pub.dev/documentation/matcher/latest/matcher/matcher-library.html

```dart
import 'package:test/test.dart';

void main() {
test('.split() splits the string on the delimiter', () {
expect('foo,bar,baz', allOf([
contains('foo'),
isNot(startsWith('bar')),
endsWith('baz')
]));
});
}
```

You can also test exceptions with the [`throwsA()`] function or a matcher
such as [`throwsFormatException`]:

[`throwsA()`]: https://pub.dev/documentation/test_api/latest/expect/throwsA.html

[`throwsFormatException`]: https://pub.dev/documentation/test_api/latest/expect/throwsFormatException-constant.html

```dart
import 'package:test/test.dart';

void main() {
test('.parse() fails on invalid input', () {
expect(() => int.parse('X'), throwsFormatException);
});
}
```

You can use the [`setUp()`] and [`tearDown()`] functions to share code between
tests. The `setUp()` callback will run before every test in a group or test
suite, and `tearDown()` will run after. `tearDown()` will run even if a test
Expand Down Expand Up @@ -478,189 +442,6 @@ Avoid uncaught async errors by ensuring that all futures have an error handler

[early-handler]:https://dart.dev/guides/libraries/futures-error-handling#potential-problem-failing-to-register-error-handlers-early

### Future Matchers

There are a number of useful functions and matchers for more advanced
asynchrony. The [`completion()`] matcher can be used to test `Futures`; it
ensures that the test doesn't finish until the `Future` completes, and runs a
matcher against that `Future`'s value.

[`completion()`]: https://pub.dev/documentation/test_api/latest/expect/completion.html

```dart
import 'dart:async';

import 'package:test/test.dart';

void main() {
test('Future.value() returns the value', () {
expect(Future.value(10), completion(equals(10)));
});
}
```

The [`throwsA()`] matcher and the various [`throwsExceptionType`] matchers work
with both synchronous callbacks and asynchronous `Future`s. They ensure that a
particular type of exception is thrown:

[`throwsExceptionType`]: https://pub.dev/documentation/test_api/latest/expect/throwsException-constant.html

```dart
import 'dart:async';

import 'package:test/test.dart';

void main() {
test('Future.error() throws the error', () {
expect(Future.error('oh no'), throwsA(equals('oh no')));
expect(Future.error(StateError('bad state')), throwsStateError);
});
}
```

The [`expectAsync()`] function wraps another function and has two jobs. First,
it asserts that the wrapped function is called a certain number of times, and
will cause the test to fail if it's called too often; second, it keeps the test
from finishing until the function is called the requisite number of times.

```dart
import 'dart:async';

import 'package:test/test.dart';

void main() {
test('Stream.fromIterable() emits the values in the iterable', () {
var stream = Stream.fromIterable([1, 2, 3]);

stream.listen(expectAsync1((number) {
expect(number, inInclusiveRange(1, 3));
}, count: 3));
});
}
```

[`expectAsync()`]: https://pub.dev/documentation/test_api/latest/test_api/expectAsync.html

### Stream Matchers

The `test` package provides a suite of powerful matchers for dealing with
[asynchronous streams][Stream]. They're expressive and composable, and make it
easy to write complex expectations about the values emitted by a stream. For
example:

[Stream]: https://api.dart.dev/stable/dart-async/Stream-class.html

```dart
import 'dart:async';

import 'package:test/test.dart';

void main() {
test('process emits status messages', () {
// Dummy data to mimic something that might be emitted by a process.
var stdoutLines = Stream.fromIterable([
'Ready.',
'Loading took 150ms.',
'Succeeded!'
]);

expect(stdoutLines, emitsInOrder([
// Values match individual events.
'Ready.',

// Matchers also run against individual events.
startsWith('Loading took'),

// Stream matchers can be nested. This asserts that one of two events are
// emitted after the "Loading took" line.
emitsAnyOf(['Succeeded!', 'Failed!']),

// By default, more events are allowed after the matcher finishes
// matching. This asserts instead that the stream emits a done event and
// nothing else.
emitsDone
]));
});
}
```

A stream matcher can also match the [`async`] package's [`StreamQueue`] class,
which allows events to be requested from a stream rather than pushed to the
consumer. The matcher will consume the matched events, but leave the rest of the
queue alone so that it can still be used by the test, unlike a normal `Stream`
which can only have one subscriber. For example:

[`async`]: https://pub.dev/packages/async

[`StreamQueue`]: https://pub.dev/documentation/async/latest/async/StreamQueue-class.html

```dart
import 'dart:async';

import 'package:async/async.dart';
import 'package:test/test.dart';

void main() {
test('process emits a WebSocket URL', () async {
// Wrap the Stream in a StreamQueue so that we can request events.
var stdout = StreamQueue(Stream.fromIterable([
'WebSocket URL:',
'ws://localhost:1234/',
'Waiting for connection...'
]));

// Ignore lines from the process until it's about to emit the URL.
await expectLater(stdout, emitsThrough('WebSocket URL:'));

// Parse the next line as a URL.
var url = Uri.parse(await stdout.next);
expect(url.host, equals('localhost'));

// You can match against the same StreamQueue multiple times.
await expectLater(stdout, emits('Waiting for connection...'));
});
}
```

The following built-in stream matchers are available:

* [`emits()`] matches a single data event.
* [`emitsError()`] matches a single error event.
* [`emitsDone`] matches a single done event.
* [`mayEmit()`] consumes events if they match an inner matcher, without
requiring them to match.
* [`mayEmitMultiple()`] works like `mayEmit()`, but it matches events against
the matcher as many times as possible.
* [`emitsAnyOf()`] consumes events matching one (or more) of several possible
matchers.
* [`emitsInOrder()`] consumes events matching multiple matchers in a row.
* [`emitsInAnyOrder()`] works like `emitsInOrder()`, but it allows the matchers
to match in any order.
* [`neverEmits()`] matches a stream that finishes *without* matching an inner
matcher.

You can also define your own custom stream matchers with [`StreamMatcher()`].

[`emits()`]: https://pub.dev/documentation/test_api/latest/expect/emits.html

[`emitsError()`]: https://pub.dev/documentation/test_api/latest/expect/emitsError.html

[`emitsDone`]: https://pub.dev/documentation/test_api/latest/expect/emitsDone.html

[`mayEmit()`]: https://pub.dev/documentation/test_api/latest/expect/mayEmit.html

[`mayEmitMultiple()`]: https://pub.dev/documentation/test_api/latest/expect/mayEmitMultiple.html

[`emitsAnyOf()`]: https://pub.dev/documentation/test_api/latest/expect/emitsAnyOf.html

[`emitsInOrder()`]: https://pub.dev/documentation/test_api/latest/expect/emitsInOrder.html

[`emitsInAnyOrder()`]: https://pub.dev/documentation/test_api/latest/expect/emitsInAnyOrder.html

[`neverEmits()`]: https://pub.dev/documentation/test_api/latest/expect/neverEmits.html

[`StreamMatcher()`]: https://pub.dev/documentation/test_api/latest/expect/StreamMatcher-class.html

## Running Tests With Custom HTML

By default, the test runner will generate its own empty HTML file for browser
Expand Down
2 changes: 1 addition & 1 deletion pkgs/test/lib/expect.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@
// 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.

export 'package:test_api/expect.dart';
export 'package:matcher/expect.dart';
9 changes: 9 additions & 0 deletions pkgs/test/lib/test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,14 @@
// 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.

export 'package:matcher/expect.dart';
// Deprecated exports not surfaced through focused libraries.
// ignore: deprecated_member_use
export 'package:matcher/src/expect/expect.dart' show ErrorFormatter;
// ignore: deprecated_member_use
export 'package:matcher/src/expect/expect_async.dart' show expectAsync;
// ignore: deprecated_member_use
export 'package:matcher/src/expect/throws_matcher.dart' show throws, Throws;
// The non-deprecated API (through a deprecated import).
// ignore: deprecated_member_use
export 'package:test_core/test_core.dart';
3 changes: 3 additions & 0 deletions pkgs/test/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,9 @@ dependencies:
# Use an exact version until the test_api and test_core package are stable.
test_api: 0.5.0
test_core: 0.5.0
# Use a tight version constraint to ensure that a constraint on matcher
# properly constrains all features it provides.
matcher: '>=0.12.15 <0.12.16'

dev_dependencies:
fake_async: ^1.0.0
Expand Down
4 changes: 4 additions & 0 deletions pkgs/test/pubspec_overrides.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,7 @@ dependency_overrides:
path: ../test_core
test_api:
path: ../test_api
matcher:
git:
url: https://github.com/dart-lang/matcher.git
ref: 3fc9b3c35c3c0465ebef9158971f8203a4fc9416
5 changes: 3 additions & 2 deletions pkgs/test/test/runner/github_reporter_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -154,8 +154,9 @@ void main() {
test.dart 8:62 main.<fn>.<fn>
::endgroup::
::group::❌ fail after completion (failed after test completion)
This test failed after it had already completed. Make sure to use [expectAsync]
or the [completes] matcher when testing async code.
This test failed after it had already completed.
Make sure to use a matching library which informs the test runner
of pending async work.
test.dart 8:62 main.<fn>.<fn>
::endgroup::
✅ second test so that the first failure is reported
Expand Down
6 changes: 3 additions & 3 deletions pkgs/test/test/runner/json_reporter_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -172,9 +172,9 @@ void main() {
errorJson(3, 'oh no'),
errorJson(
3,
'This test failed after it had already completed. Make sure to '
'use [expectAsync]\n'
'or the [completes] matcher when testing async code.'),
'This test failed after it had already completed.\n'
'Make sure to use a matching library which informs the '
'test runner\nof pending async work.'),
testDoneJson(4),
]
], doneJson(success: false));
Expand Down
Loading