diff --git a/package.json b/package.json index 3bc4666bc40..47454e9e793 100644 --- a/package.json +++ b/package.json @@ -83,7 +83,7 @@ "test:tap": "tap test/*.js test/diagnostics-channel/*.js", "test:tdd": "tap test/*.js test/diagnostics-channel/*.js -w", "test:typescript": "tsd && tsc --skipLibCheck test/imports/undici-import.ts", - "test:websocket": "tap test/websocket/*.js", + "test:websocket": "borp --coverage -p \"test/websocket/*.js\"", "test:wpt": "node test/wpt/start-fetch.mjs && node test/wpt/start-FileAPI.mjs && node test/wpt/start-mimesniff.mjs && node test/wpt/start-xhr.mjs && node test/wpt/start-websockets.mjs", "coverage": "nyc --reporter=text --reporter=html npm run test", "coverage:ci": "nyc --reporter=lcov npm run test", diff --git a/test/websocket/close.js b/test/websocket/close.js index 4d314a4f4c4..cb8825645ba 100644 --- a/test/websocket/close.js +++ b/test/websocket/close.js @@ -1,130 +1,131 @@ 'use strict' -const { test } = require('tap') +const { describe, test } = require('node:test') +const assert = require('node:assert') const { WebSocketServer } = require('ws') const { WebSocket } = require('../..') -test('Close', (t) => { - t.plan(6) - - t.test('Close with code', (t) => { - t.plan(1) - - const server = new WebSocketServer({ port: 0 }) - - server.on('connection', (ws) => { - ws.on('close', (code) => { - t.equal(code, 1000) +describe('Close', () => { + test('Close with code', () => { + return new Promise((resolve) => { + const server = new WebSocketServer({ port: 0 }) + + server.on('connection', (ws) => { + ws.on('close', (code) => { + assert.equal(code, 1000) + server.close() + resolve() + }) }) - }) - - t.teardown(server.close.bind(server)) - const ws = new WebSocket(`ws://localhost:${server.address().port}`) - ws.addEventListener('open', () => ws.close(1000)) + const ws = new WebSocket(`ws://localhost:${server.address().port}`) + ws.addEventListener('open', () => ws.close(1000)) + }) }) - t.test('Close with code and reason', (t) => { - t.plan(2) - - const server = new WebSocketServer({ port: 0 }) - - server.on('connection', (ws) => { - ws.on('close', (code, reason) => { - t.equal(code, 1000) - t.same(reason, Buffer.from('Goodbye')) + test('Close with code and reason', () => { + return new Promise((resolve) => { + const server = new WebSocketServer({ port: 0 }) + + server.on('connection', (ws) => { + ws.on('close', (code, reason) => { + assert.equal(code, 1000) + assert.deepStrictEqual(reason, Buffer.from('Goodbye')) + server.close() + resolve() + }) }) - }) - t.teardown(server.close.bind(server)) - - const ws = new WebSocket(`ws://localhost:${server.address().port}`) - ws.addEventListener('open', () => ws.close(1000, 'Goodbye')) + const ws = new WebSocket(`ws://localhost:${server.address().port}`) + ws.addEventListener('open', () => ws.close(1000, 'Goodbye')) + }) }) - t.test('Close with invalid code', (t) => { - t.plan(2) - + test('Close with invalid code', () => { const server = new WebSocketServer({ port: 0 }) - t.teardown(server.close.bind(server)) - const ws = new WebSocket(`ws://localhost:${server.address().port}`) - ws.addEventListener('open', () => { - t.throws( - () => ws.close(2999), - { - name: 'InvalidAccessError', - constructor: DOMException - } - ) - - t.throws( - () => ws.close(5000), - { - name: 'InvalidAccessError', - constructor: DOMException - } - ) - - ws.close() + + return new Promise((resolve) => { + ws.addEventListener('open', () => { + assert.throws( + () => ws.close(2999), + { + name: 'InvalidAccessError', + constructor: DOMException + } + ) + + assert.throws( + () => ws.close(5000), + { + name: 'InvalidAccessError', + constructor: DOMException + } + ) + + ws.close() + server.close() + resolve() + }) }) }) - t.test('Close with invalid reason', (t) => { - t.plan(1) - + test('Close with invalid reason', () => { const server = new WebSocketServer({ port: 0 }) - t.teardown(server.close.bind(server)) const ws = new WebSocket(`ws://localhost:${server.address().port}`) - ws.addEventListener('open', () => { - t.throws( - () => ws.close(1000, 'a'.repeat(124)), - { - name: 'SyntaxError', - constructor: DOMException - } - ) - - ws.close(1000) + return new Promise((resolve) => { + ws.addEventListener('open', () => { + assert.throws( + () => ws.close(1000, 'a'.repeat(124)), + { + name: 'SyntaxError', + constructor: DOMException + } + ) + + ws.close(1000) + server.close() + resolve() + }) }) }) - t.test('Close with no code or reason', (t) => { - t.plan(2) - + test('Close with no code or reason', () => { const server = new WebSocketServer({ port: 0 }) - server.on('connection', (ws) => { - ws.on('close', (code, reason) => { - t.equal(code, 1005) - t.same(reason, Buffer.alloc(0)) + return new Promise((resolve) => { + server.on('connection', (ws) => { + ws.on('close', (code, reason) => { + assert.equal(code, 1005) + assert.deepStrictEqual(reason, Buffer.alloc(0)) + server.close() + resolve() + }) }) - }) - t.teardown(server.close.bind(server)) - - const ws = new WebSocket(`ws://localhost:${server.address().port}`) - ws.addEventListener('open', () => ws.close()) + const ws = new WebSocket(`ws://localhost:${server.address().port}`) + ws.addEventListener('open', () => ws.close()) + }) }) - t.test('Close with a 3000 status code', (t) => { - t.plan(2) - + test('Close with a 3000 status code', () => { const server = new WebSocketServer({ port: 0 }) - server.on('connection', (ws) => { - ws.on('close', (code, reason) => { - t.equal(code, 3000) - t.same(reason, Buffer.alloc(0)) + return new Promise((resolve) => { + server.on('connection', (ws) => { + ws.on('close', (code, reason) => { + assert.equal(code, 3000) + assert.deepStrictEqual(reason, Buffer.alloc(0)) + server.close() + resolve() + }) }) - }) - - t.teardown(server.close.bind(server)) - const ws = new WebSocket(`ws://localhost:${server.address().port}`) - ws.addEventListener('open', () => ws.close(3000)) + const ws = new WebSocket(`ws://localhost:${server.address().port}`) + ws.addEventListener('open', () => ws.close(3000)) + }) }) }) diff --git a/test/websocket/constructor.js b/test/websocket/constructor.js index dd87dead652..a4a10bffad9 100644 --- a/test/websocket/constructor.js +++ b/test/websocket/constructor.js @@ -1,10 +1,11 @@ 'use strict' -const { test } = require('tap') +const { test } = require('node:test') +const assert = require('node:assert') const { WebSocket } = require('../..') -test('Constructor', (t) => { - t.throws( +test('Constructor', () => { + assert.throws( () => new WebSocket('abc'), { name: 'SyntaxError', @@ -12,7 +13,7 @@ test('Constructor', (t) => { } ) - t.throws( + assert.throws( () => new WebSocket('wss://echo.websocket.events/#a'), { name: 'SyntaxError', @@ -20,7 +21,7 @@ test('Constructor', (t) => { } ) - t.throws( + assert.throws( () => new WebSocket('wss://echo.websocket.events', ''), { name: 'SyntaxError', @@ -28,7 +29,7 @@ test('Constructor', (t) => { } ) - t.throws( + assert.throws( () => new WebSocket('wss://echo.websocket.events', ['chat', 'chat']), { name: 'SyntaxError', @@ -36,13 +37,11 @@ test('Constructor', (t) => { } ) - t.throws( + assert.throws( () => new WebSocket('wss://echo.websocket.events', ['<>@,;:\\"/[]?={}\t']), { name: 'SyntaxError', constructor: DOMException } ) - - t.end() }) diff --git a/test/websocket/custom-headers.js b/test/websocket/custom-headers.js index 01f1830d3e9..11611a84c0a 100644 --- a/test/websocket/custom-headers.js +++ b/test/websocket/custom-headers.js @@ -1,30 +1,30 @@ 'use strict' -const { test } = require('tap') +const { test } = require('node:test') const assert = require('assert') const { Agent, WebSocket } = require('../..') test('Setting custom headers', (t) => { - t.plan(1) - const headers = { 'x-khafra-hello': 'hi', Authorization: 'Bearer base64orsomethingitreallydoesntmatter' } - class TestAgent extends Agent { - dispatch (options) { - t.match(options.headers, headers) - - return false + return new Promise((resolve, reject) => { + class TestAgent extends Agent { + dispatch (options) { + assert.deepStrictEqual(options.headers['x-khafra-hello'], headers['x-khafra-hello']) + assert.deepStrictEqual(options.headers.Authorization, headers.Authorization) + resolve() + return false + } } - } - const ws = new WebSocket('wss://echo.websocket.events', { - headers, - dispatcher: new TestAgent() - }) + const ws = new WebSocket('wss://echo.websocket.events', { + headers, + dispatcher: new TestAgent() + }) - // We don't want to make a request, just ensure the headers are set. - ws.onclose = ws.onerror = ws.onmessage = assert.fail + ws.onclose = ws.onerror = ws.onmessage = reject + }) }) diff --git a/test/websocket/diagnostics-channel.js b/test/websocket/diagnostics-channel.js index c3bf05a5105..fbd75ceca8c 100644 --- a/test/websocket/diagnostics-channel.js +++ b/test/websocket/diagnostics-channel.js @@ -1,16 +1,13 @@ 'use strict' -const t = require('tap') +const { describe, test } = require('node:test') +const assert = require('node:assert') const dc = require('diagnostics_channel') const { WebSocketServer } = require('ws') const { WebSocket } = require('../..') -t.test('diagnostics channel', { jobs: 1 }, (t) => { - t.plan(2) - - t.test('undici:websocket:open', (t) => { - t.plan(3) - +describe('diagnostics channel', { concurrency: 1 }, () => { + test('undici:websocket:open', () => { const server = new WebSocketServer({ port: 0 }) server.on('connection', (ws) => { @@ -18,29 +15,26 @@ t.test('diagnostics channel', { jobs: 1 }, (t) => { }) const listener = ({ extensions, protocol }) => { - t.equal(extensions, null) - t.equal(protocol, 'chat') + assert.equal(extensions, null) + assert.equal(protocol, 'chat') } - t.teardown(() => { - dc.channel('undici:websocket:open').unsubscribe(listener) - return server.close() - }) - const { port } = server.address() dc.channel('undici:websocket:open').subscribe(listener) const ws = new WebSocket(`ws://localhost:${port}`, 'chat') - ws.addEventListener('open', () => { - t.pass('Emitted open') + return new Promise((resolve) => { + ws.addEventListener('open', () => { + dc.channel('undici:websocket:open').unsubscribe(listener) + server.close() + resolve() + }) }) }) - t.test('undici:websocket:close', (t) => { - t.plan(4) - + test('undici:websocket:close', () => { const server = new WebSocketServer({ port: 0 }) server.on('connection', (ws) => { @@ -48,24 +42,23 @@ t.test('diagnostics channel', { jobs: 1 }, (t) => { }) const listener = ({ websocket, code, reason }) => { - t.type(websocket, WebSocket) - t.equal(code, 1000) - t.equal(reason, 'goodbye') + assert.ok(websocket instanceof WebSocket) + assert.equal(code, 1000) + assert.equal(reason, 'goodbye') } - t.teardown(() => { - dc.channel('undici:websocket:close').unsubscribe(listener) - return server.close() - }) - const { port } = server.address() dc.channel('undici:websocket:close').subscribe(listener) const ws = new WebSocket(`ws://localhost:${port}`, 'chat') - ws.addEventListener('close', () => { - t.pass('Emitted open') + return new Promise((resolve) => { + ws.addEventListener('close', () => { + dc.channel('undici:websocket:close').unsubscribe(listener) + server.close() + resolve() + }) }) }) }) diff --git a/test/websocket/events.js b/test/websocket/events.js index e5b565c3e66..b7c533251aa 100644 --- a/test/websocket/events.js +++ b/test/websocket/events.js @@ -1,127 +1,144 @@ 'use strict' -const { test } = require('tap') +const { test, describe, after } = require('node:test') +const assert = require('node:assert') const { WebSocketServer } = require('ws') const { MessageEvent, CloseEvent, ErrorEvent } = require('../../lib/websocket/events') const { WebSocket } = require('../..') -test('MessageEvent', (t) => { - t.throws(() => new MessageEvent(), TypeError, 'no arguments') - t.throws(() => new MessageEvent('').initMessageEvent(), TypeError) +test('MessageEvent', () => { + assert.throws(() => new MessageEvent(), TypeError, 'no arguments') + assert.throws(() => new MessageEvent('').initMessageEvent(), TypeError) const noInitEvent = new MessageEvent('message') - t.equal(noInitEvent.origin, '') - t.equal(noInitEvent.data, null) - t.equal(noInitEvent.lastEventId, '') - t.equal(noInitEvent.source, null) - t.ok(Array.isArray(noInitEvent.ports)) - t.ok(Object.isFrozen(noInitEvent.ports)) - t.type(new MessageEvent('').initMessageEvent('message'), MessageEvent) - - t.end() + assert.equal(noInitEvent.origin, '') + assert.equal(noInitEvent.data, null) + assert.equal(noInitEvent.lastEventId, '') + assert.equal(noInitEvent.source, null) + assert.ok(Array.isArray(noInitEvent.ports)) + assert.ok(Object.isFrozen(noInitEvent.ports)) + assert.ok(new MessageEvent('').initMessageEvent('message') instanceof MessageEvent) }) -test('CloseEvent', (t) => { - t.throws(() => new CloseEvent(), TypeError) +test('CloseEvent', () => { + assert.throws(() => new CloseEvent(), TypeError) const noInitEvent = new CloseEvent('close') - t.equal(noInitEvent.wasClean, false) - t.equal(noInitEvent.code, 0) - t.equal(noInitEvent.reason, '') - - t.end() + assert.equal(noInitEvent.wasClean, false) + assert.equal(noInitEvent.code, 0) + assert.equal(noInitEvent.reason, '') }) -test('ErrorEvent', (t) => { - t.throws(() => new ErrorEvent(), TypeError) +test('ErrorEvent', () => { + assert.throws(() => new ErrorEvent(), TypeError) const noInitEvent = new ErrorEvent('error') - t.equal(noInitEvent.message, '') - t.equal(noInitEvent.filename, '') - t.equal(noInitEvent.lineno, 0) - t.equal(noInitEvent.colno, 0) - t.equal(noInitEvent.error, undefined) - - t.end() + assert.equal(noInitEvent.message, '') + assert.equal(noInitEvent.filename, '') + assert.equal(noInitEvent.lineno, 0) + assert.equal(noInitEvent.colno, 0) + assert.equal(noInitEvent.error, undefined) }) -test('Event handlers', (t) => { - t.plan(4) - +describe('Event handlers', () => { const server = new WebSocketServer({ port: 0 }) const ws = new WebSocket(`ws://localhost:${server.address().port}`) + after(() => { + server.close() + ws.close() + }) + function listen () {} - t.teardown(server.close.bind(server)) - t.teardown(() => ws.close()) + describe('onopen', () => { + test('should be null initially', () => { + assert.strictEqual(ws.onopen, null) + }) - t.test('onopen', (t) => { - t.plan(3) + test('should not allow non-function assignments', () => { + ws.onopen = 3 + assert.strictEqual(ws.onopen, null) + }) - t.equal(ws.onopen, null) - ws.onopen = 3 - t.equal(ws.onopen, null) - ws.onopen = listen - t.equal(ws.onopen, listen) + test('should allow function assignments', () => { + ws.onopen = listen + assert.strictEqual(ws.onopen, listen) + }) }) - t.test('onerror', (t) => { - t.plan(3) + describe('onerror', () => { + test('should be null initially', () => { + assert.strictEqual(ws.onerror, null) + }) - t.equal(ws.onerror, null) - ws.onerror = 3 - t.equal(ws.onerror, null) - ws.onerror = listen - t.equal(ws.onerror, listen) + test('should not allow non-function assignments', () => { + ws.onerror = 3 + assert.strictEqual(ws.onerror, null) + }) + + test('should allow function assignments', () => { + ws.onerror = listen + assert.strictEqual(ws.onerror, listen) + }) }) - t.test('onclose', (t) => { - t.plan(3) + describe('onclose', () => { + test('should be null initially', () => { + assert.strictEqual(ws.onclose, null) + }) + + test('should not allow non-function assignments', () => { + ws.onclose = 3 + assert.strictEqual(ws.onclose, null) + }) - t.equal(ws.onclose, null) - ws.onclose = 3 - t.equal(ws.onclose, null) - ws.onclose = listen - t.equal(ws.onclose, listen) + test('should allow function assignments', () => { + ws.onclose = listen + assert.strictEqual(ws.onclose, listen) + }) }) - t.test('onmessage', (t) => { - t.plan(3) + describe('onmessage', () => { + test('should be null initially', () => { + assert.strictEqual(ws.onmessage, null) + }) - t.equal(ws.onmessage, null) - ws.onmessage = 3 - t.equal(ws.onmessage, null) - ws.onmessage = listen - t.equal(ws.onmessage, listen) + test('should not allow non-function assignments', () => { + ws.onmessage = 3 + assert.strictEqual(ws.onmessage, null) + }) + + test('should allow function assignments', () => { + ws.onmessage = listen + assert.strictEqual(ws.onmessage, listen) + }) }) }) -test('CloseEvent WPTs ported', (t) => { - t.test('initCloseEvent', (t) => { +describe('CloseEvent WPTs ported', () => { + test('initCloseEvent', () => { // Taken from websockets/interfaces/CloseEvent/historical.html - t.notOk('initCloseEvent' in CloseEvent.prototype) - t.notOk('initCloseEvent' in new CloseEvent('close')) - - t.end() + assert.ok(!('initCloseEvent' in CloseEvent.prototype)) + assert.ok(!('initCloseEvent' in new CloseEvent('close'))) }) - t.test('CloseEvent constructor', (t) => { + test('CloseEvent constructor', () => { // Taken from websockets/interfaces/CloseEvent/constructor.html { const event = new CloseEvent('foo') - t.ok(event instanceof CloseEvent, 'should be a CloseEvent') - t.equal(event.type, 'foo') - t.notOk(event.bubbles, 'bubbles') - t.notOk(event.cancelable, 'cancelable') - t.notOk(event.wasClean, 'wasClean') - t.equal(event.code, 0) - t.equal(event.reason, '') + assert.ok(event instanceof CloseEvent, 'should be a CloseEvent') + assert.equal(event.type, 'foo') + assert.ok(!event.bubbles, 'bubbles') + assert.ok(!event.cancelable, 'cancelable') + assert.ok(!event.wasClean, 'wasClean') + assert.equal(event.code, 0) + assert.equal(event.reason, '') } { @@ -132,53 +149,47 @@ test('CloseEvent WPTs ported', (t) => { code: 7, reason: 'x' }) - t.ok(event instanceof CloseEvent, 'should be a CloseEvent') - t.equal(event.type, 'foo') - t.ok(event.bubbles, 'bubbles') - t.ok(event.cancelable, 'cancelable') - t.ok(event.wasClean, 'wasClean') - t.equal(event.code, 7) - t.equal(event.reason, 'x') + assert.ok(event instanceof CloseEvent, 'should be a CloseEvent') + assert.equal(event.type, 'foo') + assert.ok(event.bubbles, 'bubbles') + assert.ok(event.cancelable, 'cancelable') + assert.ok(event.wasClean, 'wasClean') + assert.equal(event.code, 7) + assert.equal(event.reason, 'x') } - - t.end() }) - - t.end() }) -test('ErrorEvent WPTs ported', (t) => { - t.test('Synthetic ErrorEvent', (t) => { +describe('ErrorEvent WPTs ported', () => { + test('Synthetic ErrorEvent', () => { // Taken from html/webappapis/scripting/events/event-handler-processing-algorithm-error/document-synthetic-errorevent.html { const e = new ErrorEvent('error') - t.equal(e.message, '') - t.equal(e.filename, '') - t.equal(e.lineno, 0) - t.equal(e.colno, 0) - t.equal(e.error, undefined) + assert.equal(e.message, '') + assert.equal(e.filename, '') + assert.equal(e.lineno, 0) + assert.equal(e.colno, 0) + assert.equal(e.error, undefined) } { const e = new ErrorEvent('error', { error: null }) - t.equal(e.error, null) + assert.equal(e.error, null) } { const e = new ErrorEvent('error', { error: undefined }) - t.equal(e.error, undefined) + assert.equal(e.error, undefined) } { const e = new ErrorEvent('error', { error: 'foo' }) - t.equal(e.error, 'foo') + assert.equal(e.error, 'foo') } - - t.end() }) - t.test('webidl', (t) => { + test('webidl', () => { // Taken from webidl/ecmascript-binding/no-regexp-special-casing.any.js const regExp = new RegExp() @@ -186,19 +197,13 @@ test('ErrorEvent WPTs ported', (t) => { const errorEvent = new ErrorEvent('type', regExp) - t.equal(errorEvent.message, 'some message') - - t.end() + assert.equal(errorEvent.message, 'some message') }) - t.test('initErrorEvent', (t) => { + test('initErrorEvent', () => { // Taken from workers/Worker_dispatchEvent_ErrorEvent.htm const e = new ErrorEvent('error') - t.notOk('initErrorEvent' in e, 'should not be supported') - - t.end() + assert.ok(!('initErrorEvent' in e), 'should not be supported') }) - - t.end() }) diff --git a/test/websocket/fragments.js b/test/websocket/fragments.js index d51db4b94c5..3c798302f80 100644 --- a/test/websocket/fragments.js +++ b/test/websocket/fragments.js @@ -1,13 +1,12 @@ 'use strict' -const { test } = require('tap') +const assert = require('node:assert') +const { test, after } = require('node:test') const { WebSocketServer } = require('ws') const { WebSocket } = require('../..') const diagnosticsChannel = require('diagnostics_channel') -test('Fragmented frame with a ping frame in the middle of it', (t) => { - t.plan(2) - +test('Fragmented frame with a ping frame in the middle of it', () => { const server = new WebSocketServer({ port: 0 }) server.on('connection', (ws) => { @@ -18,7 +17,7 @@ test('Fragmented frame with a ping frame in the middle of it', (t) => { socket.write(Buffer.from([0x80, 0x02, 0x6c, 0x6f])) // Text frame "lo" }) - t.teardown(() => { + after(() => { for (const client of server.clients) { client.close() } @@ -28,13 +27,16 @@ test('Fragmented frame with a ping frame in the middle of it', (t) => { const ws = new WebSocket(`ws://localhost:${server.address().port}`) - ws.addEventListener('message', ({ data }) => { - t.same(data, 'Hello') - - ws.close() - }) - diagnosticsChannel.channel('undici:websocket:ping').subscribe( - ({ payload }) => t.same(payload, Buffer.from('Hello')) + ({ payload }) => assert.deepStrictEqual(payload, Buffer.from('Hello')) ) + + return new Promise((resolve) => { + ws.addEventListener('message', ({ data }) => { + assert.strictEqual(data, 'Hello') + + ws.close() + resolve() + }) + }) }) diff --git a/test/websocket/frame.js b/test/websocket/frame.js index b4b73b7cf08..936bd8f69e0 100644 --- a/test/websocket/frame.js +++ b/test/websocket/frame.js @@ -1,24 +1,23 @@ 'use strict' -const { test } = require('tap') +const { test } = require('node:test') +const assert = require('node:assert') const { WebsocketFrameSend } = require('../../lib/websocket/frame') const { opcodes } = require('../../lib/websocket/constants') -test('Writing 16-bit frame length value at correct offset when buffer has a non-zero byteOffset', (t) => { +test('Writing 16-bit frame length value at correct offset when buffer has a non-zero byteOffset', () => { /* When writing 16-bit frame lengths, a `DataView` was being used without setting a `byteOffset` into the buffer: i.e. `new DataView(buffer.buffer)` instead of `new DataView(buffer.buffer, buffer.byteOffset, buffer.byteLength)`. Small `Buffers` returned by `allocUnsafe` are usually returned from the buffer pool, and thus have a non-zero `byteOffset`. Invalid frames were therefore being returned in that case. */ - t.plan(3) - const payloadLength = 126 // 126 bytes is the smallest payload to trigger a 16-bit length field const smallBuffer = Buffer.allocUnsafe(1) // make it very likely that the next buffer returned by allocUnsafe DOESN'T have a zero byteOffset const payload = Buffer.allocUnsafe(payloadLength).fill(0) const frame = new WebsocketFrameSend(payload).createFrame(opcodes.BINARY) - t.equal(frame[2], payloadLength >>> 8) - t.equal(frame[3], payloadLength & 0xff) - t.equal(smallBuffer.length, 1) // ensure smallBuffer can't be garbage-collected too soon + assert.equal(frame[2], payloadLength >>> 8) + assert.equal(frame[3], payloadLength & 0xff) + assert.equal(smallBuffer.length, 1) // ensure smallBuffer can't be garbage-collected too soon }) diff --git a/test/websocket/opening-handshake.js b/test/websocket/opening-handshake.js index b9a7989111e..4dce496e829 100644 --- a/test/websocket/opening-handshake.js +++ b/test/websocket/opening-handshake.js @@ -1,215 +1,217 @@ 'use strict' -const { test } = require('tap') +const { test } = require('node:test') +const assert = require('node:assert') const { createServer } = require('http') const { WebSocketServer } = require('ws') const { WebSocket } = require('../..') -test('WebSocket connecting to server that isn\'t a Websocket server', (t) => { - t.plan(5) - - const server = createServer((req, res) => { - t.equal(req.headers.connection, 'upgrade') - t.equal(req.headers.upgrade, 'websocket') - t.ok(req.headers['sec-websocket-key']) - t.equal(req.headers['sec-websocket-version'], '13') - - res.end() - server.unref() - }).listen(0, () => { - const ws = new WebSocket(`ws://localhost:${server.address().port}`) - - // Server isn't a websocket server - ws.onmessage = ws.onopen = t.fail - - ws.addEventListener('error', t.pass) +test('WebSocket connecting to server that isn\'t a Websocket server', () => { + return new Promise((resolve, reject) => { + const server = createServer((req, res) => { + assert.equal(req.headers.connection, 'upgrade') + assert.equal(req.headers.upgrade, 'websocket') + assert.ok(req.headers['sec-websocket-key']) + assert.equal(req.headers['sec-websocket-version'], '13') + + res.end() + server.unref() + }).listen(0, () => { + const ws = new WebSocket(`ws://localhost:${server.address().port}`) + + // Server isn't a websocket server + ws.onmessage = ws.onopen = reject + + ws.addEventListener('error', ({ error }) => { + assert.ok(error) + server.close() + resolve() + }) + }) }) - - t.teardown(server.close.bind(server)) }) -test('Open event is emitted', (t) => { - t.plan(1) - - const server = new WebSocketServer({ port: 0 }) - - server.on('connection', (ws) => { - ws.close(1000) - }) +test('Open event is emitted', () => { + return new Promise((resolve, reject) => { + const server = new WebSocketServer({ port: 0 }) - t.teardown(server.close.bind(server)) + server.on('connection', (ws) => { + ws.close(1000) + }) - const ws = new WebSocket(`ws://localhost:${server.address().port}`) + const ws = new WebSocket(`ws://localhost:${server.address().port}`) - ws.onmessage = ws.onerror = t.fail - ws.addEventListener('open', t.pass) + ws.onmessage = ws.onerror = reject + ws.addEventListener('open', () => { + server.close() + resolve() + }) + }) }) -test('Multiple protocols are joined by a comma', (t) => { - t.plan(1) +test('Multiple protocols are joined by a comma', () => { + return new Promise((resolve, reject) => { + const server = new WebSocketServer({ port: 0 }) - const server = new WebSocketServer({ port: 0 }) + server.on('connection', (ws, req) => { + assert.equal(req.headers['sec-websocket-protocol'], 'chat, echo') - server.on('connection', (ws, req) => { - t.equal(req.headers['sec-websocket-protocol'], 'chat, echo') + ws.close(1000) + server.close() + resolve() + }) - ws.close(1000) - server.close() + const ws = new WebSocket(`ws://localhost:${server.address().port}`, ['chat', 'echo']) + ws.addEventListener('open', () => ws.close()) }) - - t.teardown(server.close.bind(server)) - - const ws = new WebSocket(`ws://localhost:${server.address().port}`, ['chat', 'echo']) - - ws.addEventListener('open', () => ws.close()) }) -test('Server doesn\'t send Sec-WebSocket-Protocol header when protocols are used', (t) => { - t.plan(1) +test('Server doesn\'t send Sec-WebSocket-Protocol header when protocols are used', () => { + return new Promise((resolve, reject) => { + const server = createServer((req, res) => { + res.statusCode = 101 - const server = createServer((req, res) => { - res.statusCode = 101 + req.socket.destroy() + }).listen(0, () => { + const ws = new WebSocket(`ws://localhost:${server.address().port}`, 'chat') - req.socket.destroy() - }).listen(0, () => { - const ws = new WebSocket(`ws://localhost:${server.address().port}`, 'chat') + ws.onopen = reject - ws.onopen = t.fail - - ws.addEventListener('error', ({ error }) => { - t.ok(error) + ws.addEventListener('error', ({ error }) => { + assert.ok(error) + server.close() + resolve() + }) }) }) - - t.teardown(server.close.bind(server)) }) -test('Server sends invalid Upgrade header', (t) => { - t.plan(1) +test('Server sends invalid Upgrade header', () => { + return new Promise((resolve, reject) => { + const server = createServer((req, res) => { + res.setHeader('Upgrade', 'NotWebSocket') + res.statusCode = 101 - const server = createServer((req, res) => { - res.setHeader('Upgrade', 'NotWebSocket') - res.statusCode = 101 + req.socket.destroy() + }).listen(0, () => { + const ws = new WebSocket(`ws://localhost:${server.address().port}`) - req.socket.destroy() - }).listen(0, () => { - const ws = new WebSocket(`ws://localhost:${server.address().port}`) - - ws.onopen = t.fail + ws.onopen = reject - ws.addEventListener('error', ({ error }) => { - t.ok(error) + ws.addEventListener('error', ({ error }) => { + assert.ok(error) + server.close() + resolve() + }) }) }) - - t.teardown(server.close.bind(server)) }) -test('Server sends invalid Connection header', (t) => { - t.plan(1) +test('Server sends invalid Connection header', () => { + return new Promise((resolve, reject) => { + const server = createServer((req, res) => { + res.setHeader('Upgrade', 'websocket') + res.setHeader('Connection', 'downgrade') + res.statusCode = 101 - const server = createServer((req, res) => { - res.setHeader('Upgrade', 'websocket') - res.setHeader('Connection', 'downgrade') - res.statusCode = 101 - - req.socket.destroy() - }).listen(0, () => { - const ws = new WebSocket(`ws://localhost:${server.address().port}`) + req.socket.destroy() + }).listen(0, () => { + const ws = new WebSocket(`ws://localhost:${server.address().port}`) - ws.onopen = t.fail + ws.onopen = reject - ws.addEventListener('error', ({ error }) => { - t.ok(error) + ws.addEventListener('error', ({ error }) => { + assert.ok(error) + server.close() + resolve() + }) }) }) - - t.teardown(server.close.bind(server)) }) -test('Server sends invalid Sec-WebSocket-Accept header', (t) => { - t.plan(1) - - const server = createServer((req, res) => { - res.setHeader('Upgrade', 'websocket') - res.setHeader('Connection', 'upgrade') - res.setHeader('Sec-WebSocket-Accept', 'abc') - res.statusCode = 101 - - req.socket.destroy() - }).listen(0, () => { - const ws = new WebSocket(`ws://localhost:${server.address().port}`) - - ws.onopen = t.fail - - ws.addEventListener('error', ({ error }) => { - t.ok(error) +test('Server sends invalid Sec-WebSocket-Accept header', () => { + return new Promise((resolve, reject) => { + const server = createServer((req, res) => { + res.setHeader('Upgrade', 'websocket') + res.setHeader('Connection', 'upgrade') + res.setHeader('Sec-WebSocket-Accept', 'abc') + res.statusCode = 101 + + req.socket.destroy() + }).listen(0, () => { + const ws = new WebSocket(`ws://localhost:${server.address().port}`) + + ws.onopen = reject + + ws.addEventListener('error', ({ error }) => { + assert.ok(error) + server.close() + resolve() + }) }) }) - - t.teardown(server.close.bind(server)) }) -test('Server sends invalid Sec-WebSocket-Extensions header', (t) => { - const uid = '258EAFA5-E914-47DA-95CA-C5AB0DC85B11' - const { createHash } = require('crypto') +test('Server sends invalid Sec-WebSocket-Extensions header', () => { + return new Promise((resolve, reject) => { + const uid = '258EAFA5-E914-47DA-95CA-C5AB0DC85B11' + const { createHash } = require('crypto') - t.plan(2) + const server = createServer((req, res) => { + const key = req.headers['sec-websocket-key'] + assert.ok(key) - const server = createServer((req, res) => { - const key = req.headers['sec-websocket-key'] - t.ok(key) + const accept = createHash('sha1').update(key + uid).digest('base64') - const accept = createHash('sha1').update(key + uid).digest('base64') + res.setHeader('Upgrade', 'websocket') + res.setHeader('Connection', 'upgrade') + res.setHeader('Sec-WebSocket-Accept', accept) + res.setHeader('Sec-WebSocket-Extensions', 'InvalidExtension') + res.statusCode = 101 - res.setHeader('Upgrade', 'websocket') - res.setHeader('Connection', 'upgrade') - res.setHeader('Sec-WebSocket-Accept', accept) - res.setHeader('Sec-WebSocket-Extensions', 'InvalidExtension') - res.statusCode = 101 + res.end() + }).listen(0, () => { + const ws = new WebSocket(`ws://localhost:${server.address().port}`) - res.end() - }).listen(0, () => { - const ws = new WebSocket(`ws://localhost:${server.address().port}`) + ws.onopen = reject - ws.onopen = t.fail - - ws.addEventListener('error', ({ error }) => { - t.ok(error) + ws.addEventListener('error', ({ error }) => { + assert.ok(error) + server.close() + resolve() + }) }) }) - - t.teardown(server.close.bind(server)) }) -test('Server sends invalid Sec-WebSocket-Extensions header', (t) => { +test('Server sends invalid Sec-WebSocket-Extensions header', () => { const uid = '258EAFA5-E914-47DA-95CA-C5AB0DC85B11' const { createHash } = require('crypto') - t.plan(2) + return new Promise((resolve, reject) => { + const server = createServer((req, res) => { + const key = req.headers['sec-websocket-key'] + assert.ok(key) - const server = createServer((req, res) => { - const key = req.headers['sec-websocket-key'] - t.ok(key) + const accept = createHash('sha1').update(key + uid).digest('base64') - const accept = createHash('sha1').update(key + uid).digest('base64') + res.setHeader('Upgrade', 'websocket') + res.setHeader('Connection', 'upgrade') + res.setHeader('Sec-WebSocket-Accept', accept) + res.setHeader('Sec-WebSocket-Protocol', 'echo') // <-- + res.statusCode = 101 - res.setHeader('Upgrade', 'websocket') - res.setHeader('Connection', 'upgrade') - res.setHeader('Sec-WebSocket-Accept', accept) - res.setHeader('Sec-WebSocket-Protocol', 'echo') // <-- - res.statusCode = 101 + res.end() + }).listen(0, () => { + const ws = new WebSocket(`ws://localhost:${server.address().port}`, 'chat') - res.end() - }).listen(0, () => { - const ws = new WebSocket(`ws://localhost:${server.address().port}`, 'chat') + ws.onopen = reject - ws.onopen = t.fail - - ws.addEventListener('error', ({ error }) => { - t.ok(error) + ws.addEventListener('error', ({ error }) => { + assert.ok(error) + server.close() + resolve() + }) }) }) - - t.teardown(server.close.bind(server)) }) diff --git a/test/websocket/ping-pong.js b/test/websocket/ping-pong.js index b7c46947dd8..81ae3a478ec 100644 --- a/test/websocket/ping-pong.js +++ b/test/websocket/ping-pong.js @@ -1,46 +1,47 @@ 'use strict' -const { test } = require('tap') +const { test } = require('node:test') +const assert = require('node:assert') const { WebSocketServer } = require('ws') const diagnosticsChannel = require('diagnostics_channel') const { WebSocket } = require('../..') -test('Receives ping and parses body', (t) => { - t.plan(1) +test('Receives ping and parses body', () => { + return new Promise((resolve, reject) => { + const server = new WebSocketServer({ port: 0 }) - const server = new WebSocketServer({ port: 0 }) + server.on('connection', (ws) => { + ws.ping('Hello, world') + }) - server.on('connection', (ws) => { - ws.ping('Hello, world') - }) - - t.teardown(server.close.bind(server)) - - const ws = new WebSocket(`ws://localhost:${server.address().port}`) - ws.onerror = ws.onmessage = t.fail + const ws = new WebSocket(`ws://localhost:${server.address().port}`) + ws.onerror = ws.onmessage = reject - diagnosticsChannel.channel('undici:websocket:ping').subscribe(({ payload }) => { - t.same(payload, Buffer.from('Hello, world')) - ws.close() + diagnosticsChannel.channel('undici:websocket:ping').subscribe(({ payload }) => { + assert.deepStrictEqual(payload, Buffer.from('Hello, world')) + ws.close() + server.close() + resolve() + }) }) }) -test('Receives pong and parses body', (t) => { - t.plan(1) - - const server = new WebSocketServer({ port: 0 }) - - server.on('connection', (ws) => { - ws.pong('Pong') - }) +test('Receives pong and parses body', () => { + return new Promise((resolve, reject) => { + const server = new WebSocketServer({ port: 0 }) - t.teardown(server.close.bind(server)) + server.on('connection', (ws) => { + ws.pong('Pong') + }) - const ws = new WebSocket(`ws://localhost:${server.address().port}`) - ws.onerror = ws.onmessage = t.fail + const ws = new WebSocket(`ws://localhost:${server.address().port}`) + ws.onerror = ws.onmessage = reject - diagnosticsChannel.channel('undici:websocket:pong').subscribe(({ payload }) => { - t.same(payload, Buffer.from('Pong')) - ws.close() + diagnosticsChannel.channel('undici:websocket:pong').subscribe(({ payload }) => { + assert.deepStrictEqual(payload, Buffer.from('Pong')) + server.close() + ws.close() + resolve() + }) }) }) diff --git a/test/websocket/receive.js b/test/websocket/receive.js index a66902202a4..ad14b88d904 100644 --- a/test/websocket/receive.js +++ b/test/websocket/receive.js @@ -1,12 +1,11 @@ 'use strict' -const { test } = require('tap') +const { test } = require('node:test') +const assert = require('node:assert') const { WebSocketServer } = require('ws') const { WebSocket } = require('../..') -test('Receiving a frame with a payload length > 2^31-1 bytes', (t) => { - t.plan(1) - +test('Receiving a frame with a payload length > 2^31-1 bytes', () => { const server = new WebSocketServer({ port: 0 }) server.on('connection', (ws) => { @@ -17,21 +16,19 @@ test('Receiving a frame with a payload length > 2^31-1 bytes', (t) => { const ws = new WebSocket(`ws://localhost:${server.address().port}`) - t.teardown(() => { - ws.close() - server.close() - }) - - ws.onmessage = t.fail + return new Promise((resolve, reject) => { + ws.onmessage = reject - ws.addEventListener('error', (event) => { - t.type(event.error, Error) // error event is emitted + ws.addEventListener('error', (event) => { + assert.ok(event.error instanceof Error) // error event is emitted + ws.close() + server.close() + resolve() + }) }) }) -test('Receiving an ArrayBuffer', (t) => { - t.plan(3) - +test('Receiving an ArrayBuffer', () => { const server = new WebSocketServer({ port: 0 }) server.on('connection', (ws) => { @@ -42,19 +39,22 @@ test('Receiving an ArrayBuffer', (t) => { }) }) - t.teardown(server.close.bind(server)) const ws = new WebSocket(`ws://localhost:${server.address().port}`) ws.addEventListener('open', () => { ws.binaryType = 'what' - t.equal(ws.binaryType, 'blob') + assert.equal(ws.binaryType, 'blob') ws.binaryType = 'arraybuffer' // <-- ws.send('Hello') }) - ws.addEventListener('message', ({ data }) => { - t.type(data, ArrayBuffer) - t.same(Buffer.from(data), Buffer.from('Hello')) + return new Promise((resolve) => { + ws.addEventListener('message', ({ data }) => { + assert.ok(data instanceof ArrayBuffer) + assert.deepStrictEqual(Buffer.from(data), Buffer.from('Hello')) + server.close() + resolve() + }) }) }) diff --git a/test/websocket/send.js b/test/websocket/send.js index ac295fded73..56f48a6ec85 100644 --- a/test/websocket/send.js +++ b/test/websocket/send.js @@ -1,6 +1,7 @@ 'use strict' -const { test } = require('tap') +const { test, describe } = require('node:test') +const assert = require('node:assert') const { WebSocketServer } = require('ws') const { Blob } = require('buffer') const { WebSocket } = require('../..') @@ -9,9 +10,7 @@ const { WebSocket } = require('../..') // different ways a payload length may be specified in a WebSocket frame // (https://datatracker.ietf.org/doc/html/rfc6455#section-5.2) -test('Sending >= 2^16 bytes', (t) => { - t.plan(3) - +test('Sending >= 2^16 bytes', () => { const server = new WebSocketServer({ port: 0 }) server.on('connection', (ws) => { @@ -28,19 +27,21 @@ test('Sending >= 2^16 bytes', (t) => { ws.send(payload) }) - ws.addEventListener('message', async ({ data }) => { - t.type(data, Blob) - t.equal(data.size, payload.length) - t.same(Buffer.from(await data.arrayBuffer()), payload) + return new Promise((resolve) => { + ws.addEventListener('message', async ({ data }) => { + assert.ok(data instanceof Blob) + assert.equal(data.size, payload.length) + assert.deepStrictEqual(Buffer.from(await data.arrayBuffer()), payload) + + ws.close() + server.close() - ws.close() - server.close() + resolve() + }) }) }) -test('Sending >= 126, < 2^16 bytes', (t) => { - t.plan(3) - +test('Sending >= 126, < 2^16 bytes', () => { const server = new WebSocketServer({ port: 0 }) server.on('connection', (ws) => { @@ -57,19 +58,20 @@ test('Sending >= 126, < 2^16 bytes', (t) => { ws.send(payload) }) - ws.addEventListener('message', async ({ data }) => { - t.type(data, Blob) - t.equal(data.size, payload.length) - t.same(Buffer.from(await data.arrayBuffer()), payload) + return new Promise((resolve) => { + ws.addEventListener('message', async ({ data }) => { + assert.ok(data instanceof Blob) + assert.equal(data.size, payload.length) + assert.deepStrictEqual(Buffer.from(await data.arrayBuffer()), payload) - ws.close() - server.close() + ws.close() + server.close() + resolve() + }) }) }) -test('Sending < 126 bytes', (t) => { - t.plan(3) - +test('Sending < 126 bytes', () => { const server = new WebSocketServer({ port: 0 }) server.on('connection', (ws) => { @@ -86,49 +88,47 @@ test('Sending < 126 bytes', (t) => { ws.send(payload) }) - ws.addEventListener('message', async ({ data }) => { - t.type(data, Blob) - t.equal(data.size, payload.length) - t.same(Buffer.from(await data.arrayBuffer()), payload) + return new Promise((resolve) => { + ws.addEventListener('message', async ({ data }) => { + assert.ok(data instanceof Blob) + assert.equal(data.size, payload.length) + assert.deepStrictEqual(Buffer.from(await data.arrayBuffer()), payload) - ws.close() - server.close() + ws.close() + server.close() + resolve() + }) }) }) -test('Sending data after close', (t) => { - t.plan(2) - +test('Sending data after close', () => { const server = new WebSocketServer({ port: 0 }) - server.on('connection', (ws) => { - t.pass() + const ws = new WebSocket(`ws://localhost:${server.address().port}`) - ws.on('message', t.fail) - }) + return new Promise((resolve, reject) => { + server.on('connection', (ws) => { + ws.on('message', reject) + }) - t.teardown(server.close.bind(server)) - const ws = new WebSocket(`ws://localhost:${server.address().port}`) + ws.addEventListener('open', () => { + ws.close() + ws.send('Some message') + server.close() - ws.addEventListener('open', () => { - ws.close() - ws.send('Some message') + resolve() + }) - t.pass() + ws.addEventListener('error', reject) }) - - ws.addEventListener('error', t.fail) }) -test('Sending data before connected', (t) => { - t.plan(2) - +test('Sending data before connected', () => { const server = new WebSocketServer({ port: 0 }) - t.teardown(server.close.bind(server)) const ws = new WebSocket(`ws://localhost:${server.address().port}`) - t.throws( + assert.throws( () => ws.send('Not sent'), { name: 'InvalidStateError', @@ -136,81 +136,79 @@ test('Sending data before connected', (t) => { } ) - t.equal(ws.readyState, WebSocket.CONNECTING) + assert.equal(ws.readyState, WebSocket.CONNECTING) + server.close() }) -test('Sending data to a server', (t) => { - t.plan(3) - - t.test('Send with string', (t) => { - t.plan(2) - +describe('Sending data to a server', () => { + test('Send with string', () => { const server = new WebSocketServer({ port: 0 }) - server.on('connection', (ws) => { - ws.on('message', (data, isBinary) => { - t.notOk(isBinary, 'Received text frame') - t.same(data, Buffer.from('message')) - - ws.close(1000) - }) - }) - - t.teardown(server.close.bind(server)) - const ws = new WebSocket(`ws://localhost:${server.address().port}`) ws.addEventListener('open', () => { ws.send('message') }) - }) - t.test('Send with ArrayBuffer', (t) => { - t.plan(2) + return new Promise((resolve) => { + server.on('connection', (ws) => { + ws.on('message', (data, isBinary) => { + assert.ok(!isBinary, 'Received text frame') + assert.deepStrictEqual(data, Buffer.from('message')) + ws.close(1000) + server.close() + resolve() + }) + }) + }) + }) + test('Send with ArrayBuffer', () => { const message = new TextEncoder().encode('message') const ab = new ArrayBuffer(7) new Uint8Array(ab).set(message) const server = new WebSocketServer({ port: 0 }) - server.on('connection', (ws) => { - ws.on('message', (data, isBinary) => { - t.ok(isBinary) - t.same(new Uint8Array(data), message) - - ws.close(1000) - }) - }) - - t.teardown(server.close.bind(server)) const ws = new WebSocket(`ws://localhost:${server.address().port}`) ws.addEventListener('open', () => { ws.send(ab) }) - }) - t.test('Send with Blob', (t) => { - t.plan(2) + return new Promise((resolve) => { + server.on('connection', (ws) => { + ws.on('message', (data, isBinary) => { + assert.ok(isBinary) + assert.deepStrictEqual(new Uint8Array(data), message) + ws.close(1000) + server.close() + resolve() + }) + }) + }) + }) + test('Send with Blob', () => { const blob = new Blob(['hello']) const server = new WebSocketServer({ port: 0 }) - server.on('connection', (ws) => { - ws.on('message', (data, isBinary) => { - t.ok(isBinary) - t.same(data, Buffer.from('hello')) - - ws.close(1000) - }) - }) - - t.teardown(server.close.bind(server)) const ws = new WebSocket(`ws://localhost:${server.address().port}`) ws.addEventListener('open', () => { ws.send(blob) }) + + return new Promise((resolve) => { + server.on('connection', (ws) => { + ws.on('message', (data, isBinary) => { + assert.ok(isBinary) + assert.deepStrictEqual(data, Buffer.from('hello')) + ws.close(1000) + server.close() + resolve() + }) + }) + }) }) }) diff --git a/test/websocket/websocketinit.js b/test/websocket/websocketinit.js index 4dda3b48188..4daa16bfc48 100644 --- a/test/websocket/websocketinit.js +++ b/test/websocket/websocketinit.js @@ -1,12 +1,11 @@ 'use strict' -const { test } = require('tap') +const { test, describe } = require('node:test') +const assert = require('node:assert') const { WebSocketServer } = require('ws') const { WebSocket, Dispatcher, Agent } = require('../..') -test('WebSocketInit', (t) => { - t.plan(2) - +describe('WebSocketInit', () => { class WsDispatcher extends Dispatcher { constructor () { super() @@ -14,32 +13,30 @@ test('WebSocketInit', (t) => { } dispatch () { - t.pass() return this.agent.dispatch(...arguments) } } - t.test('WebSocketInit as 2nd param', (t) => { - t.plan(1) - + test('WebSocketInit as 2nd param', () => { const server = new WebSocketServer({ port: 0 }) server.on('connection', (ws) => { ws.send(Buffer.from('hello, world')) }) - t.teardown(server.close.bind(server)) - const ws = new WebSocket(`ws://localhost:${server.address().port}`, { dispatcher: new WsDispatcher() }) - ws.onerror = t.fail + return new Promise((resolve, reject) => { + ws.onerror = reject - ws.addEventListener('message', async (event) => { - t.equal(await event.data.text(), 'hello, world') - server.close() - ws.close() + ws.addEventListener('message', async (event) => { + assert.equal(await event.data.text(), 'hello, world') + server.close() + ws.close() + resolve() + }) }) }) })