mirror of
https://github.com/pezkuwichain/pezkuwi-dev.git
synced 2026-10-22 03:36:18 +00:00
Merge pull request #22 from pezkuwichain/fix/browser-websocket
dev-test: WebSocket and location in the browser environment (0.86.8)
This commit is contained in:
10 files changed
+80
-15
No files matched your search
@@ -15,7 +15,7 @@
|
||||
},
|
||||
"sideEffects": false,
|
||||
"type": "module",
|
||||
"version": "0.86.7",
|
||||
"version": "0.86.8",
|
||||
"main": "./index.js",
|
||||
"exports": {
|
||||
"./globals.d.ts": "./src/globals.d.ts"
|
||||
|
||||
+49
@@ -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();
|
||||
@@ -18,6 +21,7 @@ describe('browser', () => {
|
||||
it('contains the top-level objects', () => {
|
||||
expect(all.document).toBeDefined();
|
||||
expect(all.navigator).toBeDefined();
|
||||
expect(location.href).toBe('http://localhost/');
|
||||
});
|
||||
|
||||
it('contains HTML*Element', () => {
|
||||
@@ -61,4 +65,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));
|
||||
}
|
||||
});
|
||||
});
|
||||
Vendored
+15
-1
@@ -9,8 +9,13 @@ import { JSDOM } from 'jsdom';
|
||||
* Constructors that Node defines as well. A DOM node only accepts an event
|
||||
* created in its own realm, so in the browser environment the JSDOM ones
|
||||
* replace Node's, as they do under jest-environment-jsdom.
|
||||
*
|
||||
* WebSocket follows from that: Node's own dispatches its events through
|
||||
* Node's EventTarget, which rejects the JSDOM Event that replaced Node's, so
|
||||
* no open, message or error ever reaches a listener and a connection never
|
||||
* comes up. JSDOM's WebSocket dispatches events from its own realm.
|
||||
*/
|
||||
export const BROWSER_OVERRIDES: readonly string[] = ['CustomEvent', 'Event'];
|
||||
export const BROWSER_OVERRIDES: readonly string[] = ['CustomEvent', 'Event', 'WebSocket'];
|
||||
|
||||
/**
|
||||
* JSDOM does no layout, so no element ever changes size and the callback
|
||||
@@ -62,6 +67,13 @@ function events (window: DOMWindow) {
|
||||
};
|
||||
}
|
||||
|
||||
/** Network, see BROWSER_OVERRIDES for why WebSocket is JSDOM's */
|
||||
function network (window: DOMWindow) {
|
||||
return {
|
||||
WebSocket: window.WebSocket
|
||||
};
|
||||
}
|
||||
|
||||
/** Styles, geometry and the observers */
|
||||
function layout (window: DOMWindow) {
|
||||
return {
|
||||
@@ -90,6 +102,7 @@ export function browser () {
|
||||
...nodes(window),
|
||||
...events(window),
|
||||
...layout(window),
|
||||
...network(window),
|
||||
// All HTML Elements that are defined on the JSDOM window object.
|
||||
// (we copied as-is from the types definition). We cannot get this
|
||||
// via Object.keys(window).filter(...) so we have to specify explicitly
|
||||
@@ -168,6 +181,7 @@ export function browser () {
|
||||
crypto: window.crypto,
|
||||
document: window.document,
|
||||
localStorage: window.localStorage,
|
||||
location: window.location,
|
||||
navigator: window.navigator,
|
||||
// window...
|
||||
window
|
||||
|
||||
@@ -3,4 +3,4 @@
|
||||
|
||||
// Do not edit, auto-generated by @pezkuwi/dev
|
||||
|
||||
export const packageInfo = { name: '@pezkuwi/dev-test', path: 'auto', type: 'auto', version: '0.86.7' };
|
||||
export const packageInfo = { name: '@pezkuwi/dev-test', path: 'auto', type: 'auto', version: '0.86.8' };
|
||||
@@ -15,7 +15,7 @@
|
||||
},
|
||||
"sideEffects": false,
|
||||
"type": "module",
|
||||
"version": "0.86.7",
|
||||
"version": "0.86.8",
|
||||
"main": "./index.js",
|
||||
"exports": {
|
||||
"./globals.d.ts": "./src/globals.d.ts"
|
||||
|
||||
@@ -3,4 +3,4 @@
|
||||
|
||||
// Do not edit, auto-generated by @pezkuwi/dev
|
||||
|
||||
export const packageInfo = { name: '@pezkuwi/dev-ts', path: 'auto', type: 'auto', version: '0.86.7' };
|
||||
export const packageInfo = { name: '@pezkuwi/dev-ts', path: 'auto', type: 'auto', version: '0.86.8' };
|
||||
@@ -15,7 +15,7 @@
|
||||
},
|
||||
"sideEffects": false,
|
||||
"type": "module",
|
||||
"version": "0.86.7",
|
||||
"version": "0.86.8",
|
||||
"bin": {
|
||||
"pezkuwi-ci-ghact-build": "./scripts/pezkuwi-ci-ghact-build.mjs",
|
||||
"pezkuwi-ci-ghact-docs": "./scripts/pezkuwi-ci-ghact-docs.mjs",
|
||||
@@ -52,8 +52,8 @@
|
||||
"dependencies": {
|
||||
"@eslint/compat": "^2.1.1",
|
||||
"@eslint/js": "^10.0.1",
|
||||
"@pezkuwi/dev-test": "^0.86.7",
|
||||
"@pezkuwi/dev-ts": "^0.86.7",
|
||||
"@pezkuwi/dev-test": "^0.86.8",
|
||||
"@pezkuwi/dev-ts": "^0.86.8",
|
||||
"@rollup/plugin-alias": "^5.1.1",
|
||||
"@rollup/plugin-commonjs": "^29.0.3",
|
||||
"@rollup/plugin-dynamic-import-vars": "^2.1.5",
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
import JSON5 from 'json5';
|
||||
import fs from 'node:fs';
|
||||
import { builtinModules } from 'node:module';
|
||||
import path from 'node:path';
|
||||
import process from 'node:process';
|
||||
import ts from 'typescript';
|
||||
@@ -32,8 +33,9 @@ const TARGET_TSES = ts.ScriptTarget.ES2022;
|
||||
const TARGET_NODE = '>=18';
|
||||
|
||||
const IGNORE_IMPORTS = [
|
||||
// node (new-style)
|
||||
...['assert', 'child_process', 'crypto', 'fs', 'module', 'os', 'path', 'process', 'readline', 'test', 'url', 'util'].map((m) => `node:${m}`),
|
||||
// node (new-style): every builtin, none of them is a package.json dependency.
|
||||
// Some are listed with the prefix already (node:test, node:sqlite).
|
||||
...builtinModules.map((m) => m.startsWith('node:') ? m : `node:${m}`),
|
||||
// other
|
||||
'@testing-library/react',
|
||||
'react', 'react-native', 'styled-components'
|
||||
|
||||
@@ -3,4 +3,4 @@
|
||||
|
||||
// Do not edit, auto-generated by @pezkuwi/dev
|
||||
|
||||
export const packageInfo = { name: '@pezkuwi/dev', path: 'auto', type: 'auto', version: '0.86.7' };
|
||||
export const packageInfo = { name: '@pezkuwi/dev', path: 'auto', type: 'auto', version: '0.86.8' };
|
||||
@@ -1189,7 +1189,7 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@pezkuwi/dev-test@npm:^0.86.7, @pezkuwi/dev-test@workspace:packages/dev-test":
|
||||
"@pezkuwi/dev-test@npm:^0.86.8, @pezkuwi/dev-test@workspace:packages/dev-test":
|
||||
version: 0.0.0-use.local
|
||||
resolution: "@pezkuwi/dev-test@workspace:packages/dev-test"
|
||||
dependencies:
|
||||
@@ -1205,7 +1205,7 @@ __metadata:
|
||||
languageName: unknown
|
||||
linkType: soft
|
||||
|
||||
"@pezkuwi/dev-ts@npm:^0.86.7, @pezkuwi/dev-ts@workspace:packages/dev-ts":
|
||||
"@pezkuwi/dev-ts@npm:^0.86.8, @pezkuwi/dev-ts@workspace:packages/dev-ts":
|
||||
version: 0.0.0-use.local
|
||||
resolution: "@pezkuwi/dev-ts@workspace:packages/dev-ts"
|
||||
dependencies:
|
||||
@@ -1221,8 +1221,8 @@ __metadata:
|
||||
dependencies:
|
||||
"@eslint/compat": "npm:^2.1.1"
|
||||
"@eslint/js": "npm:^10.0.1"
|
||||
"@pezkuwi/dev-test": "npm:^0.86.7"
|
||||
"@pezkuwi/dev-ts": "npm:^0.86.7"
|
||||
"@pezkuwi/dev-test": "npm:^0.86.8"
|
||||
"@pezkuwi/dev-ts": "npm:^0.86.8"
|
||||
"@rollup/plugin-alias": "npm:^5.1.1"
|
||||
"@rollup/plugin-commonjs": "npm:^29.0.3"
|
||||
"@rollup/plugin-dynamic-import-vars": "npm:^2.1.5"
|
||||
|
||||
Reference in new issue
Block a user