
dart-matcher-best-practices
Best practices for using expect and package:matcher. Focuses on readable assertions, proper matcher selection, and avoiding common pitfalls.
- Installs
- 266
- Last 24h
- —
- Trending rank
- —
- Security
- Not audited
Install
Works with every agent the skills CLI supports.
npx skills add https://github.com/kevmoo/dash_skills --skill dart-matcher-best-practices- 01
Install
Run the command in your project. The CLI asks which agents to install for.
- 02
Describe the task
Ask your agent for something this skill covers. It loads dart-matcher-best-practices automatically when relevant.
- 03
Review the result
The agent follows the SKILL.md steps, scripts and references bundled with the skill.
SKILL.md
The instructions your agent reads when the skill is triggered.
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.
When NOT to use (Abstention Guardrails)
Do NOT apply this skill or refactor assertions when:
- Non-Collection Properties: The property happens to be named
.lengthbut belongs to a non-collection class (e.g. geometric scalar magnitude on aVector, duration on a buffer, or line segment distance).hasLength(n)expects aninton anIterable,Map, orString. - Custom Domain Booleans: The boolean check tests an arbitrary domain
property (e.g.
expect(switch.isEnabled, isTrue)). Do not invent non-existent matchers. - Alternative Assertion Frameworks: The package has adopted
package:checks(check(x)...). Do not revertchecksback topackage:matcher. - Already Idiomatic Assertions: Tests already use declarative matchers
(
hasLength,isEmpty,isNotEmpty,contains,containsPair,isA,throwsA). Abstain and make zero modifications.
Discovery
To find candidates for improving matcher usage, search for suboptimal patterns:
Suboptimal Length Checks
Search for length checks that should use hasLength:
- Regex:
expect\([^,]+.length,\s*
Suboptimal Boolean Checks
Search for checks on boolean properties that have specific matchers:
- Regex:
expect\([^,]+.isEmpty,\s*(true|equals\(true\)) - Regex:
expect\([^,]+.isNotEmpty,\s*(true|equals\(true\)) - Regex:
expect\([^,]+.contains\(.*\),\s*(true|equals\(true\))
Suboptimal Map Lookups
Search for manual map lookups instead of containsPair:
- Regex:
expect\([^,]+\[.*\],\s*
Core Matchers
1. Collections (hasLength, contains, isEmpty, unorderedEquals, containsPair)
-
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.
- Prefer over
expect(list.contains(item), true).
-
unorderedEquals(items):- Verify contents regardless of order.
- Prefer over
expect(list, containsAll(items)).
-
containsPair(key, value):- Verify a map contains a specific key-value pair.
- Prefer over checking
expect(map[key], value)orexpect(map.containsKey(key), true).
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. Exception Testing (Avoid try/catch with fail())
- Prefer
throwsAover imperativetry/catch:- Legacy tests often use
try { fn(); fail('should throw'); } catch (e) { expect(e, isA<T>()); }. - Replace with declarative matchers:
// Synchronous: expect(() => parseData('invalid'), throwsA(isA<FormatException>())); // Asynchronous: await expectLater(client.fetch('bad-url'), throwsA(isA<HttpException>())); - Common built-in exception matchers include
throwsArgumentError,throwsStateError,throwsRangeError,throwsFormatException,throwsNoSuchMethodError, andthrowsUnsupportedError.
- Legacy tests often use
6. 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.
FAQ
What does the dart-matcher-best-practices skill do?
Best practices for using expect and package:matcher. Focuses on readable assertions, proper matcher selection, and avoiding common pitfalls.
How do I install dart-matcher-best-practices?
Run npx skills add https://github.com/kevmoo/dash_skills --skill dart-matcher-best-practices in your project. The skills CLI detects the agents you use and copies the skill into the right folder. For Claude Code you can also place the skill folder at ~/.claude/skills/dart-matcher-best-practices/ (personal) or .claude/skills/dart-matcher-best-practices/ (project).
Which AI agents can use dart-matcher-best-practices?
Any agent that supports the open Agent Skills format (a folder with a SKILL.md file), including Claude Code, Codex, Cursor, GitHub Copilot, Gemini CLI, Windsurf, Cline, OpenCode and more.
Is dart-matcher-best-practices safe to install?
No partner security audit is available yet. Skills can run commands and scripts, so read the SKILL.md and any bundled files before installing.
Who maintains dart-matcher-best-practices?
It is published by kevmoo in kevmoo/dash_skills. It has 266 recorded installs.
More from kevmoo/dash_skills
dart-best-practices
kevmoo/dash_skills
General best practices for Dart development. Covers code style, effective Dart, and language features.
dart-test-fundamentals
kevmoo/dash_skills
Core concepts and best practices for package:test. Covers test, group, lifecycle methods (setUp, tearDown), and configuration (darttest.yaml).
dart-modern-features
kevmoo/dash_skills
Guidelines for using modern Dart features (v3.0 - v3.10) such as Records, Extension Types, Class Modifiers, Wildcards, Digit Separators, Null-Aware Elements, and Dot Shorthands.
dart-package-maintenance
kevmoo/dash_skills
Open the skill to read its SKILL.md instructions.
dart-cli-app-best-practices
kevmoo/dash_skills
Open the skill to read its SKILL.md instructions.
Popular code quality & workflow skills
grill-me
mattpocock/skills
A relentless interview to sharpen a plan or design.
improve-codebase-architecture
mattpocock/skills
Scan a codebase for deepening opportunities, present them as a visual HTML report, then grill through whichever one you pick.
handoff
mattpocock/skills
Compact the current conversation into a handoff document for another agent to pick up.
domain-modeling
mattpocock/skills
Build and sharpen a project's domain model. Use when discussing codebase terminology, writing or editing a GLOSSARY.md, or recording or editing an ADR.
codebase-design
mattpocock/skills
Shared vocabulary for designing deep modules. Use when the user wants to design or improve a module's interface, find deepening opportunities, decide where a seam goes, make code more testable or AI-navigable, or when another skill needs the deep-module vocabulary.
diagnosing-bugs
mattpocock/skills
Diagnosis loop for hard bugs and performance regressions. Use when the user says "diagnose"/"debug this", or reports something broken/throwing/failing/slow.