high priority low complexity testing pending testing specialist Tier 2

Acceptance Criteria

Test file exists at test/features/receipts/domain/receipt_threshold_validator_test.dart
Test: amount strictly below threshold returns false (e.g., 49.99 NOK with 50 NOK threshold)
Test: amount strictly above threshold returns true (e.g., 100.01 NOK with 100 NOK threshold)
Test: amount exactly equal to threshold returns true (boundary condition — receipt required at threshold)
Test: threshold is loaded from mocked OrgThresholdConfig and not hardcoded in validator
Test: when config loader throws or returns null, validator returns true using fallback default of 100 NOK
Test: different orgIds produce independent threshold lookups (no cross-org config bleed)
Test: zero-amount claim (0.0 NOK) returns false regardless of threshold
All tests pass with flutter test — no skipped or pending tests
Test coverage for the validator class is 100% line coverage

Technical Requirements

frameworks
Flutter
flutter_test
Riverpod
data models
OrgThresholdConfig
OrgReceiptConfig
performance requirements
All unit tests complete in under 500ms total

Execution Context

Execution Tier
Tier 2

Tier 2 - 518 tasks

Can start after Tier 1 completes

Implementation Notes

Use mocktail (preferred over Mockito for null-safety) to mock the config loader. Each test group should set up its own ProviderContainer to avoid state leakage between tests. For the boundary test, document clearly in the test name what the expected semantics are ('at threshold requires receipt'). For the multi-org isolation test, call requiresReceipt with two different orgIds sequentially and assert each returns the correct result from its respective mocked config.

Keep test data as named constants at the top of the file (e.g., const kDefaultThreshold = 100.0) for maintainability.

Testing Requirements

Use flutter_test with Mockito or mocktail to mock the config loader dependency. Create a MockOrgThresholdConfigLoader that returns controlled OrgThresholdConfig objects. Structure tests in clearly named groups: 'below threshold', 'above threshold', 'at threshold boundary', 'offline fallback', 'multi-org isolation'. Each test should have a descriptive name that reads as a specification.

Use ProviderContainer with overrides to test the Riverpod-exposed validator in isolation. No real Supabase calls — all external dependencies are mocked.

Component
Receipt Threshold Validator
service 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.