Unit tests for ProxyRegistrationService orchestration paths
epic-proxy-activity-registration-orchestration-task-010 — Write comprehensive unit tests for ProxyRegistrationService covering: authorization rejection path (non-coordinator principal), duplicate detected path (conflict result returned, no repository call), successful registration path (attribution applied and repository called with correct record), and repository error path (exception mapped to ProxyRegistrationError). Use mockito/mocktail to mock CoordinatorRoleGuard, ProxyDuplicateDetectionService, ActivityAttributionService, and ProxyActivityRepository.
Acceptance Criteria
Technical Requirements
Execution Context
Tier 11 - 5 tasks
Can start after Tier 10 completes
Implementation Notes
Create mock classes at the top of the test file using mocktail's `class MockCoordinatorRoleGuard extends Mock implements CoordinatorRoleGuard {}` pattern — one mock class per collaborator. In setUp(), instantiate a fresh ProxyRegistrationService with injected mocks before each test. Define shared fixture data (valid coordinator ID, valid mentor ID, sample activity template) as top-level constants to keep tests readable. For the duplicate path, ensure the mock returns a DuplicateConflict value object rather than throwing — the service should handle conflicts as control flow, not exceptions.
For the repository error path, use `thenThrow(PostgrestException(message: 'conflict', code: '23505'))` to simulate a unique constraint violation. Document each test's purpose with a comment referencing the acceptance criterion it validates.
Testing Requirements
This task IS the test implementation. Use flutter_test as the test runner and mocktail for mocking (preferred over mockito due to null-safety ergonomics in Dart 3). Structure tests in a single file: `test/orchestration/proxy_registration_service_test.dart`. Group tests by scenario using `group()`.
Each `test()` block should follow Arrange-Act-Assert structure. Use `when()` and `thenReturn()` / `thenThrow()` from mocktail. Assert return types with `isA
If the Supabase batch RPC partial-inserts some records before encountering an error and does not roll back cleanly, the bulk service may report failure while orphaned records exist in the database, corrupting reporting data.
Mitigation & Contingency
Mitigation: Wrap the bulk insert in an explicit Supabase transaction via the RPC function. Write an integration test that simulates a mid-batch constraint violation and asserts zero records were written.
Contingency: If a partial-write incident occurs, the registered_by audit field allows identification and deletion of the orphaned records. Implement a coordinator-facing bulk submission status screen to surface any such anomalies.
When a bulk submission of 15 participants has 4 duplicates, the aggregated conflict summary may be too complex for coordinators to process quickly, leading to blanket override decisions that defeat the purpose of duplicate detection.
Mitigation & Contingency
Mitigation: Design the conflict result type to support per-participant override flags, so the UI can present a clear list of conflicting participants with individual cancel/override toggles rather than a single global decision.
Contingency: If coordinator usability testing reveals the conflict review screen is too complex, simplify to a 'skip all conflicts and submit the rest' mode as an immediate fallback while a more granular UI is designed.
If the coordinator role check inside proxy-registration-service is inconsistent with the route-level guard, a regression in the guard could allow peer mentors to call the service directly via deep links, submitting records with incorrect attribution.
Mitigation & Contingency
Mitigation: Enforce role authorization at both the route guard level (coordinator-role-guard) and inside each service method independently. Write a security test that calls the service directly with a peer mentor session token and asserts rejection.
Contingency: If a bypass is discovered, immediately enable the server-side RLS policy as the final enforcement layer and audit any records written during the exposure window using the registered_by field.