OverviewHistoryStatsSecurity
npx skills add ...
Documentation
SKILL.md
npx skills add evanca/flutter-ai-rules --skill testing
Use when writing or reviewing Flutter/Dart tests (unit, widget, golden), fixing flaky tests, adding coverage, or choosing between unit and widget tests.
npx skills add evanca/flutter-ai-rules --skill testing
Write effective, meaningful Flutter and Dart tests that catch real regressions.
Use this skill when:
Before writing or accepting a test, ask:
"Can this test actually fail if the real code is broken?"
Always use group() in test files. Name the group after the class under test:
Rules:
setUp for shared object creation; use tearDown for cleanup (closing streams, controllers).group() blocks for sub-features when a class has many methods.Name test cases using "should" to describe expected behavior:
| Type | Target | Tools |
|---|---|---|
| Unit test | Pure Dart logic, repositories, cubits/blocs | test, bloc_test, mocktail |
| Widget test | Individual widgets, UI behavior, navigation | flutter_test, WidgetTester |
Default to unit tests for business logic. Use widget tests when verifying UI rendering, gesture handling, or widget interaction.
Rules:
MaterialApp (or the app's root widget) to provide MediaQuery, Directionality, etc.pump() for a single frame or pumpAndSettle() when animations must complete.find.byKey over find.text for widgets that may have localized or dynamic text.mocktail for mocks (no code generation required).registerFallbackValue() in setUpAll for custom types passed to any().lib/ folder structure under test/.<source_file>_test.dart.group('Counter', () {
late Counter counter;
setUp(() {
counter = Counter();
});
test('value should start at 0', () {
expect(counter.value, 0);
});
test('should increment value by 1', () {
counter.increment();
expect(counter.value, 1);
});
});test('should emit updated list when item is added', () { ... });
test('should throw ArgumentError when input is negative', () { ... });testWidgets('should display error message on failure', (tester) async {
await tester.pumpWidget(
MaterialApp(
home: BlocProvider<LoginCubit>.value(
value: mockLoginCubit,
child: const LoginView(),
),
),
);
// Simulate failure state
whenListen(
mockLoginCubit,
Stream.fromIterable([const LoginState(status: LoginStatus.failure, errorMessage: 'Invalid')]),
initialState: const LoginState(),
);
await tester.pump();
expect(find.text('Invalid'), findsOneWidget);
});class MockAuthRepository extends Mock implements AuthRepository {}
void main() {
setUpAll(() {
registerFallbackValue(FakeLoginRequest());
});
// ... tests
}test/
feature_a/
cubit/
feature_a_cubit_test.dart
view/
feature_a_view_test.dart
model/
feature_a_model_test.dart