mcpField
D
dart-migrate-to-checks-package

dart-migrate-to-checks-package

github.com/dhruvanbhalaraTesting & quality3046 installsUpdated 9w ago
Repository

About dart-migrate-to-checks-package

dart-migrate-to-checks-package is a skill for Dart developers moving tests from package:matcher to package:checks. It maps assertion syntax and covers asynchronous checks for Futures and Streams.

Key features

  1. 01Map common assertion syntax
  2. 02Guide dependency and import updates
  3. 03Support cascaded property checks
  4. 04Explain asynchronous Future assertions
  5. 05Explain sequential Stream assertions
  6. 06Provide a migration validation checklist

Use cases

  1. 01Convert expect assertions to check
  2. 02Rewrite Future and Stream tests
  3. 03Check analysis and tests after migration

Install

Copy the command and run it in a terminal.

$npx skills add https://github.com/dhruvanbhalara/skills --skill dart-migrate-to-checks-package

After installing, type/dart-migrate-to-checks-packagein Claude Code to confirm it loaded.

Details

From the project README

Contents

Why Migrate to package:checks

package:checks is a modern assertion library maintained by the Dart team that replaces package:matcher. It offers several benefits over traditional matchers:

  • Fluent API: Chain assertions naturally using Dart methods instead of nested helper functions.
  • Type Safety: Benefit from compiler checks on expected properties, preventing type mismatches in tests.
  • Descriptive Diagnostics: Read extremely clear failure messages showing exactly what failed and why (e.g. displaying collection differences).

Dependency Management

To add the checks library to your package:

  1. Add checks as a dev_dependency using the terminal:
    dart pub add dev:checks
    
  2. Import the main package entrypoint in all migrating test files:
    import 'package:checks/checks.dart';
    
  3. Remove explicit package:matcher dependencies from pubspec.yaml (note that package:test transitively imports matchers, which is acceptable).

Assertion Mapping and Syntax Guidelines

Migrate legacy assertions using the following mapping guidelines:

ScenarioLegacy Matcher (package:matcher)Modern Checks (package:checks)
Equalityexpect(value, equals(expected))check(value).equals(expected)
Identityexpect(value, same(expected))check(value).identicalTo(expected)
Type Checkexpect(value, isA<Type>())check(value).isA<Type>()
Nullnessexpect(value, isNull)check(value).isNull()
Booleansexpect(value, isTrue)check(value).isTrue()
Containmentexpect(list, contains(item))check(list).contains(item)
String Prefixesexpect(str, startsWith(prefix))check(str).startsWith(prefix)
Property checksexpect(user.name, equals('Alice'))check(user).has((u) => u.name, 'name').equals('Alice')
Chaining Multiple Checks

Use Dart's cascade operator (..) to assert multiple properties on a single subject without writing separate expectation statements:

check(user)
  ..has((u) => u.name, 'name').equals('Alice')
  ..has((u) => u.age, 'age').isGreaterThan(20);

Advanced Asynchronous Assertions

1. Futures

To verify Future resolutions, always await the base check statement:

// Verify completion value:
await check(fetchScore()).completes((score) => score.equals(100));

// Verify throws error:
await check(failingTask()).throws<HttpException>().has((e) => e.statusCode, 'statusCode').equals(500);
2. Streams

To assert multiple sequential items emitted by a Stream, wrap the target stream in a StreamQueue from package:async:

import 'package:async/async.dart';

final queue = StreamQueue(eventStream);
await check(queue).emits((event) => event.equals('first_event'));
await check(queue).emits((event) => event.equals('second_event'));

Workflow: Executing Syntax Migrations

Follow this checklist when migrating your test suite:

  • Dependency Setup: Install dev:checks and run dart pub get.
  • Find target files: Locate test files containing traditional expect() calls.
  • Update imports: Replace matcher imports or add import 'package:checks/checks.dart'.
  • Convert simple cases: Map basic equalities and type matches from expect to check.
  • Optimize with cascades: Group multiple assertions targeting the same object into cascades.
  • Update async calls: Rewrite asynchronous Future/Stream checks to use await and completes() closures.
  • Validate compiler checks: Run dart analyze to resolve any type mismatch warnings.
  • Execute tests: Run dart test to verify that all migrated assertions execute successfully.

Examples

Migration Comparison

This example demonstrates migrating a complete, high-fidelity user profile test case from legacy matcher syntax to modern checks syntax.

// --- Legacy Matcher Assertion Style ---
import 'package:test/test.dart';

class Account {
  final String email;
  final List<String> tags;
  Account(this.email, this.tags);
}

void badTest() {
  final account = Account('[email protected]', ['admin', 'tier1']);

  expect(account.email, equals('[email protected]'));
  expect(account.tags, contains('admin'));
  expect(account.tags.length, equals(2));
}

// --- Modern Checks Assertion Style ---
import 'package:checks/checks.dart';

void goodTest() {
  final account = Account('[email protected]', ['admin', 'tier1']);

  // Chain validations cleanly using cascades and property extractors
  check(account)
    ..has((a) => a.email, 'email').equals('[email protected]')
    ..has((a) => a.tags, 'tags').contains('admin')
    ..has((a) => a.tags.length, 'tags length').equals(2);
}
Testing Exceptions and Future Completions
import 'package:checks/checks.dart';
import 'package:test/test.dart';

Future<String> fetchRole(bool fail) async {
  await Future.delayed(const Duration(milliseconds: 10));
  if (fail) throw StateError('Fetch failed');
  return 'Manager';
}

void main() {
  group('Asynchronous Tests', () {
    test('verifies successful completion', () async {
      await check(fetchRole(false)).completes(
        (role) => role.equals('Manager'),
      );
    });

    test('verifies throwing specific state errors', () async {
      await check(fetchRole(true)).throws<StateError>().has(
        (e) => e.message, 'message',
      ).equals('Fetch failed');
    });
  });
}

Comments

Markdown supported