| [](https://pub.dev/packages/checks) | |
| [](https://pub.dev/packages/checks/publisher) | |
| `package:checks` is a library for expressing test expectations and it features | |
| a literate API. | |
| ## package:checks (experimental) | |
| `package:checks` is still experimental. For production use cases, please use | |
| `package:test` and `package:matcher`. | |
| For packages in the `labs.dart.dev` publisher we generally plan to either | |
| graduate the package into a supported publisher (`dart.dev`, `tools.dart.dev`) | |
| after a period of feedback and iteration, or discontinue the package. These | |
| packages have a much higher expected rate of API and breaking changes. | |
| To provide feedback on the API, please file [an issue][] with questions, | |
| suggestions, feature requests, or general feedback. | |
| For documentation about converting your usage of `package:matcher` to `checks`, | |
| see the [migration guide][]. | |
| [an issue]:https://github.com/dart-lang/test/issues/new?labels=package%3Achecks&template=03_checks_feedback.md | |
| [migration guide]:https://github.com/dart-lang/test/blob/master/pkgs/checks/doc/migrating_from_matcher.md | |
| ## Quickstart | |
| 1. Add a `dev_dependency` on `checks` (`dart pub add dev:checks`). | |
| 1. Add an import for `package:checks/checks.dart`. | |
| 1. Use `checks` in your test code: | |
| ```dart | |
| void main() { | |
| test('sample test', () { | |
| // test code here | |
| ... | |
| check(actual).equals(expected); | |
| check(someList).isNotEmpty; | |
| check(someObject).isA<Map>(); | |
| check(someString)..startsWith('a')..endsWith('z')..contains('lmno'); | |
| }); | |
| } | |
| ``` | |
| ## Checking expectations with `checks` | |
| Expectations start with `check`. This utility returns a `Subject`, and | |
| expectations can be checked against the subject. Expectations are defined as | |
| extension methods, and different expectations will be available for subjects | |
| with different value types. | |
| ```dart | |
| check(someValue).equals(expectedValue); | |
| check(someList).deepEquals(expectedList); | |
| check(someString).contains('expected pattern'); | |
| ``` | |
| If a failure may not have enough context about the actual or expected values | |
| from the expectation calls alone, add a "Reason" in the failure message by | |
| passing a `because:` argument to `check()`. | |
| ```dart | |
| check( | |
| because: 'log lines must start with the severity', | |
| logLines, | |
| ).every( | |
| .it() | |
| ..anyOf([ | |
| .it()..startsWith('ERROR'), | |
| .it()..startsWith('WARNING'), | |
| .it()..startsWith('INFO'), | |
| ]), | |
| ); | |
| ``` | |
| ### Composing expectations | |
| Multiple expectations can be checked against the same value using cascade | |
| syntax. When multiple expectations are checked against a single value, a failure | |
| will included descriptions of the expectations that already passed. | |
| ```dart | |
| check(someString) | |
| ..startsWith('a') | |
| ..endsWith('z') | |
| ..contains('lmno'); | |
| ``` | |
| Some nested checks may be not be possible to write with cascade syntax. | |
| There is a `which` utility for this use case which takes a `Condition`. | |
| ```dart | |
| check(someString) | |
| ..startsWith('a') | |
| // A cascade would not be possible on `length` | |
| ..length.which( | |
| .it() | |
| ..isGreaterThan(10) | |
| ..isLessThan(100), | |
| ); | |
| ``` | |
| Some expectations return a `Subject` for another value derived from the original | |
| value, such as the `length` extension. | |
| ```dart | |
| check(someString).length.equals(expectedLength); | |
| ``` | |
| Fields or derived values can be extracted from objects for checking further | |
| properties with the `has` utility. | |
| ```dart | |
| check(someValue) | |
| .has((value) => value.property, 'property') | |
| .equals(expectedPropertyValue); | |
| ``` | |
| ### Passing a set of expectations as an argument | |
| Some expectations take arguments which are themselves expectations to apply to | |
| other values. These expectations take `Condition` arguments created with the | |
| `.it()` dot shorthand. The conditions check expectations when they are applied | |
| to a `Subject`. | |
| ```dart | |
| check(someList).any(.it()..isGreaterThan(0)); | |
| ``` | |
| ### Checking asynchronous expectations | |
| Expectation extension methods checking asynchronous behavior return a `Future`. | |
| The future should typically be awaited within the test body, however | |
| asynchronous expectations will also ensure that the test is not considered | |
| complete before the expectation is complete. | |
| Expectations with no concrete end conditions, such as any expectation that a | |
| future never completes, cannot be awaited and may cause a failure after the test | |
| has already appeared to complete. | |
| Asynchronous expectations do not return a `Subject`. When an expectation | |
| extracts a derived value further expectations can be checked by passing a | |
| `Condition`. | |
| ```dart | |
| await check(someFuture).completes(.it()..isGreaterThan(0)); | |
| ``` | |
| Subjects for `Stream` instances must first be wrapped into a `StreamQueue` to | |
| allow multiple expectations to test against the stream from the same state. | |
| The `withQueue` extension can be used when a given stream instance only needs to | |
| be checked once, or if it is a broadcast stream, but if single subscription | |
| stream needs to have multiple expectations checked separately it should be | |
| wrapped with a `StreamQueue`. | |
| ```dart | |
| await check(someStream).withQueue.inOrder([ | |
| .it()..emits(.it()..equals(1)), | |
| .it()..emits(.it()..equals(2)), | |
| .it()..emits(.it()..equals(3)), | |
| .it()..isDone, | |
| ]); | |
| var someQueue = StreamQueue(someOtherStream); | |
| await check(someQueue).emits(.it()..equals(1)); | |
| // do something | |
| await check(someQueue).emits(.it()..equals(2)); | |
| // do something | |
| ``` | |
| ## Writing custom expectations | |
| Expectations are written as extensions on `Subject` with specific generics. The | |
| library `package:checks/context.dart` gives access to a `context` getter on | |
| `Subject` which offers capabilities for defining expectations on the subject's | |
| value. | |
| The `Context` allows checking an expectation with `expect`, `expectAsync` and | |
| `expectUnawaited`, or extracting a derived value for performing other checks | |
| with `nest` and `nestAsync`. Failures are reported by returning a `Rejection`, | |
| or an `Extracted.rejection`, extensions should avoid throwing exceptions. | |
| Descriptions of the clause checked by an expectation are passed through a | |
| separate callback from the predicate which checks the value. Nesting calls are | |
| made with a label directly. When there are no failures the clause callbacks are | |
| not called. When a condition is described with `describe()`, the clause | |
| callbacks are called, but the predicate callbacks are not called. Conditions can | |
| be checked against values without throwing an exception using `softCheck()`. | |
| ```dart | |
| extension CustomChecks on Subject<CustomType> { | |
| void someExpectation() { | |
| context.expect(() => ['meets this expectation'], (actual) { | |
| if (_expectationIsMet(actual)) return null; | |
| return Rejection(which: ['does not meet this expectation']); | |
| }); | |
| } | |
| Subject<Foo> get someDerivedValue => | |
| context.nest(() => ['has someDerivedValue'], (actual) { | |
| if (_cannotReadDerivedValue(actual)) { | |
| return Extracted.rejection(which: ['cannot read someDerivedValue']); | |
| } | |
| return Extracted.value(_readDerivedValue(actual)); | |
| }); | |
| // for field reads that will not get rejected, use `has` | |
| Subject<Bar> get someField => has((a) => a.someField, 'someField'); | |
| } | |
| ``` | |
| Extensions may also compose existing expectations under a single name. When | |
| such expectations fail, the test output will refer to the individual | |
| expectations that were called. | |
| ```dart | |
| extension ComposedChecks on Subject<Iterable> { | |
| void hasLengthInRange(int min, int max) { | |
| length | |
| ..isGreaterThan(min) | |
| ..isLessThan(max); | |
| } | |
| } | |
| ``` |