# TT-013 — Widget Tests **Type:** Task **Priority:** Medium **Labels:** testing, widget-tests **Depends on:** TT-006, TT-007, TT-008, TT-009, TT-010, TT-011 **Blocks:** — --- ## Summary Write widget tests for each feature screen. Tests verify correct rendering of UI states, user interactions, and provider integration. All provider dependencies are overridden with mocks via `mocktail`. ## Scope | Test file | Screen | Key scenarios | |-----------|--------|---------------| | `test/features/timer/timer_screen_test.dart` | TimerScreen | idle state, running state, start tap, stop tap | | `test/features/entries/entries_screen_test.dart` | EntriesScreen | empty state, list renders, swipe delete, add form | | `test/features/projects/projects_screen_test.dart` | ProjectsScreen | empty state, tile renders, create form, archive | | `test/features/reports/reports_screen_test.dart` | ReportsScreen | week tab, period navigation, chart renders | | `test/features/settings/settings_screen_test.dart` | SettingsScreen | theme picker, language picker, export sheet opens | ## Widget Test Pattern ```dart Widget buildTestApp({List overrides = const []}) { return ProviderScope( overrides: overrides, child: MaterialApp( localizationsDelegates: AppLocalizations.localizationsDelegates, supportedLocales: AppLocalizations.supportedLocales, home: const TimerScreen(), ), ); } testWidgets('shows START button when idle', (tester) async { when(() => mockTimerNotifier.build()).thenReturn(const TimerState.idle()); await tester.pumpWidget(buildTestApp(overrides: [ timerNotifierProvider.overrideWith(() => mockTimerNotifier), ])); expect(find.text('Start'), findsOneWidget); expect(find.text('Stop'), findsNothing); }); ``` ## Key Widget Test Cases per Screen ### TimerScreen - [ ] Idle: START visible, STOP hidden, elapsed shows `00:00:00` - [ ] Running: STOP visible, DISCARD visible, project name shown - [ ] Tap START without project → button remains disabled - [ ] Tap STOP → `timerNotifier.stop()` called once - [ ] Tap DISCARD → confirmation dialog appears ### EntriesScreen - [ ] Empty: placeholder text visible - [ ] With entries: `EntryListTile` rendered for each - [ ] Swipe left on entry → delete action visible - [ ] Tap "+" → `EntryFormSheet` appears - [ ] Date filter chip "Today" → filters visible entries ### ProjectsScreen - [ ] Empty Active tab: "No projects yet" visible - [ ] Tile shows project name and color dot - [ ] Tap tile → edit form opens pre-filled - [ ] Archive action → tile moves to Archived tab ### ReportsScreen - [ ] Week tab shows 7 bar groups - [ ] Tap ▶ → period label advances by one week - [ ] Total duration card shows formatted duration ### SettingsScreen - [ ] Theme dropdown shows current selection - [ ] Changing theme → `themeModeProvider` updated - [ ] Tap "Export data" → `ExportSheet` bottom sheet appears ## Acceptance Criteria - [ ] All listed widget test files exist and pass with `flutter test` - [ ] Each screen has ≥ 3 test cases - [ ] No test relies on real DB or real providers - [ ] Tests run in < 30 seconds total (no `sleep` / real async delays) - [ ] `pumpAndSettle` used after async interactions ## Notes - Use `find.byType()`, `find.text()`, `find.byKey()` — avoid pixel-exact finders - Add semantic labels / keys to interactive widgets to simplify test selectors - Golden tests (screenshot comparison) are optional for v1