Write integration tests for admin screen flows
epic-organization-feature-flags-ui-task-009 — Write Flutter integration tests for the Feature Flag Admin Screen covering: role guard blocks non-admin users, flag list renders with correct states, two-step toggle flow completes successfully and updates list, confirmation dialog cancel reverts staged state, audit log pagination loads additional entries, stale-cache banner appears and dismisses after manual refresh, and rollout condition edits persist correctly.
Acceptance Criteria
Technical Requirements
Execution Context
Tier 4 - 323 tasks
Can start after Tier 3 completes
Implementation Notes
Use a TestFeatureFlagRepository class (implements FeatureFlagRepository) with stubbed async methods returning predefined data—this avoids mockito/mocktail complexity for simple cases while remaining controllable. For the two-step toggle test, use find.byType(Switch) and tester.tap() in sequence, then find.byType(AlertDialog) to assert dialog presence before confirming. For audit log pagination, override the repository to return page 1 on first call and page 2 on second call using a call counter. For the stale-cache test, initialize FeatureFlagCache.lastSyncAt to DateTime.now().subtract(Duration(seconds: ttl + 1)) in the provider override.
Ensure each test pumps the widget tree with tester.pumpWidget(ProviderScope(overrides: [...], child: MaterialApp(home: FeatureFlagAdminScreen()))) for full routing context. Consider organizing tests in a describe-style using group() blocks per feature area for readability.
Testing Requirements
Integration tests use flutter_test IntegrationTestWidgetsFlutterBinding. Each test wraps the admin screen in a full ProviderScope with overridden repository and cache providers. Use mocktail to stub repository methods with controlled return values and verify call counts. For the fake clock test (stale-cache), inject a FakeClock or use DateTime override via dependency injection—do not rely on real time passage.
Structure tests with setUpAll for shared mock setup and setUp for per-test state reset. Assert both UI state (finder queries) and behavior (mock verify calls). Aim for coverage of every user-visible branch in the admin screen's state machine.
The feature flag admin screen allows persisting changes to organization_configs. If the role guard is implemented only client-side (checking role state in Riverpod), a user who manipulates their local role state could toggle flags for their organization without proper server-side authorization, potentially exposing features prematurely.
Mitigation & Contingency
Mitigation: Implement server-side authorization for flag update operations using Supabase RLS UPDATE policies that check the user's role in the memberships table. The client-side guard is UX only; the database enforces the actual restriction.
Contingency: If an unauthorized update is detected, audit the RLS policies and add a Supabase Edge Function as an authorization middleware for flag toggle operations, rejecting requests from non-admin role JWTs.
Developers on other feature teams may use FeatureGate incorrectly — for example, wrapping business logic rather than UI, or using it before flag initialization completes — leading to features that are visible but non-functional or cause runtime errors when flags are queried in a loading state.
Mitigation & Contingency
Mitigation: Add assert statements in FeatureGate's build method that throw in debug mode if the provider is still in a loading state. Write developer documentation with a clear usage contract: FeatureGate is UI-only; logic gating must use the provider's isEnabled method directly. Include lint examples in the codebase.
Contingency: If misuse is found in code reviews, add a custom Dart lint rule via custom_lint that flags FeatureGate usage outside of the widget tree, and conduct a codebase audit to find existing violations.
If the audit log is stored in the same organization_configs table without pagination or archival strategy, high-frequency flag changes during pilot testing could produce an unbounded number of rows, degrading query performance on the admin screen.
Mitigation & Contingency
Mitigation: Store audit log entries in a separate feature_flag_audit_log table with an index on (organization_id, changed_at DESC). Implement cursor-based pagination in the repository and limit the initial load to 50 entries.
Contingency: If table size becomes a performance concern, add a Supabase scheduled function to archive entries older than 90 days to cold storage, and add a database index on changed_at for range queries.