high priority medium complexity testing pending testing specialist Tier 6

Acceptance Criteria

Widget renders correctly with a mocked 3-level org tree (org → region → chapter) and all top-level nodes visible on initial render
Tapping an expandable node reveals its children; tapping again collapses them — both transitions are testable via find.byKey or find.byType
Search field filters visible nodes to only those matching the input string (case-insensitive, Norwegian characters supported)
Search with no matches shows an empty state widget or 'No results' text, not a blank screen
Selecting a leaf node updates the breadcrumb trail to reflect the full path from root to selected node
Selecting a node emits the correct OrgNodeSelectedEvent to the parent BLoC/Riverpod notifier
All interactive nodes have Semantics labels matching their org unit name for screen reader support (WCAG 2.2 AA)
Expand/collapse buttons carry distinct semantic labels ('Expand [org name]' / 'Collapse [org name]')
Tests run without real network calls — all tree data is injected via constructor or provider override
BLoC state after node selection reflects the selected scope ID and name correctly
Widget handles an empty tree gracefully (shows empty state, no exceptions thrown)
Widget handles a single-node tree (root only, no expand controls shown)

Technical Requirements

frameworks
flutter_test
bloc_test
flutter_bloc
riverpod
data models
OrgNode
OrgHierarchyTree
AdminPortalState
OrgNodeSelectedEvent
performance requirements
Each widget test pumps and settles within 2 seconds
Test suite for this widget completes in under 30 seconds total
security requirements
No real Supabase calls in widget tests — all data injected via mock providers
ui components
OrgHierarchyNavigator
OrgTreeNode (individual node tile)
BreadcrumbTrail
SearchField (within navigator)

Execution Context

Execution Tier
Tier 6

Tier 6 - 158 tasks

Can start after Tier 5 completes

Implementation Notes

Inject the org tree via a Riverpod ProviderScope override pointing to a FakeOrgHierarchyRepository that returns a hardcoded tree. Use bloc_test's whenListen to set up BLoC state if the navigator reads from a BLoC. For breadcrumb testing, assert the displayed text matches the expected 'Org → Region → Chapter' format. For WCAG testing, wrap the widget under test in a MaterialApp with a Semantics tree and use expect(tester.getSemantics(find.byType(OrgTreeNode)), ...) assertions.

Keep mock tree fixtures small (3–5 nodes) to keep tests fast. The most common mistake with tree widgets is forgetting to call tester.pumpAndSettle() after an animated expand — use it consistently. If animations cause flakiness, consider wrapping expand transitions in a flag that disables animation in test mode.

Testing Requirements

Flutter widget tests using flutter_test and bloc_test. Use MockBloc or ProviderScope overrides to inject deterministic tree data. Test scenarios: (1) initial render with 3-level tree, (2) expand top-level node, (3) expand + collapse, (4) search filtering with match, (5) search with no match, (6) node selection updates breadcrumb, (7) node selection event fired to BLoC, (8) empty tree state, (9) single-node tree, (10) semantic label presence via find.bySemanticsLabel. Use tester.pump() and tester.tap() for interaction simulation.

Assert Semantics tree correctness using tester.getSemantics(). All tests must be deterministic and side-effect free.

Epic Risks (4)
medium impact high prob technical

OrgHierarchyNavigator rendering NHF's full 1,400-chapter tree in a single widget may cause Flutter frame-rate drops below 60 fps on mid-range devices, making the navigator unusable for NHF national admins.

Mitigation & Contingency

Mitigation: Implement lazy expansion: only load immediate children on node expand rather than the full tree upfront. Use virtual scrolling for long sibling lists. Test with a synthetic 1,400-node dataset on a low-end Android device during development.

Contingency: If lazy expansion is insufficient, replace the tree widget with a paginated drill-down navigator (select level → select child) that avoids rendering more than 50 nodes at a time.

medium impact medium prob dependency

Bufdir may update their required export column structure or file format during or after development. If the AdminExportService hardcodes the current Bufdir schema, any format change requires a code release rather than a config update.

Mitigation & Contingency

Mitigation: Drive the Bufdir column mapping from a configuration repository rather than hardcoded constants. Abstract column definitions into a named schema config so that format changes require only a config update and re-deployment without service logic changes.

Contingency: If Bufdir format changes post-launch, release a config update within one sprint. If the change is structural (new required sections), scope a targeted service update and communicate timeline to partner organisations.

high impact medium prob integration

Role transition side-effects in UserManagementService (e.g., certification expiry removing mentor from chapter listing, pause triggering coordinator notification) may interact with external services like HLF's website sync. Incomplete side-effect handling could leave the system in an inconsistent state.

Mitigation & Contingency

Mitigation: Model side-effects as explicit domain events published after the primary state change is persisted. Implement event handlers as idempotent operations so re-processing is safe. Write integration tests that assert all side-effects fire correctly for each role transition type.

Contingency: If a side-effect fails after the primary change is persisted, log the failure with full context and trigger a manual reconciliation alert to the on-call team. Provide an admin-accessible re-trigger action for failed side-effects.

medium impact medium prob scope

If AdminStatisticsService cache TTL is set too long, org_admin may see significantly stale KPI values (e.g., a mentor newly paused an hour ago still appears as active), undermining trust in the dashboard.

Mitigation & Contingency

Mitigation: Default cache TTL to 5 minutes with a manual refresh action on the dashboard. Implement cache invalidation triggered by UserManagementService write operations that affect counted entities.

Contingency: If staleness causes org admin complaints post-launch, reduce TTL to 60 seconds and introduce a real-time Supabase subscription for high-impact counters (paused mentors, expiring certifications).