Back to skills
SkillHub ClubShip Full StackFull Stack

dart-matcher-best-practices

Best practices for using `expect` and `package:matcher`. Focuses on readable assertions, proper matcher selection, and avoiding common pitfalls.

Packaged view

This page reorganizes the original catalog entry around fit, installability, and workflow context first. The original raw source lives below.

Stars
118
Hot score
95
Updated
March 20, 2026
Overall rating
C3.3
Composite score
3.3
Best-practice grade
B84.0

Install command

npx @skill-hub/cli install kevmoo-dash-skills-dart-matcher-best-practices

Repository

kevmoo/dash_skills

Skill path: .agent/skills/dart-matcher-best-practices

Best practices for using `expect` and `package:matcher`. Focuses on readable assertions, proper matcher selection, and avoiding common pitfalls.

Open repository

Best for

Primary workflow: Ship Full Stack.

Technical facets: Full Stack.

Target audience: everyone.

License: Apache-2.0.

Original source

Catalog source: SkillHub Club.

Repository owner: kevmoo.

This is still a mirrored public skill entry. Review the repository before installing into production workflows.

What it helps with

  • Install dart-matcher-best-practices into Claude Code, Codex CLI, Gemini CLI, or OpenCode workflows
  • Review https://github.com/kevmoo/dash_skills before adding dart-matcher-best-practices to shared team environments
  • Use dart-matcher-best-practices for development workflows

Works across

Claude CodeCodex CLIGemini CLIOpenCode

Favorites: 0.

Sub-skills: 0.

Aggregator: No.

Original source / Raw SKILL.md

---
name: dart-matcher-best-practices
description: |-
  Best practices for using `expect` and `package:matcher`.
  Focuses on readable assertions, proper matcher selection, and avoiding common pitfalls.
license: Apache-2.0
---

# Dart Matcher Best Practices

## When to use this skill
Use this skill when:
- Writing assertions using `expect` and `package: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))` over `expect(list.length, n)`.
  - Gives better error messages on failure (shows actual list content).

- **`isEmpty` / `isNotEmpty`**:
  - Prefer `expect(list, isEmpty)` over `expect(list.isEmpty, true)`.
  - Prefer `expect(list, isNotEmpty)` over `expect(list.isNotEmpty, true)`.

- **`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()`.

- **`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 not `const`.

### 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 like `p0` to improve readability.

```dart
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 with `expect`).

### 5. Using `expectLater`

Use `await expectLater(...)` when testing async behavior to ensure proper
sequencing.

```dart
// 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

1.  **Readable Failures**: Choose matchers that produce clear error messages.
2.  **Avoid Manual Logic**: Don't use `if` statements or `for` loops for
    assertions; let matchers handle it.
3.  **Specific Matchers**: Use the most specific matcher available (e.g.,
    `containsPair` for maps instead of checking keys manually).
dart-matcher-best-practices | SkillHub