high priority medium complexity testing pending testing specialist Tier 4

Acceptance Criteria

All 7 defined test scenarios have passing integration tests in CI
Test: submitting a form with one or more required fields empty results in validationErrors non-empty and submission is not sent to Supabase
Test: simulating SpeechToText transcription result populates the target field's value in orchestrator state and triggers validation
Test: adding a WayForwardItem via the bottom sheet adds an entry to the way_forward field in currentValues
Test: editing a WayForwardItem updates the correct entry by ID
Test: removing a WayForwardItem removes the entry and updates currentValues
Test: changing any field value triggers a draft save within 2000ms (verified with fake async timers)
Test: successful submission (all fields valid, Supabase mock returns success) transitions to FormSubmitted state and no draft remains in repository
Test: a schema containing all 8 field types (text_single, text_multi, checkbox, radio_group, dropdown, number, date, way_forward) renders without Flutter errors or overflow
Test: submitting when Supabase mock returns an error transitions to FormError state with an error message
Branch coverage on FormOrchestratorBloc and CrossFieldValidatorService is ≥90% as reported by dart coverage
All tests run in under 30 seconds in CI

Technical Requirements

frameworks
Flutter
flutter_test
bloc_test
mockito or mocktail
apis
MockSupabaseClient
MockReportSchemaRepository
MockDraftRepository
CrossFieldValidatorService
data models
ReportFormSchema (with all 8 field types)
DraftReport
WayForwardItem
ValidationResult
performance requirements
Full test suite must complete in under 30 seconds
Use fakeAsync and FakeTimers for debounce testing — never use real delays
security requirements
Test fixtures must not contain real PII — use synthetic names and placeholder data
Mock Supabase client must not make real network calls — verify with network call interceptors if possible

Execution Context

Execution Tier
Tier 4

Tier 4 - 323 tasks

Can start after Tier 3 completes

Implementation Notes

For the full pipeline integration tests, instantiate the real FormOrchestratorBloc with mock repositories injected via constructor. Use BlocProvider.value in the widget test to supply it to the widget tree. For debounce testing, wrap in fakeAsync and use fake.elapse(Duration(seconds: 2)) — do not use real.delay(). For the SpeechToText scenario, mock the SpeechToTextService to synchronously return a transcription string and verify the field value updates.

Organize test files to mirror source files: test/orchestration/form_orchestrator_bloc_test.dart, test/visualization/dynamic_field_renderer_test.dart, test/visualization/way_forward_section_widget_test.dart, test/integration/form_engine_pipeline_test.dart. Use descriptive test names in the format 'given [state], when [event], then [outcome]' for readability in CI output.

Testing Requirements

This task IS the testing work. Organize tests into test groups: (1) OrchestratorBloc unit tests (bloc_test), (2) DynamicFieldRenderer widget tests, (3) WayForwardSectionWidget widget tests, (4) full pipeline integration tests using pumpWidget with real bloc wired to mock repositories. Use testWidgets for full pipeline tests. Use fakeAsync for all debounce/timer tests.

Set up a shared test fixtures file with a complete mock schema containing all 8 field types and sample options. Generate coverage report with 'flutter test --coverage' and enforce ≥90% branch coverage for orchestrator and validator in CI via lcov threshold check.

Component
Report Form Orchestrator
service high
Epic Risks (3)
high impact medium prob technical

Dynamically rendered form fields built from runtime JSON schema are significantly harder to make accessible than statically declared widgets — Flutter's Semantics tree must be correct for every possible field type and every validation state. Failures here block the entire feature for Blindeforbundet's visually impaired peer mentors.

Mitigation & Contingency

Mitigation: Define WCAG 2.2 AA semantics requirements for each field type before implementation and write widget tests using Flutter's SemanticsController for every type. Include a real-device VoiceOver test session in the acceptance gate for this epic before marking it done.

Contingency: If dynamic semantics prove too difficult to get right generically, implement field-type-specific Semantics wrappers (one per supported field type) instead of a single generic renderer, accepting slightly more code duplication in exchange for reliable accessibility.

high impact medium prob technical

The report-form-orchestrator must manage a complex state machine — schema loading, draft persistence, per-field validation, submission retries, and error recovery — across multiple async operations. Incorrect state transitions could result in lost user data, double submissions, or UI freezes.

Mitigation & Contingency

Mitigation: Define all Bloc states and events explicitly as sealed classes before writing any logic. Use a state machine diagram reviewed by the team before implementation. Write exhaustive Bloc unit tests covering every state transition, including concurrent events and network interruption mid-submission.

Contingency: If Bloc complexity becomes unmanageable, extract draft persistence into a separate DraftManagerCubit and keep report-form-orchestrator focused solely on the submit workflow. The additional granularity makes each component independently testable.

medium impact low prob scope

Organisations may require field types beyond the five currently specified (text, multiline, checkbox group, radio, date). If a new type is discovered during pilot testing, the dynamic-field-renderer must be extended, potentially requiring changes across multiple layers.

Mitigation & Contingency

Mitigation: Design dynamic-field-renderer as a registry of field-type renderers with a clear extension point. Document the pattern for adding a new field type so that it can be done in one file without touching existing renderers.

Contingency: If an unhandled field type is encountered at runtime, dynamic-field-renderer renders a labelled plain-text fallback widget and logs a warning so the missing type is surfaced in monitoring, preventing a crash while making the gap visible.