dev-test: JSDOM's WebSocket in the browser environment

The browser environment replaces Node's Event with JSDOM's. Node's WebSocket
dispatches through Node's EventTarget, which rejects that Event, so no open,
message or error reached a listener and no connection ever came up: an
ApiPromise against a live node never became ready. JSDOM's WebSocket now
replaces Node's, as Event and CustomEvent already do. A spec completes a
handshake with a local server and receives a frame.
This commit is contained in:
Satoshi Qazi Muhammed committed 2026-10-11 06:06:19 +04:00
1 parent f0ba63750f
commit 13a6acf80d
2 files changed
+62 -1

No files matched your search

+48
View File
@@ -1,6 +1,9 @@
// Copyright 2017-2026 @pezkuwi/dev-test authors & contributors
// SPDX-License-Identifier: Apache-2.0
import { createHash } from 'node:crypto';
import { createServer } from 'node:http';
import { browser } from './browser.js';
const all = browser();
@@ -61,4 +64,49 @@ describe('browser', () => {
expect(() => window.dispatchEvent(new CustomEvent('custom', { detail: 1 }))).not.toThrow();
expect(() => window.dispatchEvent(new Event('plain'))).not.toThrow();
});
it('opens a WebSocket and exchanges a message', async () => {
// the smallest server that completes the RFC 6455 handshake and sends one text frame
const server = createServer();
// an upgraded socket leaves the server's tracking, so it is closed here
const sockets: { destroy: () => void }[] = [];
server.on('upgrade', (req, socket) => {
sockets.push(socket);
const accept = createHash('sha1')
.update(`${String(req.headers['sec-websocket-key'])}258EAFA5-E914-47DA-95CA-C5AB0DC85B11`)
.digest('base64');
socket.write(`HTTP/1.1 101 Switching Protocols\r\nUpgrade: websocket\r\nConnection: Upgrade\r\nSec-WebSocket-Accept: ${accept}\r\n\r\n`);
socket.write(Buffer.from([0x81, 0x02, 0x68, 0x69]));
});
await new Promise<void>((resolve) => server.listen(0, '127.0.0.1', resolve));
const { port } = server.address() as { port: number };
const ws = new WebSocket(`ws://127.0.0.1:${port}`);
try {
const received = await new Promise<string>((resolve, reject) => {
const timer = setTimeout(() => reject(new Error('no message within 5s')), 5_000);
ws.onmessage = (event) => {
clearTimeout(timer);
resolve(String(event.data));
};
ws.onerror = () => {
clearTimeout(timer);
reject(new Error('WebSocket error'));
};
});
expect(received).toBe('hi');
} finally {
ws.close();
sockets.forEach((socket) => socket.destroy());
await new Promise((resolve) => server.close(resolve));
}
});
});