high priority medium complexity testing pending testing specialist Tier 5

Acceptance Criteria

DriverFeatureFlagGuard: test renders child when flag enabled; test renders blocked-access UI when flag disabled; test responds to flag value change mid-session
DeclarationStatusBadge: one test per status variant (pending, sent, acknowledged, error, none); each test asserts correct icon, color, and label text; test asserts no badge rendered for 'none' status
DriverAssignmentList: test empty state renders empty-state widget; test loading state renders skeleton; test populated state renders all assignment tiles; test error state renders retry button; test scrolling to bottom triggers pagination event; test pull-to-refresh triggers refresh event
DeclarationSendScreen: test send button triggers send action; test re-send button is visible after a failed or prior send; test navigation arguments are passed correctly to the BLoC
DeclarationAcknowledgementScreen: test checkbox is disabled before scroll reaches bottom; test checkbox enables after scroll completes; test submission button disabled when checkbox unchecked; test submission triggers correct BLoC event; test success state pops the route
DriverFeeRegistrationForm: test submit with empty contact shows inline error; test submit with negative amount shows inline error; test submit with amount over cap shows inline error; test valid submission triggers submitting state; test declarationRequired state renders the declaration entry point prompt
All tests use WidgetTester and do not rely on real network calls — all services are stubbed via dependency injection or Riverpod/BLoC overrides
Test file naming follows the pattern {widget_name}_test.dart and lives in test/driver/ directory
Coverage report generated with flutter test --coverage confirms 80%+ line coverage for all files under lib/features/driver/
All tests pass on CI (no flaky timers, no hardcoded delays — use fake async or pump() appropriately)

Technical Requirements

frameworks
Flutter
flutter_test
BLoC (bloc_test)
Riverpod (riverpod test utilities)
Dart
data models
DriverAssignment
DeclarationStatus
DriverFee
FeeType
FeatureFlag
performance requirements
Full widget test suite for this epic must complete in under 60 seconds on CI to avoid blocking PRs
Each individual test must complete within 5 seconds — use FakeAsync for timer-dependent flows
security requirements
Test fixtures must not contain real PII — use synthetic names like 'Test Driver 1' and fictional Norwegian national IDs
ui components
DriverFeatureFlagGuard
DeclarationStatusBadge
DriverAssignmentList
DeclarationSendScreen
DeclarationAcknowledgementScreen
DriverFeeRegistrationForm

Execution Context

Execution Tier
Tier 5

Tier 5 - 253 tasks

Can start after Tier 4 completes

Implementation Notes

Organize tests into one file per component rather than one large file, to keep test files maintainable and parallelizable on CI. Use setUp() to create fresh BLoC/provider instances before each test — never share mutable BLoC state between tests. For the scroll gate test, the real scroll detection likely uses a ScrollController with a listener; in tests, use tester.drag(find.byType(SingleChildScrollView), const Offset(0, -500)) to simulate scrolling to the bottom, then pump() to let listeners fire. For BLoC-driven tests, always use bloc_test's blocTest() to assert state sequences rather than manually pumping events and asserting state — this is less brittle.

When testing the DriverFeatureFlagGuard flag-change mid-session test, use a StreamController as the flag source and add a new value to verify the guard re-renders.

Testing Requirements

All tests are Flutter widget tests using flutter_test. Use bloc_test's blocTest() helper for BLoC unit tests. Use Riverpod's ProviderContainer with overrides for provider tests. Use mocktail for service stubbing (preferred over mockito for null-safety compatibility).

Each widget test pumps the widget under test inside a MaterialApp with the app's theme and design tokens applied so visual assertions are meaningful. Pagination tests use a FakeScrollController to simulate scroll events. The scroll gate test on DeclarationAcknowledgementScreen uses tester.drag() to simulate scroll progress. Snapshot/golden tests are out of scope for this task.

Epic Risks (3)
high impact medium prob technical

The declaration acknowledgement screen has the most complex accessibility requirements of any screen in this feature: scrollable long-form legal text, a conditional checkbox that is only enabled after reading, and a timestamp capture. Incorrect focus management or missing semantics annotations could fail VoiceOver navigation or cause the screen reader to announce the checkbox as available before the driver has scrolled, undermining the legal validity of the acknowledgement.

Mitigation & Contingency

Mitigation: Build the acknowledgement screen against the WCAG 2.2 AA checklist from the start, not as a post-hoc audit. Use semantics-wrapper-widget and live-region-announcer from the platform's accessibility toolkit. Include a VoiceOver test session in the acceptance criteria with a tester using the screen reader.

Contingency: If WCAG compliance cannot be fully achieved within the sprint, ship the screen with a documented list of accessibility gaps and a follow-up sprint commitment. Do not block the declaration workflow launch if the core interaction works but a non-critical semantics annotation is missing.

medium impact medium prob integration

Drivers receive a push notification with a deep link to the declaration acknowledgement screen for a specific assignment. If the deep link handler does not correctly route to the right screen and assignment context — particularly when the app is launched cold from the notification — the driver may see a blank screen or the wrong declaration.

Mitigation & Contingency

Mitigation: Implement and test all three notification scenarios: app foregrounded, app backgrounded, and cold start. Use the platform's existing deep-link-handler infrastructure. Add integration tests that simulate notification tap events and assert correct screen and data loading.

Contingency: If cold-start deep link routing proves unreliable, implement a notification-centre fallback where the driver can find the pending declaration from the notification centre screen, ensuring the workflow can always complete even if the direct deep link fails.

medium impact low prob technical

If the driver-feature-flag-guard has any rendering edge case — such as a brief flash of driver UI before the flag value is loaded, or a guard that fails open on a flag service error — driver-specific UI elements could be momentarily visible to coordinators in organizations that have not opted in, causing confusion and potentially a support escalation.

Mitigation & Contingency

Mitigation: Default the guard to rendering nothing (not a loading indicator) until the flag value is definitively resolved. Treat flag service errors as flag-disabled to fail closed. Write widget tests covering the loading, disabled, and enabled states including the error case.

Contingency: If fail-closed cannot be guaranteed within the sprint, add a server-side RLS check on the driver assignment endpoints so that even if the UI guard leaks, the data layer refuses to return driver data for organizations without the flag enabled.