Write unit and widget tests for theme assembly
epic-visual-design-accessibility-theme-integration-task-009 — Write unit tests covering: token-to-ColorScheme mapping for all four organisations in both light and dark modes, rejection of brand overrides that fail contrast validation, and correctness of all component theme factory outputs. Add widget tests that mount a minimal MaterialApp with each org ThemeData and assert that rendered text and button widgets pass contrast and touch target checks using the accessibility test harness.
Acceptance Criteria
Technical Requirements
Execution Context
Tier 8 - 48 tasks
Can start after Tier 7 completes
Handles integration between different epics or system components. Requires coordination across multiple development streams.
Implementation Notes
Use Riverpod ProviderContainer (not ProviderScope) for unit tests to keep tests fast and isolated — create a fresh container per test with override() to inject fixture branding configs. For ColorScheme mapping tests, define expected values as constants derived directly from the design token JSON files (parse them in a test helper) rather than hardcoding hex strings — this creates a single source of truth and makes token drift immediately visible. For contrast validation tests, create a test helper `expectContrastRatio(Color fg, Color bg, {double minRatio})` that computes relative luminance using the W3C formula — this is more reliable than relying solely on the accessibility matcher which works on rendered pixels. For widget tests, use `tester.pump()` rather than `pumpAndSettle()` where possible to keep tests fast; only use `pumpAndSettle()` when testing animated transitions.
Group tests with Dart's `group()` by organisation name to make CI output readable. Consider parameterizing org×brightness combinations with a helper to avoid 8 copies of near-identical test bodies — use a list of test cases and a loop calling `testWidgets()`.
Testing Requirements
This task IS the testing task. Self-validation: run `flutter test test/theme_builder_test.dart --coverage` and confirm 0 failures and >= 90% coverage. Peer review checklist: each test has a descriptive name following the pattern 'given_[state]_when_[action]_then_[expectation]'; no test shares mutable state with another; all widget tests call tester.pumpAndSettle() before making assertions; accessibility matcher failures produce a meaningful error message identifying which org/brightness combination failed. Regression gate: add a comment block in the test file listing the design token file hashes that the mapping tests were written against, so future token updates are flagged.
One or more of the four partner organisations may supply brand primary colors that cannot be paired with any standard foreground at 4.5:1 contrast (for example, a mid-range hue that is too light for dark text and too dark for white text). Rejecting these colors programmatically could cause a political dispute with the organisation and delay the feature.
Mitigation & Contingency
Mitigation: Before implementation begins, run all four organisations' existing brand primary colors through the contrast-ratio-validator against both white (#FFFFFF) and a near-black (#1A1A1A). Share the results with each organisation's contact person ahead of the theme builder sprint so any problematic colors can be adjusted collaboratively with advance notice.
Contingency: If an organisation insists on a non-compliant brand color, produce a compliant near-match (lightened or darkened along the hue's luminance axis) and present both options with contrast ratio evidence. Document the adjusted token in the manifest with an explicit note that the original brand color was non-compliant, and obtain written sign-off from the organisation.
Flutter's ThemeData contains over 30 component theme properties. If the theme-builder only addresses the most common ones (Button, InputDecoration, Card) and leaves others at Flutter defaults, downstream feature teams may unknowingly use default-themed widgets that do not meet sizing or contrast requirements.
Mitigation & Contingency
Mitigation: Produce a full inventory of all ThemeData component theme properties and map each to either a token-driven override or an explicit pass-through decision documented in the theme builder code. Prioritise the inventory by frequency of use in the existing codebase (identified via Grep). Include a check in the CI lint runner that flags widgets using Flutter default component themes not covered by the theme builder.
Contingency: If the full inventory scope exceeds the sprint budget, ship with the highest-frequency components covered and add a tracked backlog item for each uncovered component theme, pairing with a temporary lint suppression comment that includes the backlog reference.