high priority low complexity testing pending testing specialist Tier 4

Acceptance Criteria

Widget test verifies that an earned BadgeCardWidget renders the unlocked badge icon asset (not the locked placeholder) and displays the correct badge name label text
Widget test verifies that a locked BadgeCardWidget renders the locked icon and applies muted/greyed styling (reduced opacity or muted color token) to name and icon
Widget test verifies that the milestone progress indicator displays the correct percentage string (e.g., '60%') or progress bar value matching the input progress fraction
Widget test uses SemanticsChecker or finds Semantics widgets and asserts that the semantic label describes earned state (e.g., 'Badge earned: Mentor Star') for earned cards
Widget test asserts that locked card semantic label conveys locked state and progress (e.g., 'Badge locked. Progress: 3 of 5 assignments')
Widget test verifies that tapping an earned card invokes the onTap callback exactly once
Widget test verifies that tapping a locked card does NOT invoke onTap when callback is null or when locked state is passed
All tests pass with flutter_test accessibility checks enabled (no accessibility violations reported)
Tests use pumpWidget with a MaterialApp wrapper and correct design token theme injection
Test file is placed in test/ directory mirroring the lib/ directory structure of BadgeCardWidget

Technical Requirements

frameworks
Flutter
flutter_test
flutter/material.dart
data models
BadgeDefinition
EarnedBadge
BadgeCriteria
performance requirements
All widget tests complete within 30 seconds total for the test file
No memory leaks — each testWidgets block disposes widget tree cleanly
security requirements
Tests must not include real user data or real badge IDs — use stub/fixture data only
ui components
BadgeCardWidget
BadgeIconAssetManager (mocked or stubbed)
Milestone progress indicator widget
Semantics widget wrappers

Execution Context

Execution Tier
Tier 4

Tier 4 - 323 tasks

Can start after Tier 3 completes

Implementation Notes

Wrap each testWidgets call with tester.ensureSemantics() and dispose the handle in tearDown or at end of test to avoid state leakage. Use find.byType(Semantics) or find.bySemanticsLabel() to assert on accessibility. For locked/muted styling, assert using find.byWidgetPredicate() checking Opacity or color property of Text/Icon widgets against design token values — avoid hardcoded hex colors in assertions. Stub BadgeIconAssetManager by passing a known asset path string directly to the widget rather than relying on asset resolution in tests (asset resolution can fail in test environments without full asset bundle setup).

Use pumpAndSettle() only when animations are present; prefer pump() for static widget tests. Follow the existing test conventions in the project test/ directory.

Testing Requirements

All tests are widget-level using flutter_test testWidgets(). Write at minimum 6 test cases: (1) earned badge full render, (2) locked badge muted render, (3) milestone progress percentage display, (4) semantic label for earned state, (5) semantic label for locked/progress state, (6) onTap callback invocation. Enable SemanticsHandle via tester.ensureSemantics() in each accessibility test and assert using tester.getSemantics(). Use a shared BadgeCardWidget factory helper to reduce boilerplate.

No mocking frameworks needed beyond simple stub model instances. Tests must be deterministic — avoid any DateTime.now() in widget state without injection.

Component
Badge Card Widget
ui low
Epic Risks (2)
high impact medium prob scope

Badge criteria are stored as structured JSON in badge_definitions. If the JSON schema for criteria (threshold counts, streak lengths, training completion flags) is not well-defined upfront, the evaluation service will be built against a moving target, requiring costly migrations and refactors.

Mitigation & Contingency

Mitigation: Define and document the criteria JSON schema in a shared type file before any repository code is written. Review the schema with all three organisations' badge requirements — especially Blindeforbundet's honorar thresholds — and version the JSON schema using a 'criteria_version' field from day one.

Contingency: If the criteria schema must change after services are built, write a Supabase migration to backfill existing rows and add a migration version column. Keep the evaluation service criteria parser isolated behind an interface so only one function needs updating.

medium impact medium prob dependency

Badge icon assets may not yet exist or may fail WCAG 2.2 AA contrast validation (minimum 3:1 for graphical objects) when rendered over design-token backgrounds. Missing or non-compliant icons could block UI epic delivery for Blindeforbundet, for whom screen reader and visual accessibility is non-negotiable.

Mitigation & Contingency

Mitigation: During this epic, implement the contrast-ratio validator in badge-icon-asset-manager and run it as a Flutter test against all candidate icon assets early. Coordinate with the design team to provide WCAG-compliant SVG icons in both locked and unlocked variants before the UI epic begins.

Contingency: If assets are late or fail contrast checks, ship placeholder icons that are guaranteed compliant (solid design-token colour fills with text labels) and swap in final assets post-QA without requiring a code change.