Unit Tests: User Management Service
epic-admin-portal-core-services-task-018 — Write unit tests for UserManagementService covering: CRUD happy paths, invalid role transition rejection, out-of-scope write rejection, certification expiry side-effects (chapter listing removal), and transactional rollback on side-effect failure. Mock OrgHierarchyService and notification dispatcher.
Acceptance Criteria
Technical Requirements
Execution Context
Tier 5 - 253 tasks
Can start after Tier 4 completes
Implementation Notes
This is the most complex service to test due to the interaction of role validation, scope checks, side-effects, and rollback. Structure tests with the Arrange-Act-Assert (AAA) pattern with explicit comments delineating each section. For transactional rollback testing, if the service does not currently have an injectable transaction manager or unit-of-work abstraction, coordinate with the implementation owner to add one before writing rollback tests — testing rollback against real Supabase transactions is not feasible in unit tests. Mock OrgHierarchyService.getSubtreeIds to return a fixed set of org IDs for scope tests; assert via verify that UserRepository.save is called only when the target user's orgId is within that set.
For certification expiry tests, pass a User object with a certificationExpiryDate in the past and verify the side-effect mock is called; for a User with a future expiry date, verify the side-effect is NOT called. Keep each test focused on one behaviour — do not combine CRUD and role transition in a single test case.
Testing Requirements
Pure Dart unit tests (flutter_test) with mocktail mocks for all external dependencies. Organise in test groups: 'CRUD happy paths', 'role transition validation', 'scope enforcement', 'certification expiry side-effects', 'transactional integrity', 'notification dispatch'. Use when().thenReturn() / when().thenThrow() from mocktail to simulate both success and failure paths for each side-effect. For rollback tests, if the service uses a database transaction abstraction, mock the transaction object and verify commit() is not called on failure.
All exception-type assertions should use throwsA(isA
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.
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.
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.
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).