test(e2e): make vacuous feed/SSE tests assert real behavior
Several tests ran green while asserting nothing. Replace them with real assertions, and fix the SSE helper they depend on. sse-listener: exchange the JWT for a single-use ticket (POST /stream/ticket) and connect via ?ticket= — the helper still used the dead ?token= scheme, so every SSE-based assertion would have silently failed to receive events. like-comment: - "like is idempotent" asserted nothing (void feed; void b) → now seeds a real upload and pins the like contract: counted once per user, toggles off on repeat (guards double-count), and a second user's like is counted independently. - "comment → SSE to B" asserted length >= 0 (always true) → B now subscribes to the stream, A comments, and B must receive the new-comment event for that upload (comment_count === 1). ~30s due to reverse-proxy SSE buffering; timeout raised. sse-realtime: only checked a nav link was visible → now counts EventSource opens and asserts a fresh stream connection after hidden→visible (also fixes the sim, which set visibilityState but not document.hidden, so the close never fired). multi-tab "SSE delivers to both": only checked nav links → now asserts each tab opens its own stream connection (delivery isn't asserted — it hinges on the ~30s proxy buffering; connection establishment is the reliable, honest signal). safe-area: delete the /join probe whose only assertion was Array.isArray(x) === true (always true); the real sheet-level env() check already exists below it. All verified green against the live backend. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -3,8 +3,9 @@
|
||||
* `like-update` arrived for upload X within 5 seconds" without driving a
|
||||
* second browser tab.
|
||||
*
|
||||
* The backend authenticates the SSE endpoint via `?token=` query param
|
||||
* (the EventSource API can't set headers).
|
||||
* The backend authenticates the SSE endpoint via a single-use `?ticket=` minted
|
||||
* at POST /api/v1/stream/ticket (the raw JWT is never put in the URL). This helper
|
||||
* does that exchange internally, so callers still just pass a JWT to `start()`.
|
||||
*/
|
||||
|
||||
export type SseEvent = { type: string; data: any; receivedAt: number };
|
||||
@@ -17,7 +18,17 @@ export class SseListener {
|
||||
constructor(private baseUrl: string = process.env.E2E_FRONTEND_URL ?? 'http://localhost:3101') {}
|
||||
|
||||
async start(token: string): Promise<void> {
|
||||
const url = `${this.baseUrl}/api/v1/stream?token=${encodeURIComponent(token)}`;
|
||||
// Exchange the JWT for a single-use SSE ticket (the stream endpoint no longer
|
||||
// accepts ?token=).
|
||||
const ticketRes = await fetch(`${this.baseUrl}/api/v1/stream/ticket`, {
|
||||
method: 'POST',
|
||||
headers: { Authorization: `Bearer ${token}` },
|
||||
});
|
||||
if (ticketRes.status !== 200) {
|
||||
throw new Error(`SSE ticket mint failed: ${ticketRes.status} ${await ticketRes.text()}`);
|
||||
}
|
||||
const { ticket } = await ticketRes.json();
|
||||
const url = `${this.baseUrl}/api/v1/stream?ticket=${encodeURIComponent(ticket)}`;
|
||||
// Use fetch with streaming since Node has no EventSource by default.
|
||||
const res = await fetch(url, { signal: this.controller.signal });
|
||||
if (!res.body) throw new Error('SSE response has no body');
|
||||
|
||||
Reference in New Issue
Block a user