Dart Checks Migration
When to use this skill
Use this skill when:
- Migrating existing test files from
package:matcher to package:checks.
- A user specifically asks for "modern checks" or similar.
The Workflow
- Analysis:
- Use
grep to identify files using expect or package:matcher.
- Review custom matchers; these may require manual migration.
- Tools & Dependencies:
- Ensure
dev_dependencies includes checks.
- Run
dart pub add --dev checks if missing.
- Discovery:
- Use the Strategies for Discovery below to find candidates.
- Replacement:
- Add
import 'package:checks/checks.dart';.
- Apply the Common Patterns below.
- Final Step: Replace
import 'package:test/test.dart'; with
import 'package:test/scaffolding.dart'; ONLY after all expect calls
are replaced. This ensures incremental progress.
- Verification:
- Ensure the code analyzes cleanly.
- Ensure tests pass.
Common Patterns
Legacy expect |
Modern check |
expect(a, equals(b)) |
check(a).equals(b) |
expect(a, isTrue) |
check(a).isTrue() |
expect(a, isFalse) |
check(a).isFalse() |
expect(a, isNull) |
check(a).isNull() |
expect(a, isNotNull) |
check(a).isNotNull() |
expect(() => fn(), throwsA<T>()) |
check(() => fn()).throws<T>() |
expect(list, hasLength(n)) |
check(list).length.equals(n) |
expect(a, closeTo(b, delta)) |
check(a).isA<num>().isCloseTo(b, delta) |
expect(a, greaterThan(b)) |
check(a).isGreaterThan(b) |
expect(a, lessThan(b)) |
check(a).isLessThan(b) |
expect(list, isEmpty) |
check(list).isEmpty() |
expect(list, isNotEmpty) |
check(list).isNotEmpty() |
expect(list, contains(item)) |
check(list).contains(item) |
expect(map, equals(otherMap)) |
check(map).deepEquals(otherMap) |
expect(list, equals(otherList)) |
check(list).deepEquals(otherList) |
expect(future, completes) |
await check(future).completes() |
expect(stream, emitsInOrder(...)) |
await check(stream).withQueue.inOrder(...) |
Async & Futures (CRITICAL)
Checking async functions:
check(() => asyncFunc()).throws<T>() causes FALSE POSITIVES because the
closure returns a Future, which is a value, so it "completes normally"
(as a Future).
Correct Usage:
await check(asyncFunc()).throws<T>();
Chaining on void returns:
Many async check methods (like throws) return Future<void>. You cannot
chain directly on them. Use cascades or callbacks.
Wrong:
await check(future).throws<Error>().has((e) => e.message, 'message').equals('foo');
Correct:
await check(future).throws<Error>((it) => it.has((e) => e.message, 'message').equals('foo'));
Complex Examples
Deep Verification with isA and having:
Legacy:
expect(() => foo(), throwsA(isA<ArgumentError>()
.having((e) => e.message, 'message', contains('MSG'))));
Modern:
check(() => foo())
.throws<ArgumentError>()
.has((e) => e.message, 'message')
.contains('MSG');
Property Extraction:
Legacy:
expect(obj.prop, equals(value)); // When checking multiple props
Modern:
check(obj)
..has((e) => e.prop, 'prop').equals(value)
..has((e) => e.other, 'other').equals(otherValue);
One-line Cascades:
Since checks often return void, use cascades for multiple assertions on the
same subject.
check(it)..isGreaterThan(10)..isLessThan(20);
Constraints
- Scope: Only modify files in
test/ (and pubspec.yaml).
- Correctness: One failing test is unacceptable. If a test fails after
migration and you cannot fix it immediately, REVERT that specific change.
- Type Safety:
package:checks is stricter about types than matcher.
You may need to add explicit as T casts or isA<T>() checks in the chain.
Related Skills
1---2name: dart-checks-migration3description: Replace the usage of `expect` and similar functions from `package:matcher` to `package:checks` equivalents.4license: Apache-2.05---67# Dart Checks Migration89## When to use this skill10Use this skill when:11- Migrating existing test files from `package:matcher` to `package:checks`.12- A user specifically asks for "modern checks" or similar.1314## The Workflow15161. **Analysis**:17 - Use `grep` to identify files using `expect` or `package:matcher`.18 - Review custom matchers; these may require manual migration.192. **Tools & Dependencies**:20 - Ensure `dev_dependencies` includes `checks`.21 - Run `dart pub add --dev checks` if missing.223. **Discovery**:23 - Use the **Strategies for Discovery** below to find candidates.244. **Replacement**:25 - Add `import 'package:checks/checks.dart';`.26 - Apply the **Common Patterns** below.27 - **Final Step**: Replace `import 'package:test/test.dart';` with28 `import 'package:test/scaffolding.dart';` ONLY after all `expect` calls29 are replaced. This ensures incremental progress.305. **Verification**:31 - Ensure the code analyzes cleanly.32 - Ensure tests pass.3334## Common Patterns3536| Legacy `expect` | Modern `check` |37| :--- | :--- |38| `expect(a, equals(b))` | `check(a).equals(b)` |39| `expect(a, isTrue)` | `check(a).isTrue()` |40| `expect(a, isFalse)` | `check(a).isFalse()` |41| `expect(a, isNull)` | `check(a).isNull()` |42| `expect(a, isNotNull)` | `check(a).isNotNull()` |43| `expect(() => fn(), throwsA<T>())` | `check(() => fn()).throws<T>()` |44| `expect(list, hasLength(n))` | `check(list).length.equals(n)` |45| `expect(a, closeTo(b, delta))` | `check(a).isA<num>().isCloseTo(b, delta)` |46| `expect(a, greaterThan(b))` | `check(a).isGreaterThan(b)` |47| `expect(a, lessThan(b))` | `check(a).isLessThan(b)` |48| `expect(list, isEmpty)` | `check(list).isEmpty()` |49| `expect(list, isNotEmpty)` | `check(list).isNotEmpty()` |50| `expect(list, contains(item))` | `check(list).contains(item)` |51| `expect(map, equals(otherMap))` | `check(map).deepEquals(otherMap)` |52| `expect(list, equals(otherList))` | `check(list).deepEquals(otherList)` |53| `expect(future, completes)` | `await check(future).completes()` |54| `expect(stream, emitsInOrder(...))` | `await check(stream).withQueue.inOrder(...)` |5556### Async & Futures (CRITICAL)5758- **Checking async functions:**59 `check(() => asyncFunc()).throws<T>()` causes **FALSE POSITIVES** because the60 closure returns a `Future`, which is a value, so it "completes normally"61 (as a Future).62 **Correct Usage:**63 ```dart64 await check(asyncFunc()).throws<T>();65 ```6667- **Chaining on void returns:**68 Many async check methods (like `throws`) return `Future<void>`. You cannot69 chain directly on them. Use cascades or callbacks.70 **Wrong:**71 ```dart72 await check(future).throws<Error>().has((e) => e.message, 'message').equals('foo');73 ```74 **Correct:**75 ```dart76 await check(future).throws<Error>((it) => it.has((e) => e.message, 'message').equals('foo'));77 ```7879## Complex Examples8081*Deep Verification with `isA` and `having`:*8283**Legacy:**84```dart85expect(() => foo(), throwsA(isA<ArgumentError>()86 .having((e) => e.message, 'message', contains('MSG'))));87```8889**Modern:**90```dart91check(() => foo())92 .throws<ArgumentError>()93 .has((e) => e.message, 'message')94 .contains('MSG');95```9697*Property Extraction:*9899**Legacy:**100```dart101expect(obj.prop, equals(value)); // When checking multiple props102```103104**Modern:**105```dart106check(obj)107 ..has((e) => e.prop, 'prop').equals(value)108 ..has((e) => e.other, 'other').equals(otherValue);109```110111*One-line Cascades:*112Since checks often return `void`, use cascades for multiple assertions on the113same subject.114```dart115check(it)..isGreaterThan(10)..isLessThan(20);116```117118## Constraints119120- **Scope**: Only modify files in `test/` (and `pubspec.yaml`).121- **Correctness**: One failing test is unacceptable. If a test fails after122 migration and you cannot fix it immediately, REVERT that specific change.123- **Type Safety**: `package:checks` is stricter about types than `matcher`.124 You may need to add explicit `as T` casts or `isA<T>()` checks in the chain.125126## Related Skills127128- **[dart-test-fundamentals]**: Core129 concepts for structuring tests, lifecycles, and configuration.130- **[dart-matcher-best-practices]**:131 Best practices for the traditional `package:matcher` that is being migrated132 away from.133134[dart-test-fundamentals]: https://github.com/kevmoo/dash_skills/blob/main/.agent/skills/dart-test-fundamentals/SKILL.md135[dart-matcher-best-practices]: https://github.com/kevmoo/dash_skills/blob/main/.agent/skills/dart-matcher-best-practices/SKILL.md