medium priority low complexity testing pending testing specialist Tier 2

Acceptance Criteria

Test file at test/data/receipt/receipt_image_picker_integration_test.dart covers all specified scenarios
pickFromGallery returns ReceiptImageResult with non-empty bytes and valid MIME type when image selected
pickFromCamera returns ReceiptImageResult with non-empty bytes and valid MIME type when photo taken
pickFromGallery returns null when user cancels (mock returns null XFile)
pickFromCamera returns null when user cancels
ReceiptPickerPermissionDeniedException is thrown when mock throws PlatformException with camera_access_denied code
Riverpod ProviderContainer test verifies that overriding the provider with a mock resolves correctly
All tests pass with flutter test — no platform channel calls required (fully mocked)
Test coverage for receipt_image_picker_integration.dart reported at 100% branch coverage

Technical Requirements

frameworks
Flutter
flutter_test
Riverpod
dart
performance requirements
All unit tests must complete in under 2 seconds total (no real I/O)
security requirements
Test byte fixtures must not contain real personal data or real receipt images
Mock implementation must not write any files to disk

Execution Context

Execution Tier
Tier 2

Tier 2 - 518 tasks

Can start after Tier 1 completes

Implementation Notes

Run build_runner to generate mockito mocks: flutter pub run build_runner build --delete-conflicting-outputs. The synthetic JPEG fixture can be a minimal valid JPEG (4 bytes: FFD8FFD9) for unit tests since MIME detection is based on the XFile.mimeType field which the mock controls. For the Riverpod provider test, use ProviderContainer(overrides: [receiptImagePickerProvider.overrideWithValue(mockImpl)]) and dispose the container in tearDown. Be explicit about the difference between unit tests (this task) and integration tests (task-009's widget-level tests) in the test file header comment.

Testing Requirements

Pure unit tests using flutter_test and mockito. Generate mockito mocks for ImagePicker using @GenerateMocks([ImagePicker]) and build_runner. Test file structure: group('pickFromGallery', ...), group('pickFromCamera', ...), group('Riverpod provider', ...). For Riverpod provider tests, use ProviderContainer from riverpod and override the receiptImagePickerProvider with a mock.

Assert that ref.read(receiptImagePickerProvider) returns the mock instance. No widget pump or Flutter binding required — these are pure logic tests.

Component
Receipt Image Picker Integration
infrastructure low
Epic Risks (3)
high impact medium prob security

Supabase Storage RLS policies using org/user/claim path scoping may not enforce correctly if claim ownership is not present in the JWT or if path segments are constructed differently at upload vs. read time, leading to data leakage or access denial for legitimate users.

Mitigation & Contingency

Mitigation: Define and test RLS policies in isolation before wiring to app code. Write integration tests that assert cross-org and cross-user access is denied. Use service-role key only in edge functions, never in client code.

Contingency: If client-side RLS proves insufficient, route all storage reads through a Supabase Edge Function that validates ownership before generating signed URLs, adding a controlled server-side enforcement layer.

high impact medium prob technical

Aggressive image compression may reduce receipt legibility below the threshold required for financial auditing, causing claim rejections or compliance failures despite technically successful uploads.

Mitigation & Contingency

Mitigation: Define minimum legibility requirements with HLF finance team before implementation. Set compression targets conservatively (e.g., max 1MB, min 80% JPEG quality) and validate with sample receipt images. Provide compression statistics in verbose/debug mode.

Contingency: If post-compression quality is disputed by auditors, increase the quality floor at the cost of larger file sizes, and add a manual override allowing users to skip compression for PDFs and high-quality scans.

medium impact medium prob dependency

The Flutter image_picker package behaves differently on iOS 17+ (PHPicker) vs older Android (Intent-based), particularly for file types, permission flows, and PDF selection, which may cause platform-specific failures not caught in development.

Mitigation & Contingency

Mitigation: Test image picker integration on physical devices for both platforms early in the sprint. Pin the image_picker package version and review changelogs before updates. Write widget tests using mock file results for each platform branch.

Contingency: If PHPicker or Android Intent differences cause blocking issues, implement separate platform-specific picker delegates behind the unified interface, allowing platform-specific fixes without breaking the shared API.