trustgraph/ts/packages/client/src/__tests__/websocket-adapter.test.ts

72 lines
2 KiB
TypeScript

import { afterEach, describe, expect, it, vi } from "vitest";
import {
getRandomValues as fillRandomValues,
getWebSocketConstructor,
WebSocketAdapterError,
WS_OPEN,
} from "../socket/websocket-adapter.js";
class FakeWebSocket {
readonly readyState = WS_OPEN;
constructor(readonly url: string) {}
send(_data: string): void {}
close(_code?: number, _reason?: string): void {}
addEventListener(_type: string, _listener: (event: { readonly type: string }) => void): void {}
removeEventListener(_type: string, _listener: (event: { readonly type: string }) => void): void {}
}
describe("websocket adapter", () => {
afterEach(() => {
vi.unstubAllGlobals();
});
it("prefers a compatible global WebSocket constructor", () => {
vi.stubGlobal("WebSocket", FakeWebSocket);
const Constructor = getWebSocketConstructor();
const socket = new Constructor("ws://example.test/rpc");
expect(socket).toBeInstanceOf(FakeWebSocket);
expect(socket.readyState).toBe(WS_OPEN);
});
it("loads the optional ws constructor when no global WebSocket exists", () => {
vi.stubGlobal("WebSocket", undefined);
expect(getWebSocketConstructor()).toBeTypeOf("function");
});
it("uses global crypto when available", () => {
const getRandomValues = vi.fn((target: Uint32Array) => {
target[0] = 42;
return target;
});
vi.stubGlobal("crypto", { getRandomValues });
const values = fillRandomValues(new Uint32Array(1));
expect(values[0]).toBe(42);
expect(getRandomValues).toHaveBeenCalledOnce();
});
it("raises a typed error when no crypto source is available", () => {
vi.stubGlobal("crypto", undefined);
expect(() => fillRandomValues(new Uint32Array(2))).toThrow(WebSocketAdapterError);
});
it("exposes typed adapter errors", () => {
const error = WebSocketAdapterError.make({
operation: "test",
message: "typed",
});
expect(error._tag).toBe("WebSocketAdapterError");
expect(error.message).toBe("typed");
});
});