Unit-test ExpenseTypeConfig completeness
epic-expense-type-selection-foundation-task-003 — Write exhaustive unit tests that assert every ExpenseType variant has a corresponding config entry, that all formula parameters are within valid business ranges (rate > 0, threshold >= 0), and that JSON round-trip serialisation is lossless. Tests must run in under 200 ms with no network or disk access.
Acceptance Criteria
Technical Requirements
Execution Context
Tier 2 - 518 tasks
Can start after Tier 1 completes
Implementation Notes
The most robust pattern for exhaustive enum coverage in Dart is to iterate ExpenseType.values in a loop inside the test rather than listing variants explicitly — this way adding a new enum value without a config entry automatically fails the test without requiring test updates. For the JSON round-trip, ensure the toJson/fromJson cycle preserves double precision for rate and threshold (avoid int/double coercion). If ExpenseTypeConfig uses freezed or json_serializable, confirm the generated code is committed before this test runs. Keep test fixtures as const maps defined at the top of the file for readability.
Testing Requirements
Unit tests only using flutter_test. Use group() blocks to organise: 'completeness' (every enum variant has a config), 'business constraints' (rate/threshold ranges), and 'serialisation' (JSON round-trip). Use expect(ExpenseType.values, everyElement(predicate(...))) for exhaustive enum coverage. Assert serialisation with expect(decoded, equals(original)) leveraging Equatable or a manual == override on ExpenseTypeConfig.
No mocking required. Run with: flutter test test/expense_type/expense_type_config_test.dart
The compatibility matrix might be under-specified in source documentation. If a new organisation adds expense types or redefines rules, hardcoded pairwise logic becomes a maintenance liability and can silently allow previously excluded combinations.
Mitigation & Contingency
Mitigation: Model the matrix as a const Map<ExpenseType, Set<ExpenseType>> rather than if-else chains; add a unit test that exhaustively asserts every pair combination so any future matrix change forces explicit test updates.
Contingency: If per-organisation matrix variants are requested before the epic closes, extract matrix loading into expense-type-config with an org-override slot and defer per-org configuration to the repository epic.
VoiceOver (iOS) and TalkBack (Android) handle Semantics widget announcements differently in Flutter. Live-region behaviour for disabled state changes is inconsistent across Flutter versions and may require platform-specific workarounds that are not yet documented.
Mitigation & Contingency
Mitigation: Write accessibility integration tests using Flutter's SemanticsController targeting both iOS and Android simulators from the outset; pin to a Flutter version known to handle Semantics.liveRegion correctly.
Contingency: If platform parity is unachievable before release, ship with a known gap documented in the WCAG audit log and schedule a dedicated accessibility sprint; do not block other epics.