high priority medium complexity testing pending testing specialist Tier 7

Acceptance Criteria

bloc_test expectation verifies EmailChanged with invalid email emits LoginFormIdleState with emailError set
bloc_test verifies EmailChanged with valid email emits LoginFormIdleState with emailError null
bloc_test verifies PasswordChanged with empty password emits LoginFormIdleState with passwordError set
bloc_test verifies SubmitPressed with invalid fields emits idle state with errors, NOT LoginLoading
bloc_test verifies SubmitPressed with valid fields emits [LoginLoading, LoginSuccess] in sequence
bloc_test verifies SubmitPressed resulting in InvalidCredentialsException emits [LoginLoading, LoginCredentialError]
bloc_test verifies SubmitPressed resulting in NetworkException emits [LoginLoading, LoginNetworkError]
bloc_test verifies SubmitPressed resulting in RateLimitException emits [LoginLoading, LoginRateLimitError]
bloc_test verifies SubmitPressed resulting in ServerException emits [LoginLoading, LoginServerError]
LoginCredentialError, LoginNetworkError, LoginRateLimitError, LoginServerError are asserted as distinct typed classes (not isA<LoginError>)
bloc_test for BLoC init with valid stored session verifies [LoginLoading, LoginSuccess] emitted without any user event
bloc_test for BLoC init with no stored session verifies [LoginLoading, LoginFormIdleState] emitted
All error state instances carry non-null, non-empty messageKey field
All tests use mock AuthService and mock CredentialValidator injected via BLoC constructor

Technical Requirements

frameworks
Flutter
flutter_bloc
bloc_test
flutter_test
data models
LoginFormBLoC
LoginFormIdleState
LoginLoading
LoginSuccess
LoginCredentialError
LoginNetworkError
LoginRateLimitError
LoginServerError
AuthSession
UserRole
performance requirements
Each bloc_test case must complete in under 500ms
Use FakeAsync if any internal timers are present in the BLoC
security requirements
Test data must use clearly fake credentials (e.g. 'test@example.com') — never real user data
Verify password field is not present in any emitted state after SubmitPressed

Execution Context

Execution Tier
Tier 7

Tier 7 - 84 tasks

Can start after Tier 6 completes

Implementation Notes

The key insight for accessibility compliance: assert `isA()`, `isA()` etc. explicitly — a generic `isA()` assertion would pass even with broken mapping. This distinction is what the requirement means by 'accessibility requirement compliance' — each error state drives different UI copy and ARIA-equivalent semantics. Use `when(() => mockAuthService.signIn(any(), any())).thenThrow(...)` pattern for error path setup.

For session restoration tests, set up the mock before constructing the BLoC since restoration fires in the constructor. Use `wait` parameter in blocTest if restoration is async.

Testing Requirements

Use bloc_test package's blocTest() helper for all tests. Provide act callback to dispatch events and expect callback with ordered state list. Use setUp() to initialize fresh mocks and BLoC instance per test. Group tests by scenario: 'field validation', 'submit with validation failure', 'submit with auth success', 'submit with auth errors', 'session restoration'.

Verify accessibility requirement by asserting specific error state types (not base class) — this confirms each error surface point is individually identifiable for screen readers and error UI. File: `test/auth/login_form_bloc_test.dart`.

Component
Login Form BLoC
service medium
Epic Risks (2)
high impact medium prob integration

Supabase GoTrue returns HTTP error codes and string messages that may change between SDK versions. Incorrect or incomplete mapping could cause the wrong user-facing message to be shown (e.g., showing a generic error instead of a specific credential error), violating the plain-language feedback acceptance criteria and potentially exposing security-sensitive information.

Mitigation & Contingency

Mitigation: Pin the supabase_flutter SDK to a specific minor version in pubspec.yaml. Write integration tests that mock the Supabase HTTP layer and assert each error code maps to the correct domain exception. Document the mapping table as a constant in AuthService.

Contingency: If an unrecognized error code is received at runtime, catch it as an UnknownAuthException and display a generic safe message. Alert via crash reporting for triage and SDK update.

medium impact medium prob technical

If the user taps the sign-in button multiple times rapidly, concurrent authentication requests could result in race conditions: duplicate network calls, out-of-order state emissions, or multiple session tokens being written to secure storage.

Mitigation & Contingency

Mitigation: Use bloc concurrency transformer (droppable or restartable) to ensure only one authentication event is processed at a time. The BLoC should guard against submission while in LoginLoading state.

Contingency: Add a UI-level disable on the submit button when loading state is active as a secondary guard independent of BLoC concurrency control.