high priority medium complexity testing pending testing specialist Tier 2

Acceptance Criteria

captureWidget returns a Uint8List with length greater than 0 when run on a physical device or emulator with a real rendered widget tree
The first 8 bytes of the returned Uint8List match the PNG magic bytes [137, 80, 78, 71, 13, 10, 26, 10]
Calling captureWidget with pixelRatio=1.0 and pixelRatio=2.0 on the same 200×100 logical-pixel widget produces outputs where the 2.0 image width (extracted from PNG IHDR chunk) is exactly twice the 1.0 image width
captureToFile writes a non-empty file to the system temp directory that can be opened and read back as bytes identical to those from captureWidget
shareWidget completes without throwing when the share sheet is dismissed by the test harness (using integration_test's robot pattern or by tapping dismiss)
After captureWidget completes, the RepaintBoundary GlobalKey still resolves to a live RenderRepaintBoundary (the capture does not detach or corrupt the widget tree)
Running captureWidget 10 consecutive times on the same widget does not cause an OutOfMemoryError or a significant heap growth (verified by comparing Dart VM heap before and after via flutter_driver or integration_test memory profiling)
All temp files created during the integration test run are cleaned up (file system state is identical before and after the test)
Tests run successfully on both Android API 29+ emulator and iOS 16+ simulator as part of the CI pipeline
Test execution time is under 30 seconds for all 6 integration test scenarios combined

Technical Requirements

frameworks
flutter_test (integration_test package)
integration_test (Flutter SDK)
dart:io (File, Directory)
path_provider (getTemporaryDirectory)
apis
IntegrationTestWidgetsFlutterBinding.ensureInitialized()
WidgetTester.pumpWidget() with a real material app
ScreenshotCaptureUtility.captureWidget()
ScreenshotCaptureUtility.captureToFile()
ScreenshotCaptureUtility.shareWidget()
PNG IHDR chunk parsing (bytes 16-24) for dimension verification
data models
annual_summary
performance requirements
All 6 integration test cases complete within 30 seconds on a standard CI emulator
10 consecutive captures must not grow heap by more than 20 MB over baseline
security requirements
Integration tests must not access production Supabase — use a mock or local Supabase instance for any data displayed in the captured widget
Temporary files created during tests must be deleted in tearDown to prevent test data accumulation on CI runners
ui components
A minimal test harness widget wrapped in RepaintBoundary (SizedBox 200x100 with solid color background)

Execution Context

Execution Tier
Tier 2

Tier 2 - 518 tasks

Can start after Tier 1 completes

Implementation Notes

The integration test file must live in the `integration_test/` directory and import `package:integration_test/integration_test.dart`. Use `testWidgets()` from integration_test. To verify PNG dimensions from IHDR: bytes 16-19 are width (big-endian uint32), bytes 20-23 are height — parse with `ByteData.sublistView(bytes.buffer.asByteData(), 16, 24)` and `byteData.getUint32(0, Endian.big)`. For the memory stability test, run in a `for` loop and check `ProcessInfo.currentRss` before and after; flag if growth exceeds 20 MB.

For shareWidget, wrap in a try/catch and use `expect(threw, isFalse)` rather than attempting to interact with the native share sheet UI (which is outside Flutter's widget tree). Add tearDown to delete any temp files created during each test using `Directory(tempDir.path).listSync().where((f) => f.path.endsWith('.png')).forEach((f) => f.deleteSync())`. Ensure the test app's AndroidManifest.xml includes the FileProvider configuration required by share_plus.

Testing Requirements

Flutter integration tests using the integration_test package, executable via `flutter test integration_test/screenshot_capture_utility_test.dart` on a connected device or emulator. Use IntegrationTestWidgetsFlutterBinding.ensureInitialized() at test entry point. Create a minimal test harness widget (SizedBox with a Container of known dimensions and solid color) wrapped in a RepaintBoundary with a known GlobalKey. Test groups: 'output validity', 'pixel ratio scaling', 'file I/O', 'share sheet', 'memory stability'.

For memory test, record dartVM.memory before and after 10 captures. For share sheet test, use the MethodChannel mock approach or accept that the share sheet cannot be dismissed programmatically and simply verify no exception is thrown. Run in TestFlight builds as part of the QA pipeline.

Component
Screenshot Capture Utility
infrastructure medium
Epic Risks (3)
medium impact medium prob dependency

Rive animation files may not be available at implementation time, blocking the wrapped-animation-controller from being fully tested. If asset delivery is delayed, the controller cannot be validated for memory-leak-free disposal.

Mitigation & Contingency

Mitigation: Implement the animation controller with stub/placeholder AnimationController instances first so the lifecycle and disposal logic can be unit-tested independently of Rive assets. Define a named animation registry interface early so UI components can reference animations by name without coupling to specific Rive files.

Contingency: If Rive assets are not delivered before Epic 3 begins, replace Rive animations with Flutter implicit animations (AnimatedOpacity, ScaleTransition) as a drop-in and schedule Rive integration as a follow-on task once assets arrive.

high impact medium prob technical

The annual_summaries Supabase RPC aggregating 12 months of activity records per mentor may exceed acceptable query latency (>2s) for mentors with high activity volumes such as the HLF mentor with 380 registrations cited in workshop notes.

Mitigation & Contingency

Mitigation: Design the RPC to materialise summary results into the annual_summaries table via a scheduled edge function rather than computing on demand. The repository reads pre-computed rows, keeping query latency constant regardless of activity volume.

Contingency: If on-demand queries are required for real-time period switching, add a PostgreSQL partial index on (mentor_id, activity_date) and implement a client-side loading skeleton so slow queries degrade gracefully rather than blocking the UI.

medium impact low prob technical

iOS requires photo library permission before saving a screenshot to the gallery. If the permission prompt is triggered at an unexpected point in the share flow, the UX breaks and users may deny permission permanently, making gallery save unavailable.

Mitigation & Contingency

Mitigation: Trigger the permission request only when the user explicitly chooses 'Save to gallery' in the share overlay, not on screen load. Implement a pre-prompt explanation screen following Apple HIG so users understand why the permission is needed before the system dialog appears.

Contingency: If permission is denied, gracefully fall back to clipboard copy and system share sheet options which do not require photo library access, and surface a non-blocking snackbar explaining the limitation.