import * as tls from "tls"; import { test, expect } from "@playwright/test"; import { BASE, requireAuth } from "./helpers"; test.describe("WebSocket", () => { // Test WS via raw TLS to avoid browser HTTP/2 and Node.js http module quirks. test("WS handshake with valid token succeeds", async () => { const auth = requireAuth(); const statusCode = await new Promise((resolve) => { const socket = tls.connect( { host: "localhost", port: 443, rejectUnauthorized: false }, () => { const handshake = [ "GET /api/ws HTTP/1.1", "Host: localhost", "Upgrade: websocket", "Connection: Upgrade", "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==", "Sec-WebSocket-Version: 13", `Authorization: Bearer ${auth.accessToken!}`, "", "", ].join("\r\n"); socket.write(handshake); }, ); let buf = ""; socket.on("data", (chunk) => { buf += chunk.toString(); const firstLine = buf.split("\r\n")[0] ?? ""; const m = firstLine.match(/HTTP\/1\.\d\s+(\d+)/); if (m) { socket.destroy(); resolve(parseInt(m[1], 10)); } }); socket.on("error", () => resolve(0)); setTimeout(() => { socket.destroy(); resolve(0); }, 8000); }); expect(statusCode, `WS upgrade returned ${statusCode}`).toBe(101); }); test("WS handshake without token is rejected", async ({ page }) => { const result = await page.evaluate((wsUrl) => { return new Promise<{ code: number }>((resolve) => { const ws = new WebSocket(wsUrl); ws.onclose = (e) => resolve({ code: e.code }); setTimeout(() => resolve({ code: -1 }), 6000); }); }, BASE.replace("https", "wss") + "/api/ws"); expect(result.code).not.toBe(1000); }); });