high priority medium complexity testing pending testing specialist Tier 3

Acceptance Criteria

Fixture JPEG images are committed to test/fixtures/images/ with at least three variants: small (320x240, ~30KB), medium (1920x1080, ~500KB), large (3840x2160, ~3MB)
Test: compressing the medium fixture with default config produces output where max(width,height) <= 800
Test: compressing any fixture produces output bytes fewer than input bytes
Test: compression ratio (output/input) for the large fixture is below 0.5 (at least 50% reduction)
Test: compressing the small fixture (already under 800px) does not upscale — output dimensions equal input dimensions
Test: passing Uint8List(0) throws CompressionException with message containing 'empty'
Test: passing random non-image bytes throws CompressionException with message containing 'decode'
Test: custom OrgCompressionConfig with maxDimensionPx=400 produces output max dimension <= 400
Test: maxFileSizeBytes constraint (set to 50KB) on the large fixture produces output <= 51200 bytes
All tests pass with flutter test test/features/receipts/domain/receipt_image_compressor_test.dart

Technical Requirements

frameworks
Flutter
flutter_test
Riverpod
apis
dart:typed_data
dart:ui
data models
OrgCompressionConfig
CompressionResult
CompressionException
performance requirements
Test suite must complete in under 30 seconds on CI
Fixture images must be under 5MB total to keep repo size manageable

Execution Context

Execution Tier
Tier 3

Tier 3 - 413 tasks

Can start after Tier 2 completes

Implementation Notes

Add fixture images to test/fixtures/images/ and register them in pubspec.yaml under flutter.assets with a test-only conditional if supported, or load them directly via File in the test. Use the image Dart package to decode output JPEG bytes and read dimensions — this avoids needing a full Flutter binding for dimension checks. Structure tests in groups: 'dimension constraints', 'size reduction', 'error handling', 'org config overrides'. For the iterative quality reduction test, use a very small maxFileSizeBytes (e.g., 10KB) to force multiple iterations and assert the loop terminates.

Add a test for the edge case where even quality=30 cannot meet the constraint — assert the compressor returns the best-effort result rather than throwing.

Testing Requirements

All tests are unit tests using flutter_test. Load fixture images using rootBundle or direct File reads in the test environment. Decode output bytes to verify dimensions using the image package (not dart:ui, which requires a Flutter binding). Use expect(outputBytes.length, lessThan(inputBytes.length)) for size assertions.

Use a tolerance of 5% on dimension checks to account for rounding. Parameterize tests over all three fixture images using a loop where applicable. Verify CompressionException type with isA() matcher — not just catching generic Exception.

Component
Receipt Image Compressor
service medium
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.