Write unit tests for BulkApprovalProcessor
epic-expense-approval-workflow-bulk-and-action-task-011 — Write unit tests for BulkApprovalProcessor covering: successful batch with all records approved, partial failure where some records fail without rolling back successful ones, complete batch failure, empty input handling, and correct delegation to ApprovalWorkflowService per record. Mock ApprovalWorkflowService to isolate processor logic.
Acceptance Criteria
Technical Requirements
Execution Context
Tier 3 - 413 tasks
Can start after Tier 2 completes
Implementation Notes
BulkApprovalProcessor should process records sequentially (not in parallel) by default to avoid overwhelming the Supabase connection pool and to produce deterministic test behavior. Each record's success or failure is captured independently — use a try/catch per iteration. Return a BulkApprovalResult value object: { successCount, failureCount, failedClaimIds, errors }. The processor should accept ApprovalWorkflowService as a constructor parameter (dependency injection) to enable mocking.
Test fixture factory: create a helper makeTestClaim({String? id}) that returns a minimal ExpenseClaim with a generated UUID ID. Avoid using real models with required fields that are tedious to populate — use copyWith or factory constructors.
Testing Requirements
Use flutter_test with mocktail (or mockito with build_runner). Structure test file with group() blocks per scenario: 'all success', 'partial failure', 'complete failure', 'empty input'. Each test uses setUp to reinitialize mock and processor. Use verify(mockService.approveExpenseClaim(any)).called(N) for interaction counts.
For async tests use async/await with expect(await processor.processAll(claims), isA
If a bulk approval batch partially fails (some claims approved, some failed), the UI must communicate which specific claims failed without overwhelming the coordinator. A poorly designed error display could cause coordinators to re-approve already-approved claims or miss claims that still need attention.
Mitigation & Contingency
Mitigation: Design the BulkApprovalResult display to show a clear summary (e.g., '14 approved, 2 failed') with a collapsible list of failed claims including their IDs and submitter names. Failed claims should remain selected in the queue so the coordinator can retry them individually.
Contingency: If the summary UI proves insufficient, add a dedicated 'bulk action history' sheet showing the last bulk operation result, accessible from the queue screen header.
If the app is backgrounded or the network drops while the coordinator has the ApprovalActionSheet open mid-decision, the typed comment could be lost and the transition state could be ambiguous, potentially causing a coordinator to believe they approved a claim that was never submitted.
Mitigation & Contingency
Mitigation: Persist the in-progress action sheet state (selected action + comment text) to a local draft store keyed on claim ID. On sheet re-open for the same claim, restore the draft. After confirmed submission, verify the resulting claim status from the server before dismissing the sheet.
Contingency: On network error during submission, display a persistent retry banner within the sheet rather than dismissing it, so the coordinator can resubmit without re-entering their comment.