Static fulfilled SSE bodies closed immediately and made ordinary UI cases reconnect. Serve persistent fixture streams, retain outage and cursor recovery coverage, and update legacy approval and investigation assertions for current disclosures and SVG diagrams. Validation: 12 related browser scenarios, 877 unit tests, type checking, scoped ESLint, and diff checks. Unrelated SCADA replay changes remain outside this commit.
49 lines
2.0 KiB
TypeScript
49 lines
2.0 KiB
TypeScript
import { createServer, type ServerResponse } from "node:http";
|
|
import type { AddressInfo } from "node:net";
|
|
import type { Page } from "@playwright/test";
|
|
|
|
const fixtures = new WeakMap<Page, { cursors: string[] }>();
|
|
|
|
// route.fulfill() closes an SSE response after its body. UI fixtures need a
|
|
// real open response so the application stays live until the page disconnects.
|
|
export async function mockWorkbenchEventStream(page: Page) {
|
|
const existing = fixtures.get(page);
|
|
if (existing) return existing;
|
|
const clients = new Set<ServerResponse>();
|
|
const cursors: string[] = [];
|
|
const server = createServer((request, response) => {
|
|
response.setHeader("Access-Control-Allow-Origin", "*");
|
|
response.setHeader("Access-Control-Allow-Headers", "Authorization, Content-Type, Last-Event-ID, X-Project-Id");
|
|
response.setHeader("Access-Control-Allow-Methods", "GET, OPTIONS");
|
|
if (request.method === "OPTIONS") {
|
|
response.writeHead(204).end();
|
|
return;
|
|
}
|
|
cursors.push(new URL(request.url!, "http://localhost").searchParams.get("after") ?? "");
|
|
response.writeHead(200, { "Content-Type": "text/event-stream", "Cache-Control": "no-cache" });
|
|
response.write(": fixture connected\n\n");
|
|
clients.add(response);
|
|
response.on("close", () => clients.delete(response));
|
|
});
|
|
await new Promise<void>((resolve, reject) => {
|
|
server.once("error", reject);
|
|
server.listen(0, "127.0.0.1", resolve);
|
|
});
|
|
const { port } = server.address() as AddressInfo;
|
|
page.on("close", () => {
|
|
for (const client of clients) client.destroy();
|
|
server.close();
|
|
server.closeAllConnections();
|
|
});
|
|
await page.route("**/api/v1/workbench/events**", (route) => {
|
|
const query = new URL(route.request().url()).search;
|
|
return route.fulfill({ status: 307, headers: {
|
|
"Access-Control-Allow-Origin": "*",
|
|
"Location": `http://127.0.0.1:${port}/events${query}`
|
|
} });
|
|
});
|
|
const fixture = { cursors };
|
|
fixtures.set(page, fixture);
|
|
return fixture;
|
|
}
|