diff --git a/package.json b/package.json index 05d9fdb479b..17015f7b1b8 100644 --- a/package.json +++ b/package.json @@ -78,7 +78,7 @@ "test": "node scripts/generate-pem && npm run test:tap && npm run test:node-fetch && npm run test:fetch && npm run test:cookies && npm run test:wpt && npm run test:websocket && npm run test:jest && npm run test:typescript && npm run test:node-test", "test:cookies": "borp --coverage -p \"test/cookie/*.js\"", "test:node-fetch": "mocha --exit test/node-fetch", - "test:fetch": "npm run build:node && tap --expose-gc test/fetch/*.js && borp --coverage -p \"test/webidl/*.js\"", + "test:fetch": "npm run build:node && borp --expose-gc --coverage -p \"test/fetch/*.js\" && borp --coverage -p \"test/webidl/*.js\"", "test:jest": "jest", "test:tap": "tap test/*.js test/diagnostics-channel/*.js", "test:node-test": "borp --coverage -p \"test/node-test/*.js\"", @@ -102,7 +102,7 @@ "@types/node": "^18.0.3", "abort-controller": "^3.0.0", "atomic-sleep": "^1.0.0", - "borp": "^0.4.2", + "borp": "^0.5.0", "chai": "^4.3.4", "chai-as-promised": "^7.1.1", "chai-iterator": "^3.0.2", diff --git a/test/fetch/407-statuscode-window-null.js b/test/fetch/407-statuscode-window-null.js index e22554fac15..4311b0ed96b 100644 --- a/test/fetch/407-statuscode-window-null.js +++ b/test/fetch/407-statuscode-window-null.js @@ -3,7 +3,8 @@ const { fetch } = require('../..') const { createServer } = require('http') const { once } = require('events') -const { test } = require('tap') +const { test } = require('node:test') +const assert = require('node:assert') test('Receiving a 407 status code w/ a window option present should reject', async (t) => { const server = createServer((req, res) => { @@ -11,10 +12,10 @@ test('Receiving a 407 status code w/ a window option present should reject', asy res.end() }).listen(0) - t.teardown(server.close.bind(server)) + t.after(server.close.bind(server)) await once(server, 'listening') // if init.window exists, the spec tells us to set request.window to 'no-window', // which later causes the request to be rejected if the status code is 407 - await t.rejects(fetch(`http://localhost:${server.address().port}`, { window: null })) + await assert.rejects(fetch(`http://localhost:${server.address().port}`, { window: null })) }) diff --git a/test/fetch/abort.js b/test/fetch/abort.js index 367201f3a16..1f819dae6be 100644 --- a/test/fetch/abort.js +++ b/test/fetch/abort.js @@ -1,6 +1,8 @@ 'use strict' -const { test } = require('tap') +const { test } = require('node:test') +const assert = require('node:assert') +const { tspl } = require('@matteo.collina/tspl') const { fetch } = require('../..') const { createServer } = require('http') const { once } = require('events') @@ -17,7 +19,7 @@ test('Allow the usage of custom implementation of AbortController', async (t) => res.end(JSON.stringify(body)) }) - t.teardown(server.close.bind(server)) + t.after(server.close.bind(server)) server.listen(0) await once(server, 'listening') @@ -31,43 +33,42 @@ test('Allow the usage of custom implementation of AbortController', async (t) => signal }) } catch (e) { - t.equal(e.code, DOMException.ABORT_ERR) + assert.strictEqual(e.code, DOMException.ABORT_ERR) } }) test('allows aborting with custom errors', async (t) => { const server = createServer().listen(0) - t.teardown(server.close.bind(server)) + t.after(server.close.bind(server)) await once(server, 'listening') - t.test('Using AbortSignal.timeout with cause', async (t) => { - t.plan(2) - + await t.test('Using AbortSignal.timeout with cause', async () => { + const { strictEqual } = tspl(t, { plan: 2 }) try { await fetch(`http://localhost:${server.address().port}`, { signal: AbortSignal.timeout(50) }) - t.fail('should throw') + assert.fail('should throw') } catch (err) { if (err.name === 'TypeError') { const cause = err.cause - t.equal(cause.name, 'HeadersTimeoutError') - t.equal(cause.code, 'UND_ERR_HEADERS_TIMEOUT') + strictEqual(cause.name, 'HeadersTimeoutError') + strictEqual(cause.code, 'UND_ERR_HEADERS_TIMEOUT') } else if (err.name === 'TimeoutError') { - t.equal(err.code, DOMException.TIMEOUT_ERR) - t.equal(err.cause, undefined) + strictEqual(err.code, DOMException.TIMEOUT_ERR) + strictEqual(err.cause, undefined) } else { - t.error(err) + throw err } } }) - t.test('Error defaults to an AbortError DOMException', async (t) => { + t.test('Error defaults to an AbortError DOMException', async () => { const ac = new AbortController() ac.abort() // no reason - await t.rejects( + await assert.rejects( fetch(`http://localhost:${server.address().port}`, { signal: ac.signal }), diff --git a/test/fetch/abort2.js b/test/fetch/abort2.js index b07482d9706..03a58a78baa 100644 --- a/test/fetch/abort2.js +++ b/test/fetch/abort2.js @@ -1,6 +1,7 @@ 'use strict' -const { test } = require('tap') +const { test } = require('node:test') +const assert = require('node:assert') const { fetch } = require('../..') const { createServer } = require('http') const { once } = require('events') @@ -18,7 +19,7 @@ test('parallel fetch with the same AbortController works as expected', async (t) res.end(JSON.stringify(body)) }) - t.teardown(server.close.bind(server)) + t.after(server.close.bind(server)) const abortController = new AbortController() @@ -49,11 +50,9 @@ test('parallel fetch with the same AbortController works as expected', async (t) return a }, { resolved: [], rejected: [] }) - t.equal(rejected.length, 9) // out of 10 requests, only 1 should succeed - t.equal(resolved.length, 1) + assert.strictEqual(rejected.length, 9) // out of 10 requests, only 1 should succeed + assert.strictEqual(resolved.length, 1) - t.ok(rejected.every(rej => rej.reason?.code === DOMException.ABORT_ERR)) - t.same(resolved[0].value, body) - - t.end() + assert.ok(rejected.every(rej => rej.reason?.code === DOMException.ABORT_ERR)) + assert.deepStrictEqual(resolved[0].value, body) }) diff --git a/test/fetch/about-uri.js b/test/fetch/about-uri.js index ac9cbf2be90..fc8ef5f3455 100644 --- a/test/fetch/about-uri.js +++ b/test/fetch/about-uri.js @@ -1,21 +1,20 @@ 'use strict' -const { test } = require('tap') +const { test } = require('node:test') +const assert = require('node:assert') const { fetch } = require('../..') test('fetching about: uris', async (t) => { - t.test('about:blank', async (t) => { - await t.rejects(fetch('about:blank')) + await t.test('about:blank', async () => { + await assert.rejects(fetch('about:blank')) }) - t.test('All other about: urls should return an error', async (t) => { + await t.test('All other about: urls should return an error', async () => { try { await fetch('about:config') - t.fail('fetching about:config should fail') + assert.fail('fetching about:config should fail') } catch (e) { - t.ok(e, 'this error was expected') - } finally { - t.end() + assert.ok(e, 'this error was expected') } }) }) diff --git a/test/fetch/blob-uri.js b/test/fetch/blob-uri.js index f9db96c36b1..9ba2c5f30ca 100644 --- a/test/fetch/blob-uri.js +++ b/test/fetch/blob-uri.js @@ -1,6 +1,7 @@ 'use strict' -const { test } = require('tap') +const { test } = require('node:test') +const assert = require('node:assert') const { fetch } = require('../..') const { Blob } = require('buffer') @@ -16,85 +17,73 @@ test('fetching blob: uris', async (t) => { objectURL = URL.createObjectURL(blob) }) - t.test('a normal fetch request works', async (t) => { + await t.test('a normal fetch request works', async () => { const res = await fetch(objectURL) - t.equal(blobContents, await res.text()) - t.equal(blob.type, res.headers.get('Content-Type')) - t.equal(`${blob.size}`, res.headers.get('Content-Length')) - t.end() + assert.strictEqual(blobContents, await res.text()) + assert.strictEqual(blob.type, res.headers.get('Content-Type')) + assert.strictEqual(`${blob.size}`, res.headers.get('Content-Length')) }) - t.test('non-GET method to blob: fails', async (t) => { + await t.test('non-GET method to blob: fails', async () => { try { await fetch(objectURL, { method: 'POST' }) - t.fail('expected POST to blob: uri to fail') + assert.fail('expected POST to blob: uri to fail') } catch (e) { - t.ok(e, 'Got the expected error') - } finally { - t.end() + assert.ok(e, 'Got the expected error') } }) // https://github.com/web-platform-tests/wpt/blob/7b0ebaccc62b566a1965396e5be7bb2bc06f841f/FileAPI/url/resources/fetch-tests.js#L36-L41 - t.test('fetching revoked URL should fail', async (t) => { + await t.test('fetching revoked URL should fail', async () => { URL.revokeObjectURL(objectURL) try { await fetch(objectURL) - t.fail('expected revoked blob: url to fail') + assert.fail('expected revoked blob: url to fail') } catch (e) { - t.ok(e, 'Got the expected error') - } finally { - t.end() + assert.ok(e, 'Got the expected error') } }) // https://github.com/web-platform-tests/wpt/blob/7b0ebaccc62b566a1965396e5be7bb2bc06f841f/FileAPI/url/resources/fetch-tests.js#L28-L34 - t.test('works with a fragment', async (t) => { + await t.test('works with a fragment', async () => { const res = await fetch(objectURL + '#fragment') - t.equal(blobContents, await res.text()) - t.end() + assert.strictEqual(blobContents, await res.text()) }) // https://github.com/web-platform-tests/wpt/blob/7b0ebaccc62b566a1965396e5be7bb2bc06f841f/FileAPI/url/resources/fetch-tests.js#L52-L56 - t.test('Appending a query string to blob: url should cause fetch to fail', async (t) => { + await t.test('Appending a query string to blob: url should cause fetch to fail', async () => { try { await fetch(objectURL + '?querystring') - t.fail('expected ?querystring blob: url to fail') + assert.fail('expected ?querystring blob: url to fail') } catch (e) { - t.ok(e, 'Got the expected error') - } finally { - t.end() + assert.ok(e, 'Got the expected error') } }) // https://github.com/web-platform-tests/wpt/blob/7b0ebaccc62b566a1965396e5be7bb2bc06f841f/FileAPI/url/resources/fetch-tests.js#L58-L62 - t.test('Appending a path should cause fetch to fail', async (t) => { + await t.test('Appending a path should cause fetch to fail', async () => { try { await fetch(objectURL + '/path') - t.fail('expected /path blob: url to fail') + assert.fail('expected /path blob: url to fail') } catch (e) { - t.ok(e, 'Got the expected error') - } finally { - t.end() + assert.ok(e, 'Got the expected error') } }) // https://github.com/web-platform-tests/wpt/blob/7b0ebaccc62b566a1965396e5be7bb2bc06f841f/FileAPI/url/resources/fetch-tests.js#L64-L70 - t.test('these http methods should fail', async (t) => { + await t.test('these http methods should fail', async () => { for (const method of ['HEAD', 'POST', 'DELETE', 'OPTIONS', 'PUT', 'CUSTOM']) { try { await fetch(objectURL, { method }) - t.fail(`${method} fetch should have failed`) + assert.fail(`${method} fetch should have failed`) } catch (e) { - t.ok(e, `${method} blob url - test succeeded`) + assert.ok(e, `${method} blob url - test succeeded`) } } - - t.end() }) }) diff --git a/test/fetch/bundle.js b/test/fetch/bundle.js index 93e605bf357..f38b81d583f 100644 --- a/test/fetch/bundle.js +++ b/test/fetch/bundle.js @@ -1,26 +1,25 @@ 'use strict' -const { test } = require('tap') +const { test } = require('node:test') +const assert = require('node:assert') const { Response, Request, FormData, Headers } = require('../../undici-fetch') -test('bundle sets constructor.name and .name properly', (t) => { - t.equal(new Response().constructor.name, 'Response') - t.equal(Response.name, 'Response') +test('bundle sets constructor.name and .name properly', () => { + assert.strictEqual(new Response().constructor.name, 'Response') + assert.strictEqual(Response.name, 'Response') - t.equal(new Request('http://a').constructor.name, 'Request') - t.equal(Request.name, 'Request') + assert.strictEqual(new Request('http://a').constructor.name, 'Request') + assert.strictEqual(Request.name, 'Request') - t.equal(new Headers().constructor.name, 'Headers') - t.equal(Headers.name, 'Headers') + assert.strictEqual(new Headers().constructor.name, 'Headers') + assert.strictEqual(Headers.name, 'Headers') - t.equal(new FormData().constructor.name, 'FormData') - t.equal(FormData.name, 'FormData') - - t.end() + assert.strictEqual(new FormData().constructor.name, 'FormData') + assert.strictEqual(FormData.name, 'FormData') }) -test('regression test for https://github.com/nodejs/node/issues/50263', (t) => { +test('regression test for https://github.com/nodejs/node/issues/50263', () => { const request = new Request('https://a', { headers: { test: 'abc' @@ -30,6 +29,5 @@ test('regression test for https://github.com/nodejs/node/issues/50263', (t) => { const request1 = new Request(request, { body: 'does not matter' }) - t.equal(request1.headers.get('test'), 'abc') - t.end() + assert.strictEqual(request1.headers.get('test'), 'abc') }) diff --git a/test/fetch/client-error-stack-trace.js b/test/fetch/client-error-stack-trace.js index 7d94aa8b73c..ddc7f4d25cf 100644 --- a/test/fetch/client-error-stack-trace.js +++ b/test/fetch/client-error-stack-trace.js @@ -1,6 +1,7 @@ 'use strict' -const { test } = require('tap') +const { test } = require('node:test') +const assert = require('node:assert') const { fetch } = require('../..') const { fetch: fetchIndex } = require('../../index-fetch') @@ -8,7 +9,7 @@ test('FETCH: request errors and prints trimmed stack trace', async (t) => { try { await fetch('http://a.com') } catch (error) { - t.match(error.stack, `at Test. (${__filename}`) + assert.ok(error.stack.includes(`at async TestContext. (${__filename}`)) } }) @@ -16,6 +17,6 @@ test('FETCH-index: request errors and prints trimmed stack trace', async (t) => try { await fetchIndex('http://a.com') } catch (error) { - t.match(error.stack, `at Test. (${__filename}`) + assert.ok(error.stack.includes(`at async TestContext. (${__filename}`)) } }) diff --git a/test/fetch/client-fetch.js b/test/fetch/client-fetch.js index 4046785f795..70e2f6cfc6c 100644 --- a/test/fetch/client-fetch.js +++ b/test/fetch/client-fetch.js @@ -2,12 +2,13 @@ 'use strict' -const { test, teardown } = require('tap') +const { test, after } = require('node:test') +const assert = require('node:assert') +const { tspl } = require('@matteo.collina/tspl') const { createServer } = require('http') const { Blob } = require('buffer') const { fetch, Response, Request, FormData, File } = require('../..') const { Client, setGlobalDispatcher, Agent } = require('../..') -const { nodeMajor, nodeMinor } = require('../../lib/core/util') const nodeFetch = require('../../index-fetch') const { once } = require('events') const { gzipSync } = require('zlib') @@ -20,86 +21,90 @@ setGlobalDispatcher(new Agent({ })) test('function signature', (t) => { - t.plan(2) + const { strictEqual } = tspl(t, { plan: 2 }) - t.equal(fetch.name, 'fetch') - t.equal(fetch.length, 1) + strictEqual(fetch.name, 'fetch') + strictEqual(fetch.length, 1) }) test('args validation', async (t) => { - t.plan(2) + const { rejects } = tspl(t, { plan: 2 }) - await t.rejects(fetch(), TypeError) - await t.rejects(fetch('ftp://unsupported'), TypeError) + await rejects(fetch(), TypeError) + await rejects(fetch('ftp://unsupported'), TypeError) }) -test('request json', (t) => { - t.plan(1) +test('request json', (t, done) => { + const { deepStrictEqual } = tspl(t, { plan: 1 }) const obj = { asd: true } const server = createServer((req, res) => { res.end(JSON.stringify(obj)) }) - t.teardown(server.close.bind(server)) + t.after(server.close.bind(server)) server.listen(0, async () => { const body = await fetch(`http://localhost:${server.address().port}`) - t.strictSame(obj, await body.json()) + deepStrictEqual(obj, await body.json()) + done() }) }) -test('request text', (t) => { - t.plan(1) +test('request text', (t, done) => { + const { strictEqual } = tspl(t, { plan: 1 }) const obj = { asd: true } const server = createServer((req, res) => { res.end(JSON.stringify(obj)) }) - t.teardown(server.close.bind(server)) + t.after(server.close.bind(server)) server.listen(0, async () => { const body = await fetch(`http://localhost:${server.address().port}`) - t.strictSame(JSON.stringify(obj), await body.text()) + strictEqual(JSON.stringify(obj), await body.text()) + done() }) }) -test('request arrayBuffer', (t) => { - t.plan(1) +test('request arrayBuffer', (t, done) => { + const { deepStrictEqual } = tspl(t, { plan: 1 }) const obj = { asd: true } const server = createServer((req, res) => { res.end(JSON.stringify(obj)) }) - t.teardown(server.close.bind(server)) + t.after(server.close.bind(server)) server.listen(0, async () => { const body = await fetch(`http://localhost:${server.address().port}`) - t.strictSame(Buffer.from(JSON.stringify(obj)), Buffer.from(await body.arrayBuffer())) + deepStrictEqual(Buffer.from(JSON.stringify(obj)), Buffer.from(await body.arrayBuffer())) + done() }) }) -test('should set type of blob object to the value of the `Content-Type` header from response', (t) => { - t.plan(1) +test('should set type of blob object to the value of the `Content-Type` header from response', (t, done) => { + const { strictEqual } = tspl(t, { plan: 1 }) const obj = { asd: true } const server = createServer((req, res) => { res.setHeader('Content-Type', 'application/json') res.end(JSON.stringify(obj)) }) - t.teardown(server.close.bind(server)) + t.after(server.close.bind(server)) server.listen(0, async () => { const response = await fetch(`http://localhost:${server.address().port}`) - t.equal('application/json', (await response.blob()).type) + strictEqual('application/json', (await response.blob()).type) + done() }) }) -test('pre aborted with readable request body', (t) => { - t.plan(2) +test('pre aborted with readable request body', (t, done) => { + const { strictEqual } = tspl(t, { plan: 2 }) const server = createServer((req, res) => { }) - t.teardown(server.close.bind(server)) + t.after(server.close.bind(server)) server.listen(0, async () => { const ac = new AbortController() @@ -109,33 +114,33 @@ test('pre aborted with readable request body', (t) => { method: 'POST', body: new ReadableStream({ async cancel (reason) { - t.equal(reason.name, 'AbortError') + strictEqual(reason.name, 'AbortError') } }), duplex: 'half' }).catch(err => { - t.equal(err.name, 'AbortError') - }) + strictEqual(err.name, 'AbortError') + }).finally(done) }) }) -test('pre aborted with closed readable request body', (t) => { - t.plan(2) +test('pre aborted with closed readable request body', (t, done) => { + const { ok, strictEqual } = tspl(t, { plan: 2 }) const server = createServer((req, res) => { }) - t.teardown(server.close.bind(server)) + t.after(server.close.bind(server)) server.listen(0, async () => { const ac = new AbortController() ac.abort() const body = new ReadableStream({ async start (c) { - t.pass() + ok(true) c.close() }, async cancel (reason) { - t.fail() + assert.fail() } }) queueMicrotask(() => { @@ -145,32 +150,34 @@ test('pre aborted with closed readable request body', (t) => { body, duplex: 'half' }).catch(err => { - t.equal(err.name, 'AbortError') - }) + strictEqual(err.name, 'AbortError') + }).finally(done) }) }) }) -test('unsupported formData 1', (t) => { - t.plan(1) +test('unsupported formData 1', (t, done) => { + const { strictEqual } = tspl(t, { plan: 1 }) const server = createServer((req, res) => { res.setHeader('content-type', 'asdasdsad') res.end() }) - t.teardown(server.close.bind(server)) + t.after(server.close.bind(server)) server.listen(0, () => { fetch(`http://localhost:${server.address().port}`) .then(res => res.formData()) .catch(err => { - t.equal(err.name, 'TypeError') + strictEqual(err.name, 'TypeError') }) + .finally(done) }) }) test('multipart formdata not base64', async (t) => { - t.plan(2) + const { strictEqual } = tspl(t, { plan: 2 }) + // Construct example form data, with text and blob fields const formData = new FormData() formData.append('field1', 'value1') @@ -186,23 +193,21 @@ test('multipart formdata not base64', async (t) => { res.write(formRaw) res.end() }) - t.teardown(server.close.bind(server)) + t.after(server.close.bind(server)) const listen = promisify(server.listen.bind(server)) await listen(0) const res = await fetch(`http://localhost:${server.address().port}`) const form = await res.formData() - t.equal(form.get('field1'), 'value1') + strictEqual(form.get('field1'), 'value1') const text = await form.get('field2').text() - t.equal(text, 'example\ntext file') + strictEqual(text, 'example\ntext file') }) -// TODO(@KhafraDev): re-enable this test once the issue is fixed -// See https://github.com/nodejs/node/issues/47301 -test('multipart formdata base64', { skip: nodeMajor >= 19 && nodeMinor >= 8 }, (t) => { - t.plan(1) +test('multipart formdata base64', (t, done) => { + const { strictEqual } = tspl(t, { plan: 1 }) // Example form data with base64 encoding const data = randomFillSync(Buffer.alloc(256)) @@ -216,7 +221,7 @@ test('multipart formdata base64', { skip: nodeMajor >= 19 && nodeMinor >= 8 }, ( } res.end() }) - t.teardown(server.close.bind(server)) + t.after(server.close.bind(server)) server.listen(0, () => { fetch(`http://localhost:${server.address().port}`) @@ -224,13 +229,14 @@ test('multipart formdata base64', { skip: nodeMajor >= 19 && nodeMinor >= 8 }, ( .then(form => form.get('file').arrayBuffer()) .then(buffer => createHash('sha256').update(Buffer.from(buffer)).digest('base64')) .then(digest => { - t.equal(createHash('sha256').update(data).digest('base64'), digest) + strictEqual(createHash('sha256').update(data).digest('base64'), digest) }) + .finally(done) }) }) test('multipart fromdata non-ascii filed names', async (t) => { - t.plan(1) + const { strictEqual } = tspl(t, { plan: 1 }) const request = new Request('http://localhost', { method: 'POST', @@ -246,11 +252,11 @@ test('multipart fromdata non-ascii filed names', async (t) => { }) const form = await request.formData() - t.equal(form.get('fiŝo'), 'value1') + strictEqual(form.get('fiŝo'), 'value1') }) test('busboy emit error', async (t) => { - t.plan(1) + const { rejects } = tspl(t, { plan: 1 }) const formData = new FormData() formData.append('field1', 'value1') @@ -262,121 +268,125 @@ test('busboy emit error', async (t) => { res.write(formRaw) res.end() }) - t.teardown(server.close.bind(server)) + t.after(server.close.bind(server)) const listen = promisify(server.listen.bind(server)) await listen(0) const res = await fetch(`http://localhost:${server.address().port}`) - await t.rejects(res.formData(), 'Unexpected end of multipart data') + await rejects(res.formData(), 'Unexpected end of multipart data') }) // https://github.com/nodejs/undici/issues/2244 test('parsing formData preserve full path on files', async (t) => { - t.plan(1) + const { strictEqual } = tspl(t, { plan: 1 }) const formData = new FormData() formData.append('field1', new File(['foo'], 'a/b/c/foo.txt')) const tempRes = new Response(formData) const form = await tempRes.formData() - t.equal(form.get('field1').name, 'a/b/c/foo.txt') + strictEqual(form.get('field1').name, 'a/b/c/foo.txt') }) -test('urlencoded formData', (t) => { - t.plan(2) +test('urlencoded formData', (t, done) => { + const { strictEqual } = tspl(t, { plan: 2 }) const server = createServer((req, res) => { res.setHeader('content-type', 'application/x-www-form-urlencoded') res.end('field1=value1&field2=value2') }) - t.teardown(server.close.bind(server)) + t.after(server.close.bind(server)) server.listen(0, () => { fetch(`http://localhost:${server.address().port}`) .then(res => res.formData()) .then(formData => { - t.equal(formData.get('field1'), 'value1') - t.equal(formData.get('field2'), 'value2') + strictEqual(formData.get('field1'), 'value1') + strictEqual(formData.get('field2'), 'value2') }) + .finally(done) }) }) -test('text with BOM', (t) => { - t.plan(1) +test('text with BOM', (t, done) => { + const { strictEqual } = tspl(t, { plan: 1 }) const server = createServer((req, res) => { res.setHeader('content-type', 'application/x-www-form-urlencoded') res.end('\uFEFFtest=\uFEFF') }) - t.teardown(server.close.bind(server)) + t.after(server.close.bind(server)) server.listen(0, () => { fetch(`http://localhost:${server.address().port}`) .then(res => res.text()) .then(text => { - t.equal(text, 'test=\uFEFF') + strictEqual(text, 'test=\uFEFF') }) + .finally(done) }) }) -test('formData with BOM', (t) => { - t.plan(1) +test('formData with BOM', (t, done) => { + const { strictEqual } = tspl(t, { plan: 1 }) const server = createServer((req, res) => { res.setHeader('content-type', 'application/x-www-form-urlencoded') res.end('\uFEFFtest=\uFEFF') }) - t.teardown(server.close.bind(server)) + t.after(server.close.bind(server)) server.listen(0, () => { fetch(`http://localhost:${server.address().port}`) .then(res => res.formData()) .then(formData => { - t.equal(formData.get('\uFEFFtest'), '\uFEFF') + strictEqual(formData.get('\uFEFFtest'), '\uFEFF') }) + .finally(done) }) }) -test('locked blob body', (t) => { - t.plan(1) +test('locked blob body', (t, done) => { + const { strictEqual } = tspl(t, { plan: 1 }) const server = createServer((req, res) => { res.end() }) - t.teardown(server.close.bind(server)) + t.after(server.close.bind(server)) server.listen(0, async () => { const res = await fetch(`http://localhost:${server.address().port}`) const reader = res.body.getReader() res.blob().catch(err => { - t.equal(err.message, 'Body is unusable') + strictEqual(err.message, 'Body is unusable') reader.cancel() - }) + }).finally(done) }) }) -test('disturbed blob body', (t) => { - t.plan(2) +test('disturbed blob body', (t, done) => { + const { ok, strictEqual } = tspl(t, { plan: 2 }) const server = createServer((req, res) => { res.end() }) - t.teardown(server.close.bind(server)) + t.after(server.close.bind(server)) server.listen(0, async () => { const res = await fetch(`http://localhost:${server.address().port}`) - res.blob().then(() => { - t.pass(2) + await res.blob().then(() => { + ok(true) }) - res.blob().catch(err => { - t.equal(err.message, 'Body is unusable') + await res.blob().catch(err => { + strictEqual(err.message, 'Body is unusable') }) + done() }) }) -test('redirect with body', (t) => { - t.plan(3) +test('redirect with body', (t, done) => { + const { strictEqual } = tspl(t, { plan: 3 }) let count = 0 const server = createServer(async (req, res) => { @@ -384,7 +394,7 @@ test('redirect with body', (t) => { for await (const chunk of req) { body += chunk } - t.equal(body, 'asd') + strictEqual(body, 'asd') if (count++ === 0) { res.setHeader('location', 'asd') res.statusCode = 302 @@ -393,19 +403,20 @@ test('redirect with body', (t) => { res.end(String(count)) } }) - t.teardown(server.close.bind(server)) + t.after(server.close.bind(server)) server.listen(0, async () => { const res = await fetch(`http://localhost:${server.address().port}`, { method: 'PUT', body: 'asd' }) - t.equal(await res.text(), '2') + strictEqual(await res.text(), '2') + done() }) }) -test('redirect with stream', (t) => { - t.plan(3) +test('redirect with stream', (t, done) => { + const { strictEqual } = tspl(t, { plan: 3 }) const location = '/asd' const body = 'hello!' @@ -420,20 +431,21 @@ test('redirect with stream', (t) => { } }, 50) }) - t.teardown(server.close.bind(server)) + t.after(server.close.bind(server)) server.listen(0, async () => { const res = await fetch(`http://localhost:${server.address().port}`, { redirect: 'manual' }) - t.equal(res.status, 302) - t.equal(res.headers.get('location'), location) - t.equal(await res.text(), body) + strictEqual(res.status, 302) + strictEqual(res.headers.get('location'), location) + strictEqual(await res.text(), body) + done() }) }) test('fail to extract locked body', (t) => { - t.plan(1) + const { strictEqual } = tspl(t, { plan: 1 }) const stream = new ReadableStream({}) const reader = stream.getReader() @@ -441,13 +453,13 @@ test('fail to extract locked body', (t) => { // eslint-disable-next-line new Response(stream) } catch (err) { - t.equal(err.name, 'TypeError') + strictEqual(err.name, 'TypeError') } reader.cancel() }) test('fail to extract locked body', (t) => { - t.plan(1) + const { strictEqual } = tspl(t, { plan: 1 }) const stream = new ReadableStream({}) const reader = stream.getReader() @@ -459,13 +471,13 @@ test('fail to extract locked body', (t) => { keepalive: true }) } catch (err) { - t.equal(err.message, 'keepalive') + strictEqual(err.message, 'keepalive') } reader.cancel() }) -test('post FormData with Blob', (t) => { - t.plan(1) +test('post FormData with Blob', (t, done) => { + const { ok } = tspl(t, { plan: 1 }) const body = new FormData() body.append('field1', new Blob(['asd1'])) @@ -473,19 +485,20 @@ test('post FormData with Blob', (t) => { const server = createServer((req, res) => { req.pipe(res) }) - t.teardown(server.close.bind(server)) + t.after(server.close.bind(server)) server.listen(0, async () => { const res = await fetch(`http://localhost:${server.address().port}`, { method: 'PUT', body }) - t.ok(/asd1/.test(await res.text())) + ok(/asd1/.test(await res.text())) + done() }) }) -test('post FormData with File', (t) => { - t.plan(2) +test('post FormData with File', (t, done) => { + const { ok } = tspl(t, { plan: 2 }) const body = new FormData() body.append('field1', new File(['asd1'], 'filename123')) @@ -493,7 +506,7 @@ test('post FormData with File', (t) => { const server = createServer((req, res) => { req.pipe(res) }) - t.teardown(server.close.bind(server)) + t.after(server.close.bind(server)) server.listen(0, async () => { const res = await fetch(`http://localhost:${server.address().port}`, { @@ -501,29 +514,30 @@ test('post FormData with File', (t) => { body }) const result = await res.text() - t.ok(/asd1/.test(result)) - t.ok(/filename123/.test(result)) + ok(/asd1/.test(result)) + ok(/filename123/.test(result)) + done() }) }) test('invalid url', async (t) => { - t.plan(1) + const { match } = tspl(t, { plan: 1 }) try { await fetch('http://invalid') } catch (e) { - t.match(e.cause.message, 'invalid') + match(e.cause.message, /invalid/) } }) -test('custom agent', (t) => { - t.plan(2) +test('custom agent', (t, done) => { + const { ok, deepStrictEqual } = tspl(t, { plan: 2 }) const obj = { asd: true } const server = createServer((req, res) => { res.end(JSON.stringify(obj)) }) - t.teardown(server.close.bind(server)) + t.after(server.close.bind(server)) server.listen(0, async () => { const dispatcher = new Client('http://localhost:' + server.address().port, { @@ -532,25 +546,26 @@ test('custom agent', (t) => { }) const oldDispatch = dispatcher.dispatch dispatcher.dispatch = function (options, handler) { - t.pass('custom dispatcher') + ok(true) return oldDispatch.call(this, options, handler) } - t.teardown(server.close.bind(server)) + t.after(server.close.bind(server)) const body = await fetch(`http://localhost:${server.address().port}`, { dispatcher }) - t.strictSame(obj, await body.json()) + deepStrictEqual(obj, await body.json()) + done() }) }) -test('custom agent node fetch', (t) => { - t.plan(2) +test('custom agent node fetch', (t, done) => { + const { ok, deepStrictEqual } = tspl(t, { plan: 2 }) const obj = { asd: true } const server = createServer((req, res) => { res.end(JSON.stringify(obj)) }) - t.teardown(server.close.bind(server)) + t.after(server.close.bind(server)) server.listen(0, async () => { const dispatcher = new Client('http://localhost:' + server.address().port, { @@ -559,41 +574,43 @@ test('custom agent node fetch', (t) => { }) const oldDispatch = dispatcher.dispatch dispatcher.dispatch = function (options, handler) { - t.pass('custom dispatcher') + ok(true) return oldDispatch.call(this, options, handler) } - t.teardown(server.close.bind(server)) + t.after(server.close.bind(server)) const body = await nodeFetch.fetch(`http://localhost:${server.address().port}`, { dispatcher }) - t.strictSame(obj, await body.json()) + deepStrictEqual(obj, await body.json()) + done() }) }) -test('error on redirect', async (t) => { +test('error on redirect', (t, done) => { const server = createServer((req, res) => { res.statusCode = 302 res.end() }) - t.teardown(server.close.bind(server)) + t.after(server.close.bind(server)) server.listen(0, async () => { const errorCause = await fetch(`http://localhost:${server.address().port}`, { redirect: 'error' }).catch((e) => e.cause) - t.equal(errorCause.message, 'unexpected redirect') + assert.strictEqual(errorCause.message, 'unexpected redirect') + done() }) }) // https://github.com/nodejs/undici/issues/1527 test('fetching with Request object - issue #1527', async (t) => { const server = createServer((req, res) => { - t.pass() + assert.ok(true) res.end() }).listen(0) - t.teardown(server.close.bind(server)) + t.after(server.close.bind(server)) await once(server, 'listening') const body = JSON.stringify({ foo: 'bar' }) @@ -602,17 +619,16 @@ test('fetching with Request object - issue #1527', async (t) => { body }) - await t.resolves(fetch(request)) - t.end() + await assert.doesNotReject(fetch(request)) }) -test('do not decode redirect body', (t) => { - t.plan(3) +test('do not decode redirect body', (t, done) => { + const { ok, strictEqual } = tspl(t, { plan: 3 }) const obj = { asd: true } const server = createServer((req, res) => { if (req.url === '/resource') { - t.pass('we redirect') + ok(true) res.statusCode = 301 res.setHeader('location', '/resource/') // Some dumb http servers set the content-encoding gzip @@ -621,34 +637,36 @@ test('do not decode redirect body', (t) => { res.end() return } - t.pass('actual response') + ok(true) res.setHeader('content-encoding', 'gzip') res.end(gzipSync(JSON.stringify(obj))) }) - t.teardown(server.close.bind(server)) + t.after(server.close.bind(server)) server.listen(0, async () => { const body = await fetch(`http://localhost:${server.address().port}/resource`) - t.strictSame(JSON.stringify(obj), await body.text()) + strictEqual(JSON.stringify(obj), await body.text()) + done() }) }) -test('decode non-redirect body with location header', (t) => { - t.plan(2) +test('decode non-redirect body with location header', (t, done) => { + const { ok, strictEqual } = tspl(t, { plan: 2 }) const obj = { asd: true } const server = createServer((req, res) => { - t.pass('response') + ok(true) res.statusCode = 201 res.setHeader('location', '/resource/') res.setHeader('content-encoding', 'gzip') res.end(gzipSync(JSON.stringify(obj))) }) - t.teardown(server.close.bind(server)) + t.after(server.close.bind(server)) server.listen(0, async () => { const body = await fetch(`http://localhost:${server.address().port}/resource`) - t.strictSame(JSON.stringify(obj), await body.text()) + strictEqual(JSON.stringify(obj), await body.text()) + done() }) }) @@ -669,7 +687,7 @@ test('Receiving non-Latin1 headers', async (t) => { res.end() }).listen(0) - t.teardown(server.close.bind(server)) + t.after(server.close.bind(server)) await once(server, 'listening') const url = `http://localhost:${server.address().port}` @@ -679,9 +697,8 @@ test('Receiving non-Latin1 headers', async (t) => { .map(([, v]) => v) const lengths = cdHeaders.map(h => h.length) - t.same(cdHeaders, ContentDisposition) - t.same(lengths, [30, 34, 94, 104, 90]) - t.end() + assert.deepStrictEqual(cdHeaders, ContentDisposition) + assert.deepStrictEqual(lengths, [30, 34, 94, 104, 90]) }) -teardown(() => process.exit()) +after(() => process.exit()) diff --git a/test/fetch/client-node-max-header-size.js b/test/fetch/client-node-max-header-size.js index 432a576b97e..260e11ec378 100644 --- a/test/fetch/client-node-max-header-size.js +++ b/test/fetch/client-node-max-header-size.js @@ -1,23 +1,22 @@ 'use strict' const { execSync } = require('node:child_process') -const { test } = require('tap') +const { test } = require('node:test') +const assert = require('node:assert') const command = 'node -e "require(\'./undici-fetch.js\').fetch(\'https://httpbin.org/get\')"' -test("respect Node.js' --max-http-header-size", async (t) => { - t.throws( +test("respect Node.js' --max-http-header-size", async () => { + assert.throws( // TODO: Drop the `--unhandled-rejections=throw` once we drop Node.js 14 () => execSync(`${command} --max-http-header-size=1 --unhandled-rejections=throw`), /UND_ERR_HEADERS_OVERFLOW/, 'max-http-header-size=1 should throw' ) - t.doesNotThrow( + assert.doesNotThrow( () => execSync(command), /UND_ERR_HEADERS_OVERFLOW/, 'default max-http-header-size should not throw' ) - - t.end() }) diff --git a/test/fetch/content-length.js b/test/fetch/content-length.js index 9264091069b..f4fb966afbc 100644 --- a/test/fetch/content-length.js +++ b/test/fetch/content-length.js @@ -1,6 +1,7 @@ 'use strict' -const { test } = require('tap') +const { test } = require('node:test') +const assert = require('node:assert') const { createServer } = require('http') const { once } = require('events') const { Blob } = require('buffer') @@ -10,13 +11,13 @@ const { fetch, FormData } = require('../..') test('Content-Length is set when using a FormData body with fetch', async (t) => { const server = createServer((req, res) => { // TODO: check the length's value once the boundary has a fixed length - t.ok('content-length' in req.headers) // request has content-length header - t.ok(!Number.isNaN(Number(req.headers['content-length']))) + assert.ok('content-length' in req.headers) // request has content-length header + assert.ok(!Number.isNaN(Number(req.headers['content-length']))) res.end() }).listen(0) await once(server, 'listening') - t.teardown(server.close.bind(server)) + t.after(server.close.bind(server)) const fd = new FormData() fd.set('file', new Blob(['hello world 👋'], { type: 'text/plain' }), 'readme.md') diff --git a/test/fetch/cookies.js b/test/fetch/cookies.js index 18b001d8644..225aeed4e92 100644 --- a/test/fetch/cookies.js +++ b/test/fetch/cookies.js @@ -2,7 +2,9 @@ const { once } = require('events') const { createServer } = require('http') -const { test } = require('tap') +const { test } = require('node:test') +const assert = require('node:assert') +const { tspl } = require('@matteo.collina/tspl') const { fetch, Headers } = require('../..') test('Can receive set-cookie headers from a server using fetch - issue #1262', async (t) => { @@ -11,29 +13,27 @@ test('Can receive set-cookie headers from a server using fetch - issue #1262', a res.end() }).listen(0) - t.teardown(server.close.bind(server)) + t.after(server.close.bind(server)) await once(server, 'listening') const response = await fetch(`http://localhost:${server.address().port}`) - t.equal(response.headers.get('set-cookie'), 'name=value; Domain=example.com') + assert.strictEqual(response.headers.get('set-cookie'), 'name=value; Domain=example.com') const response2 = await fetch(`http://localhost:${server.address().port}`, { credentials: 'include' }) - t.equal(response2.headers.get('set-cookie'), 'name=value; Domain=example.com') - - t.end() + assert.strictEqual(response2.headers.get('set-cookie'), 'name=value; Domain=example.com') }) test('Can send cookies to a server with fetch - issue #1463', async (t) => { const server = createServer((req, res) => { - t.equal(req.headers.cookie, 'value') + assert.strictEqual(req.headers.cookie, 'value') res.end() }).listen(0) - t.teardown(server.close.bind(server)) + t.after(server.close.bind(server)) await once(server, 'listening') const headersInit = [ @@ -45,19 +45,17 @@ test('Can send cookies to a server with fetch - issue #1463', async (t) => { for (const headers of headersInit) { await fetch(`http://localhost:${server.address().port}`, { headers }) } - - t.end() }) test('Cookie header is delimited with a semicolon rather than a comma - issue #1905', async (t) => { - t.plan(1) + const { strictEqual } = tspl(t, { plan: 1 }) const server = createServer((req, res) => { - t.equal(req.headers.cookie, 'FOO=lorem-ipsum-dolor-sit-amet; BAR=the-quick-brown-fox') + strictEqual(req.headers.cookie, 'FOO=lorem-ipsum-dolor-sit-amet; BAR=the-quick-brown-fox') res.end() }).listen(0) - t.teardown(server.close.bind(server)) + t.after(server.close.bind(server)) await once(server, 'listening') await fetch(`http://localhost:${server.address().port}`, { diff --git a/test/fetch/data-uri.js b/test/fetch/data-uri.js index 6191bfe6aa5..de3c44a6eef 100644 --- a/test/fetch/data-uri.js +++ b/test/fetch/data-uri.js @@ -1,6 +1,8 @@ 'use strict' -const { test } = require('tap') +const { test } = require('node:test') +const assert = require('node:assert') +const { tspl } = require('@matteo.collina/tspl') const { URLSerializer, collectASequenceOfCodePoints, @@ -10,62 +12,52 @@ const { } = require('../../lib/fetch/dataURL') const { fetch } = require('../..') -test('https://url.spec.whatwg.org/#concept-url-serializer', (t) => { - t.test('url scheme gets appended', (t) => { +test('https://url.spec.whatwg.org/#concept-url-serializer', async (t) => { + await t.test('url scheme gets appended', () => { const url = new URL('https://www.google.com/') const serialized = URLSerializer(url) - t.ok(serialized.startsWith(url.protocol)) - t.end() + assert.ok(serialized.startsWith(url.protocol)) }) - t.test('non-null url host with authentication', (t) => { + await t.test('non-null url host with authentication', () => { const url = new URL('https://username:password@google.com') const serialized = URLSerializer(url) - t.ok(serialized.includes(`//${url.username}:${url.password}`)) - t.ok(serialized.endsWith('@google.com/')) - t.end() + assert.ok(serialized.includes(`//${url.username}:${url.password}`)) + assert.ok(serialized.endsWith('@google.com/')) }) - t.test('null url host', (t) => { + await t.test('null url host', () => { for (const url of ['web+demo:/.//not-a-host/', 'web+demo:/path/..//not-a-host/']) { - t.equal( + assert.strictEqual( URLSerializer(new URL(url)), 'web+demo:/.//not-a-host/' ) } - - t.end() }) - t.test('url with query works', (t) => { - t.equal( + await t.test('url with query works', () => { + assert.strictEqual( URLSerializer(new URL('https://www.google.com/?fetch=undici')), 'https://www.google.com/?fetch=undici' ) - - t.end() }) - t.test('exclude fragment', (t) => { - t.equal( + await t.test('exclude fragment', () => { + assert.strictEqual( URLSerializer(new URL('https://www.google.com/#frag')), 'https://www.google.com/#frag' ) - t.equal( + assert.strictEqual( URLSerializer(new URL('https://www.google.com/#frag'), true), 'https://www.google.com/' ) - - t.end() }) - - t.end() }) -test('https://infra.spec.whatwg.org/#collect-a-sequence-of-code-points', (t) => { +test('https://infra.spec.whatwg.org/#collect-a-sequence-of-code-points', () => { const input = 'text/plain;base64,' const position = { position: 0 } const result = collectASequenceOfCodePoints( @@ -74,96 +66,84 @@ test('https://infra.spec.whatwg.org/#collect-a-sequence-of-code-points', (t) => position ) - t.strictSame(result, 'text/plain') - t.strictSame(position.position, input.indexOf(';')) - t.end() + assert.strictEqual(result, 'text/plain') + assert.strictEqual(position.position, input.indexOf(';')) }) -test('https://url.spec.whatwg.org/#string-percent-decode', (t) => { - t.test('encodes %{2} in range properly', (t) => { +test('https://url.spec.whatwg.org/#string-percent-decode', async (t) => { + await t.test('encodes %{2} in range properly', () => { const input = '%FF' const percentDecoded = stringPercentDecode(input) - t.same(percentDecoded, new Uint8Array([255])) - t.end() + assert.deepStrictEqual(percentDecoded, new Uint8Array([255])) }) - t.test('encodes %{2} not in range properly', (t) => { + await t.test('encodes %{2} not in range properly', () => { const input = 'Hello %XD World' const percentDecoded = stringPercentDecode(input) const expected = [...input].map(c => c.charCodeAt(0)) - t.same(percentDecoded, expected) - t.end() + assert.deepStrictEqual(percentDecoded, new Uint8Array(expected)) }) - t.test('normal string works', (t) => { + await t.test('normal string works', () => { const input = 'Hello world' const percentDecoded = stringPercentDecode(input) const expected = [...input].map(c => c.charCodeAt(0)) - t.same(percentDecoded, Uint8Array.from(expected)) - t.end() + assert.deepStrictEqual(percentDecoded, Uint8Array.from(expected)) }) - - t.end() }) -test('https://mimesniff.spec.whatwg.org/#parse-a-mime-type', (t) => { - t.same(parseMIMEType('text/plain'), { +test('https://mimesniff.spec.whatwg.org/#parse-a-mime-type', () => { + assert.deepStrictEqual(parseMIMEType('text/plain'), { type: 'text', subtype: 'plain', parameters: new Map(), essence: 'text/plain' }) - t.same(parseMIMEType('text/html;charset="shift_jis"iso-2022-jp'), { + assert.deepStrictEqual(parseMIMEType('text/html;charset="shift_jis"iso-2022-jp'), { type: 'text', subtype: 'html', parameters: new Map([['charset', 'shift_jis']]), essence: 'text/html' }) - t.same(parseMIMEType('application/javascript'), { + assert.deepStrictEqual(parseMIMEType('application/javascript'), { type: 'application', subtype: 'javascript', parameters: new Map(), essence: 'application/javascript' }) - - t.end() }) -test('https://fetch.spec.whatwg.org/#collect-an-http-quoted-string', (t) => { +test('https://fetch.spec.whatwg.org/#collect-an-http-quoted-string', async (t) => { // https://fetch.spec.whatwg.org/#example-http-quoted-string - t.test('first', (t) => { + await t.test('first', () => { const position = { position: 0 } - t.strictSame(collectAnHTTPQuotedString('"\\', { + assert.strictEqual(collectAnHTTPQuotedString('"\\', { position: 0 }), '"\\') - t.strictSame(collectAnHTTPQuotedString('"\\', position, true), '\\') - t.strictSame(position.position, 2) - t.end() + assert.strictEqual(collectAnHTTPQuotedString('"\\', position, true), '\\') + assert.strictEqual(position.position, 2) }) - t.test('second', (t) => { + await t.test('second', () => { const position = { position: 0 } const input = '"Hello" World' - t.strictSame(collectAnHTTPQuotedString(input, { + assert.strictEqual(collectAnHTTPQuotedString(input, { position: 0 }), '"Hello"') - t.strictSame(collectAnHTTPQuotedString(input, position, true), 'Hello') - t.strictSame(position.position, 7) - t.end() + assert.strictEqual(collectAnHTTPQuotedString(input, position, true), 'Hello') + assert.strictEqual(position.position, 7) }) - - t.end() }) // https://github.com/nodejs/undici/issues/1574 -test('too long base64 url', async (t) => { +test('too long base64 url', async () => { const inputStr = 'a'.repeat(1 << 20) const base64 = Buffer.from(inputStr).toString('base64') const dataURIPrefix = 'data:application/octet-stream;base64,' @@ -172,43 +152,43 @@ test('too long base64 url', async (t) => { const res = await fetch(dataURL) const buf = await res.arrayBuffer() const outputStr = Buffer.from(buf).toString('ascii') - t.same(outputStr, inputStr) + assert.strictEqual(outputStr, inputStr) } catch (e) { - t.fail(`failed to fetch ${dataURL}`) + assert.fail(`failed to fetch ${dataURL}`) } }) test('https://domain.com/#', (t) => { - t.plan(1) + const { strictEqual } = tspl(t, { plan: 1 }) const domain = 'https://domain.com/#a' const serialized = URLSerializer(new URL(domain)) - t.equal(serialized, domain) + strictEqual(serialized, domain) }) test('https://domain.com/?', (t) => { - t.plan(1) + const { strictEqual } = tspl(t, { plan: 1 }) const domain = 'https://domain.com/?a=b' const serialized = URLSerializer(new URL(domain)) - t.equal(serialized, domain) + strictEqual(serialized, domain) }) // https://github.com/nodejs/undici/issues/2474 test('hash url', (t) => { - t.plan(1) + const { strictEqual } = tspl(t, { plan: 1 }) const domain = 'https://domain.com/#a#b' const url = new URL(domain) const serialized = URLSerializer(url, true) - t.equal(serialized, url.href.substring(0, url.href.length - url.hash.length)) + strictEqual(serialized, url.href.substring(0, url.href.length - url.hash.length)) }) // https://github.com/nodejs/undici/issues/2474 test('data url that includes the hash', async (t) => { - t.plan(1) + const { strictEqual, fail } = tspl(t, { plan: 1 }) const dataURL = 'data:,node#js#' try { const res = await fetch(dataURL) - t.equal(await res.text(), 'node') + strictEqual(await res.text(), 'node') } catch (error) { - t.fail(`failed to fetch ${dataURL}`) + fail(`failed to fetch ${dataURL}`) } }) diff --git a/test/fetch/encoding.js b/test/fetch/encoding.js index 75d8fc37d5b..fe9af0dfc25 100644 --- a/test/fetch/encoding.js +++ b/test/fetch/encoding.js @@ -1,6 +1,7 @@ 'use strict' -const { test } = require('tap') +const { test } = require('node:test') +const assert = require('node:assert') const { createServer } = require('http') const { once } = require('events') const { fetch } = require('../..') @@ -23,13 +24,13 @@ test('content-encoding header is case-iNsENsITIve', async (t) => { brotli.end() }).listen(0) - t.teardown(server.close.bind(server)) + t.after(server.close.bind(server)) await once(server, 'listening') const response = await fetch(`http://localhost:${server.address().port}`) - t.equal(await response.text(), text) - t.equal(response.headers.get('content-encoding'), contentCodings) + assert.strictEqual(await response.text(), text) + assert.strictEqual(response.headers.get('content-encoding'), contentCodings) }) test('response decompression according to content-encoding should be handled in a correct order', async (t) => { @@ -49,10 +50,10 @@ test('response decompression according to content-encoding should be handled in gzip.end() }).listen(0) - t.teardown(server.close.bind(server)) + t.after(server.close.bind(server)) await once(server, 'listening') const response = await fetch(`http://localhost:${server.address().port}`) - t.equal(await response.text(), text) + assert.strictEqual(await response.text(), text) }) diff --git a/test/fetch/fetch-leak.js b/test/fetch/fetch-leak.js index b8e6b16709f..3ea821aaa0f 100644 --- a/test/fetch/fetch-leak.js +++ b/test/fetch/fetch-leak.js @@ -1,21 +1,22 @@ 'use strict' -const { test } = require('tap') +const { test } = require('node:test') +const assert = require('node:assert') +const { tspl } = require('@matteo.collina/tspl') const { fetch } = require('../..') const { createServer } = require('http') -test('do not leak', (t) => { - t.plan(1) - +test('do not leak', (t, done) => { + const { ok } = tspl(t, { plan: 1 }) const server = createServer((req, res) => { res.end() }) - t.teardown(server.close.bind(server)) + t.after(server.close.bind(server)) let url - let done = false + let isDone = false server.listen(0, function attack () { - if (done) { + if (isDone) { return } url ??= new URL(`http://127.0.0.1:${server.address().port}`) @@ -29,16 +30,17 @@ test('do not leak', (t) => { let prev = Infinity let count = 0 const interval = setInterval(() => { - done = true + isDone = true global.gc() const next = process.memoryUsage().heapUsed if (next <= prev) { - t.pass() + ok(true) + done() } else if (count++ > 20) { - t.fail() + assert.fail() } else { prev = next } }, 1e3) - t.teardown(() => clearInterval(interval)) + t.after(() => clearInterval(interval)) }) diff --git a/test/fetch/fetch-timeouts.js b/test/fetch/fetch-timeouts.js index b659aaa08d6..6fe72be969c 100644 --- a/test/fetch/fetch-timeouts.js +++ b/test/fetch/fetch-timeouts.js @@ -1,25 +1,25 @@ 'use strict' -const { test } = require('tap') +const { test } = require('node:test') +const { tspl } = require('@matteo.collina/tspl') const { fetch, Agent } = require('../..') const timers = require('../../lib/timers') const { createServer } = require('http') const FakeTimers = require('@sinonjs/fake-timers') -test('Fetch very long request, timeout overridden so no error', (t) => { +test('Fetch very long request, timeout overridden so no error', (t, done) => { const minutes = 6 const msToDelay = 1000 * 60 * minutes - t.setTimeout(undefined) - t.plan(1) + const { strictEqual } = tspl(t, { plan: 1 }) const clock = FakeTimers.install() - t.teardown(clock.uninstall.bind(clock)) + t.after(clock.uninstall.bind(clock)) const orgTimers = { ...timers } Object.assign(timers, { setTimeout, clearTimeout }) - t.teardown(() => { + t.after(() => { Object.assign(timers, orgTimers) }) @@ -29,7 +29,7 @@ test('Fetch very long request, timeout overridden so no error', (t) => { }, msToDelay) clock.tick(msToDelay + 1) }) - t.teardown(server.close.bind(server)) + t.after(server.close.bind(server)) server.listen(0, () => { fetch(`http://localhost:${server.address().port}`, { @@ -43,12 +43,12 @@ test('Fetch very long request, timeout overridden so no error', (t) => { }) .then((response) => response.text()) .then((response) => { - t.equal('hello', response) - t.end() + strictEqual('hello', response) + done() }) .catch((err) => { // This should not happen, a timeout error should not occur - t.error(err) + throw err }) clock.tick(msToDelay - 1) diff --git a/test/fetch/file.js b/test/fetch/file.js index 59015413eb0..0e2cac2f10c 100644 --- a/test/fetch/file.js +++ b/test/fetch/file.js @@ -1,190 +1,177 @@ 'use strict' const { Blob } = require('buffer') -const { test } = require('tap') +const { test } = require('node:test') +const assert = require('node:assert') +const { tspl } = require('@matteo.collina/tspl') const { File, FileLike } = require('../../lib/fetch/file') test('args validation', (t) => { - t.plan(14) + const { throws, doesNotThrow, strictEqual } = tspl(t, { plan: 14 }) - t.throws(() => { + throws(() => { File.prototype.name.toString() }, TypeError) - t.throws(() => { + throws(() => { File.prototype.lastModified.toString() }, TypeError) - t.doesNotThrow(() => { + doesNotThrow(() => { File.prototype[Symbol.toStringTag].charAt(0) }, TypeError) - t.throws(() => { + throws(() => { FileLike.prototype.stream.call(null) }, TypeError) - t.throws(() => { + throws(() => { FileLike.prototype.arrayBuffer.call(null) }, TypeError) - t.throws(() => { + throws(() => { FileLike.prototype.slice.call(null) }, TypeError) - t.throws(() => { + throws(() => { FileLike.prototype.text.call(null) }, TypeError) - t.throws(() => { + throws(() => { FileLike.prototype.size.toString() }, TypeError) - t.throws(() => { + throws(() => { FileLike.prototype.type.toString() }, TypeError) - t.throws(() => { + throws(() => { FileLike.prototype.name.toString() }, TypeError) - t.throws(() => { + throws(() => { FileLike.prototype.lastModified.toString() }, TypeError) - t.doesNotThrow(() => { + doesNotThrow(() => { FileLike.prototype[Symbol.toStringTag].charAt(0) }, TypeError) - t.equal(File.prototype[Symbol.toStringTag], 'File') - t.equal(FileLike.prototype[Symbol.toStringTag], 'File') + strictEqual(File.prototype[Symbol.toStringTag], 'File') + strictEqual(FileLike.prototype[Symbol.toStringTag], 'File') }) test('return value of File.lastModified', (t) => { - t.plan(2) + const { ok } = tspl(t, { plan: 2 }) const f = new File(['asd1'], 'filename123') const lastModified = f.lastModified - t.ok(typeof lastModified === typeof Date.now()) - t.ok(lastModified >= 0 && lastModified <= Date.now()) + ok(typeof lastModified === typeof Date.now()) + ok(lastModified >= 0 && lastModified <= Date.now()) }) test('Symbol.toStringTag', (t) => { - t.plan(2) - t.equal(new File([], '')[Symbol.toStringTag], 'File') - t.equal(new FileLike()[Symbol.toStringTag], 'File') + const { strictEqual } = tspl(t, { plan: 2 }) + strictEqual(new File([], '')[Symbol.toStringTag], 'File') + strictEqual(new FileLike()[Symbol.toStringTag], 'File') }) -test('arguments', (t) => { - t.throws(() => { +test('arguments', () => { + assert.throws(() => { new File() // eslint-disable-line no-new }, TypeError) - t.throws(() => { + assert.throws(() => { new File([]) // eslint-disable-line no-new }, TypeError) - - t.end() }) -test('lastModified', (t) => { +test('lastModified', () => { const file = new File([], '') const lastModified = Date.now() - 69_000 - t.notOk(file === 0) + assert.ok(file !== 0) const file1 = new File([], '', { lastModified }) - t.equal(file1.lastModified, lastModified) + assert.strictEqual(file1.lastModified, lastModified) - t.equal(new File([], '', { lastModified: 0 }).lastModified, 0) + assert.strictEqual(new File([], '', { lastModified: 0 }).lastModified, 0) - t.equal( + assert.strictEqual( new File([], '', { lastModified: true }).lastModified, 1 ) - - t.end() }) test('File.prototype.text', async (t) => { - t.test('With Blob', async (t) => { + await t.test('With Blob', async () => { const blob1 = new Blob(['hello']) const blob2 = new Blob([' ']) const blob3 = new Blob(['world']) const file = new File([blob1, blob2, blob3], 'hello_world.txt') - t.equal(await file.text(), 'hello world') - t.end() + assert.strictEqual(await file.text(), 'hello world') }) /* eslint-disable camelcase */ - t.test('With TypedArray', async (t) => { + await t.test('With TypedArray', async () => { const uint8_1 = new Uint8Array(Buffer.from('hello')) const uint8_2 = new Uint8Array(Buffer.from(' ')) const uint8_3 = new Uint8Array(Buffer.from('world')) const file = new File([uint8_1, uint8_2, uint8_3], 'hello_world.txt') - t.equal(await file.text(), 'hello world') - t.end() + assert.strictEqual(await file.text(), 'hello world') }) - t.test('With TypedArray range', async (t) => { + await t.test('With TypedArray range', async () => { const uint8_1 = new Uint8Array(Buffer.from('hello world')) const uint8_2 = new Uint8Array(uint8_1.buffer, 1, 4) const file = new File([uint8_2], 'hello_world.txt') - t.equal(await file.text(), 'ello') - t.end() + assert.strictEqual(await file.text(), 'ello') }) /* eslint-enable camelcase */ - t.test('With ArrayBuffer', async (t) => { + await t.test('With ArrayBuffer', async () => { const uint8 = new Uint8Array([65, 66, 67]) const ab = uint8.buffer const file = new File([ab], 'file.txt') - t.equal(await file.text(), 'ABC') - t.end() + assert.strictEqual(await file.text(), 'ABC') }) - t.test('With string', async (t) => { + await t.test('With string', async () => { const string = 'hello world' const file = new File([string], 'hello_world.txt') - t.equal(await file.text(), 'hello world') - t.end() + assert.strictEqual(await file.text(), 'hello world') }) - t.test('With Buffer', async (t) => { + await t.test('With Buffer', async () => { const buffer = Buffer.from('hello world') const file = new File([buffer], 'hello_world.txt') - t.equal(await file.text(), 'hello world') - t.end() + assert.strictEqual(await file.text(), 'hello world') }) - t.test('Mixed', async (t) => { + await t.test('Mixed', async () => { const blob = new Blob(['Hello, ']) const uint8 = new Uint8Array(Buffer.from('world! This')) const string = ' is a test! Hope it passes!' const file = new File([blob, uint8, string], 'mixed-messages.txt') - t.equal( + assert.strictEqual( await file.text(), 'Hello, world! This is a test! Hope it passes!' ) - t.end() }) - - t.end() }) -test('endings=native', async (t) => { +test('endings=native', async () => { const file = new File(['Hello\nWorld'], 'text.txt', { endings: 'native' }) const text = await file.text() if (process.platform === 'win32') { - t.equal(text, 'Hello\r\nWorld', 'on windows, LF is replace with CRLF') + assert.strictEqual(text, 'Hello\r\nWorld', 'on windows, LF is replace with CRLF') } else { - t.equal(text, 'Hello\nWorld', `on ${process.platform} LF stays LF`) + assert.strictEqual(text, 'Hello\nWorld', `on ${process.platform} LF stays LF`) } - - t.end() }) diff --git a/test/fetch/formdata.js b/test/fetch/formdata.js index fed95bfb3da..157b7a77868 100644 --- a/test/fetch/formdata.js +++ b/test/fetch/formdata.js @@ -1,236 +1,224 @@ 'use strict' -const { test } = require('tap') +const { test } = require('node:test') +const assert = require('node:assert') +const { tspl } = require('@matteo.collina/tspl') const { FormData, File, Response } = require('../../') const { Blob: ThirdPartyBlob } = require('formdata-node') const { Blob } = require('buffer') const { isFormDataLike } = require('../../lib/core/util') const ThirdPartyFormDataInvalid = require('form-data') -test('arg validation', (t) => { +test('arg validation', () => { const form = new FormData() // constructor - t.throws(() => { + assert.throws(() => { // eslint-disable-next-line new FormData('asd') }, TypeError) // append - t.throws(() => { + assert.throws(() => { FormData.prototype.append.call(null) }, TypeError) - t.throws(() => { + assert.throws(() => { form.append() }, TypeError) - t.throws(() => { + assert.throws(() => { form.append('k', 'not usv', '') }, TypeError) // delete - t.throws(() => { + assert.throws(() => { FormData.prototype.delete.call(null) }, TypeError) - t.throws(() => { + assert.throws(() => { form.delete() }, TypeError) // get - t.throws(() => { + assert.throws(() => { FormData.prototype.get.call(null) }, TypeError) - t.throws(() => { + assert.throws(() => { form.get() }, TypeError) // getAll - t.throws(() => { + assert.throws(() => { FormData.prototype.getAll.call(null) }, TypeError) - t.throws(() => { + assert.throws(() => { form.getAll() }, TypeError) // has - t.throws(() => { + assert.throws(() => { FormData.prototype.has.call(null) }, TypeError) - t.throws(() => { + assert.throws(() => { form.has() }, TypeError) // set - t.throws(() => { + assert.throws(() => { FormData.prototype.set.call(null) }, TypeError) - t.throws(() => { + assert.throws(() => { form.set('k') }, TypeError) - t.throws(() => { + assert.throws(() => { form.set('k', 'not usv', '') }, TypeError) // iterator - t.throws(() => { + assert.throws(() => { Reflect.apply(FormData.prototype[Symbol.iterator], null) }, TypeError) // toStringTag - t.doesNotThrow(() => { + assert.doesNotThrow(() => { FormData.prototype[Symbol.toStringTag].charAt(0) }) - - t.end() }) -test('append file', (t) => { +test('append file', () => { const form = new FormData() form.set('asd', new File([], 'asd1', { type: 'text/plain' }), 'asd2') form.append('asd2', new File([], 'asd1'), 'asd2') - t.equal(form.has('asd'), true) - t.equal(form.has('asd2'), true) - t.equal(form.get('asd').name, 'asd2') - t.equal(form.get('asd2').name, 'asd2') - t.equal(form.get('asd').type, 'text/plain') + assert.strictEqual(form.has('asd'), true) + assert.strictEqual(form.has('asd2'), true) + assert.strictEqual(form.get('asd').name, 'asd2') + assert.strictEqual(form.get('asd2').name, 'asd2') + assert.strictEqual(form.get('asd').type, 'text/plain') form.delete('asd') - t.equal(form.get('asd'), null) - t.equal(form.has('asd2'), true) - t.equal(form.has('asd'), false) - - t.end() + assert.strictEqual(form.get('asd'), null) + assert.strictEqual(form.has('asd2'), true) + assert.strictEqual(form.has('asd'), false) }) -test('append blob', async (t) => { +test('append blob', async () => { const form = new FormData() form.set('asd', new Blob(['asd1'], { type: 'text/plain' })) - t.equal(form.has('asd'), true) - t.equal(form.get('asd').type, 'text/plain') - t.equal(await form.get('asd').text(), 'asd1') + assert.strictEqual(form.has('asd'), true) + assert.strictEqual(form.get('asd').type, 'text/plain') + assert.strictEqual(await form.get('asd').text(), 'asd1') form.delete('asd') - t.equal(form.get('asd'), null) - - t.end() + assert.strictEqual(form.get('asd'), null) }) -test('append third-party blob', async (t) => { +test('append third-party blob', async () => { const form = new FormData() form.set('asd', new ThirdPartyBlob(['asd1'], { type: 'text/plain' })) - t.equal(form.has('asd'), true) - t.equal(form.get('asd').type, 'text/plain') - t.equal(await form.get('asd').text(), 'asd1') + assert.strictEqual(form.has('asd'), true) + assert.strictEqual(form.get('asd').type, 'text/plain') + assert.strictEqual(await form.get('asd').text(), 'asd1') form.delete('asd') - t.equal(form.get('asd'), null) - - t.end() + assert.strictEqual(form.get('asd'), null) }) -test('append string', (t) => { +test('append string', () => { const form = new FormData() form.set('k1', 'v1') form.set('k2', 'v2') - t.same([...form], [['k1', 'v1'], ['k2', 'v2']]) - t.equal(form.has('k1'), true) - t.equal(form.get('k1'), 'v1') + assert.deepStrictEqual([...form], [['k1', 'v1'], ['k2', 'v2']]) + assert.strictEqual(form.has('k1'), true) + assert.strictEqual(form.get('k1'), 'v1') form.append('k1', 'v1+') - t.same(form.getAll('k1'), ['v1', 'v1+']) + assert.deepStrictEqual(form.getAll('k1'), ['v1', 'v1+']) form.set('k2', 'v1++') - t.equal(form.get('k2'), 'v1++') + assert.strictEqual(form.get('k2'), 'v1++') form.delete('asd') - t.equal(form.get('asd'), null) - t.end() + assert.strictEqual(form.get('asd'), null) }) -test('formData.entries', (t) => { - t.plan(2) +test('formData.entries', async (t) => { const form = new FormData() - t.test('with 0 entries', (t) => { - t.plan(1) + await t.test('with 0 entries', (t) => { + const { deepStrictEqual } = tspl(t, { plan: 1 }) const entries = [...form.entries()] - t.same(entries, []) + deepStrictEqual(entries, []) }) - t.test('with 1+ entries', (t) => { - t.plan(2) + await t.test('with 1+ entries', (t) => { + const { deepStrictEqual } = tspl(t, { plan: 2 }) form.set('k1', 'v1') form.set('k2', 'v2') const entries = [...form.entries()] const entries2 = [...form.entries()] - t.same(entries, [['k1', 'v1'], ['k2', 'v2']]) - t.same(entries, entries2) + deepStrictEqual(entries, [['k1', 'v1'], ['k2', 'v2']]) + deepStrictEqual(entries, entries2) }) }) -test('formData.keys', (t) => { - t.plan(2) +test('formData.keys', async (t) => { const form = new FormData() - t.test('with 0 keys', (t) => { - t.plan(1) + await t.test('with 0 keys', (t) => { + const { deepStrictEqual } = tspl(t, { plan: 1 }) const keys = [...form.entries()] - t.same(keys, []) + deepStrictEqual(keys, []) }) - t.test('with 1+ keys', (t) => { - t.plan(2) + await t.test('with 1+ keys', (t) => { + const { deepStrictEqual } = tspl(t, { plan: 2 }) form.set('k1', 'v1') form.set('k2', 'v2') const keys = [...form.keys()] const keys2 = [...form.keys()] - t.same(keys, ['k1', 'k2']) - t.same(keys, keys2) + deepStrictEqual(keys, ['k1', 'k2']) + deepStrictEqual(keys, keys2) }) }) -test('formData.values', (t) => { - t.plan(2) +test('formData.values', async (t) => { const form = new FormData() - t.test('with 0 values', (t) => { - t.plan(1) + await t.test('with 0 values', (t) => { + const { deepStrictEqual } = tspl(t, { plan: 1 }) const values = [...form.values()] - t.same(values, []) + deepStrictEqual(values, []) }) - t.test('with 1+ values', (t) => { - t.plan(2) + await t.test('with 1+ values', (t) => { + const { deepStrictEqual } = tspl(t, { plan: 2 }) form.set('k1', 'v1') form.set('k2', 'v2') const values = [...form.values()] const values2 = [...form.values()] - t.same(values, ['v1', 'v2']) - t.same(values, values2) + deepStrictEqual(values, ['v1', 'v2']) + deepStrictEqual(values, values2) }) }) -test('formData forEach', (t) => { - t.test('invalid arguments', (t) => { - t.throws(() => { +test('formData forEach', async (t) => { + await t.test('invalid arguments', () => { + assert.throws(() => { FormData.prototype.forEach.call({}) }, TypeError('Illegal invocation')) - t.throws(() => { + assert.throws(() => { const fd = new FormData() fd.forEach({}) }, TypeError) - - t.end() }) - t.test('with a callback', (t) => { + await t.test('with a callback', () => { const fd = new FormData() fd.set('a', 'b') @@ -239,58 +227,48 @@ test('formData forEach', (t) => { let i = 0 fd.forEach((value, key, self) => { if (i++ === 0) { - t.equal(value, 'b') - t.equal(key, 'a') + assert.strictEqual(value, 'b') + assert.strictEqual(key, 'a') } else { - t.equal(value, 'd') - t.equal(key, 'c') + assert.strictEqual(value, 'd') + assert.strictEqual(key, 'c') } - t.equal(fd, self) + assert.strictEqual(fd, self) }) - - t.end() }) - t.test('with a thisArg', (t) => { + await t.test('with a thisArg', () => { const fd = new FormData() fd.set('b', 'a') fd.forEach(function (value, key, self) { - t.equal(this, globalThis) - t.equal(fd, self) - t.equal(key, 'b') - t.equal(value, 'a') + assert.strictEqual(this, globalThis) + assert.strictEqual(fd, self) + assert.strictEqual(key, 'b') + assert.strictEqual(value, 'a') }) const thisArg = Symbol('thisArg') fd.forEach(function () { - t.equal(this, thisArg) + assert.strictEqual(this, thisArg) }, thisArg) - - t.end() }) - - t.end() }) -test('formData toStringTag', (t) => { +test('formData toStringTag', () => { const form = new FormData() - t.equal(form[Symbol.toStringTag], 'FormData') - t.equal(FormData.prototype[Symbol.toStringTag], 'FormData') - t.end() + assert.strictEqual(form[Symbol.toStringTag], 'FormData') + assert.strictEqual(FormData.prototype[Symbol.toStringTag], 'FormData') }) -test('formData.constructor.name', (t) => { +test('formData.constructor.name', () => { const form = new FormData() - t.equal(form.constructor.name, 'FormData') - t.end() + assert.strictEqual(form.constructor.name, 'FormData') }) -test('formData should be an instance of FormData', (t) => { - t.plan(3) - - t.test('Invalid class FormData', (t) => { +test('formData should be an instance of FormData', async (t) => { + await t.test('Invalid class FormData', () => { class FormData { constructor () { this.data = [] @@ -306,11 +284,10 @@ test('formData should be an instance of FormData', (t) => { } const form = new FormData() - t.equal(isFormDataLike(form), false) - t.end() + assert.strictEqual(isFormDataLike(form), false) }) - t.test('Invalid function FormData', (t) => { + await t.test('Invalid function FormData', () => { function FormData () { const data = [] return { @@ -324,25 +301,22 @@ test('formData should be an instance of FormData', (t) => { } const form = new FormData() - t.equal(isFormDataLike(form), false) - t.end() + assert.strictEqual(isFormDataLike(form), false) }) - test('Invalid third-party FormData', (t) => { + await t.test('Invalid third-party FormData', () => { const form = new ThirdPartyFormDataInvalid() - t.equal(isFormDataLike(form), false) - t.end() + assert.strictEqual(isFormDataLike(form), false) }) - t.test('Valid FormData', (t) => { + await t.test('Valid FormData', () => { const form = new FormData() - t.equal(isFormDataLike(form), true) - t.end() + assert.strictEqual(isFormDataLike(form), true) }) }) test('FormData should be compatible with third-party libraries', (t) => { - t.plan(1) + const { strictEqual } = tspl(t, { plan: 1 }) class FormData { constructor () { @@ -366,23 +340,21 @@ test('FormData should be compatible with third-party libraries', (t) => { } const form = new FormData() - t.equal(isFormDataLike(form), true) + strictEqual(isFormDataLike(form), true) }) -test('arguments', (t) => { - t.equal(FormData.constructor.length, 1) - t.equal(FormData.prototype.append.length, 2) - t.equal(FormData.prototype.delete.length, 1) - t.equal(FormData.prototype.get.length, 1) - t.equal(FormData.prototype.getAll.length, 1) - t.equal(FormData.prototype.has.length, 1) - t.equal(FormData.prototype.set.length, 2) - - t.end() +test('arguments', () => { + assert.strictEqual(FormData.constructor.length, 1) + assert.strictEqual(FormData.prototype.append.length, 2) + assert.strictEqual(FormData.prototype.delete.length, 1) + assert.strictEqual(FormData.prototype.get.length, 1) + assert.strictEqual(FormData.prototype.getAll.length, 1) + assert.strictEqual(FormData.prototype.has.length, 1) + assert.strictEqual(FormData.prototype.set.length, 2) }) // https://github.com/nodejs/undici/pull/1814 -test('FormData returned from bodyMixin.formData is not a clone', async (t) => { +test('FormData returned from bodyMixin.formData is not a clone', async () => { const fd = new FormData() fd.set('foo', 'bar') @@ -391,11 +363,11 @@ test('FormData returned from bodyMixin.formData is not a clone', async (t) => { const fd2 = await res.formData() - t.equal(fd2.get('foo'), 'bar') - t.equal(fd.get('foo'), 'foo') + assert.strictEqual(fd2.get('foo'), 'bar') + assert.strictEqual(fd.get('foo'), 'foo') fd2.set('foo', 'baz') - t.equal(fd2.get('foo'), 'baz') - t.equal(fd.get('foo'), 'foo') + assert.strictEqual(fd2.get('foo'), 'baz') + assert.strictEqual(fd.get('foo'), 'foo') }) diff --git a/test/fetch/general.js b/test/fetch/general.js index 0469875aa2d..e93e67ba794 100644 --- a/test/fetch/general.js +++ b/test/fetch/general.js @@ -1,6 +1,7 @@ 'use strict' -const { test } = require('tap') +const { test } = require('node:test') +const assert = require('node:assert') const { File, FormData, @@ -9,7 +10,7 @@ const { Response } = require('../../index') -test('Symbol.toStringTag descriptor', (t) => { +test('Symbol.toStringTag descriptor', () => { for (const cls of [ File, FormData, @@ -18,13 +19,11 @@ test('Symbol.toStringTag descriptor', (t) => { Response ]) { const desc = Object.getOwnPropertyDescriptor(cls.prototype, Symbol.toStringTag) - t.same(desc, { + assert.deepStrictEqual(desc, { value: cls.name, writable: false, enumerable: false, configurable: true }) } - - t.end() }) diff --git a/test/fetch/headers.js b/test/fetch/headers.js index fcf6f5f4891..51218f12ee9 100644 --- a/test/fetch/headers.js +++ b/test/fetch/headers.js @@ -1,119 +1,115 @@ 'use strict' -const tap = require('tap') +const { test } = require('node:test') +const assert = require('node:assert') +const { tspl } = require('@matteo.collina/tspl') const { Headers, fill } = require('../../lib/fetch/headers') const { kGuard } = require('../../lib/fetch/symbols') const { once } = require('events') const { fetch } = require('../..') const { createServer } = require('http') -tap.test('Headers initialization', t => { - t.plan(8) +test('Headers initialization', async (t) => { + await t.test('allows undefined', () => { + const { doesNotThrow } = tspl(t, { plan: 1 }) - t.test('allows undefined', t => { - t.plan(1) - - t.doesNotThrow(() => new Headers()) + doesNotThrow(() => new Headers()) }) - t.test('with array of header entries', t => { - t.plan(3) - - t.test('fails on invalid array-based init', t => { - t.plan(3) - t.throws( + await t.test('with array of header entries', async (t) => { + await t.test('fails on invalid array-based init', (t) => { + const { throws } = tspl(t, { plan: 3 }) + throws( () => new Headers([['undici', 'fetch'], ['fetch']]), TypeError('Headers constructor: expected name/value pair to be length 2, found 1.') ) - t.throws(() => new Headers(['undici', 'fetch', 'fetch']), TypeError) - t.throws( + throws(() => new Headers(['undici', 'fetch', 'fetch']), TypeError) + throws( () => new Headers([0, 1, 2]), TypeError('Sequence: Value of type Number is not an Object.') ) }) - t.test('allows even length init', t => { - t.plan(1) + await t.test('allows even length init', (t) => { + const { doesNotThrow } = tspl(t, { plan: 1 }) const init = [['undici', 'fetch'], ['fetch', 'undici']] - t.doesNotThrow(() => new Headers(init)) + doesNotThrow(() => new Headers(init)) }) - t.test('fails for event flattened init', t => { - t.plan(1) + await t.test('fails for event flattened init', (t) => { + const { throws } = tspl(t, { plan: 1 }) const init = ['undici', 'fetch', 'fetch', 'undici'] - t.throws( + throws( () => new Headers(init), TypeError('Sequence: Value of type String is not an Object.') ) }) }) - t.test('with object of header entries', t => { - t.plan(1) + await t.test('with object of header entries', (t) => { + const { doesNotThrow } = tspl(t, { plan: 1 }) const init = { undici: 'fetch', fetch: 'undici' } - t.doesNotThrow(() => new Headers(init)) + doesNotThrow(() => new Headers(init)) }) - t.test('fails silently if a boxed primitive object is passed', t => { - t.plan(3) + await t.test('fails silently if a boxed primitive object is passed', (t) => { + const { doesNotThrow } = tspl(t, { plan: 3 }) /* eslint-disable no-new-wrappers */ - t.doesNotThrow(() => new Headers(new Number())) - t.doesNotThrow(() => new Headers(new Boolean())) - t.doesNotThrow(() => new Headers(new String())) + doesNotThrow(() => new Headers(new Number())) + doesNotThrow(() => new Headers(new Boolean())) + doesNotThrow(() => new Headers(new String())) /* eslint-enable no-new-wrappers */ }) - t.test('fails if primitive is passed', t => { - t.plan(2) + await t.test('fails if primitive is passed', (t) => { + const { throws } = tspl(t, { plan: 2 }) const expectedTypeError = TypeError - t.throws(() => new Headers(1), expectedTypeError) - t.throws(() => new Headers('1'), expectedTypeError) + throws(() => new Headers(1), expectedTypeError) + throws(() => new Headers('1'), expectedTypeError) }) - t.test('allows some weird stuff (because of webidl)', t => { - t.doesNotThrow(() => { + await t.test('allows some weird stuff (because of webidl)', () => { + assert.doesNotThrow(() => { new Headers(function () {}) // eslint-disable-line no-new }) - t.doesNotThrow(() => { + assert.doesNotThrow(() => { new Headers(Function) // eslint-disable-line no-new }) - - t.end() }) - t.test('allows a myriad of header values to be passed', t => { - t.plan(4) + await t.test('allows a myriad of header values to be passed', (t) => { + const { doesNotThrow, throws } = tspl(t, { plan: 4 }) // Headers constructor uses Headers.append - t.doesNotThrow(() => new Headers([ + doesNotThrow(() => new Headers([ ['a', ['b', 'c']], ['d', ['e', 'f']] ]), 'allows any array values') - t.doesNotThrow(() => new Headers([ + doesNotThrow(() => new Headers([ ['key', null] ]), 'allows null values') - t.throws(() => new Headers([ + throws(() => new Headers([ ['key'] ]), 'throws when 2 arguments are not passed') - t.throws(() => new Headers([ + throws(() => new Headers([ ['key', 'value', 'value2'] ]), 'throws when too many arguments are passed') }) - t.test('accepts headers as objects with array values', t => { - t.plan(1) + await t.test('accepts headers as objects with array values', (t) => { + const { deepStrictEqual } = tspl(t, { plan: 1 }) const headers = new Headers({ c: '5', b: ['3', '4'], a: ['1', '2'] }) - t.same([...headers.entries()], [ + deepStrictEqual([...headers.entries()], [ ['a', '1,2'], ['b', '3,4'], ['c', '5'] @@ -121,21 +117,19 @@ tap.test('Headers initialization', t => { }) }) -tap.test('Headers append', t => { - t.plan(3) - - t.test('adds valid header entry to instance', t => { - t.plan(2) +test('Headers append', async (t) => { + await t.test('adds valid header entry to instance', (t) => { + const { doesNotThrow, strictEqual } = tspl(t, { plan: 2 }) const headers = new Headers() const name = 'undici' const value = 'fetch' - t.doesNotThrow(() => headers.append(name, value)) - t.equal(headers.get(name), value) + doesNotThrow(() => headers.append(name, value)) + strictEqual(headers.get(name), value) }) - t.test('adds valid header to existing entry', t => { - t.plan(4) + await t.test('adds valid header to existing entry', (t) => { + const { strictEqual, doesNotThrow } = tspl(t, { plan: 4 }) const headers = new Headers() const name = 'undici' @@ -143,218 +137,200 @@ tap.test('Headers append', t => { const value2 = 'fetch2' const value3 = 'fetch3' headers.append(name, value1) - t.equal(headers.get(name), value1) - t.doesNotThrow(() => headers.append(name, value2)) - t.doesNotThrow(() => headers.append(name, value3)) - t.equal(headers.get(name), [value1, value2, value3].join(', ')) + strictEqual(headers.get(name), value1) + doesNotThrow(() => headers.append(name, value2)) + doesNotThrow(() => headers.append(name, value3)) + strictEqual(headers.get(name), [value1, value2, value3].join(', ')) }) - t.test('throws on invalid entry', t => { - t.plan(3) + await t.test('throws on invalid entry', (t) => { + const { throws } = tspl(t, { plan: 3 }) const headers = new Headers() - t.throws(() => headers.append(), 'throws on missing name and value') - t.throws(() => headers.append('undici'), 'throws on missing value') - t.throws(() => headers.append('invalid @ header ? name', 'valid value'), 'throws on invalid name') + throws(() => headers.append(), 'throws on missing name and value') + throws(() => headers.append('undici'), 'throws on missing value') + throws(() => headers.append('invalid @ header ? name', 'valid value'), 'throws on invalid name') }) }) -tap.test('Headers delete', t => { - t.plan(4) - - t.test('deletes valid header entry from instance', t => { - t.plan(3) +test('Headers delete', async (t) => { + await t.test('deletes valid header entry from instance', (t) => { + const { strictEqual, doesNotThrow } = tspl(t, { plan: 3 }) const headers = new Headers() const name = 'undici' const value = 'fetch' headers.append(name, value) - t.equal(headers.get(name), value) - t.doesNotThrow(() => headers.delete(name)) - t.equal(headers.get(name), null) + strictEqual(headers.get(name), value) + doesNotThrow(() => headers.delete(name)) + strictEqual(headers.get(name), null) }) - t.test('does not mutate internal list when no match is found', t => { - t.plan(3) + await t.test('does not mutate internal list when no match is found', (t) => { + const { strictEqual, doesNotThrow } = tspl(t, { plan: 3 }) const headers = new Headers() const name = 'undici' const value = 'fetch' headers.append(name, value) - t.equal(headers.get(name), value) - t.doesNotThrow(() => headers.delete('not-undici')) - t.equal(headers.get(name), value) + strictEqual(headers.get(name), value) + doesNotThrow(() => headers.delete('not-undici')) + strictEqual(headers.get(name), value) }) - t.test('throws on invalid entry', t => { - t.plan(2) + await t.test('throws on invalid entry', (t) => { + const { throws } = tspl(t, { plan: 2 }) const headers = new Headers() - t.throws(() => headers.delete(), 'throws on missing namee') - t.throws(() => headers.delete('invalid @ header ? name'), 'throws on invalid name') + throws(() => headers.delete(), 'throws on missing namee') + throws(() => headers.delete('invalid @ header ? name'), 'throws on invalid name') }) // https://github.com/nodejs/undici/issues/2429 - t.test('`Headers#delete` returns undefined', t => { - t.plan(2) + await t.test('`Headers#delete` returns undefined', (t) => { + const { strictEqual } = tspl(t, { plan: 2 }) const headers = new Headers({ test: 'test' }) - t.same(headers.delete('test'), undefined) - t.same(headers.delete('test2'), undefined) + strictEqual(headers.delete('test'), undefined) + strictEqual(headers.delete('test2'), undefined) }) }) -tap.test('Headers get', t => { - t.plan(3) - - t.test('returns null if not found in instance', t => { - t.plan(1) +test('Headers get', async (t) => { + await t.test('returns null if not found in instance', (t) => { + const { strictEqual } = tspl(t, { plan: 1 }) const headers = new Headers() headers.append('undici', 'fetch') - t.equal(headers.get('not-undici'), null) + strictEqual(headers.get('not-undici'), null) }) - t.test('returns header values from valid header name', t => { - t.plan(2) + await t.test('returns header values from valid header name', (t) => { + const { strictEqual } = tspl(t, { plan: 2 }) const headers = new Headers() const name = 'undici'; const value1 = 'fetch1'; const value2 = 'fetch2' headers.append(name, value1) - t.equal(headers.get(name), value1) + strictEqual(headers.get(name), value1) headers.append(name, value2) - t.equal(headers.get(name), [value1, value2].join(', ')) + strictEqual(headers.get(name), [value1, value2].join(', ')) }) - t.test('throws on invalid entry', t => { - t.plan(2) + await t.test('throws on invalid entry', (t) => { + const { throws } = tspl(t, { plan: 2 }) const headers = new Headers() - t.throws(() => headers.get(), 'throws on missing name') - t.throws(() => headers.get('invalid @ header ? name'), 'throws on invalid name') + throws(() => headers.get(), 'throws on missing name') + throws(() => headers.get('invalid @ header ? name'), 'throws on invalid name') }) }) -tap.test('Headers has', t => { - t.plan(2) - - t.test('returns boolean existence for a header name', t => { - t.plan(2) +test('Headers has', async (t) => { + await t.test('returns boolean existence for a header name', (t) => { + const { strictEqual } = tspl(t, { plan: 2 }) const headers = new Headers() const name = 'undici' headers.append('not-undici', 'fetch') - t.equal(headers.has(name), false) + strictEqual(headers.has(name), false) headers.append(name, 'fetch') - t.equal(headers.has(name), true) + strictEqual(headers.has(name), true) }) - t.test('throws on invalid entry', t => { - t.plan(2) + await t.test('throws on invalid entry', (t) => { + const { throws } = tspl(t, { plan: 2 }) const headers = new Headers() - t.throws(() => headers.has(), 'throws on missing name') - t.throws(() => headers.has('invalid @ header ? name'), 'throws on invalid name') + throws(() => headers.has(), 'throws on missing name') + throws(() => headers.has('invalid @ header ? name'), 'throws on invalid name') }) }) -tap.test('Headers set', t => { - t.plan(5) - - t.test('sets valid header entry to instance', t => { - t.plan(2) +test('Headers set', async (t) => { + await t.test('sets valid header entry to instance', (t) => { + const { doesNotThrow, strictEqual } = tspl(t, { plan: 2 }) const headers = new Headers() const name = 'undici' const value = 'fetch' headers.append('not-undici', 'fetch') - t.doesNotThrow(() => headers.set(name, value)) - t.equal(headers.get(name), value) + doesNotThrow(() => headers.set(name, value)) + strictEqual(headers.get(name), value) }) - t.test('overwrites existing entry', t => { - t.plan(4) + await t.test('overwrites existing entry', (t) => { + const { doesNotThrow, strictEqual } = tspl(t, { plan: 4 }) const headers = new Headers() const name = 'undici' const value1 = 'fetch1' const value2 = 'fetch2' - t.doesNotThrow(() => headers.set(name, value1)) - t.equal(headers.get(name), value1) - t.doesNotThrow(() => headers.set(name, value2)) - t.equal(headers.get(name), value2) + doesNotThrow(() => headers.set(name, value1)) + strictEqual(headers.get(name), value1) + doesNotThrow(() => headers.set(name, value2)) + strictEqual(headers.get(name), value2) }) - t.test('allows setting a myriad of values', t => { - t.plan(4) + await t.test('allows setting a myriad of values', (t) => { + const { doesNotThrow, throws } = tspl(t, { plan: 4 }) const headers = new Headers() - t.doesNotThrow(() => headers.set('a', ['b', 'c']), 'sets array values properly') - t.doesNotThrow(() => headers.set('b', null), 'allows setting null values') - t.throws(() => headers.set('c'), 'throws when 2 arguments are not passed') - t.doesNotThrow(() => headers.set('c', 'd', 'e'), 'ignores extra arguments') + doesNotThrow(() => headers.set('a', ['b', 'c']), 'sets array values properly') + doesNotThrow(() => headers.set('b', null), 'allows setting null values') + throws(() => headers.set('c'), 'throws when 2 arguments are not passed') + doesNotThrow(() => headers.set('c', 'd', 'e'), 'ignores extra arguments') }) - t.test('throws on invalid entry', t => { - t.plan(3) + await t.test('throws on invalid entry', (t) => { + const { throws } = tspl(t, { plan: 3 }) const headers = new Headers() - t.throws(() => headers.set(), 'throws on missing name and value') - t.throws(() => headers.set('undici'), 'throws on missing value') - t.throws(() => headers.set('invalid @ header ? name', 'valid value'), 'throws on invalid name') + throws(() => headers.set(), 'throws on missing name and value') + throws(() => headers.set('undici'), 'throws on missing value') + throws(() => headers.set('invalid @ header ? name', 'valid value'), 'throws on invalid name') }) // https://github.com/nodejs/undici/issues/2431 - t.test('`Headers#set` returns undefined', t => { - t.plan(2) + await t.test('`Headers#set` returns undefined', (t) => { + const { strictEqual, ok } = tspl(t, { plan: 2 }) const headers = new Headers() - t.same(headers.set('a', 'b'), undefined) + strictEqual(headers.set('a', 'b'), undefined) - t.notOk(headers.set('c', 'd') instanceof Map) + ok(!(headers.set('c', 'd') instanceof Map)) }) }) -tap.test('Headers forEach', t => { +test('Headers forEach', async (t) => { const headers = new Headers([['a', 'b'], ['c', 'd']]) - t.test('standard', t => { - t.equal(typeof headers.forEach, 'function') + await t.test('standard', () => { + assert.strictEqual(typeof headers.forEach, 'function') headers.forEach((value, key, headerInstance) => { - t.ok(value === 'b' || value === 'd') - t.ok(key === 'a' || key === 'c') - t.equal(headers, headerInstance) + assert.ok(value === 'b' || value === 'd') + assert.ok(key === 'a' || key === 'c') + assert.strictEqual(headers, headerInstance) }) - - t.end() }) - t.test('when no thisArg is set, it is globalThis', (t) => { + await t.test('when no thisArg is set, it is globalThis', () => { headers.forEach(function () { - t.equal(this, globalThis) + assert.strictEqual(this, globalThis) }) - - t.end() }) - t.test('with thisArg', t => { + await t.test('with thisArg', () => { const thisArg = { a: Math.random() } headers.forEach(function () { - t.equal(this, thisArg) + assert.strictEqual(this, thisArg) }, thisArg) - - t.end() }) - - t.end() }) -tap.test('Headers as Iterable', t => { - t.plan(7) - - t.test('should freeze values while iterating', t => { - t.plan(1) +test('Headers as Iterable', async (t) => { + await t.test('should freeze values while iterating', (t) => { + const { deepStrictEqual } = tspl(t, { plan: 1 }) const init = [ ['foo', '123'], ['bar', '456'] @@ -368,11 +344,11 @@ tap.test('Headers as Iterable', t => { headers.delete(key) headers.set(`x-${key}`, val) } - t.strictSame([...headers], expected) + deepStrictEqual([...headers], expected) }) - t.test('returns combined and sorted entries using .forEach()', t => { - t.plan(8) + await t.test('returns combined and sorted entries using .forEach()', (t) => { + const { deepStrictEqual, strictEqual } = tspl(t, { plan: 8 }) const init = [ ['a', '1'], ['b', '2'], @@ -390,13 +366,13 @@ tap.test('Headers as Iterable', t => { const that = {} let i = 0 headers.forEach(function (value, key, _headers) { - t.strictSame(expected[i++], [key, value]) - t.equal(this, that) + deepStrictEqual(expected[i++], [key, value]) + strictEqual(this, that) }, that) }) - t.test('returns combined and sorted entries using .entries()', t => { - t.plan(4) + await t.test('returns combined and sorted entries using .entries()', (t) => { + const { deepStrictEqual } = tspl(t, { plan: 4 }) const init = [ ['a', '1'], ['b', '2'], @@ -413,12 +389,12 @@ tap.test('Headers as Iterable', t => { const headers = new Headers(init) let i = 0 for (const header of headers.entries()) { - t.strictSame(header, expected[i++]) + deepStrictEqual(header, expected[i++]) } }) - t.test('returns combined and sorted keys using .keys()', t => { - t.plan(4) + await t.test('returns combined and sorted keys using .keys()', (t) => { + const { strictEqual } = tspl(t, { plan: 4 }) const init = [ ['a', '1'], ['b', '2'], @@ -430,12 +406,12 @@ tap.test('Headers as Iterable', t => { const headers = new Headers(init) let i = 0 for (const key of headers.keys()) { - t.strictSame(key, expected[i++]) + strictEqual(key, expected[i++]) } }) - t.test('returns combined and sorted values using .values()', t => { - t.plan(4) + await t.test('returns combined and sorted values using .values()', (t) => { + const { strictEqual } = tspl(t, { plan: 4 }) const init = [ ['a', '1'], ['b', '2'], @@ -447,12 +423,12 @@ tap.test('Headers as Iterable', t => { const headers = new Headers(init) let i = 0 for (const value of headers.values()) { - t.strictSame(value, expected[i++]) + strictEqual(value, expected[i++]) } }) - t.test('returns combined and sorted entries using for...of loop', t => { - t.plan(5) + await t.test('returns combined and sorted entries using for...of loop', (t) => { + const { deepStrictEqual } = tspl(t, { plan: 5 }) const init = [ ['a', '1'], ['b', '2'], @@ -470,12 +446,12 @@ tap.test('Headers as Iterable', t => { ] let i = 0 for (const header of new Headers(init)) { - t.strictSame(header, expected[i++]) + deepStrictEqual(header, expected[i++]) } }) - t.test('validate append ordering', t => { - t.plan(1) + await t.test('validate append ordering', (t) => { + const { deepStrictEqual } = tspl(t, { plan: 1 }) const headers = new Headers([['b', '2'], ['c', '3'], ['e', '5']]) headers.append('d', '4') headers.append('a', '1') @@ -493,180 +469,164 @@ tap.test('Headers as Iterable', t => { ['f', '6'] ])] - t.same([...headers], expected) + deepStrictEqual([...headers], expected) }) }) -tap.test('arg validation', (t) => { +test('arg validation', () => { // fill - t.throws(() => { + assert.throws(() => { fill({}, 0) }, TypeError) const headers = new Headers() // constructor - t.throws(() => { + assert.throws(() => { // eslint-disable-next-line new Headers(0) }, TypeError) // get [Symbol.toStringTag] - t.doesNotThrow(() => { + assert.doesNotThrow(() => { Object.prototype.toString.call(Headers.prototype) }) // toString - t.doesNotThrow(() => { + assert.doesNotThrow(() => { Headers.prototype.toString.call(null) }) // append - t.throws(() => { + assert.throws(() => { Headers.prototype.append.call(null) }, TypeError) - t.throws(() => { + assert.throws(() => { headers.append() }, TypeError) // delete - t.throws(() => { + assert.throws(() => { Headers.prototype.delete.call(null) }, TypeError) - t.throws(() => { + assert.throws(() => { headers.delete() }, TypeError) // get - t.throws(() => { + assert.throws(() => { Headers.prototype.get.call(null) }, TypeError) - t.throws(() => { + assert.throws(() => { headers.get() }, TypeError) // has - t.throws(() => { + assert.throws(() => { Headers.prototype.has.call(null) }, TypeError) - t.throws(() => { + assert.throws(() => { headers.has() }, TypeError) // set - t.throws(() => { + assert.throws(() => { Headers.prototype.set.call(null) }, TypeError) - t.throws(() => { + assert.throws(() => { headers.set() }, TypeError) // forEach - t.throws(() => { + assert.throws(() => { Headers.prototype.forEach.call(null) }, TypeError) - t.throws(() => { + assert.throws(() => { headers.forEach() }, TypeError) - t.throws(() => { + assert.throws(() => { headers.forEach(1) }, TypeError) // inspect - t.throws(() => { + assert.throws(() => { Headers.prototype[Symbol.for('nodejs.util.inspect.custom')].call(null) }, TypeError) - - t.end() }) -tap.test('function signature verification', (t) => { - t.test('function length', (t) => { - t.equal(Headers.prototype.append.length, 2) - t.equal(Headers.prototype.constructor.length, 0) - t.equal(Headers.prototype.delete.length, 1) - t.equal(Headers.prototype.entries.length, 0) - t.equal(Headers.prototype.forEach.length, 1) - t.equal(Headers.prototype.get.length, 1) - t.equal(Headers.prototype.has.length, 1) - t.equal(Headers.prototype.keys.length, 0) - t.equal(Headers.prototype.set.length, 2) - t.equal(Headers.prototype.values.length, 0) - t.equal(Headers.prototype[Symbol.iterator].length, 0) - t.equal(Headers.prototype.toString.length, 0) - - t.end() +test('function signature verification', async (t) => { + await t.test('function length', () => { + assert.strictEqual(Headers.prototype.append.length, 2) + assert.strictEqual(Headers.prototype.constructor.length, 0) + assert.strictEqual(Headers.prototype.delete.length, 1) + assert.strictEqual(Headers.prototype.entries.length, 0) + assert.strictEqual(Headers.prototype.forEach.length, 1) + assert.strictEqual(Headers.prototype.get.length, 1) + assert.strictEqual(Headers.prototype.has.length, 1) + assert.strictEqual(Headers.prototype.keys.length, 0) + assert.strictEqual(Headers.prototype.set.length, 2) + assert.strictEqual(Headers.prototype.values.length, 0) + assert.strictEqual(Headers.prototype[Symbol.iterator].length, 0) + assert.strictEqual(Headers.prototype.toString.length, 0) }) - t.test('function equality', (t) => { - t.equal(Headers.prototype.entries, Headers.prototype[Symbol.iterator]) - t.equal(Headers.prototype.toString, Object.prototype.toString) - - t.end() + await t.test('function equality', () => { + assert.strictEqual(Headers.prototype.entries, Headers.prototype[Symbol.iterator]) + assert.strictEqual(Headers.prototype.toString, Object.prototype.toString) }) - t.test('toString and Symbol.toStringTag', (t) => { - t.equal(Object.prototype.toString.call(Headers.prototype), '[object Headers]') - t.equal(Headers.prototype[Symbol.toStringTag], 'Headers') - t.equal(Headers.prototype.toString.call(null), '[object Null]') - - t.end() + await t.test('toString and Symbol.toStringTag', () => { + assert.strictEqual(Object.prototype.toString.call(Headers.prototype), '[object Headers]') + assert.strictEqual(Headers.prototype[Symbol.toStringTag], 'Headers') + assert.strictEqual(Headers.prototype.toString.call(null), '[object Null]') }) - - t.end() }) -tap.test('various init paths of Headers', (t) => { +test('various init paths of Headers', () => { const h1 = new Headers() const h2 = new Headers({}) const h3 = new Headers(undefined) - t.equal([...h1.entries()].length, 0) - t.equal([...h2.entries()].length, 0) - t.equal([...h3.entries()].length, 0) - - t.end() + assert.strictEqual([...h1.entries()].length, 0) + assert.strictEqual([...h2.entries()].length, 0) + assert.strictEqual([...h3.entries()].length, 0) }) -tap.test('immutable guard', (t) => { +test('immutable guard', () => { const headers = new Headers() headers.set('key', 'val') headers[kGuard] = 'immutable' - t.throws(() => { + assert.throws(() => { headers.set('asd', 'asd') }) - t.throws(() => { + assert.throws(() => { headers.append('asd', 'asd') }) - t.throws(() => { + assert.throws(() => { headers.delete('asd') }) - t.equal(headers.get('key'), 'val') - t.equal(headers.has('key'), true) - - t.end() + assert.strictEqual(headers.get('key'), 'val') + assert.strictEqual(headers.has('key'), true) }) -tap.test('request-no-cors guard', (t) => { +test('request-no-cors guard', () => { const headers = new Headers() headers[kGuard] = 'request-no-cors' - t.doesNotThrow(() => { headers.set('key', 'val') }) - t.doesNotThrow(() => { headers.append('key', 'val') }) - t.doesNotThrow(() => { headers.delete('key') }) - t.end() + assert.doesNotThrow(() => { headers.set('key', 'val') }) + assert.doesNotThrow(() => { headers.append('key', 'val') }) }) -tap.test('invalid headers', (t) => { - t.doesNotThrow(() => new Headers({ "abcdefghijklmnopqrstuvwxyz0123456789!#$%&'*+-.^_`|~": 'test' })) +test('invalid headers', () => { + assert.doesNotThrow(() => new Headers({ "abcdefghijklmnopqrstuvwxyz0123456789!#$%&'*+-.^_`|~": 'test' })) const chars = '"(),/:;<=>?@[\\]{}'.split('') for (const char of chars) { - t.throws(() => new Headers({ [char]: 'test' }), TypeError, `The string "${char}" should throw an error.`) + assert.throws(() => new Headers({ [char]: 'test' }), TypeError, `The string "${char}" should throw an error.`) } for (const byte of ['\r', '\n', '\t', ' ', String.fromCharCode(128), '']) { - t.throws(() => { + assert.throws(() => { new Headers().set(byte, 'test') }, TypeError, 'invalid header name') } @@ -676,39 +636,35 @@ tap.test('invalid headers', (t) => { '\r', '\n' ]) { - t.throws(() => { + assert.throws(() => { new Headers().set('a', `a${byte}b`) }, TypeError, 'not allowed at all in header value') } - t.doesNotThrow(() => { + assert.doesNotThrow(() => { new Headers().set('a', '\r') }) - t.doesNotThrow(() => { + assert.doesNotThrow(() => { new Headers().set('a', '\n') }) - t.throws(() => { + assert.throws(() => { new Headers().set('a', Symbol('symbol')) }, TypeError, 'symbols should throw') - - t.end() }) -tap.test('headers that might cause a ReDoS', (t) => { - t.doesNotThrow(() => { +test('headers that might cause a ReDoS', () => { + assert.doesNotThrow(() => { // This test will time out if the ReDoS attack is successful. const headers = new Headers() const attack = 'a' + '\t'.repeat(500_000) + '\ta' headers.append('fhqwhgads', attack) }) - - t.end() }) -tap.test('Headers.prototype.getSetCookie', (t) => { - t.test('Mutating the returned list does not affect the set-cookie list', (t) => { +test('Headers.prototype.getSetCookie', async (t) => { + await t.test('Mutating the returned list does not affect the set-cookie list', () => { const h = new Headers([ ['set-cookie', 'a=b'], ['set-cookie', 'c=d'] @@ -718,35 +674,32 @@ tap.test('Headers.prototype.getSetCookie', (t) => { h.getSetCookie().push('oh=no') const now = h.getSetCookie() - t.same(old, now) - t.end() + assert.deepStrictEqual(old, now) }) // https://github.com/nodejs/undici/issues/1935 - t.test('When Headers are cloned, so are the cookies', async (t) => { + await t.test('When Headers are cloned, so are the cookies', async (t) => { const server = createServer((req, res) => { res.setHeader('Set-Cookie', 'test=onetwo') res.end('Hello World!') }).listen(0) await once(server, 'listening') - t.teardown(server.close.bind(server)) + t.after(server.close.bind(server)) const res = await fetch(`http://localhost:${server.address().port}`) const entries = Object.fromEntries(res.headers.entries()) - t.same(res.headers.getSetCookie(), ['test=onetwo']) - t.ok('set-cookie' in entries) + assert.deepStrictEqual(res.headers.getSetCookie(), ['test=onetwo']) + assert.ok('set-cookie' in entries) }) - - t.end() }) -tap.test('When the value is updated, update the cache', (t) => { - t.plan(2) +test('When the value is updated, update the cache', (t) => { + const { deepStrictEqual } = tspl(t, { plan: 2 }) const expected = [['a', 'a'], ['b', 'b'], ['c', 'c']] const headers = new Headers(expected) - t.same([...headers], expected) + deepStrictEqual([...headers], expected) headers.append('d', 'd') - t.same([...headers], [...expected, ['d', 'd']]) + deepStrictEqual([...headers], [...expected, ['d', 'd']]) }) diff --git a/test/fetch/http2.js b/test/fetch/http2.js index 2168e54a171..16aea7a5ec2 100644 --- a/test/fetch/http2.js +++ b/test/fetch/http2.js @@ -6,16 +6,15 @@ const { once } = require('node:events') const { Blob } = require('node:buffer') const { Readable } = require('node:stream') -const { test, plan } = require('tap') +const { test } = require('node:test') +const { tspl } = require('@matteo.collina/tspl') const pem = require('https-pem') const { Client, fetch, Headers } = require('../..') const nodeVersion = Number(process.version.split('v')[1].split('.')[0]) -plan(8) - -test('[Fetch] Issue#2311', async t => { +test('[Fetch] Issue#2311', async (t) => { const expectedBody = 'hello from client!' const server = createSecureServer(pem, async (req, res) => { @@ -35,7 +34,7 @@ test('[Fetch] Issue#2311', async t => { res.end(body) }) - t.plan(1) + const { strictEqual } = tspl(t, { plan: 1 }) server.listen() await once(server, 'listening') @@ -63,13 +62,13 @@ test('[Fetch] Issue#2311', async t => { const responseBody = await response.text() - t.teardown(server.close.bind(server)) - t.teardown(client.close.bind(client)) + t.after(server.close.bind(server)) + t.after(() => client.close()) - t.equal(responseBody, expectedBody) + strictEqual(responseBody, expectedBody) }) -test('[Fetch] Simple GET with h2', async t => { +test('[Fetch] Simple GET with h2', async (t) => { const server = createSecureServer(pem) const expectedRequestBody = 'hello h2!' @@ -84,7 +83,7 @@ test('[Fetch] Simple GET with h2', async t => { stream.end(expectedRequestBody) }) - t.plan(5) + const { strictEqual, throws } = tspl(t, { plan: 5 }) server.listen() await once(server, 'listening') @@ -111,22 +110,22 @@ test('[Fetch] Simple GET with h2', async t => { const responseBody = await response.text() - t.teardown(server.close.bind(server)) - t.teardown(client.close.bind(client)) + t.after(server.close.bind(server)) + t.after(() => client.close()) - t.equal(responseBody, expectedRequestBody) - t.equal(response.headers.get('x-method'), 'GET') - t.equal(response.headers.get('x-custom-h2'), 'foo') + strictEqual(responseBody, expectedRequestBody) + strictEqual(response.headers.get('x-method'), 'GET') + strictEqual(response.headers.get('x-custom-h2'), 'foo') // https://github.com/nodejs/undici/issues/2415 - t.throws(() => { + throws(() => { response.headers.get(':status') }, TypeError) // See https://fetch.spec.whatwg.org/#concept-response-status-message - t.equal(response.statusText, '') + strictEqual(response.statusText, '') }) -test('[Fetch] Should handle h2 request with body (string or buffer)', async t => { +test('[Fetch] Should handle h2 request with body (string or buffer)', async (t) => { const server = createSecureServer(pem) const expectedBody = 'hello from client!' const expectedRequestBody = 'hello h2!' @@ -144,7 +143,7 @@ test('[Fetch] Should handle h2 request with body (string or buffer)', async t => stream.end(expectedRequestBody) }) - t.plan(2) + const { strictEqual } = tspl(t, { plan: 2 }) server.listen() await once(server, 'listening') @@ -172,27 +171,29 @@ test('[Fetch] Should handle h2 request with body (string or buffer)', async t => const responseBody = await response.text() - t.teardown(server.close.bind(server)) - t.teardown(client.close.bind(client)) + t.after(server.close.bind(server)) + t.after(() => client.close()) - t.equal(Buffer.concat(requestBody).toString('utf-8'), expectedBody) - t.equal(responseBody, expectedRequestBody) + strictEqual(Buffer.concat(requestBody).toString('utf-8'), expectedBody) + strictEqual(responseBody, expectedRequestBody) }) // Skipping for now, there is something odd in the way the body is handled test( '[Fetch] Should handle h2 request with body (stream)', { skip: nodeVersion === 16 }, - async t => { + async (t) => { const server = createSecureServer(pem) const expectedBody = readFileSync(__filename, 'utf-8') const stream = createReadStream(__filename) const requestChunks = [] + const { strictEqual } = tspl(t, { plan: 8 }) + server.on('stream', async (stream, headers) => { - t.equal(headers[':method'], 'PUT') - t.equal(headers[':path'], '/') - t.equal(headers[':scheme'], 'https') + strictEqual(headers[':method'], 'PUT') + strictEqual(headers[':path'], '/') + strictEqual(headers[':scheme'], 'https') stream.respond({ 'content-type': 'text/plain; charset=utf-8', @@ -207,8 +208,6 @@ test( stream.end('hello h2!') }) - t.plan(8) - server.listen(0) await once(server, 'listening') @@ -219,8 +218,8 @@ test( allowH2: true }) - t.teardown(server.close.bind(server)) - t.teardown(client.close.bind(client)) + t.after(server.close.bind(server)) + t.after(() => client.close()) const response = await fetch( `https://localhost:${server.address().port}/`, @@ -239,14 +238,14 @@ test( const responseBody = await response.text() - t.equal(response.status, 200) - t.equal(response.headers.get('content-type'), 'text/plain; charset=utf-8') - t.equal(response.headers.get('x-custom-h2'), 'foo') - t.equal(responseBody, 'hello h2!') - t.equal(Buffer.concat(requestChunks).toString('utf-8'), expectedBody) + strictEqual(response.status, 200) + strictEqual(response.headers.get('content-type'), 'text/plain; charset=utf-8') + strictEqual(response.headers.get('x-custom-h2'), 'foo') + strictEqual(responseBody, 'hello h2!') + strictEqual(Buffer.concat(requestChunks).toString('utf-8'), expectedBody) } ) -test('Should handle h2 request with body (Blob)', { skip: !Blob }, async t => { +test('Should handle h2 request with body (Blob)', { skip: !Blob }, async (t) => { const server = createSecureServer(pem) const expectedBody = 'asd' const requestChunks = [] @@ -254,10 +253,12 @@ test('Should handle h2 request with body (Blob)', { skip: !Blob }, async t => { type: 'text/plain' }) + const { strictEqual } = tspl(t, { plan: 8 }) + server.on('stream', async (stream, headers) => { - t.equal(headers[':method'], 'POST') - t.equal(headers[':path'], '/') - t.equal(headers[':scheme'], 'https') + strictEqual(headers[':method'], 'POST') + strictEqual(headers[':path'], '/') + strictEqual(headers[':scheme'], 'https') stream.on('data', chunk => requestChunks.push(chunk)) @@ -270,8 +271,6 @@ test('Should handle h2 request with body (Blob)', { skip: !Blob }, async t => { stream.end('hello h2!') }) - t.plan(8) - server.listen(0) await once(server, 'listening') @@ -282,8 +281,8 @@ test('Should handle h2 request with body (Blob)', { skip: !Blob }, async t => { allowH2: true }) - t.teardown(server.close.bind(server)) - t.teardown(client.close.bind(client)) + t.after(server.close.bind(server)) + t.after(() => client.close()) const response = await fetch( `https://localhost:${server.address().port}/`, @@ -301,17 +300,17 @@ test('Should handle h2 request with body (Blob)', { skip: !Blob }, async t => { const responseBody = await response.arrayBuffer() - t.equal(response.status, 200) - t.equal(response.headers.get('content-type'), 'text/plain; charset=utf-8') - t.equal(response.headers.get('x-custom-h2'), 'foo') - t.same(new TextDecoder().decode(responseBody).toString(), 'hello h2!') - t.equal(Buffer.concat(requestChunks).toString('utf-8'), expectedBody) + strictEqual(response.status, 200) + strictEqual(response.headers.get('content-type'), 'text/plain; charset=utf-8') + strictEqual(response.headers.get('x-custom-h2'), 'foo') + strictEqual(new TextDecoder().decode(responseBody).toString(), 'hello h2!') + strictEqual(Buffer.concat(requestChunks).toString('utf-8'), expectedBody) }) test( 'Should handle h2 request with body (Blob:ArrayBuffer)', { skip: !Blob }, - async t => { + async (t) => { const server = createSecureServer(pem) const expectedBody = 'hello' const requestChunks = [] @@ -321,10 +320,12 @@ test( buf.copy(new Uint8Array(body)) + const { strictEqual, deepStrictEqual } = tspl(t, { plan: 8 }) + server.on('stream', async (stream, headers) => { - t.equal(headers[':method'], 'PUT') - t.equal(headers[':path'], '/') - t.equal(headers[':scheme'], 'https') + strictEqual(headers[':method'], 'PUT') + strictEqual(headers[':path'], '/') + strictEqual(headers[':scheme'], 'https') stream.on('data', chunk => requestChunks.push(chunk)) @@ -337,8 +338,6 @@ test( stream.end(JSON.stringify(expectedResponseBody)) }) - t.plan(8) - server.listen(0) await once(server, 'listening') @@ -349,8 +348,8 @@ test( allowH2: true }) - t.teardown(server.close.bind(server)) - t.teardown(client.close.bind(client)) + t.after(server.close.bind(server)) + t.after(() => client.close()) const response = await fetch( `https://localhost:${server.address().port}/`, @@ -368,16 +367,16 @@ test( const responseBody = await response.json() - t.equal(response.status, 200) - t.equal(response.headers.get('content-type'), 'application/json') - t.equal(response.headers.get('x-custom-h2'), 'foo') - t.same(responseBody, expectedResponseBody) - t.equal(Buffer.concat(requestChunks).toString('utf-8'), expectedBody) + strictEqual(response.status, 200) + strictEqual(response.headers.get('content-type'), 'application/json') + strictEqual(response.headers.get('x-custom-h2'), 'foo') + deepStrictEqual(responseBody, expectedResponseBody) + strictEqual(Buffer.concat(requestChunks).toString('utf-8'), expectedBody) } ) test('Issue#2415', async (t) => { - t.plan(1) + const { doesNotThrow } = tspl(t, { plan: 1 }) const server = createSecureServer(pem) server.on('stream', async (stream, headers) => { @@ -408,13 +407,13 @@ test('Issue#2415', async (t) => { await response.text() - t.teardown(server.close.bind(server)) - t.teardown(client.close.bind(client)) + t.after(server.close.bind(server)) + t.after(() => client.close()) - t.doesNotThrow(() => new Headers(response.headers)) + doesNotThrow(() => new Headers(response.headers)) }) -test('Issue #2386', async t => { +test('Issue #2386', async (t) => { const server = createSecureServer(pem) const body = Buffer.from('hello') const requestChunks = [] @@ -422,10 +421,12 @@ test('Issue #2386', async t => { const controller = new AbortController() const signal = controller.signal + const { strictEqual, ok } = tspl(t, { plan: 4 }) + server.on('stream', async (stream, headers) => { - t.equal(headers[':method'], 'PUT') - t.equal(headers[':path'], '/') - t.equal(headers[':scheme'], 'https') + strictEqual(headers[':method'], 'PUT') + strictEqual(headers[':path'], '/') + strictEqual(headers[':scheme'], 'https') stream.on('data', chunk => requestChunks.push(chunk)) @@ -438,8 +439,6 @@ test('Issue #2386', async t => { stream.end(JSON.stringify(expectedResponseBody)) }) - t.plan(4) - server.listen(0) await once(server, 'listening') @@ -450,28 +449,24 @@ test('Issue #2386', async t => { allowH2: true }) - t.teardown(server.close.bind(server)) - t.teardown(client.close.bind(client)) + t.after(server.close.bind(server)) + t.after(() => client.close()) - try { - await fetch( - `https://localhost:${server.address().port}/`, - // Needs to be passed to disable the reject unauthorized - { - body, - signal, - method: 'PUT', - dispatcher: client, - headers: { - 'x-my-header': 'foo', - 'content-type': 'text-plain' - } + await fetch( + `https://localhost:${server.address().port}/`, + // Needs to be passed to disable the reject unauthorized + { + body, + signal, + method: 'PUT', + dispatcher: client, + headers: { + 'x-my-header': 'foo', + 'content-type': 'text-plain' } - ) + } + ) - controller.abort() - t.pass() - } catch (error) { - t.error(error) - } + controller.abort() + ok(true) }) diff --git a/test/fetch/issue-2171.js b/test/fetch/issue-2171.js index 72770f3713f..cd4368b9d86 100644 --- a/test/fetch/issue-2171.js +++ b/test/fetch/issue-2171.js @@ -3,16 +3,17 @@ const { fetch } = require('../..') const { once } = require('events') const { createServer } = require('http') -const { test } = require('tap') +const { test } = require('node:test') +const assert = require('node:assert') test('error reason is forwarded - issue #2171', { skip: !AbortSignal.timeout }, async (t) => { const server = createServer(() => {}).listen(0) - t.teardown(server.close.bind(server)) + t.after(server.close.bind(server)) await once(server, 'listening') const timeout = AbortSignal.timeout(100) - await t.rejects( + await assert.rejects( fetch(`http://localhost:${server.address().port}`, { signal: timeout }),