dart-matcher-best-practices
SKILL.md
Dart Matcher Best Practices
When to use this skill
Use this skill when:
- Writing assertions using
expectandpackage:matcher. - Migrating legacy manual checks to cleaner matchers.
- Debugging confusing test failures.
Core Matchers
1. Collections (hasLength, contains, isEmpty)
-
hasLength(n):- Prefer
expect(list, hasLength(n))overexpect(list.length, n). - Gives better error messages on failure (shows actual list content).
- Prefer
-
isEmpty/isNotEmpty:- Prefer
expect(list, isEmpty)overexpect(list.isEmpty, true). - Prefer
expect(list, isNotEmpty)overexpect(list.isNotEmpty, true).
- Prefer
-
contains(item):- Verify existence without manual iteration.
-
unorderedEquals(items):- Verify contents regardless of order.
2. Type Checks (isA<T> and TypeMatcher<T>)
-
isA<T>():- Prefer for inline assertions:
expect(obj, isA<Type>()). - More concise and readable than
TypeMatcher<Type>(). - Allows chaining constraints using
.having().
- Prefer for inline assertions:
-
TypeMatcher<T>:- Prefer when defining top-level reusable matchers.
- Use
const:const isMyType = TypeMatcher<MyType>(); - Chaining
.having()works here too, but the resulting matcher is notconst.
3. Object Properties (having)
Use .having() on isA<T>() or other TypeMatchers to check properties.
- Descriptive Names: Use meaningful parameter names in the closure (e.g.,
(e) => e.message) instead of generic ones likep0to improve readability.
expect(person, isA<Person>()
.having((p) => p.name, 'name', 'Alice')
.having((p) => p.age, 'age', greaterThan(18)));
This provides detailed failure messages indicating exactly which property failed.
4. Async Assertions
-
completion(matcher):- Wait for a future to complete and check its value.
- Prefer
await expectLater(...)to ensure the future completes before the test continues. await expectLater(future, completion(equals(42))).
-
throwsA(matcher):- Check that a future or function throws an exception.
await expectLater(future, throwsA(isA<StateError>())).expect(() => function(), throwsA(isA<ArgumentError>()))(synchronous function throwing is fine withexpect).
5. Using expectLater
Use await expectLater(...) when testing async behavior to ensure proper
sequencing.
// GOOD: Waits for future to complete before checking side effects
await expectLater(future, completion(equals(42)));
expect(sideEffectState, equals('done'));
// BAD: Side effect check might run before future completes
expect(future, completion(equals(42)));
expect(sideEffectState, equals('done')); // Race condition!
Principles
- Readable Failures: Choose matchers that produce clear error messages.
- Avoid Manual Logic: Don't use
ifstatements orforloops for assertions; let matchers handle it. - Specific Matchers: Use the most specific matcher available (e.g.,
containsPairfor maps instead of checking keys manually).
Related Skills
dart-test-fundamentals: Core concepts for structuring tests, lifecycles, and configuration.dart-checks-migration: Use this skill if you are migrating tests frompackage:matcherto modernpackage:checks.
Weekly Installs
49
Repository
kevmoo/dash_skillsGitHub Stars
118
First Seen
Feb 16, 2026
Security Audits
Installed on
antigravity37
github-copilot20
codex20
opencode19
gemini-cli19
cursor19