high priority high complexity testing pending testing specialist Tier 4

Acceptance Criteria

All required Bufdir payload fields (organisation_id, period_start, period_end, peer_mentor_records) are covered by unit tests that assert correct mapping from internal Dart models to the canonical JSON structure
All optional payload fields (duplicate_warnings, scope_level, region_id) are tested with both present and absent values to confirm null-safety and correct serialization
Authentication token acquisition is tested: valid token path, expired token triggers refresh, refresh failure propagates a typed AuthenticationException
Token refresh retry logic is tested: exactly one refresh attempt per expired token, no infinite refresh loops
Integration test simulating a successful 2xx API submission verifies that bufdir_reference_number is extracted from the response body and persisted to Supabase via the repository layer
Integration test simulating a 422 validation error verifies that a typed BufdirValidationException is thrown with the server error details accessible to callers
Integration test simulating a 500 server error followed by a successful retry confirms the retry policy executes the correct number of attempts with exponential back-off before either succeeding or surfacing a BufdirServerException
Integration test simulating total retry exhaustion confirms the client does not persist a reference number and surfaces the terminal error
Test coverage for the bufdir-api-client module is measured and confirmed to be 90% or above using flutter_test coverage tooling
All tests pass with `flutter test` in CI with no flakiness across three consecutive runs
Tests do not make real HTTP calls — all HTTP interactions are intercepted by a mock server or stub (e.g., MockClient from http package or a local HttpServer fixture)

Technical Requirements

frameworks
flutter_test
mockito or mocktail for Dart mocking
http (dart) MockClient or dart:io HttpServer for mock server
apis
Bufdir API (mocked)
Supabase client (mocked repository layer)
data models
BufdirPayload
BufdirSubmissionResult
BufdirValidationException
BufdirServerException
AuthenticationException
PeerMentorRecord
performance requirements
Full test suite must complete in under 60 seconds
No real network calls — all I/O must be synchronous or mocked to avoid flaky timing
security requirements
No real credentials or API keys in test fixtures — use placeholder strings
Ensure token values in test logs are not printed in plaintext; assert only on error type, not token content

Execution Context

Execution Tier
Tier 4

Tier 4 - 323 tasks

Can start after Tier 3 completes

Integration Task

Handles integration between different epics or system components. Requires coordination across multiple development streams.

Implementation Notes

Structure tests in three files mirroring the production structure: `bufdir_request_mapper_test.dart` (pure unit, no I/O), `bufdir_auth_handler_test.dart` (unit with mocked token store), `bufdir_api_client_integration_test.dart` (mock HTTP server). Use Dart's `http` package MockClient for HTTP stubbing — avoid real HttpServer unless response streaming behaviour must be tested. For the retry integration test, use a stateful counter in the mock handler that returns 500 for the first N calls then 200, and assert the counter reached the expected value. For Supabase persistence assertions, inject a mock repository implementing the same interface as the real one (follow the repository pattern already established in the codebase).

Keep test data in `test/fixtures/bufdir/` as JSON files to keep test methods readable. Do not use `print` in tests — use `fail()` with descriptive messages instead.

Testing Requirements

Unit tests: cover every public method on the API client class using flutter_test with mocked HTTP and mocked Supabase repository. Integration tests: spin up a local MockClient or dart:io HttpServer that returns scripted HTTP responses (200 with reference number, 422 with validation body, 500 then 200 on retry). Use setUp/tearDown to isolate test state. Assert both the returned Dart objects and side-effects (repository.persist called with correct reference number).

Coverage: run `flutter test --coverage` and use lcov or the built-in reporter to confirm the 90% threshold. Failure modes to test: network timeout, malformed JSON response body, missing reference_number field in success response.

Component
Bufdir API Client
service high
Epic Risks (2)
medium impact high prob dependency

Norse Digital Products has not yet completed API negotiations with Bufdir. If negotiations stall or Bufdir's API design diverges significantly from expectations, the API client may need substantial rework, or the epic may be blocked indefinitely.

Mitigation & Contingency

Mitigation: Implement the client against a locally defined stub of the expected Bufdir API schema. Isolate all Bufdir-specific schema mapping in a single adapter class so that changes to the actual API schema require changes in only one place. Keep the epic in 'interface-ready' status until real API credentials are available for integration testing.

Contingency: If API negotiations are not completed within the planned window, defer this epic without impact on any other epic — the PDF/CSV fallback path from Epics 1–4 delivers full standalone value. Mark the epic as blocked and resurface when negotiations conclude.

high impact low prob security

Bufdir API credentials stored in the application or edge function environment could be exposed through misconfigured secrets management, log leakage, or a compromised deployment pipeline, allowing unauthorised Bufdir submissions on behalf of the organisation.

Mitigation & Contingency

Mitigation: Store all Bufdir API credentials exclusively in Supabase Vault (or the integration credential vault component), never in client-side code or environment variables accessible to the Flutter app. Transmit credentials only from within the edge function, not from the Flutter client. Implement credential rotation support from the outset.

Contingency: If a credential leak is detected, immediately revoke and rotate the affected API credentials through Bufdir's credential management portal, audit submission logs for any unauthorised calls, and notify Bufdir's technical contact per the API agreement's security incident clause.