/** * The realtime gateway URL (TASK-0095 S13 — the client-path defect fix). * * The server's onUpgrade accepts ONLY the `/realtime` path (a root-path * upgrade is destroyed without an HTTP response), so the client MUST * connect to `/realtime`. `realtimeUrl` is the single source of * truth for that; the E2E suite (tests/e2e/realtime.spec.ts) is the * browser-side proof. */ import { describe, it, expect } from "vitest"; import { realtimeUrl } from "../realtime"; describe("realtimeUrl", () => { it("appends the /realtime path (the server's only accepted path)", () => { expect(realtimeUrl("tok", "ws://localhost:4001")).toBe( "ws://localhost:4001/realtime?token=tok", ); }); it("token-only URL is still on the /realtime path", () => { expect(realtimeUrl(null, "ws://localhost:4001")).toBe( "ws://localhost:4001/realtime", ); expect(realtimeUrl(undefined, "ws://localhost:4001")).toBe( "ws://localhost:4001/realtime", ); }); it("percent-encodes the token (JWTs are URL-safe, but be exact)", () => { expect(realtimeUrl("a b/c+d", "ws://localhost:4001")).toBe( "ws://localhost:4001/realtime?token=a%20b%2Fc%2Bd", ); }); it("trims a trailing slash on the base (NEXT_PUBLIC_WS_URL hygiene)", () => { expect(realtimeUrl("t", "ws://localhost:4001/")).toBe( "ws://localhost:4001/realtime?token=t", ); expect(realtimeUrl("t", "ws://localhost:4001//")).toBe( "ws://localhost:4001/realtime?token=t", ); }); it("works with the production-shape base (origin only, per constants.ts)", () => { // The documented contract: `NEXT_PUBLIC_WS_URL` is the ORIGIN // (constants.ts default: ws://localhost:4001); this appends /realtime. expect(realtimeUrl("t", "ws://realtime.factory.example")).toBe( "ws://realtime.factory.example/realtime?token=t", ); }); });