mirror of
https://github.com/pezkuwichain/pezkuwi-dev.git
synced 2026-10-22 11:46:18 +00:00
The browser environment copied window, document, navigator and localStorage onto the global, but not location. Code that reads the bare global, such as the apps URL type decoder, threw "location is not defined" while an ApiPromise was being created, so the api never became ready. location is now exposed with the other window objects.
114 lines
3.9 KiB
TypeScript
114 lines
3.9 KiB
TypeScript
// 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();
|
|
|
|
describe('browser', () => {
|
|
it('contains window', () => {
|
|
expect(all.window).toBeDefined();
|
|
});
|
|
|
|
it('contains a crypto implementation', () => {
|
|
expect(all.crypto).toBeTruthy();
|
|
expect(typeof all.crypto.getRandomValues).toBe('function');
|
|
});
|
|
|
|
it('contains the top-level objects', () => {
|
|
expect(all.document).toBeDefined();
|
|
expect(all.navigator).toBeDefined();
|
|
expect(location.href).toBe('http://localhost/');
|
|
});
|
|
|
|
it('contains HTML*Element', () => {
|
|
expect(typeof all.HTMLElement).toBe('function');
|
|
});
|
|
|
|
it('contains the DOM node hierarchy', () => {
|
|
const div = document.createElement('div');
|
|
|
|
expect(div).toBeInstanceOf(Element);
|
|
expect(div).toBeInstanceOf(Node);
|
|
expect(document.createTextNode('text')).toBeInstanceOf(Text);
|
|
expect(document.createDocumentFragment()).toBeInstanceOf(DocumentFragment);
|
|
expect(document.createElementNS('http://www.w3.org/2000/svg', 'svg')).toBeInstanceOf(SVGElement);
|
|
expect(div.attachShadow({ mode: 'open' })).toBeInstanceOf(ShadowRoot);
|
|
expect(document).toBeInstanceOf(Document);
|
|
});
|
|
|
|
it('contains the UI event constructors', () => {
|
|
const div = document.createElement('div');
|
|
|
|
expect(() => div.dispatchEvent(new MouseEvent('click'))).not.toThrow();
|
|
expect(() => div.dispatchEvent(new KeyboardEvent('keydown', { key: 'Enter' }))).not.toThrow();
|
|
expect(new FocusEvent('focus')).toBeInstanceOf(UIEvent);
|
|
});
|
|
|
|
it('contains getComputedStyle and the observers', () => {
|
|
const div = document.createElement('div');
|
|
|
|
div.style.display = 'none';
|
|
document.body.appendChild(div);
|
|
|
|
expect(getComputedStyle(div).display).toBe('none');
|
|
expect(() => new MutationObserver(() => undefined).observe(div, { childList: true })).not.toThrow();
|
|
expect(() => new ResizeObserver(() => undefined).observe(div)).not.toThrow();
|
|
|
|
div.remove();
|
|
});
|
|
|
|
it('dispatches the global CustomEvent and Event on window', () => {
|
|
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));
|
|
}
|
|
});
|
|
});
|