high priority medium complexity testing pending testing specialist Tier 4

Acceptance Criteria

Unit tests exist for all five adapters: Xledger, Microsoft Dynamics, Cornerstone, Consio, and Bufdir
Each adapter's authenticate() method is tested with a mocked HTTP client: (a) successful token response, (b) invalid credentials 401, (c) network timeout, (d) server error 500
Each adapter's testConnection() method is tested: (a) successful ping, (b) authentication failure before ping, (c) connection refused / network error
Payload serialization tests verify that sendPayload() constructs the correct HTTP method, URL, headers, and body for each adapter's API contract
Error normalization is tested for each adapter: HTTP 400, 401, 403, 404, 422, 429, 500 responses are all mapped to the correct normalized AdapterError domain type
Retry logic tests verify that transient errors (429, 500, 503) trigger retries up to the configured maximum, and permanent errors (401, 403, 404) do not retry
getCapabilities() is tested for each adapter: returned AdapterCapabilities contains all expected required fields and scopes
Each adapter test verifies the adapter implements all methods of the uniform adapter interface (compile-time and runtime contract)
No test makes real HTTP calls — all HTTP interactions are intercepted by mock clients
All 5 × (authentication + testConnection + serialization + error normalization + retry + capabilities) = 30+ distinct test cases are present and passing

Technical Requirements

frameworks
Dart
flutter_test
mockito or mocktail (for HTTP client mocking)
http package mock client
apis
Xledger REST API contract
Microsoft Dynamics REST API contract
Cornerstone REST API contract
Consio REST API contract
Bufdir REST API contract
Adapter uniform interface contract
data models
AdapterCapabilities
AdapterError
AuthToken
ConnectionTestResult
AdapterPayload
performance requirements
All unit tests must complete within 30 seconds total
Each individual test must complete within 2 seconds (no real network waits)
security requirements
Test fixtures must not contain real API keys, tokens, or credentials — use clearly fake values like 'test-api-key-xledger'
Mock HTTP responses must not be sourced from live API calls — use static JSON fixtures checked into the test directory

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 each adapter test file with a `setUp` that creates an adapter instance injected with a `MockHttpClient` (not a real one). For retry logic, use a stateful mock client that returns 500 on the first N calls then 200 — this verifies the retry count without real delays (set retry delays to zero in test mode via a testDelayOverride parameter). For serialization tests, capture the request object passed to the mock client and assert on `request.url`, `request.method`, `request.headers['Authorization']`, and `request.body`. For error normalization, the test structure should be a parameterized loop over a map of `{httpStatusCode: expectedAdapterErrorType}` to avoid repetitive test code.

The interface conformance check can be a compile-time guarantee: write `final IntegrationAdapter adapter = XledgerAdapter(...)` in the test setup — if XledgerAdapter doesn't implement the interface, this won't compile. Use `group()` nesting to keep tests organized: `group('XledgerAdapter', () { group('authenticate', () { ... }); })`. All five adapter test files should follow the identical structure for consistency.

Testing Requirements

This task IS the testing work. Structure: create a test file per adapter (e.g., `test/adapters/xledger_adapter_test.dart`). Use `MockClient` from the `http` package (or mocktail's `MockHttpClient`) to intercept HTTP calls. Organize each test file into groups: 'authenticate', 'testConnection', 'sendPayload', 'normalizeError', 'retryBehavior', 'getCapabilities'.

Use `setUp()` to create a fresh adapter instance with the mock client before each test. For OAuth flows, mock the token endpoint separately from the data endpoint. Store mock response JSON in `test/fixtures/adapters/` as .json files. Use `json.decode(File('test/fixtures/...').readAsStringSync())` to load fixtures.

After all tests pass, run `flutter test --coverage` and ensure each adapter file reaches 85%+ line coverage.

Component
REST API Adapter Registry
service high
Epic Risks (3)
medium impact high prob technical

Each of the five external systems (Xledger, Dynamics, Cornerstone, Consio, Bufdir) has a different authentication flow, field schema, and error format. Forcing them into a uniform adapter interface may require compromises that result in leaky abstractions or make the adapter contract too complex to maintain.

Mitigation & Contingency

Mitigation: Design the IntegrationAdapter interface with a loose invoke() payload rather than a typed one, allowing each adapter to declare its own input/output schema. Use integration type metadata in the registry to document per-adapter quirks. Build Xledger first as the most documented API, then adapt the interface based on learnings.

Contingency: If the uniform interface cannot accommodate all five systems, split into two interface tiers: a simple polling/export adapter and a richer bidirectional adapter, with the registry declaring which tier each system implements.

medium impact high prob dependency

Development and testing of the Cornerstone and Consio adapters depends on NHF providing sandbox API access. If credentials or documentation are delayed, these adapters cannot be validated, blocking the epic's acceptance criteria.

Mitigation & Contingency

Mitigation: Implement Xledger and Dynamics adapters first (better-documented, sandbox available). Create a mock adapter for Cornerstone/Consio using recorded API responses for CI testing. Proactively request sandbox access from NHF at project kickoff.

Contingency: Ship the epic with Cornerstone/Consio adapters in a 'stub' state (connectivity test returns a simulated success, invoke() is not production-wired) and gate the NHF integration behind a feature flag until real API access is obtained.

medium impact medium prob scope

Real-world field mappings may include nested transformations, conditional logic, and data type coercions (e.g., Norwegian date formats, currency rounding rules) that the Field Mapping Resolver's initial design does not accommodate, requiring scope expansion mid-epic.

Mitigation & Contingency

Mitigation: Gather actual field mapping examples from Blindeforbundet (Xledger) and HLF (Dynamics) before designing the resolver. Identify the most complex transformation required and ensure the resolver design handles it. Limit Phase 1 to direct field renaming and format conversion only.

Contingency: If complex transformations are required, implement a simple expression evaluator (e.g., JSONata or a custom mini-DSL) as an extension point in the resolver, delivering basic mappings first and complex ones in a follow-up task.