skills/dart/dart-migrate-to-checks-package/SKILL.md
Migrate test suites from legacy `package:matcher` (using `expect()`) to the modern, fluent, and highly descriptive assertions of `package:checks`.
npx skillsauth add dhruvanbhalara/skills dart-migrate-to-checks-packageInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
package:checks is a modern assertion library maintained by the Dart team that replaces package:matcher. It offers several benefits over traditional matchers:
To add the checks library to your package:
checks as a dev_dependency using the terminal:
dart pub add dev:checks
import 'package:checks/checks.dart';
package:matcher dependencies from pubspec.yaml (note that package:test transitively imports matchers, which is acceptable).Migrate legacy assertions using the following mapping guidelines:
| Scenario | Legacy Matcher (package:matcher) | Modern Checks (package:checks) |
|---|---|---|
| Equality | expect(value, equals(expected)) | check(value).equals(expected) |
| Identity | expect(value, same(expected)) | check(value).identicalTo(expected) |
| Type Check | expect(value, isA<Type>()) | check(value).isA<Type>() |
| Nullness | expect(value, isNull) | check(value).isNull() |
| Booleans | expect(value, isTrue) | check(value).isTrue() |
| Containment | expect(list, contains(item)) | check(list).contains(item) |
| String Prefixes | expect(str, startsWith(prefix)) | check(str).startsWith(prefix) |
| Property checks | expect(user.name, equals('Alice')) | check(user).has((u) => u.name, 'name').equals('Alice') |
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);
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);
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'));
Follow this checklist when migrating your test suite:
dev:checks and run dart pub get.expect() calls.import 'package:checks/checks.dart'.expect to check.await and completes() closures.dart analyze to resolve any type mismatch warnings.dart test to verify that all migrated assertions execute successfully.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', 'premium']);
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', 'premium']);
// 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);
}
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');
});
});
}
development
Perform REST API networking operations (GET, POST, PUT, DELETE) using the lightweight and robust standard `http` package, including platform configurations and background parsing models.
development
Configure internationalization and localization support using Flutter's built-in l10n system, App Resource Bundle (ARB) files, and ICU formatting syntax.
development
Create model classes with fromJson/toJson using dart:convert and Dart 3 pattern matching. Use when manually mapping JSON to classes, parsing HTTP responses, or choosing between manual and code-generated serialization.
data-ai
Diagnose and fix Flutter layout constraint violations (RenderFlex overflow, unbounded height/width, ParentData misuse). Use when encountering layout exceptions, yellow-black overflow stripes, or red error screens.