high priority medium complexity testing pending testing specialist Tier 3

Acceptance Criteria

XledgerExporter: field mapping test verifies that each claim field maps to the correct Xledger CSV column using a fixture claim record with all fields populated
XledgerExporter: validation test verifies that a missing or null value for each required field produces a typed ValidationError, not an unhandled exception
XledgerExporter: payload structure test verifies the output CSV matches the Xledger import specification (column order, delimiter, encoding, header row)
DynamicsExporter: field mapping test verifies each claim field maps to the correct Dynamics 365 JSON property with correct data types
DynamicsExporter: validation test verifies that malformed values (e.g., invalid date format, non-numeric amount) produce a typed ValidationError per field
DynamicsExporter: payload structure test verifies the output JSON matches the Dynamics 365 API contract (required envelope, property names, nesting)
Both exporters: test that the AccountingExporter interface contract is satisfied — all interface methods are implemented and return the expected types
Chart of Accounts Mapper dependency is fully mocked in all exporter tests — no real mapping logic executed
File Generator dependency is fully mocked — tests verify the correct payload string is passed to the generator, not the file output
Test fixtures represent realistic claim data including edge cases: zero-amount claims, maximum field length values, special characters in text fields
All tests pass with flutter_test — no external test runner required

Technical Requirements

frameworks
flutter_test
mocktail
apis
Xledger REST API (spec used as reference for payload validation)
Microsoft Dynamics 365 REST API (spec used as reference for payload validation)
data models
activity
activity_type
annual_summary
claim_event
performance requirements
Full unit test suite for both exporters must complete in under 15 seconds
security requirements
Test fixtures must not contain real personnummer, real names, or real financial data — use synthetic test data only
Xledger and Dynamics API credentials must not appear in test files — mock the HTTP clients entirely

Execution Context

Execution Tier
Tier 3

Tier 3 - 413 tasks

Can start after Tier 2 completes

Implementation Notes

The most important tests are the validation tests — they document the contract between the exporter and its callers. For each required field, write a parameterised test that sets that field to null/invalid and asserts a specific ValidationError type is returned. Use Dart's test package's group() and test() functions to keep test organisation readable. For CSV payload tests, parse the output string into a list of maps (header row as keys) before asserting field values — this is more robust than positional assertions.

For JSON payload tests, use Dart's jsonDecode and assert on the decoded Map. Keep fixture data in a dedicated fixtures/ directory under test/ — don't inline large JSON blobs in test files. Mock the Chart of Accounts Mapper to return a fixed account code ('1000') so mapping logic doesn't interfere with field mapping assertions.

Testing Requirements

Unit tests only (no integration tests in this task). Use flutter_test with mocktail for all dependency mocking. Organise tests into two files: xledger_exporter_test.dart and dynamics_exporter_test.dart. Each file contains groups: 'field mapping', 'validation', 'payload structure', 'interface contract'.

Use a shared test fixture factory (test/fixtures/claim_fixture.dart) to create consistent claim records. For payload structure tests, parse the generated CSV/JSON and assert each required field is present with the correct value — do not use string matching on the full payload. Aim for 100% branch coverage on both exporter classes.

Component
Xledger Exporter
service high
Epic Risks (3)
high impact medium prob dependency

The Xledger CSV/JSON import specification may not be available in full detail at implementation time. If the field format, column ordering, encoding requirements, or required fields differ from assumptions, the generated file will be rejected by Xledger on first production use.

Mitigation & Contingency

Mitigation: Obtain the official Xledger import specification document from Blindeforbundet before starting XledgerExporter implementation. Build a dedicated acceptance test that validates a sample export file against all documented constraints.

Contingency: If the spec arrives late, implement a configurable column-mapping layer so that field order and names can be adjusted via configuration without code changes. Ship a file-based export that coordinators can manually verify before connecting to Xledger import.

high impact low prob technical

The atomic claim-marking transaction in Double-Export Guard could fail under high concurrency if two coordinators trigger an export for overlapping date ranges simultaneously, potentially allowing duplicate exports to proceed past the guard.

Mitigation & Contingency

Mitigation: Use a database-level advisory lock or a SELECT FOR UPDATE on the relevant claim rows within the export transaction to serialize concurrent exports per organization. Add an integration test that simulates concurrent export triggers.

Contingency: If locking proves problematic at the database level, implement an application-level distributed lock using a Supabase row in a dedicated export_locks table with an expiry timestamp and automatic cleanup on failure.

medium impact high prob integration

HLF's Dynamics portal API endpoint may not be available or documented in time for Phase 1, leaving DynamicsExporter unable to be validated against a real system and potentially shipping with an incorrect field schema.

Mitigation & Contingency

Mitigation: Design DynamicsExporter for file-based export first (CSV/JSON download), with the API push implemented behind a feature flag. Request a Dynamics test environment or sandbox from HLF as early as possible.

Contingency: Ship DynamicsExporter as a file export only for Phase 1. Phase the API push integration into a follow-on task once the Dynamics sandbox is available, using the same AccountingExporter interface with no breaking changes.