high priority low complexity testing pending testing specialist Tier 3

Acceptance Criteria

Integration test file exists at `integration_test/no_access_foundation_smoke_test.dart`
Test fetches `adminPortalUrl` from `NoAccessConfigRepository` configured with either a seeded local constant or a dedicated test Supabase project
The fetched URL is passed to `UrlLauncherUtil.launchUrl()`; the test asserts the returned `UrlLaunchResult` is `UrlLaunchSuccess` (using a mocked platform) or `UrlLaunchUnsupported` if the test environment has no handler—both are acceptable and documented
Test documents the expected URL value so regressions in config seeding are immediately visible
No real external network calls are made to the Supabase production project during CI
Test can be run in isolation with `flutter test integration_test/no_access_foundation_smoke_test.dart`
Test passes consistently (no flakiness from timing or uninitialised state)
CI pipeline (if present) executes this test as part of the integration test suite

Technical Requirements

frameworks
Flutter
flutter_test
integration_test (Flutter SDK package)
apis
Supabase (test project or local seed)
data models
NoAccessConfig
NoAccessConfigRepository
UrlLauncherUtil
UrlLaunchResult
performance requirements
Integration test completes in under 10 seconds including app startup
No network timeout failures—use local seed/mock Supabase if CI has no outbound access
security requirements
Test Supabase credentials (if used) stored in `.env.test` excluded from version control
Production Supabase URL/key must not appear in test files

Execution Context

Execution Tier
Tier 3

Tier 3 - 413 tasks

Can start after Tier 2 completes

Implementation Notes

The primary value of this test is verifying the data contract between the two components—specifically that the URL string format returned by the repository is compatible with what `UrlLauncherUtil` expects (valid URI, correct scheme). Use the local-constant fallback path of `NoAccessConfigRepository` to avoid Supabase dependency in CI: construct the repository with a flag or subclass that always returns the seeded constant. This makes the test deterministic and fast. Document in a comment why the Supabase real-fetch path is skipped in CI and how a developer can opt in locally by setting an environment variable.

Keep the test narrow—it should not test UI rendering (that belongs to widget tests in the UI epic). If a `testWidgets` wrapper is needed for `BuildContext`, use a minimal `MaterialApp` pump.

Testing Requirements

Integration test using the `integration_test` Flutter package (not `flutter_test` alone). Wire the real `NoAccessConfigRepository` with either a local constant seed (preferred for CI reliability) or a dedicated Supabase test table seeded before the test run. Wire the real `UrlLauncherUtil` with a mock platform interface to avoid actual browser opening. Assert the end-to-end data flow: repository returns a config, the URL field is non-empty, and passing it to the util returns a well-typed result.

Add a `group('smoke: no-access foundation pipeline')` wrapper for clear test output identification.

Epic Risks (2)
high impact medium prob technical

Supabase remote config may be unavailable at app startup (network error, cold start), causing the repository to return no blocked-role list. If the fallback is empty, blocked users could access the app.

Mitigation & Contingency

Mitigation: Define a local constants fallback list of blocked roles compiled into the app binary. Remote config enriches or overrides this list when available.

Contingency: If remote config repeatedly fails in production, pin the blocked-role list to local constants only and disable remote override until the Supabase config endpoint is stabilised.

medium impact low prob dependency

url_launcher package behaviour differs between iOS and Android (e.g. canLaunchUrl returning false on some Android configurations), leading to silent failures when the admin portal link is tapped.

Mitigation & Contingency

Mitigation: Run canLaunchUrl check before every launch attempt and surface a descriptive inline error message (e.g. 'Could not open link — visit admin.example.org manually') when the check fails.

Contingency: If canLaunchUrl is consistently unreliable on a target platform, replace the tap-to-open pattern with a copyable text field showing the URL as a fallback.