matcher-to-checks
npx skills add https://github.com/kevmoo/dash_skills --skill matcher-to-checks
Agent 安装分布
Skill 文档
When to use this skill
In a Dart or Flutter project.
When a user asks to migrate to package:checks or just “checks”.
The Workflow
- Analysis:
- Use
grepto identify files usingexpectorpackage:matcher. - Review custom matchers; these may require manual migration.
- Use
- Tools & Dependencies:
- Ensure
dev_dependenciesincludeschecks. - Run
dart pub add --dev checksif missing.
- Ensure
- 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';withimport 'package:test/scaffolding.dart';ONLY after allexpectcalls are replaced. This ensures incremental progress.
- Add
- Verification:
- Ensure the code analyzes cleanly.
- Ensure tests pass.
- Prefer using the Dart MCP server (vs the dart command line) if available.
Strategies for Discovery
Use these commands to find migration candidates:
- Find usages of expect:
grep -r "expect(" test/ - Find usages of expectLater:
grep -r "expectLater(" test/ - Find specific matchers (e.g.
isTrue):grep -r "isTrue" test/
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(a, unorderedEquals(b)) |
check(a).unorderedEquals(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 aFuture, 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) returnFuture<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');
Every Element:
Legacy:
expect(list, everyElement(isA<int>().having((e) => e.isEven, 'isEven', isTrue)));
Modern:
check(list).every((e) => e.isA<int>()
.has((v) => v.isEven, 'isEven').isTrue());
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/(andpubspec.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:checksis stricter about types thanmatcher. You may need to add explicitas Tcasts orisA<T>()checks in the chain.