# Test — SSE Lifecycle & Bearer Rotation

**Task**: AZ-458_test_sse_lifecycle
**Name**: SSE lifecycle + bearer-rotation reconnect
**Description**: Implement every blackbox test that exercises the SPA's SSE streams — live-GPS, annotation-status — covering open/close lifecycle and the bearer-rotation reconnect (≤5 s) after a token refresh.
**Complexity**: 5 points
**Dependencies**: AZ-456_test_infrastructure
**Component**: 01_api-transport + 05_flights + 06_annotations (Blackbox Tests)
**Tracker**: AZ-458
**Epic**: AZ-455

## Problem

The SPA holds two long-running `EventSource` connections — live-GPS (per `<FlightsPage>`) and annotation-status (per `<AnnotationsPage>`) — using the in-query-string bearer pattern (ADR-008). The open/close timing and the reconnect-on-refresh path must be deterministic; otherwise tests downstream see flapping streams and undefined ordering.

## Outcome

- 9 test scenarios pass, asserting open/close timing and bearer-rotation reconnect behavior.
- Fast tests use `tests/helpers/sse-mock.ts` (per AZ-456 Risk 3); e2e tests use the embedded LiveGPS + annotation-status generators in the suite test images.
- No test reads or manipulates `src/api/sse.ts` internals.

## Scope

### Included

| Scenario | Profile | Source file | results_report row |
|----------|---------|-------------|--------------------|
| FT-P-09 — annotation-status SSE opens on `<AnnotationsPage>` mount | fast + e2e | blackbox-tests.md | per FT-P-09 |
| FT-P-10 — annotation-status SSE closes on unmount | fast | blackbox-tests.md | per FT-P-10 |
| FT-P-18 — live-GPS SSE opens within 5 s of flight select | fast + e2e | blackbox-tests.md | per FT-P-18 |
| FT-P-19 — live-GPS SSE closes within 1 s of deselect | fast | blackbox-tests.md | per FT-P-19 |
| NFT-PERF-03 — SSE bearer-rotation reconnect ≤ 5 s | e2e | performance-tests.md | per NFT-PERF-03 |
| NFT-PERF-04 — live-GPS SSE opens within 5 s of flight select | fast | performance-tests.md | per NFT-PERF-04 |
| NFT-PERF-05 — live-GPS SSE closes within 1 s of deselect | fast | performance-tests.md | per NFT-PERF-05 |
| NFT-PERF-06 — annotation-status SSE unsubscribes within 1 s on page unmount | fast | performance-tests.md | per NFT-PERF-06 |
| NFT-RES-02 — SSE bearer rotation — both streams reconnect within 5 s | e2e | resilience-tests.md | per NFT-RES-02 |

### Excluded

- SSE server-disconnect indicator (covered in 23_test_network_resilience).
- The 401-retry path on `fetch` (covered in 02_test_auth_token_handling).
- The async-video detect SSE (covered in 06_test_detection_endpoints — quarantined as Phase B target).

## Acceptance Criteria

**AC-1: Open/close timing**
Given a freshly-mounted `<FlightsPage>` or `<AnnotationsPage>`,
When the relevant SSE should open or close per the scenario,
Then the event happens within the timing budget and the observable EventSource state matches (`readyState: 1` for open, closed connection for close).

**AC-2: Bearer rotation**
Given an active SSE stream and an upcoming token refresh,
When the bearer rotates,
Then both live-GPS and annotation-status streams reconnect with the new bearer within 5 s; no event from before the rotation is replayed AFTER the new bearer is in use.

**AC-3: No internal stubs**
The fast profile uses the published `sse-mock.ts` helper to simulate the wire-level SSE event stream. Tests MUST NOT replace `src/api/sse.ts` with a stub; if the SSE module misbehaves, the test FAILS.

## System Under Test Boundary

- System under test: `src/api/sse.ts` + the consumer hooks in `<FlightsPage>` / `<AnnotationsPage>` + the React tree.
- Allowed stubs: the suite-side SSE endpoints — stubbed via the MSW SSE adapter / `sse-mock.ts` in `fast`, real `flights/` and `annotations/` services in `e2e`.
- Disallowed: stubbing `src/api/sse.ts`, the SPA's SSE hooks, or the React tree.
- Expected observables per `results_report.md` rows for FT-P-09, 10, 18, 19, NFT-PERF-03..06, NFT-RES-02.

## Constraints

- E2E tests rely on the embedded LiveGPS simulator and annotation-status event generator in the suite's test-mode images (per test-data.md).
- Bearer in SSE URL `?token=` per ADR-008 — tests assert the URL pattern, not stripped headers.
- Bearer-rotation tests MUST drive the rotation through `<AuthContext>`'s normal refresh path, not by directly calling `setToken`.

## Risks & Mitigation

**Risk 1 — MSW SSE polyfill brittleness (AZ-456 Risk 3)**
- *Risk*: MSW 2.x does not have first-class SSE support. The `sse-mock.ts` helper introduces a small abstraction that, if buggy, makes tests pass that shouldn't.
- *Mitigation*: every fast SSE scenario also has an e2e companion that exercises the real wire. If the two disagree, the e2e wins and the fast test is QUARANTINEd until the helper is fixed.
