---
description: "Riverpod testing conventions for TaskFlow"
alwaysApply: false
---

# Riverpod Testing Standards — TaskFlow

## Test pattern
```dart
// final container = ProviderContainer(overrides: [myProvider.overrideWithValue(mockValue)]); addTearDown(container.dispose);

void main() {
  late ProviderContainer container;
  late MockProductRepository mockRepo;

  setUp(() {
    mockRepo = MockProductRepository();
    container = ProviderContainer(overrides: [
      productRepositoryProvider.overrideWithValue(mockRepo),
    ]);
  });

  tearDown(() => container.dispose()); // ALWAYS dispose

  test('ProductsNotifier loads products successfully', () async {
    when(() => mockRepo.getProducts()).thenAnswer((_) async => [fakeProduct]);

    final notifier = container.read(productsProvider.notifier);
    await notifier.loadProducts();

    final state = container.read(productsProvider);
    expect(state, isA<AsyncData<List<Product>>>());
    expect(state.value, [fakeProduct]);
  });
}
```

## Widget tests with Riverpod
```dart
testWidgets('ProductScreen shows shimmer while loading', (tester) async {
  await tester.pumpWidget(
    ProviderScope(
      overrides: [
        productsProvider.overrideWith((ref) => const AsyncLoading()),
      ],
      child: const MaterialApp(home: ProductScreen()),
    ),
  );
  expect(find.byType(ProductShimmer), findsOneWidget);
});
```

## Rules
- **Never** use a real `ProviderScope` in unit tests — always use `ProviderContainer` with overrides
- `addTearDown(container.dispose)` in every test that creates a container
- Test all three `AsyncValue` states: loading, data, error
