diff --git a/.taprc b/.taprc deleted file mode 100644 index 61f70513a70..00000000000 --- a/.taprc +++ /dev/null @@ -1,7 +0,0 @@ -ts: false -jsx: false -flow: false -coverage: false -expose-gc: true -timeout: 60 -check-coverage: false diff --git a/package.json b/package.json index acbb493382d..18abf647a3d 100644 --- a/package.json +++ b/package.json @@ -76,15 +76,15 @@ "build:wasm": "node build/wasm.js --docker", "lint": "standard | snazzy", "lint:fix": "standard --fix | snazzy", - "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:eventsource && npm run test:wpt && npm run test:websocket && npm run test:jest && npm run test:typescript && npm run test:node-test", + "test": "node scripts/generate-pem && npm run test:unit && npm run test:node-fetch && npm run test:fetch && npm run test:cookies && npm run test:eventsource && 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": "borp --coverage -p \"test/node-fetch/**/*.js\"", "test:eventsource": "npm run build:node && borp --expose-gc --coverage -p \"test/eventsource/*.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:unit": "borp --expose-gc -p \"test/*.js\"", "test:node-test": "borp --coverage -p \"test/node-test/**/*.js\"", - "test:tdd": "tap test/*.js --coverage -w", + "test:tdd": "borp --coverage --expose-gc -p \"test/*.js\"", "test:tdd:node-test": "borp -p \"test/node-test/**/*.js\" -w", "test:typescript": "tsd && tsc --skipLibCheck test/imports/undici-import.ts", "test:websocket": "borp --coverage -p \"test/websocket/*.js\"", @@ -130,7 +130,6 @@ "snazzy": "^9.0.0", "standard": "^17.0.0", "superagent": "^8.1.2", - "tap": "^16.1.0", "tsd": "^0.30.1", "typescript": "^5.0.2", "wait-on": "^7.0.1", diff --git a/test/client-request.js b/test/client-request.js index cafcd39989b..2b73d3b01d0 100644 --- a/test/client-request.js +++ b/test/client-request.js @@ -2,7 +2,8 @@ 'use strict' -const { test } = require('tap') +const { tspl } = require('@matteo.collina/tspl') +const { test, after } = require('node:test') const { Client, errors } = require('..') const { createServer } = require('node:http') const EE = require('node:events') @@ -13,51 +14,53 @@ const { promisify } = require('node:util') const { NotSupportedError } = require('../lib/core/errors') const { parseFormDataString } = require('./utils/formdata') -test('request dump', (t) => { - t.plan(3) +test('request dump', async (t) => { + t = tspl(t, { plan: 3 }) const server = createServer((req, res) => { res.end('hello') }) - t.teardown(server.close.bind(server)) + after(() => server.close()) server.listen(0, () => { const client = new Client(`http://localhost:${server.address().port}`) - t.teardown(client.destroy.bind(client)) + after(() => client.destroy()) let dumped = false client.on('disconnect', () => { - t.equal(dumped, true) + t.strictEqual(dumped, true) }) client.request({ path: '/', method: 'GET' }, (err, { body }) => { - t.error(err) + t.ifError(err) body.dump().then(() => { dumped = true t.ok(true, 'pass') }) }) }) + + await t.completed }) -test('request dump with abort signal', (t) => { - t.plan(2) +test('request dump with abort signal', async (t) => { + t = tspl(t, { plan: 2 }) const server = createServer((req, res) => { res.write('hello') }) - t.teardown(server.close.bind(server)) + after(() => server.close()) server.listen(0, () => { const client = new Client(`http://localhost:${server.address().port}`) - t.teardown(client.destroy.bind(client)) + after(() => client.destroy()) client.request({ path: '/', method: 'GET' }, (err, { body }) => { - t.error(err) + t.ifError(err) let ac if (!global.AbortController) { const { AbortController } = require('abort-controller') @@ -66,50 +69,54 @@ test('request dump with abort signal', (t) => { ac = new AbortController() } body.dump({ signal: ac.signal }).catch((err) => { - t.equal(err.name, 'AbortError') + t.strictEqual(err.name, 'AbortError') server.close() }) ac.abort() }) }) + + await t.completed }) -test('request hwm', (t) => { - t.plan(2) +test('request hwm', async (t) => { + t = tspl(t, { plan: 2 }) const server = createServer((req, res) => { res.write('hello') }) - t.teardown(server.close.bind(server)) + after(() => server.close()) server.listen(0, () => { const client = new Client(`http://localhost:${server.address().port}`) - t.teardown(client.destroy.bind(client)) + after(() => client.destroy()) client.request({ path: '/', method: 'GET', highWaterMark: 1000 }, (err, { body }) => { - t.error(err) - t.same(body.readableHighWaterMark, 1000) + t.ifError(err) + t.deepStrictEqual(body.readableHighWaterMark, 1000) body.dump() }) }) + + await t.completed }) -test('request abort before headers', (t) => { - t.plan(6) +test('request abort before headers', async (t) => { + t = tspl(t, { plan: 6 }) const signal = new EE() const server = createServer((req, res) => { res.end('hello') signal.emit('abort') }) - t.teardown(server.close.bind(server)) + after(() => server.close()) server.listen(0, () => { const client = new Client(`http://localhost:${server.address().port}`) - t.teardown(client.destroy.bind(client)) + after(() => client.destroy()) client[kConnect](() => { client.request({ @@ -118,9 +125,9 @@ test('request abort before headers', (t) => { signal }, (err) => { t.ok(err instanceof errors.RequestAbortedError) - t.equal(signal.listenerCount('abort'), 0) + t.strictEqual(signal.listenerCount('abort'), 0) }) - t.equal(signal.listenerCount('abort'), 1) + t.strictEqual(signal.listenerCount('abort'), 1) client.request({ path: '/', @@ -128,23 +135,25 @@ test('request abort before headers', (t) => { signal }, (err) => { t.ok(err instanceof errors.RequestAbortedError) - t.equal(signal.listenerCount('abort'), 0) + t.strictEqual(signal.listenerCount('abort'), 0) }) - t.equal(signal.listenerCount('abort'), 2) + t.strictEqual(signal.listenerCount('abort'), 2) }) }) + + await t.completed }) -test('request body destroyed on invalid callback', (t) => { - t.plan(1) +test('request body destroyed on invalid callback', async (t) => { + t = tspl(t, { plan: 1 }) const server = createServer((req, res) => { }) - t.teardown(server.close.bind(server)) + after(() => server.close()) server.listen(0, () => { const client = new Client(`http://localhost:${server.address().port}`) - t.teardown(client.destroy.bind(client)) + after(() => client.destroy()) const body = new Readable({ read () {} @@ -156,24 +165,26 @@ test('request body destroyed on invalid callback', (t) => { body }, null) } catch (err) { - t.equal(body.destroyed, true) + t.strictEqual(body.destroyed, true) } }) + + await t.completed }) -test('trailers', (t) => { - t.plan(1) +test('trailers', async (t) => { + t = tspl(t, { plan: 1 }) const server = createServer((req, res) => { res.writeHead(200, { Trailer: 'Content-MD5' }) res.addTrailers({ 'Content-MD5': 'test' }) res.end() }) - t.teardown(server.close.bind(server)) + after(() => server.close()) server.listen(0, async () => { const client = new Client(`http://localhost:${server.address().port}`) - t.teardown(client.close.bind(client)) + after(() => client.close()) const { body, trailers } = await client.request({ path: '/', @@ -183,13 +194,15 @@ test('trailers', (t) => { body .on('data', () => t.fail()) .on('end', () => { - t.strictSame(trailers, { 'content-md5': 'test' }) + t.deepStrictEqual(trailers, { 'content-md5': 'test' }) }) }) + + await t.completed }) -test('destroy socket abruptly', { skip: true }, async (t) => { - t.plan(2) +test('destroy socket abruptly', async (t) => { + t = tspl(t, { plan: 2 }) const server = net.createServer((socket) => { const lines = [ @@ -205,18 +218,18 @@ test('destroy socket abruptly', { skip: true }, async (t) => { // therefore we delay it to the next event loop run. setImmediate(socket.destroy.bind(socket)) }) - t.teardown(server.close.bind(server)) + after(() => server.close()) await promisify(server.listen.bind(server))(0) const client = new Client(`http://localhost:${server.address().port}`) - t.teardown(client.close.bind(client)) + after(() => client.close()) const { statusCode, body } = await client.request({ path: '/', method: 'GET' }) - t.equal(statusCode, 200) + t.strictEqual(statusCode, 200) body.setEncoding('utf8') @@ -226,11 +239,11 @@ test('destroy socket abruptly', { skip: true }, async (t) => { actual += chunk } - t.equal(actual, 'the body') + t.strictEqual(actual, 'the body') }) -test('destroy socket abruptly with keep-alive', { skip: true }, async (t) => { - t.plan(2) +test('destroy socket abruptly with keep-alive', async (t) => { + t = tspl(t, { plan: 2 }) const server = net.createServer((socket) => { const lines = [ @@ -247,18 +260,18 @@ test('destroy socket abruptly with keep-alive', { skip: true }, async (t) => { // therefore we delay it to the next event loop run. setImmediate(socket.destroy.bind(socket)) }) - t.teardown(server.close.bind(server)) + after(() => server.close()) await promisify(server.listen.bind(server))(0) const client = new Client(`http://localhost:${server.address().port}`) - t.teardown(client.close.bind(client)) + after(() => client.close()) const { statusCode, body } = await client.request({ path: '/', method: 'GET' }) - t.equal(statusCode, 200) + t.strictEqual(statusCode, 200) body.setEncoding('utf8') @@ -274,81 +287,87 @@ test('destroy socket abruptly with keep-alive', { skip: true }, async (t) => { } }) -test('request json', (t) => { - t.plan(1) +test('request json', async (t) => { + t = tspl(t, { plan: 1 }) const obj = { asd: true } const server = createServer((req, res) => { res.end(JSON.stringify(obj)) }) - t.teardown(server.close.bind(server)) + after(() => server.close()) server.listen(0, async () => { const client = new Client(`http://localhost:${server.address().port}`) - t.teardown(client.destroy.bind(client)) + after(() => client.destroy()) const { body } = await client.request({ path: '/', method: 'GET' }) - t.strictSame(obj, await body.json()) + t.deepStrictEqual(obj, await body.json()) }) + + await t.completed }) -test('request long multibyte json', (t) => { - t.plan(1) +test('request long multibyte json', async (t) => { + t = tspl(t, { plan: 1 }) const obj = { asd: 'あ'.repeat(100000) } const server = createServer((req, res) => { res.end(JSON.stringify(obj)) }) - t.teardown(server.close.bind(server)) + after(() => server.close()) server.listen(0, async () => { const client = new Client(`http://localhost:${server.address().port}`) - t.teardown(client.destroy.bind(client)) + after(() => client.destroy()) const { body } = await client.request({ path: '/', method: 'GET' }) - t.strictSame(obj, await body.json()) + t.deepStrictEqual(obj, await body.json()) }) + + await t.completed }) -test('request text', (t) => { - t.plan(1) +test('request text', async (t) => { + t = tspl(t, { plan: 1 }) const obj = { asd: true } const server = createServer((req, res) => { res.end(JSON.stringify(obj)) }) - t.teardown(server.close.bind(server)) + after(() => server.close()) server.listen(0, async () => { const client = new Client(`http://localhost:${server.address().port}`) - t.teardown(client.destroy.bind(client)) + after(() => client.destroy()) const { body } = await client.request({ path: '/', method: 'GET' }) - t.strictSame(JSON.stringify(obj), await body.text()) + t.strictEqual(JSON.stringify(obj), await body.text()) }) + + await t.completed }) -test('empty host header', (t) => { - t.plan(3) +test('empty host header', async (t) => { + t = tspl(t, { plan: 3 }) const server = createServer((req, res) => { res.end(req.headers.host) }) - t.teardown(server.close.bind(server)) + after(() => server.close()) server.listen(0, async () => { const serverAddress = `localhost:${server.address().port}` const client = new Client(`http://${serverAddress}`) - t.teardown(client.destroy.bind(client)) + after(() => client.destroy()) const getWithHost = async (host, wanted) => { const { body } = await client.request({ @@ -356,49 +375,53 @@ test('empty host header', (t) => { method: 'GET', headers: { host } }) - t.strictSame(await body.text(), wanted) + t.strictEqual(await body.text(), wanted) } await getWithHost('test', 'test') await getWithHost(undefined, serverAddress) await getWithHost('', '') }) + + await t.completed }) -test('request long multibyte text', (t) => { - t.plan(1) +test('request long multibyte text', async (t) => { + t = tspl(t, { plan: 1 }) const obj = { asd: 'あ'.repeat(100000) } const server = createServer((req, res) => { res.end(JSON.stringify(obj)) }) - t.teardown(server.close.bind(server)) + after(() => server.close()) server.listen(0, async () => { const client = new Client(`http://localhost:${server.address().port}`) - t.teardown(client.destroy.bind(client)) + after(() => client.destroy()) const { body } = await client.request({ path: '/', method: 'GET' }) - t.strictSame(JSON.stringify(obj), await body.text()) + t.strictEqual(JSON.stringify(obj), await body.text()) }) + + await t.completed }) -test('request blob', (t) => { - t.plan(2) +test('request blob', async (t) => { + t = tspl(t, { plan: 2 }) 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)) + after(() => server.close()) server.listen(0, async () => { const client = new Client(`http://localhost:${server.address().port}`) - t.teardown(client.destroy.bind(client)) + after(() => client.destroy()) const { body } = await client.request({ path: '/', @@ -406,23 +429,25 @@ test('request blob', (t) => { }) const blob = await body.blob() - t.strictSame(obj, JSON.parse(await blob.text())) - t.equal(blob.type, 'application/json') + t.deepStrictEqual(obj, JSON.parse(await blob.text())) + t.strictEqual(blob.type, 'application/json') }) + + await t.completed }) -test('request arrayBuffer', (t) => { - t.plan(2) +test('request arrayBuffer', async (t) => { + t = tspl(t, { plan: 2 }) const obj = { asd: true } const server = createServer((req, res) => { res.end(JSON.stringify(obj)) }) - t.teardown(server.close.bind(server)) + after(() => server.close()) server.listen(0, async () => { const client = new Client(`http://localhost:${server.address().port}`) - t.teardown(client.destroy.bind(client)) + after(() => client.destroy()) const { body } = await client.request({ path: '/', @@ -430,23 +455,25 @@ test('request arrayBuffer', (t) => { }) const ab = await body.arrayBuffer() - t.strictSame(Buffer.from(JSON.stringify(obj)), Buffer.from(ab)) + t.deepStrictEqual(Buffer.from(JSON.stringify(obj)), Buffer.from(ab)) t.ok(ab instanceof ArrayBuffer) }) + + await t.completed }) -test('request body', (t) => { - t.plan(1) +test('request body', async (t) => { + t = tspl(t, { plan: 1 }) const obj = { asd: true } const server = createServer((req, res) => { res.end(JSON.stringify(obj)) }) - t.teardown(server.close.bind(server)) + after(() => server.close()) server.listen(0, async () => { const client = new Client(`http://localhost:${server.address().port}`) - t.teardown(client.destroy.bind(client)) + after(() => client.destroy()) const { body } = await client.request({ path: '/', @@ -457,26 +484,28 @@ test('request body', (t) => { for await (const chunk of body.body) { x += Buffer.from(chunk) } - t.strictSame(JSON.stringify(obj), x) + t.strictEqual(JSON.stringify(obj), x) }) + + await t.completed }) -test('request post body no missing data', (t) => { - t.plan(2) +test('request post body no missing data', async (t) => { + t = tspl(t, { plan: 2 }) const server = createServer(async (req, res) => { let ret = '' for await (const chunk of req) { ret += chunk } - t.equal(ret, 'asd') + t.strictEqual(ret, 'asd') res.end() }) - t.teardown(server.close.bind(server)) + after(() => server.close()) server.listen(0, async () => { const client = new Client(`http://localhost:${server.address().port}`) - t.teardown(client.destroy.bind(client)) + after(() => client.destroy()) const { body } = await client.request({ path: '/', @@ -492,24 +521,26 @@ test('request post body no missing data', (t) => { await body.text() t.ok(true, 'pass') }) + + await t.completed }) -test('request post body no extra data handler', (t) => { - t.plan(3) +test('request post body no extra data handler', async (t) => { + t = tspl(t, { plan: 3 }) const server = createServer(async (req, res) => { let ret = '' for await (const chunk of req) { ret += chunk } - t.equal(ret, 'asd') + t.strictEqual(ret, 'asd') res.end() }) - t.teardown(server.close.bind(server)) + after(() => server.close()) server.listen(0, async () => { const client = new Client(`http://localhost:${server.address().port}`) - t.teardown(client.destroy.bind(client)) + after(() => client.destroy()) const reqBody = new Readable({ read () { @@ -518,7 +549,7 @@ test('request post body no extra data handler', (t) => { } }) process.nextTick(() => { - t.equal(reqBody.listenerCount('data'), 0) + t.strictEqual(reqBody.listenerCount('data'), 0) }) const { body } = await client.request({ path: '/', @@ -529,46 +560,50 @@ test('request post body no extra data handler', (t) => { await body.text() t.ok(true, 'pass') }) + + await t.completed }) -test('request with onInfo callback', (t) => { - t.plan(3) +test('request with onInfo callback', async (t) => { + t = tspl(t, { plan: 3 }) const infos = [] const server = createServer((req, res) => { res.writeProcessing() res.setHeader('Content-Type', 'application/json') res.end(JSON.stringify({ foo: 'bar' })) }) - t.teardown(server.close.bind(server)) + after(() => server.close()) server.listen(0, async () => { const client = new Client(`http://localhost:${server.address().port}`) - t.teardown(client.destroy.bind(client)) + after(() => client.destroy()) await client.request({ path: '/', method: 'GET', onInfo: (x) => { infos.push(x) } }) - t.equal(infos.length, 1) - t.equal(infos[0].statusCode, 102) + t.strictEqual(infos.length, 1) + t.strictEqual(infos[0].statusCode, 102) t.ok(true, 'pass') }) + + await t.completed }) -test('request with onInfo callback but socket is destroyed before end of response', (t) => { - t.plan(5) +test('request with onInfo callback but socket is destroyed before end of response', async (t) => { + t = tspl(t, { plan: 5 }) const infos = [] let response const server = createServer((req, res) => { response = res res.writeProcessing() }) - t.teardown(server.close.bind(server)) + after(() => server.close()) server.listen(0, async () => { const client = new Client(`http://localhost:${server.address().port}`) - t.teardown(client.destroy.bind(client)) + after(() => client.destroy()) try { await client.request({ path: '/', @@ -578,19 +613,21 @@ test('request with onInfo callback but socket is destroyed before end of respons response.destroy() } }) - t.error() + t.fail() } catch (e) { t.ok(e) - t.equal(e.message, 'other side closed') + t.strictEqual(e.message, 'other side closed') } - t.equal(infos.length, 1) - t.equal(infos[0].statusCode, 102) + t.strictEqual(infos.length, 1) + t.strictEqual(infos[0].statusCode, 102) t.ok(true, 'pass') }) + + await t.completed }) test('request onInfo callback headers parsing', async (t) => { - t.plan(4) + t = tspl(t, { plan: 4 }) const infos = [] const server = net.createServer((socket) => { @@ -606,12 +643,12 @@ test('request onInfo callback headers parsing', async (t) => { ] socket.end(lines.join('\r\n')) }) - t.teardown(server.close.bind(server)) + after(() => server.close()) await promisify(server.listen.bind(server))(0) const client = new Client(`http://localhost:${server.address().port}`) - t.teardown(client.close.bind(client)) + after(() => client.close()) const { body } = await client.request({ path: '/', @@ -619,14 +656,14 @@ test('request onInfo callback headers parsing', async (t) => { onInfo: (x) => { infos.push(x) } }) await body.dump() - t.equal(infos.length, 1) - t.equal(infos[0].statusCode, 103) - t.same(infos[0].headers, { link: '; rel=preload; as=style' }) + t.strictEqual(infos.length, 1) + t.strictEqual(infos[0].statusCode, 103) + t.deepStrictEqual(infos[0].headers, { link: '; rel=preload; as=style' }) t.ok(true, 'pass') }) test('request raw responseHeaders', async (t) => { - t.plan(4) + t = tspl(t, { plan: 4 }) const infos = [] const server = net.createServer((socket) => { @@ -642,12 +679,12 @@ test('request raw responseHeaders', async (t) => { ] socket.end(lines.join('\r\n')) }) - t.teardown(server.close.bind(server)) + after(() => server.close()) await promisify(server.listen.bind(server))(0) const client = new Client(`http://localhost:${server.address().port}`) - t.teardown(client.close.bind(client)) + after(() => client.close()) const { body, headers } = await client.request({ path: '/', @@ -656,24 +693,24 @@ test('request raw responseHeaders', async (t) => { onInfo: (x) => { infos.push(x) } }) await body.dump() - t.equal(infos.length, 1) - t.same(infos[0].headers, ['Link', '; rel=preload; as=style']) - t.same(headers, ['Date', 'Sat, 09 Oct 2010 14:28:02 GMT', 'Connection', 'close']) + t.strictEqual(infos.length, 1) + t.deepStrictEqual(infos[0].headers, ['Link', '; rel=preload; as=style']) + t.deepStrictEqual(headers, ['Date', 'Sat, 09 Oct 2010 14:28:02 GMT', 'Connection', 'close']) t.ok(true, 'pass') }) -test('request formData', (t) => { - t.plan(1) +test('request formData', async (t) => { + t = tspl(t, { plan: 1 }) const obj = { asd: true } const server = createServer((req, res) => { res.end(JSON.stringify(obj)) }) - t.teardown(server.close.bind(server)) + after(() => server.close()) server.listen(0, async () => { const client = new Client(`http://localhost:${server.address().port}`) - t.teardown(client.destroy.bind(client)) + after(() => client.destroy()) const { body } = await client.request({ path: '/', @@ -687,20 +724,22 @@ test('request formData', (t) => { t.ok(error instanceof NotSupportedError) } }) + + await t.completed }) -test('request text2', (t) => { - t.plan(2) +test('request text2', async (t) => { + t = tspl(t, { plan: 2 }) const obj = { asd: true } const server = createServer((req, res) => { res.end(JSON.stringify(obj)) }) - t.teardown(server.close.bind(server)) + after(() => server.close()) server.listen(0, async () => { const client = new Client(`http://localhost:${server.address().port}`) - t.teardown(client.destroy.bind(client)) + after(() => client.destroy()) const { body } = await client.request({ path: '/', @@ -711,13 +750,15 @@ test('request text2', (t) => { body.on('data', chunk => { ret += chunk }).on('end', () => { - t.equal(JSON.stringify(obj), ret) + t.strictEqual(JSON.stringify(obj), ret) }) - t.strictSame(JSON.stringify(obj), await p) + t.strictEqual(JSON.stringify(obj), await p) }) + + await t.completed }) -test('request with FormData body', (t) => { +test('request with FormData body', async (t) => { const { FormData } = require('../') const { Blob } = require('node:buffer') @@ -741,10 +782,10 @@ test('request with FormData body', (t) => { contentType ) - t.same(fields[0], { key: 'key', value: 'value' }) + t.deepStrictEqual(fields[0], { key: 'key', value: 'value' }) t.ok(fileMap.has('file')) - t.equal(fileMap.get('file').data.toString(), 'Hello, world!') - t.same(fileMap.get('file').info, { + t.strictEqual(fileMap.get('file').data.toString(), 'Hello, world!') + t.deepStrictEqual(fileMap.get('file').info, { filename: 'hello_world.txt', encoding: '7bit', mimeType: 'application/octet-stream' @@ -752,11 +793,11 @@ test('request with FormData body', (t) => { return res.end() }) - t.teardown(server.close.bind(server)) + after(() => server.close()) server.listen(0, async () => { const client = new Client(`http://localhost:${server.address().port}`) - t.teardown(client.destroy.bind(client)) + after(() => client.destroy()) await client.request({ path: '/', @@ -766,10 +807,12 @@ test('request with FormData body', (t) => { t.end() }) + + await t.completed }) -test('request post body Buffer from string', (t) => { - t.plan(2) +test('request post body Buffer from string', async (t) => { + t = tspl(t, { plan: 2 }) const requestBody = Buffer.from('abcdefghijklmnopqrstuvwxyz') const server = createServer(async (req, res) => { @@ -777,14 +820,14 @@ test('request post body Buffer from string', (t) => { for await (const chunk of req) { ret += chunk } - t.equal(ret, 'abcdefghijklmnopqrstuvwxyz') + t.strictEqual(ret, 'abcdefghijklmnopqrstuvwxyz') res.end() }) - t.teardown(server.close.bind(server)) + after(() => server.close()) server.listen(0, async () => { const client = new Client(`http://localhost:${server.address().port}`) - t.teardown(client.destroy.bind(client)) + after(() => client.destroy()) const { body } = await client.request({ path: '/', @@ -795,10 +838,12 @@ test('request post body Buffer from string', (t) => { await body.text() t.ok(true, 'pass') }) + + await t.completed }) -test('request post body Buffer from buffer', (t) => { - t.plan(2) +test('request post body Buffer from buffer', async (t) => { + t = tspl(t, { plan: 2 }) const fullBuffer = new TextEncoder().encode('abcdefghijklmnopqrstuvwxyz') const requestBody = Buffer.from(fullBuffer.buffer, 8, 16) @@ -807,14 +852,14 @@ test('request post body Buffer from buffer', (t) => { for await (const chunk of req) { ret += chunk } - t.equal(ret, 'ijklmnopqrstuvwx') + t.strictEqual(ret, 'ijklmnopqrstuvwx') res.end() }) - t.teardown(server.close.bind(server)) + after(() => server.close()) server.listen(0, async () => { const client = new Client(`http://localhost:${server.address().port}`) - t.teardown(client.destroy.bind(client)) + after(() => client.destroy()) const { body } = await client.request({ path: '/', @@ -825,10 +870,12 @@ test('request post body Buffer from buffer', (t) => { await body.text() t.ok(true, 'pass') }) + + await t.completed }) -test('request post body Uint8Array', (t) => { - t.plan(2) +test('request post body Uint8Array', async (t) => { + t = tspl(t, { plan: 2 }) const fullBuffer = new TextEncoder().encode('abcdefghijklmnopqrstuvwxyz') const requestBody = new Uint8Array(fullBuffer.buffer, 8, 16) @@ -837,14 +884,14 @@ test('request post body Uint8Array', (t) => { for await (const chunk of req) { ret += chunk } - t.equal(ret, 'ijklmnopqrstuvwx') + t.strictEqual(ret, 'ijklmnopqrstuvwx') res.end() }) - t.teardown(server.close.bind(server)) + after(() => server.close()) server.listen(0, async () => { const client = new Client(`http://localhost:${server.address().port}`) - t.teardown(client.destroy.bind(client)) + after(() => client.destroy()) const { body } = await client.request({ path: '/', @@ -855,10 +902,12 @@ test('request post body Uint8Array', (t) => { await body.text() t.ok(true, 'pass') }) + + await t.completed }) -test('request post body Uint32Array', (t) => { - t.plan(2) +test('request post body Uint32Array', async (t) => { + t = tspl(t, { plan: 2 }) const fullBuffer = new TextEncoder().encode('abcdefghijklmnopqrstuvwxyz') const requestBody = new Uint32Array(fullBuffer.buffer, 8, 4) @@ -867,14 +916,14 @@ test('request post body Uint32Array', (t) => { for await (const chunk of req) { ret += chunk } - t.equal(ret, 'ijklmnopqrstuvwx') + t.strictEqual(ret, 'ijklmnopqrstuvwx') res.end() }) - t.teardown(server.close.bind(server)) + after(() => server.close()) server.listen(0, async () => { const client = new Client(`http://localhost:${server.address().port}`) - t.teardown(client.destroy.bind(client)) + after(() => client.destroy()) const { body } = await client.request({ path: '/', @@ -885,10 +934,12 @@ test('request post body Uint32Array', (t) => { await body.text() t.ok(true, 'pass') }) + + await t.completed }) -test('request post body Float64Array', (t) => { - t.plan(2) +test('request post body Float64Array', async (t) => { + t = tspl(t, { plan: 2 }) const fullBuffer = new TextEncoder().encode('abcdefghijklmnopqrstuvwxyz') const requestBody = new Float64Array(fullBuffer.buffer, 8, 2) @@ -897,14 +948,14 @@ test('request post body Float64Array', (t) => { for await (const chunk of req) { ret += chunk } - t.equal(ret, 'ijklmnopqrstuvwx') + t.strictEqual(ret, 'ijklmnopqrstuvwx') res.end() }) - t.teardown(server.close.bind(server)) + after(() => server.close()) server.listen(0, async () => { const client = new Client(`http://localhost:${server.address().port}`) - t.teardown(client.destroy.bind(client)) + after(() => client.destroy()) const { body } = await client.request({ path: '/', @@ -915,10 +966,12 @@ test('request post body Float64Array', (t) => { await body.text() t.ok(true, 'pass') }) + + await t.completed }) -test('request post body BigUint64Array', (t) => { - t.plan(2) +test('request post body BigUint64Array', async (t) => { + t = tspl(t, { plan: 2 }) const fullBuffer = new TextEncoder().encode('abcdefghijklmnopqrstuvwxyz') const requestBody = new BigUint64Array(fullBuffer.buffer, 8, 2) @@ -927,14 +980,14 @@ test('request post body BigUint64Array', (t) => { for await (const chunk of req) { ret += chunk } - t.equal(ret, 'ijklmnopqrstuvwx') + t.strictEqual(ret, 'ijklmnopqrstuvwx') res.end() }) - t.teardown(server.close.bind(server)) + after(() => server.close()) server.listen(0, async () => { const client = new Client(`http://localhost:${server.address().port}`) - t.teardown(client.destroy.bind(client)) + after(() => client.destroy()) const { body } = await client.request({ path: '/', @@ -945,10 +998,12 @@ test('request post body BigUint64Array', (t) => { await body.text() t.ok(true, 'pass') }) + + await t.completed }) -test('request post body DataView', (t) => { - t.plan(2) +test('request post body DataView', async (t) => { + t = tspl(t, { plan: 2 }) const fullBuffer = new TextEncoder().encode('abcdefghijklmnopqrstuvwxyz') const requestBody = new DataView(fullBuffer.buffer, 8, 16) @@ -957,14 +1012,14 @@ test('request post body DataView', (t) => { for await (const chunk of req) { ret += chunk } - t.equal(ret, 'ijklmnopqrstuvwx') + t.strictEqual(ret, 'ijklmnopqrstuvwx') res.end() }) - t.teardown(server.close.bind(server)) + after(() => server.close()) server.listen(0, async () => { const client = new Client(`http://localhost:${server.address().port}`) - t.teardown(client.destroy.bind(client)) + after(() => client.destroy()) const { body } = await client.request({ path: '/', @@ -975,4 +1030,6 @@ test('request post body DataView', (t) => { await body.text() t.ok(true, 'pass') }) + + await t.completed }) diff --git a/test/client.js b/test/client.js index 7c3c8d0fcb3..155023f936e 100644 --- a/test/client.js +++ b/test/client.js @@ -1,9 +1,10 @@ 'use strict' +const { tspl } = require('@matteo.collina/tspl') const { readFileSync, createReadStream } = require('node:fs') const { createServer } = require('node:http') const { Readable } = require('node:stream') -const { test } = require('tap') +const { test, after } = require('node:test') const { Client, errors } = require('..') const { kSocket } = require('../lib/core/symbols') const { wrapWithAsyncIterable } = require('./utils/async-iterators') @@ -18,20 +19,20 @@ const hasIPv6 = (() => { ) })() -test('basic get', (t) => { - t.plan(24) +test('basic get', async (t) => { + t = tspl(t, { plan: 24 }) const server = createServer((req, res) => { - t.equal('/', req.url) - t.equal('GET', req.method) - t.equal(`localhost:${server.address().port}`, req.headers.host) - t.equal(undefined, req.headers.foo) - t.equal('bar', req.headers.bar) - t.equal(undefined, req.headers['content-length']) + t.strictEqual('/', req.url) + t.strictEqual('GET', req.method) + t.strictEqual(`localhost:${server.address().port}`, req.headers.host) + t.strictEqual(undefined, req.headers.foo) + t.strictEqual('bar', req.headers.bar) + t.strictEqual(undefined, req.headers['content-length']) res.setHeader('Content-Type', 'text/plain') res.end('hello') }) - t.teardown(server.close.bind(server)) + after(() => server.close()) const reqHeaders = { foo: undefined, @@ -42,9 +43,9 @@ test('basic get', (t) => { const client = new Client(`http://localhost:${server.address().port}`, { keepAliveTimeout: 300e3 }) - t.teardown(client.close.bind(client)) + after(() => client.close()) - t.equal(client[kUrl].origin, `http://localhost:${server.address().port}`) + t.strictEqual(client[kUrl].origin, `http://localhost:${server.address().port}`) const signal = new EE() client.request({ @@ -53,56 +54,58 @@ test('basic get', (t) => { method: 'GET', headers: reqHeaders }, (err, data) => { - t.error(err) + t.ifError(err) const { statusCode, headers, body } = data - t.equal(statusCode, 200) - t.equal(signal.listenerCount('abort'), 1) - t.equal(headers['content-type'], 'text/plain') + t.strictEqual(statusCode, 200) + t.strictEqual(signal.listenerCount('abort'), 1) + t.strictEqual(headers['content-type'], 'text/plain') const bufs = [] body.on('data', (buf) => { bufs.push(buf) }) body.on('end', () => { - t.equal(signal.listenerCount('abort'), 0) - t.equal('hello', Buffer.concat(bufs).toString('utf8')) + t.strictEqual(signal.listenerCount('abort'), 0) + t.strictEqual('hello', Buffer.concat(bufs).toString('utf8')) }) }) - t.equal(signal.listenerCount('abort'), 1) + t.strictEqual(signal.listenerCount('abort'), 1) client.request({ path: '/', method: 'GET', headers: reqHeaders }, (err, { statusCode, headers, body }) => { - t.error(err) - t.equal(statusCode, 200) - t.equal(headers['content-type'], 'text/plain') + t.ifError(err) + t.strictEqual(statusCode, 200) + t.strictEqual(headers['content-type'], 'text/plain') const bufs = [] body.on('data', (buf) => { bufs.push(buf) }) body.on('end', () => { - t.equal('hello', Buffer.concat(bufs).toString('utf8')) + t.strictEqual('hello', Buffer.concat(bufs).toString('utf8')) }) }) }) + + await t.completed }) -test('basic get with custom request.reset=true', (t) => { - t.plan(26) +test('basic get with custom request.reset=true', async (t) => { + t = tspl(t, { plan: 26 }) const server = createServer((req, res) => { - t.equal('/', req.url) - t.equal('GET', req.method) - t.equal(`localhost:${server.address().port}`, req.headers.host) - t.equal(req.headers.connection, 'close') - t.equal(undefined, req.headers.foo) - t.equal('bar', req.headers.bar) - t.equal(undefined, req.headers['content-length']) + t.strictEqual('/', req.url) + t.strictEqual('GET', req.method) + t.strictEqual(`localhost:${server.address().port}`, req.headers.host) + t.strictEqual(req.headers.connection, 'close') + t.strictEqual(undefined, req.headers.foo) + t.strictEqual('bar', req.headers.bar) + t.strictEqual(undefined, req.headers['content-length']) res.setHeader('Content-Type', 'text/plain') res.end('hello') }) - t.teardown(server.close.bind(server)) + after(() => server.close()) const reqHeaders = { foo: undefined, @@ -111,9 +114,9 @@ test('basic get with custom request.reset=true', (t) => { server.listen(0, () => { const client = new Client(`http://localhost:${server.address().port}`, {}) - t.teardown(client.close.bind(client)) + after(() => client.close()) - t.equal(client[kUrl].origin, `http://localhost:${server.address().port}`) + t.strictEqual(client[kUrl].origin, `http://localhost:${server.address().port}`) const signal = new EE() client.request({ @@ -123,21 +126,21 @@ test('basic get with custom request.reset=true', (t) => { reset: true, headers: reqHeaders }, (err, data) => { - t.error(err) + t.ifError(err) const { statusCode, headers, body } = data - t.equal(statusCode, 200) - t.equal(signal.listenerCount('abort'), 1) - t.equal(headers['content-type'], 'text/plain') + t.strictEqual(statusCode, 200) + t.strictEqual(signal.listenerCount('abort'), 1) + t.strictEqual(headers['content-type'], 'text/plain') const bufs = [] body.on('data', (buf) => { bufs.push(buf) }) body.on('end', () => { - t.equal(signal.listenerCount('abort'), 0) - t.equal('hello', Buffer.concat(bufs).toString('utf8')) + t.strictEqual(signal.listenerCount('abort'), 0) + t.strictEqual('hello', Buffer.concat(bufs).toString('utf8')) }) }) - t.equal(signal.listenerCount('abort'), 1) + t.strictEqual(signal.listenerCount('abort'), 1) client.request({ path: '/', @@ -145,26 +148,28 @@ test('basic get with custom request.reset=true', (t) => { method: 'GET', headers: reqHeaders }, (err, { statusCode, headers, body }) => { - t.error(err) - t.equal(statusCode, 200) - t.equal(headers['content-type'], 'text/plain') + t.ifError(err) + t.strictEqual(statusCode, 200) + t.strictEqual(headers['content-type'], 'text/plain') const bufs = [] body.on('data', (buf) => { bufs.push(buf) }) body.on('end', () => { - t.equal('hello', Buffer.concat(bufs).toString('utf8')) + t.strictEqual('hello', Buffer.concat(bufs).toString('utf8')) }) }) }) + + await t.completed }) -test('basic get with query params', (t) => { - t.plan(4) +test('basic get with query params', async (t) => { + t = tspl(t, { plan: 4 }) const server = createServer((req, res) => { const searchParamsObject = buildParams(req.url) - t.strictSame(searchParamsObject, { + t.deepStrictEqual(searchParamsObject, { bool: 'true', foo: '1', bar: 'bar', @@ -177,7 +182,7 @@ test('basic get with query params', (t) => { res.statusCode = 200 res.end('hello') }) - t.teardown(server.close.bind(server)) + after(() => server.close()) const query = { bool: true, @@ -193,7 +198,7 @@ test('basic get with query params', (t) => { const client = new Client(`http://localhost:${server.address().port}`, { keepAliveTimeout: 300e3 }) - t.teardown(client.close.bind(client)) + after(() => client.close()) const signal = new EE() client.request({ @@ -202,21 +207,23 @@ test('basic get with query params', (t) => { method: 'GET', query }, (err, data) => { - t.error(err) + t.ifError(err) const { statusCode } = data - t.equal(statusCode, 200) + t.strictEqual(statusCode, 200) }) - t.equal(signal.listenerCount('abort'), 1) + t.strictEqual(signal.listenerCount('abort'), 1) }) + + await t.completed }) -test('basic get with query params fails if url includes hashmark', (t) => { - t.plan(1) +test('basic get with query params fails if url includes hashmark', async (t) => { + t = tspl(t, { plan: 1 }) const server = createServer((req, res) => { t.fail() }) - t.teardown(server.close.bind(server)) + after(() => server.close()) const query = { foo: 1, @@ -228,7 +235,7 @@ test('basic get with query params fails if url includes hashmark', (t) => { const client = new Client(`http://localhost:${server.address().port}`, { keepAliveTimeout: 300e3 }) - t.teardown(client.close.bind(client)) + after(() => client.close()) const signal = new EE() client.request({ @@ -237,22 +244,24 @@ test('basic get with query params fails if url includes hashmark', (t) => { method: 'GET', query }, (err, data) => { - t.equal(err.message, 'Query params cannot be passed when url already contains "?" or "#".') + t.strictEqual(err.message, 'Query params cannot be passed when url already contains "?" or "#".') }) }) + + await t.completed }) -test('basic get with empty query params', (t) => { - t.plan(4) +test('basic get with empty query params', async (t) => { + t = tspl(t, { plan: 4 }) const server = createServer((req, res) => { const searchParamsObject = buildParams(req.url) - t.strictSame(searchParamsObject, {}) + t.deepStrictEqual(searchParamsObject, {}) res.statusCode = 200 res.end('hello') }) - t.teardown(server.close.bind(server)) + after(() => server.close()) const query = {} @@ -260,7 +269,7 @@ test('basic get with empty query params', (t) => { const client = new Client(`http://localhost:${server.address().port}`, { keepAliveTimeout: 300e3 }) - t.teardown(client.close.bind(client)) + after(() => client.close()) const signal = new EE() client.request({ @@ -269,21 +278,23 @@ test('basic get with empty query params', (t) => { method: 'GET', query }, (err, data) => { - t.error(err) + t.ifError(err) const { statusCode } = data - t.equal(statusCode, 200) + t.strictEqual(statusCode, 200) }) - t.equal(signal.listenerCount('abort'), 1) + t.strictEqual(signal.listenerCount('abort'), 1) }) + + await t.completed }) -test('basic get with query params partially in path', (t) => { - t.plan(1) +test('basic get with query params partially in path', async (t) => { + t = tspl(t, { plan: 1 }) const server = createServer((req, res) => { t.fail() }) - t.teardown(server.close.bind(server)) + after(() => server.close()) const query = { foo: 1 @@ -293,7 +304,7 @@ test('basic get with query params partially in path', (t) => { const client = new Client(`http://localhost:${server.address().port}`, { keepAliveTimeout: 300e3 }) - t.teardown(client.close.bind(client)) + after(() => client.close()) const signal = new EE() client.request({ @@ -302,25 +313,27 @@ test('basic get with query params partially in path', (t) => { method: 'GET', query }, (err, data) => { - t.equal(err.message, 'Query params cannot be passed when url already contains "?" or "#".') + t.strictEqual(err.message, 'Query params cannot be passed when url already contains "?" or "#".') }) }) + + await t.completed }) -test('basic get returns 400 when configured to throw on errors (callback)', (t) => { - t.plan(7) +test('basic get returns 400 when configured to throw on errors (callback)', async (t) => { + t = tspl(t, { plan: 7 }) const server = createServer((req, res) => { res.statusCode = 400 res.end('hello') }) - t.teardown(server.close.bind(server)) + after(() => server.close()) server.listen(0, () => { const client = new Client(`http://localhost:${server.address().port}`, { keepAliveTimeout: 300e3 }) - t.teardown(client.close.bind(client)) + after(() => client.close()) const signal = new EE() client.request({ @@ -329,31 +342,33 @@ test('basic get returns 400 when configured to throw on errors (callback)', (t) method: 'GET', throwOnError: true }, (err) => { - t.equal(err.message, 'Response status code 400: Bad Request') - t.equal(err.status, 400) - t.equal(err.statusCode, 400) - t.equal(err.headers.connection, 'keep-alive') - t.equal(err.headers['content-length'], '5') - t.same(err.body, null) + t.strictEqual(err.message, 'Response status code 400: Bad Request') + t.strictEqual(err.status, 400) + t.strictEqual(err.statusCode, 400) + t.strictEqual(err.headers.connection, 'keep-alive') + t.strictEqual(err.headers['content-length'], '5') + t.strictEqual(err.body, undefined) }) - t.equal(signal.listenerCount('abort'), 1) + t.strictEqual(signal.listenerCount('abort'), 1) }) + + await t.completed }) -test('basic get returns 400 when configured to throw on errors and correctly handles malformed json (callback)', (t) => { - t.plan(6) +test('basic get returns 400 when configured to throw on errors and correctly handles malformed json (callback)', async (t) => { + t = tspl(t, { plan: 6 }) const server = createServer((req, res) => { res.writeHead(400, 'Invalid params', { 'content-type': 'application/json' }) res.end('Invalid params') }) - t.teardown(server.close.bind(server)) + after(() => server.close()) server.listen(0, () => { const client = new Client(`http://localhost:${server.address().port}`, { keepAliveTimeout: 300e3 }) - t.teardown(client.close.bind(client)) + after(() => client.close()) const signal = new EE() client.request({ @@ -362,30 +377,32 @@ test('basic get returns 400 when configured to throw on errors and correctly han method: 'GET', throwOnError: true }, (err) => { - t.equal(err.message, 'Response status code 400: Invalid params') - t.equal(err.status, 400) - t.equal(err.statusCode, 400) - t.equal(err.headers.connection, 'keep-alive') - t.same(err.body, null) + t.strictEqual(err.message, 'Response status code 400: Invalid params') + t.strictEqual(err.status, 400) + t.strictEqual(err.statusCode, 400) + t.strictEqual(err.headers.connection, 'keep-alive') + t.strictEqual(err.body, undefined) }) - t.equal(signal.listenerCount('abort'), 1) + t.strictEqual(signal.listenerCount('abort'), 1) }) + + await t.completed }) -test('basic get returns 400 when configured to throw on errors (promise)', (t) => { - t.plan(6) +test('basic get returns 400 when configured to throw on errors (promise)', async (t) => { + t = tspl(t, { plan: 6 }) const server = createServer((req, res) => { res.writeHead(400, 'Invalid params', { 'content-type': 'text/plain' }) res.end('Invalid params') }) - t.teardown(server.close.bind(server)) + after(() => server.close()) server.listen(0, async () => { const client = new Client(`http://localhost:${server.address().port}`, { keepAliveTimeout: 300e3 }) - t.teardown(client.close.bind(client)) + after(() => client.close()) const signal = new EE() try { @@ -397,18 +414,20 @@ test('basic get returns 400 when configured to throw on errors (promise)', (t) = }) t.fail('Should throw an error') } catch (err) { - t.equal(err.message, 'Response status code 400: Invalid params') - t.equal(err.status, 400) - t.equal(err.statusCode, 400) - t.equal(err.body, 'Invalid params') - t.equal(err.headers.connection, 'keep-alive') - t.equal(err.headers['content-type'], 'text/plain') + t.strictEqual(err.message, 'Response status code 400: Invalid params') + t.strictEqual(err.status, 400) + t.strictEqual(err.statusCode, 400) + t.strictEqual(err.body, 'Invalid params') + t.strictEqual(err.headers.connection, 'keep-alive') + t.strictEqual(err.headers['content-type'], 'text/plain') } }) + + await t.completed }) -test('basic get returns error body when configured to throw on errors', (t) => { - t.plan(6) +test('basic get returns error body when configured to throw on errors', async (t) => { + t = tspl(t, { plan: 6 }) const server = createServer((req, res) => { const body = { msg: 'Error', details: { code: 94 } } @@ -418,13 +437,13 @@ test('basic get returns error body when configured to throw on errors', (t) => { }) res.end(bodyAsString) }) - t.teardown(server.close.bind(server)) + after(() => server.close()) server.listen(0, async () => { const client = new Client(`http://localhost:${server.address().port}`, { keepAliveTimeout: 300e3 }) - t.teardown(client.close.bind(client)) + after(() => client.close()) const signal = new EE() try { @@ -436,36 +455,38 @@ test('basic get returns error body when configured to throw on errors', (t) => { }) t.fail('Should throw an error') } catch (err) { - t.equal(err.message, 'Response status code 400: Invalid params') - t.equal(err.status, 400) - t.equal(err.statusCode, 400) - t.equal(err.headers.connection, 'keep-alive') - t.equal(err.headers['content-type'], 'application/json') - t.same(err.body, { msg: 'Error', details: { code: 94 } }) + t.strictEqual(err.message, 'Response status code 400: Invalid params') + t.strictEqual(err.status, 400) + t.strictEqual(err.statusCode, 400) + t.strictEqual(err.headers.connection, 'keep-alive') + t.strictEqual(err.headers['content-type'], 'application/json') + t.deepStrictEqual(err.body, { msg: 'Error', details: { code: 94 } }) } }) + + await t.completed }) -test('basic head', (t) => { - t.plan(14) +test('basic head', async (t) => { + t = tspl(t, { plan: 14 }) const server = createServer((req, res) => { - t.equal('/123', req.url) - t.equal('HEAD', req.method) - t.equal(`localhost:${server.address().port}`, req.headers.host) + t.strictEqual('/123', req.url) + t.strictEqual('HEAD', req.method) + t.strictEqual(`localhost:${server.address().port}`, req.headers.host) res.setHeader('content-type', 'text/plain') res.end('hello') }) - t.teardown(server.close.bind(server)) + after(() => server.close()) server.listen(0, () => { const client = new Client(`http://localhost:${server.address().port}`) - t.teardown(client.close.bind(client)) + after(() => client.close()) client.request({ path: '/123', method: 'HEAD' }, (err, { statusCode, headers, body }) => { - t.error(err) - t.equal(statusCode, 200) - t.equal(headers['content-type'], 'text/plain') + t.ifError(err) + t.strictEqual(statusCode, 200) + t.strictEqual(headers['content-type'], 'text/plain') body .resume() .on('end', () => { @@ -474,9 +495,9 @@ test('basic head', (t) => { }) client.request({ path: '/123', method: 'HEAD' }, (err, { statusCode, headers, body }) => { - t.error(err) - t.equal(statusCode, 200) - t.equal(headers['content-type'], 'text/plain') + t.ifError(err) + t.strictEqual(statusCode, 200) + t.strictEqual(headers['content-type'], 'text/plain') body .resume() .on('end', () => { @@ -484,28 +505,30 @@ test('basic head', (t) => { }) }) }) + + await t.completed }) -test('basic head (IPv6)', { skip: !hasIPv6 }, (t) => { - t.plan(14) +test('basic head (IPv6)', { skip: !hasIPv6 }, async (t) => { + t = tspl(t, { plan: 15 }) const server = createServer((req, res) => { - t.equal('/123', req.url) - t.equal('HEAD', req.method) - t.equal(`[::1]:${server.address().port}`, req.headers.host) + t.strictEqual('/123', req.url) + t.strictEqual('HEAD', req.method) + t.strictEqual(`[::1]:${server.address().port}`, req.headers.host) res.setHeader('content-type', 'text/plain') res.end('hello') }) - t.teardown(server.close.bind(server)) + after(() => server.close()) server.listen(0, '::', () => { const client = new Client(`http://[::1]:${server.address().port}`) - t.teardown(client.close.bind(client)) + after(() => client.close()) client.request({ path: '/123', method: 'HEAD' }, (err, { statusCode, headers, body }) => { - t.error(err) - t.equal(statusCode, 200) - t.equal(headers['content-type'], 'text/plain') + t.ifError(err) + t.strictEqual(statusCode, 200) + t.strictEqual(headers['content-type'], 'text/plain') body .resume() .on('end', () => { @@ -514,9 +537,9 @@ test('basic head (IPv6)', { skip: !hasIPv6 }, (t) => { }) client.request({ path: '/123', method: 'HEAD' }, (err, { statusCode, headers, body }) => { - t.error(err) - t.equal(statusCode, 200) - t.equal(headers['content-type'], 'text/plain') + t.ifError(err) + t.strictEqual(statusCode, 200) + t.strictEqual(headers['content-type'], 'text/plain') body .resume() .on('end', () => { @@ -524,90 +547,96 @@ test('basic head (IPv6)', { skip: !hasIPv6 }, (t) => { }) }) }) + + await t.completed }) -test('get with host header', (t) => { - t.plan(7) +test('get with host header', async (t) => { + t = tspl(t, { plan: 7 }) const server = createServer((req, res) => { - t.equal('/', req.url) - t.equal('GET', req.method) - t.equal('example.com', req.headers.host) + t.strictEqual('/', req.url) + t.strictEqual('GET', req.method) + t.strictEqual('example.com', req.headers.host) res.setHeader('content-type', 'text/plain') res.end('hello from ' + req.headers.host) }) - t.teardown(server.close.bind(server)) + after(() => server.close()) server.listen(0, () => { const client = new Client(`http://localhost:${server.address().port}`) - t.teardown(client.close.bind(client)) + after(() => client.close()) client.request({ path: '/', method: 'GET', headers: { host: 'example.com' } }, (err, { statusCode, headers, body }) => { - t.error(err) - t.equal(statusCode, 200) - t.equal(headers['content-type'], 'text/plain') + t.ifError(err) + t.strictEqual(statusCode, 200) + t.strictEqual(headers['content-type'], 'text/plain') const bufs = [] body.on('data', (buf) => { bufs.push(buf) }) body.on('end', () => { - t.equal('hello from example.com', Buffer.concat(bufs).toString('utf8')) + t.strictEqual('hello from example.com', Buffer.concat(bufs).toString('utf8')) }) }) }) + + await t.completed }) -test('get with host header (IPv6)', { skip: !hasIPv6 }, (t) => { - t.plan(7) +test('get with host header (IPv6)', { skip: !hasIPv6 }, async (t) => { + t = tspl(t, { plan: 7 }) const server = createServer((req, res) => { - t.equal('/', req.url) - t.equal('GET', req.method) - t.equal('[::1]', req.headers.host) + t.strictEqual('/', req.url) + t.strictEqual('GET', req.method) + t.strictEqual('[::1]', req.headers.host) res.setHeader('content-type', 'text/plain') res.end('hello from ' + req.headers.host) }) - t.teardown(server.close.bind(server)) + after(() => server.close()) server.listen(0, '::', () => { const client = new Client(`http://[::1]:${server.address().port}`) - t.teardown(client.close.bind(client)) + after(() => client.close()) client.request({ path: '/', method: 'GET', headers: { host: '[::1]' } }, (err, { statusCode, headers, body }) => { - t.error(err) - t.equal(statusCode, 200) - t.equal(headers['content-type'], 'text/plain') + t.ifError(err) + t.strictEqual(statusCode, 200) + t.strictEqual(headers['content-type'], 'text/plain') const bufs = [] body.on('data', (buf) => { bufs.push(buf) }) body.on('end', () => { - t.equal('hello from [::1]', Buffer.concat(bufs).toString('utf8')) + t.strictEqual('hello from [::1]', Buffer.concat(bufs).toString('utf8')) }) }) }) + + await t.completed }) -test('head with host header', (t) => { - t.plan(7) +test('head with host header', async (t) => { + t = tspl(t, { plan: 7 }) const server = createServer((req, res) => { - t.equal('/', req.url) - t.equal('HEAD', req.method) - t.equal('example.com', req.headers.host) + t.strictEqual('/', req.url) + t.strictEqual('HEAD', req.method) + t.strictEqual('example.com', req.headers.host) res.setHeader('content-type', 'text/plain') res.end('hello from ' + req.headers.host) }) - t.teardown(server.close.bind(server)) + after(() => server.close()) server.listen(0, () => { const client = new Client(`http://localhost:${server.address().port}`) - t.teardown(client.close.bind(client)) + after(() => client.close()) client.request({ path: '/', method: 'HEAD', headers: { host: 'example.com' } }, (err, { statusCode, headers, body }) => { - t.error(err) - t.equal(statusCode, 200) - t.equal(headers['content-type'], 'text/plain') + t.ifError(err) + t.strictEqual(statusCode, 200) + t.strictEqual(headers['content-type'], 'text/plain') body .resume() .on('end', () => { @@ -615,13 +644,15 @@ test('head with host header', (t) => { }) }) }) + + await t.completed }) function postServer (t, expected) { return function (req, res) { - t.equal(req.url, '/') - t.equal(req.method, 'POST') - t.notSame(req.headers['content-length'], null) + t.strictEqual(req.url, '/') + t.strictEqual(req.method, 'POST') + t.notStrictEqual(req.headers['content-length'], null) req.setEncoding('utf8') let data = '' @@ -629,74 +660,78 @@ function postServer (t, expected) { req.on('data', function (d) { data += d }) req.on('end', () => { - t.equal(data, expected) + t.strictEqual(data, expected) res.end('hello') }) } } -test('basic POST with string', (t) => { - t.plan(7) +test('basic POST with string', async (t) => { + t = tspl(t, { plan: 7 }) const expected = readFileSync(__filename, 'utf8') const server = createServer(postServer(t, expected)) - t.teardown(server.close.bind(server)) + after(() => server.close()) server.listen(0, () => { const client = new Client(`http://localhost:${server.address().port}`) - t.teardown(client.close.bind(client)) + after(() => client.close()) client.request({ path: '/', method: 'POST', body: expected }, (err, data) => { - t.error(err) - t.equal(data.statusCode, 200) + t.ifError(err) + t.strictEqual(data.statusCode, 200) const bufs = [] data.body .on('data', (buf) => { bufs.push(buf) }) .on('end', () => { - t.equal('hello', Buffer.concat(bufs).toString('utf8')) + t.strictEqual('hello', Buffer.concat(bufs).toString('utf8')) }) }) }) + + await t.completed }) -test('basic POST with empty string', (t) => { - t.plan(7) +test('basic POST with empty string', async (t) => { + t = tspl(t, { plan: 7 }) const server = createServer(postServer(t, '')) - t.teardown(server.close.bind(server)) + after(() => server.close()) server.listen(0, () => { const client = new Client(`http://localhost:${server.address().port}`) - t.teardown(client.close.bind(client)) + after(() => client.close()) client.request({ path: '/', method: 'POST', body: '' }, (err, { statusCode, headers, body }) => { - t.error(err) - t.equal(statusCode, 200) + t.ifError(err) + t.strictEqual(statusCode, 200) const bufs = [] body.on('data', (buf) => { bufs.push(buf) }) body.on('end', () => { - t.equal('hello', Buffer.concat(bufs).toString('utf8')) + t.strictEqual('hello', Buffer.concat(bufs).toString('utf8')) }) }) }) + + await t.completed }) -test('basic POST with string and content-length', (t) => { - t.plan(7) +test('basic POST with string and content-length', async (t) => { + t = tspl(t, { plan: 7 }) const expected = readFileSync(__filename, 'utf8') const server = createServer(postServer(t, expected)) - t.teardown(server.close.bind(server)) + after(() => server.close()) server.listen(0, () => { const client = new Client(`http://localhost:${server.address().port}`) - t.teardown(client.close.bind(client)) + after(() => client.close()) client.request({ path: '/', @@ -706,56 +741,60 @@ test('basic POST with string and content-length', (t) => { }, body: expected }, (err, { statusCode, headers, body }) => { - t.error(err) - t.equal(statusCode, 200) + t.ifError(err) + t.strictEqual(statusCode, 200) const bufs = [] body.on('data', (buf) => { bufs.push(buf) }) body.on('end', () => { - t.equal('hello', Buffer.concat(bufs).toString('utf8')) + t.strictEqual('hello', Buffer.concat(bufs).toString('utf8')) }) }) }) + + await t.completed }) -test('basic POST with Buffer', (t) => { - t.plan(7) +test('basic POST with Buffer', async (t) => { + t = tspl(t, { plan: 7 }) const expected = readFileSync(__filename) const server = createServer(postServer(t, expected.toString())) - t.teardown(server.close.bind(server)) + after(() => server.close()) server.listen(0, () => { const client = new Client(`http://localhost:${server.address().port}`) - t.teardown(client.close.bind(client)) + after(() => client.close()) client.request({ path: '/', method: 'POST', body: expected }, (err, { statusCode, headers, body }) => { - t.error(err) - t.equal(statusCode, 200) + t.ifError(err) + t.strictEqual(statusCode, 200) const bufs = [] body.on('data', (buf) => { bufs.push(buf) }) body.on('end', () => { - t.equal('hello', Buffer.concat(bufs).toString('utf8')) + t.strictEqual('hello', Buffer.concat(bufs).toString('utf8')) }) }) }) + + await t.completed }) -test('basic POST with stream', (t) => { - t.plan(7) +test('basic POST with stream', async (t) => { + t = tspl(t, { plan: 7 }) const expected = readFileSync(__filename, 'utf8') const server = createServer(postServer(t, expected)) - t.teardown(server.close.bind(server)) + after(() => server.close()) server.listen(0, () => { const client = new Client(`http://localhost:${server.address().port}`) - t.teardown(client.close.bind(client)) + after(() => client.close()) client.request({ path: '/', @@ -766,30 +805,32 @@ test('basic POST with stream', (t) => { headersTimeout: 0, body: createReadStream(__filename) }, (err, { statusCode, headers, body }) => { - t.error(err) - t.equal(statusCode, 200) + t.ifError(err) + t.strictEqual(statusCode, 200) const bufs = [] body.on('data', (buf) => { bufs.push(buf) }) body.on('end', () => { - t.equal('hello', Buffer.concat(bufs).toString('utf8')) + t.strictEqual('hello', Buffer.concat(bufs).toString('utf8')) }) }) }) + + await t.completed }) -test('basic POST with paused stream', (t) => { - t.plan(7) +test('basic POST with paused stream', async (t) => { + t = tspl(t, { plan: 7 }) const expected = readFileSync(__filename, 'utf8') const server = createServer(postServer(t, expected)) - t.teardown(server.close.bind(server)) + after(() => server.close()) server.listen(0, () => { const client = new Client(`http://localhost:${server.address().port}`) - t.teardown(client.close.bind(client)) + after(() => client.close()) const stream = createReadStream(__filename) stream.pause() @@ -802,32 +843,34 @@ test('basic POST with paused stream', (t) => { headersTimeout: 0, body: stream }, (err, { statusCode, headers, body }) => { - t.error(err) - t.equal(statusCode, 200) + t.ifError(err) + t.strictEqual(statusCode, 200) const bufs = [] body.on('data', (buf) => { bufs.push(buf) }) body.on('end', () => { - t.equal('hello', Buffer.concat(bufs).toString('utf8')) + t.strictEqual('hello', Buffer.concat(bufs).toString('utf8')) }) }) }) + + await t.completed }) -test('basic POST with custom stream', (t) => { - t.plan(4) +test('basic POST with custom stream', async (t) => { + t = tspl(t, { plan: 4 }) const server = createServer((req, res) => { req.resume().on('end', () => { res.end('hello') }) }) - t.teardown(server.close.bind(server)) + after(() => server.close()) server.listen(0, () => { const client = new Client(`http://localhost:${server.address().port}`) - t.teardown(client.close.bind(client)) + after(() => client.close()) const body = new EE() body.pipe = () => {} @@ -837,17 +880,17 @@ test('basic POST with custom stream', (t) => { headersTimeout: 0, body }, (err, data) => { - t.error(err) - t.equal(data.statusCode, 200) + t.ifError(err) + t.strictEqual(data.statusCode, 200) const bufs = [] data.body.on('data', (buf) => { bufs.push(buf) }) data.body.on('end', () => { - t.equal('hello', Buffer.concat(bufs).toString('utf8')) + t.strictEqual('hello', Buffer.concat(bufs).toString('utf8')) }) }) - t.strictSame(client[kBusy], true) + t.deepStrictEqual(client[kBusy], true) body.on('close', () => { body.emit('end') @@ -866,10 +909,12 @@ test('basic POST with custom stream', (t) => { }) }) }) + + await t.completed }) -test('basic POST with iterator', (t) => { - t.plan(3) +test('basic POST with iterator', async (t) => { + t = tspl(t, { plan: 3 }) const expected = 'hello' @@ -878,7 +923,7 @@ test('basic POST with iterator', (t) => { res.end(expected) }) }) - t.teardown(server.close.bind(server)) + after(() => server.close()) const iterable = { [Symbol.iterator]: function * () { @@ -891,7 +936,7 @@ test('basic POST with iterator', (t) => { server.listen(0, () => { const client = new Client(`http://localhost:${server.address().port}`) - t.teardown(client.close.bind(client)) + after(() => client.close()) client.request({ path: '/', @@ -899,24 +944,26 @@ test('basic POST with iterator', (t) => { requestTimeout: 0, body: iterable }, (err, { statusCode, body }) => { - t.error(err) - t.equal(statusCode, 200) + t.ifError(err) + t.strictEqual(statusCode, 200) const bufs = [] body.on('data', (buf) => { bufs.push(buf) }) body.on('end', () => { - t.equal('hello', Buffer.concat(bufs).toString('utf8')) + t.strictEqual('hello', Buffer.concat(bufs).toString('utf8')) }) }) }) + + await t.completed }) -test('basic POST with iterator with invalid data', (t) => { - t.plan(1) +test('basic POST with iterator with invalid data', async (t) => { + t = tspl(t, { plan: 1 }) const server = createServer(() => {}) - t.teardown(server.close.bind(server)) + after(() => server.close()) const iterable = { [Symbol.iterator]: function * () { @@ -926,7 +973,7 @@ test('basic POST with iterator with invalid data', (t) => { server.listen(0, () => { const client = new Client(`http://localhost:${server.address().port}`) - t.teardown(client.close.bind(client)) + after(() => client.close()) client.request({ path: '/', @@ -937,19 +984,21 @@ test('basic POST with iterator with invalid data', (t) => { t.ok(err instanceof TypeError) }) }) + + await t.completed }) -test('basic POST with async iterator', (t) => { - t.plan(7) +test('basic POST with async iterator', async (t) => { + t = tspl(t, { plan: 7 }) const expected = readFileSync(__filename, 'utf8') const server = createServer(postServer(t, expected)) - t.teardown(server.close.bind(server)) + after(() => server.close()) server.listen(0, () => { const client = new Client(`http://localhost:${server.address().port}`) - t.teardown(client.close.bind(client)) + after(() => client.close()) client.request({ path: '/', @@ -960,28 +1009,30 @@ test('basic POST with async iterator', (t) => { headersTimeout: 0, body: wrapWithAsyncIterable(createReadStream(__filename)) }, (err, { statusCode, headers, body }) => { - t.error(err) - t.equal(statusCode, 200) + t.ifError(err) + t.strictEqual(statusCode, 200) const bufs = [] body.on('data', (buf) => { bufs.push(buf) }) body.on('end', () => { - t.equal('hello', Buffer.concat(bufs).toString('utf8')) + t.strictEqual('hello', Buffer.concat(bufs).toString('utf8')) }) }) }) + + await t.completed }) -test('basic POST with transfer encoding: chunked', (t) => { - t.plan(8) +test('basic POST with transfer encoding: chunked', async (t) => { + t = tspl(t, { plan: 8 }) let body const server = createServer(function (req, res) { - t.equal(req.url, '/') - t.equal(req.method, 'POST') - t.same(req.headers['content-length'], null) - t.equal(req.headers['transfer-encoding'], 'chunked') + t.strictEqual(req.url, '/') + t.strictEqual(req.method, 'POST') + t.strictEqual(req.headers['content-length'], undefined) + t.strictEqual(req.headers['transfer-encoding'], 'chunked') body.push(null) @@ -991,15 +1042,15 @@ test('basic POST with transfer encoding: chunked', (t) => { req.on('data', function (d) { data += d }) req.on('end', () => { - t.equal(data, 'asd') + t.strictEqual(data, 'asd') res.end('hello') }) }) - t.teardown(server.close.bind(server)) + after(() => server.close()) server.listen(0, () => { const client = new Client(`http://localhost:${server.address().port}`) - t.teardown(client.close.bind(client)) + after(() => client.close()) body = new Readable({ read () { } @@ -1011,31 +1062,33 @@ test('basic POST with transfer encoding: chunked', (t) => { // no content-length header body }, (err, { statusCode, headers, body }) => { - t.error(err) - t.equal(statusCode, 200) + t.ifError(err) + t.strictEqual(statusCode, 200) const bufs = [] body.on('data', (buf) => { bufs.push(buf) }) body.on('end', () => { - t.equal('hello', Buffer.concat(bufs).toString('utf8')) + t.strictEqual('hello', Buffer.concat(bufs).toString('utf8')) }) }) }) + + await t.completed }) -test('basic POST with empty stream', (t) => { - t.plan(4) +test('basic POST with empty stream', async (t) => { + t = tspl(t, { plan: 4 }) const server = createServer(function (req, res) { - t.same(req.headers['content-length'], 0) + t.deepStrictEqual(req.headers['content-length'], '0') req.pipe(res) }) - t.teardown(server.close.bind(server)) + after(() => server.close()) server.listen(0, () => { const client = new Client(`http://localhost:${server.address().port}`) - t.teardown(client.close.bind(client)) + after(() => client.close()) const body = new Readable({ autoDestroy: false, @@ -1046,7 +1099,7 @@ test('basic POST with empty stream', (t) => { } }).on('end', () => { process.nextTick(() => { - t.equal(body.destroyed, true) + t.strictEqual(body.destroyed, true) }) }) body.push(null) @@ -1055,7 +1108,7 @@ test('basic POST with empty stream', (t) => { method: 'POST', body }, (err, { statusCode, headers, body }) => { - t.error(err) + t.ifError(err) body .on('data', () => { t.fail() @@ -1065,20 +1118,22 @@ test('basic POST with empty stream', (t) => { }) }) }) + + await t.completed }) -test('10 times GET', (t) => { +test('10 times GET', async (t) => { const num = 10 - t.plan(3 * 10) + t = tspl(t, { plan: 3 * num }) const server = createServer((req, res) => { res.end(req.url) }) - t.teardown(server.close.bind(server)) + after(() => server.close()) server.listen(0, () => { const client = new Client(`http://localhost:${server.address().port}`) - t.teardown(client.close.bind(client)) + after(() => client.close()) for (let i = 0; i < num; i++) { makeRequest(i) @@ -1086,32 +1141,34 @@ test('10 times GET', (t) => { function makeRequest (i) { client.request({ path: '/' + i, method: 'GET' }, (err, { statusCode, headers, body }) => { - t.error(err) - t.equal(statusCode, 200) + t.ifError(err) + t.strictEqual(statusCode, 200) const bufs = [] body.on('data', (buf) => { bufs.push(buf) }) body.on('end', () => { - t.equal('/' + i, Buffer.concat(bufs).toString('utf8')) + t.strictEqual('/' + i, Buffer.concat(bufs).toString('utf8')) }) }) } }) + + await t.completed }) -test('10 times HEAD', (t) => { +test('10 times HEAD', async (t) => { const num = 10 - t.plan(3 * 10) + t = tspl(t, { plan: num * 3 }) const server = createServer((req, res) => { res.end(req.url) }) - t.teardown(server.close.bind(server)) + after(() => server.close()) server.listen(0, () => { const client = new Client(`http://localhost:${server.address().port}`) - t.teardown(client.close.bind(client)) + after(() => client.close()) for (let i = 0; i < num; i++) { makeRequest(i) @@ -1119,8 +1176,8 @@ test('10 times HEAD', (t) => { function makeRequest (i) { client.request({ path: '/' + i, method: 'HEAD' }, (err, { statusCode, headers, body }) => { - t.error(err) - t.equal(statusCode, 200) + t.ifError(err) + t.strictEqual(statusCode, 200) body .resume() .on('end', () => { @@ -1129,49 +1186,53 @@ test('10 times HEAD', (t) => { }) } }) + + await t.completed }) -test('Set-Cookie', (t) => { - t.plan(4) +test('Set-Cookie', async (t) => { + t = tspl(t, { plan: 4 }) const server = createServer((req, res) => { res.setHeader('content-type', 'text/plain') res.setHeader('Set-Cookie', ['a cookie', 'another cookie', 'more cookies']) res.end('hello') }) - t.teardown(server.close.bind(server)) + after(() => server.close()) server.listen(0, () => { const client = new Client(`http://localhost:${server.address().port}`) - t.teardown(client.close.bind(client)) + after(() => client.close()) client.request({ path: '/', method: 'GET' }, (err, { statusCode, headers, body }) => { - t.error(err) - t.equal(statusCode, 200) - t.strictSame(headers['set-cookie'], ['a cookie', 'another cookie', 'more cookies']) + t.ifError(err) + t.strictEqual(statusCode, 200) + t.deepStrictEqual(headers['set-cookie'], ['a cookie', 'another cookie', 'more cookies']) const bufs = [] body.on('data', (buf) => { bufs.push(buf) }) body.on('end', () => { - t.equal('hello', Buffer.concat(bufs).toString('utf8')) + t.strictEqual('hello', Buffer.concat(bufs).toString('utf8')) }) }) }) + + await t.completed }) -test('ignore request header mutations', (t) => { - t.plan(2) +test('ignore request header mutations', async (t) => { + t = tspl(t, { plan: 2 }) const server = createServer((req, res) => { - t.equal(req.headers.test, 'test') + t.strictEqual(req.headers.test, 'test') res.end() }) - t.teardown(server.close.bind(server)) + after(() => server.close()) server.listen(0, () => { const client = new Client(`http://localhost:${server.address().port}`) - t.teardown(client.close.bind(client)) + after(() => client.close()) const headers = { test: 'test' } client.request({ @@ -1179,20 +1240,22 @@ test('ignore request header mutations', (t) => { method: 'GET', headers }, (err, { body }) => { - t.error(err) + t.ifError(err) body.resume() }) headers.test = 'asd' }) + + await t.completed }) -test('url-like url', (t) => { - t.plan(1) +test('url-like url', async (t) => { + t = tspl(t, { plan: 1 }) const server = createServer((req, res) => { res.end() }) - t.teardown(server.close.bind(server)) + after(() => server.close()) server.listen(0, () => { const client = new Client({ @@ -1200,25 +1263,27 @@ test('url-like url', (t) => { port: server.address().port, protocol: 'http:' }) - t.teardown(client.close.bind(client)) + after(() => client.close()) client.request({ path: '/', method: 'GET' }, (err, data) => { - t.error(err) + t.ifError(err) data.body.resume() }) }) + + await t.completed }) -test('an absolute url as path', (t) => { - t.plan(2) +test('an absolute url as path', async (t) => { + t = tspl(t, { plan: 2 }) const path = 'http://example.com' const server = createServer((req, res) => { - t.equal(req.url, path) + t.strictEqual(req.url, path) res.end() }) - t.teardown(server.close.bind(server)) + after(() => server.close()) server.listen(0, () => { const client = new Client({ @@ -1226,22 +1291,24 @@ test('an absolute url as path', (t) => { port: server.address().port, protocol: 'http:' }) - t.teardown(client.close.bind(client)) + after(() => client.close()) client.request({ path, method: 'GET' }, (err, data) => { - t.error(err) + t.ifError(err) data.body.resume() }) }) + + await t.completed }) -test('multiple destroy callback', (t) => { - t.plan(4) +test('multiple destroy callback', async (t) => { + t = tspl(t, { plan: 4 }) const server = createServer((req, res) => { res.end() }) - t.teardown(server.close.bind(server)) + after(() => server.close()) server.listen(0, () => { const client = new Client({ @@ -1249,51 +1316,53 @@ test('multiple destroy callback', (t) => { port: server.address().port, protocol: 'http:' }) - t.teardown(client.destroy.bind(client)) + after(() => client.destroy()) client.request({ path: '/', method: 'GET' }, (err, data) => { - t.error(err) + t.ifError(err) data.body .resume() - .on('error', () => { - t.ok(true, 'pass') + .on('error', (err) => { + t.ok(err instanceof Error) }) client.destroy(new Error(), (err) => { - t.error(err) + t.ifError(err) }) client.destroy(new Error(), (err) => { - t.error(err) + t.ifError(err) }) }) }) + + await t.completed }) -test('only one streaming req at a time', (t) => { - t.plan(7) +test('only one streaming req at a time', async (t) => { + t = tspl(t, { plan: 7 }) const server = createServer((req, res) => { req.pipe(res) }) - t.teardown(server.close.bind(server)) + after(() => server.close()) server.listen(0, () => { const client = new Client(`http://localhost:${server.address().port}`, { pipelining: 4 }) - t.teardown(client.destroy.bind(client)) + after(() => client.destroy()) client.request({ path: '/', method: 'GET' }, (err, data) => { - t.error(err) + t.ifError(err) data.body.resume() client.request({ path: '/', method: 'GET' }, (err, data) => { - t.error(err) + t.ifError(err) data.body.resume() }) @@ -1304,58 +1373,60 @@ test('only one streaming req at a time', (t) => { body: new Readable({ read () { setImmediate(() => { - t.equal(client[kBusy], true) + t.strictEqual(client[kBusy], true) this.push(null) }) } }).on('resume', () => { - t.equal(client[kSize], 1) + t.strictEqual(client[kSize], 1) }) }, (err, data) => { - t.error(err) + t.ifError(err) data.body .resume() .on('end', () => { t.ok(true, 'pass') }) }) - t.equal(client[kBusy], true) + t.strictEqual(client[kBusy], true) }) }) + + await t.completed }) -test('only one async iterating req at a time', (t) => { - t.plan(6) +test('only one async iterating req at a time', async (t) => { + t = tspl(t, { plan: 6 }) const server = createServer((req, res) => { req.pipe(res) }) - t.teardown(server.close.bind(server)) + after(() => server.close()) server.listen(0, () => { const client = new Client(`http://localhost:${server.address().port}`, { pipelining: 4 }) - t.teardown(client.destroy.bind(client)) + after(() => client.destroy()) client.request({ path: '/', method: 'GET' }, (err, data) => { - t.error(err) + t.ifError(err) data.body.resume() client.request({ path: '/', method: 'GET' }, (err, data) => { - t.error(err) + t.ifError(err) data.body.resume() }) const body = wrapWithAsyncIterable(new Readable({ read () { setImmediate(() => { - t.equal(client[kBusy], true) + t.strictEqual(client[kBusy], true) this.push(null) }) } @@ -1366,48 +1437,52 @@ test('only one async iterating req at a time', (t) => { idempotent: true, body }, (err, data) => { - t.error(err) + t.ifError(err) data.body .resume() .on('end', () => { t.ok(true, 'pass') }) }) - t.equal(client[kBusy], true) + t.strictEqual(client[kBusy], true) }) }) + + await t.completed }) -test('300 requests succeed', (t) => { - t.plan(300 * 3) +test('300 requests succeed', async (t) => { + t = tspl(t, { plan: 300 * 3 }) const server = createServer((req, res) => { res.end('asd') }) - t.teardown(server.close.bind(server)) + after(() => server.close()) server.listen(0, () => { const client = new Client(`http://localhost:${server.address().port}`) - t.teardown(client.destroy.bind(client)) + after(() => client.destroy()) for (let n = 0; n < 300; ++n) { client.request({ path: '/', method: 'GET' }, (err, data) => { - t.error(err) + t.ifError(err) data.body.on('data', (chunk) => { - t.equal(chunk.toString(), 'asd') + t.strictEqual(chunk.toString(), 'asd') }).on('end', () => { t.ok(true, 'pass') }) }) } }) + + await t.completed }) -test('request args validation', (t) => { - t.plan(2) +test('request args validation', async (t) => { + t = tspl(t, { plan: 2 }) const client = new Client('http://localhost:5000') @@ -1420,29 +1495,33 @@ test('request args validation', (t) => { } catch (err) { t.ok(err instanceof errors.InvalidArgumentError) } + + await t.completed }) -test('request args validation promise', (t) => { - t.plan(1) +test('request args validation promise', async (t) => { + t = tspl(t, { plan: 1 }) const client = new Client('http://localhost:5000') client.request(null).catch((err) => { t.ok(err instanceof errors.InvalidArgumentError) }) + + await t.completed }) -test('increase pipelining', (t) => { - t.plan(4) +test('increase pipelining', async (t) => { + t = tspl(t, { plan: 4 }) const server = createServer((req, res) => { req.resume() }) - t.teardown(server.close.bind(server)) + after(() => server.close()) server.listen(0, () => { const client = new Client(`http://localhost:${server.address().port}`) - t.teardown(client.destroy.bind(client)) + after(() => client.destroy()) client.request({ path: '/', @@ -1462,34 +1541,36 @@ test('increase pipelining', (t) => { } }) - t.equal(client[kRunning], 0) + t.strictEqual(client[kRunning], 0) client.on('connect', () => { - t.equal(client[kRunning], 0) + t.strictEqual(client[kRunning], 0) process.nextTick(() => { - t.equal(client[kRunning], 1) + t.strictEqual(client[kRunning], 1) client.pipelining = 3 - t.equal(client[kRunning], 2) + t.strictEqual(client[kRunning], 2) }) }) }) + + await t.completed }) -test('destroy in push', (t) => { - t.plan(4) +test('destroy in push', async (t) => { + t = tspl(t, { plan: 4 }) let _res const server = createServer((req, res) => { res.write('asd') _res = res }) - t.teardown(server.close.bind(server)) + after(() => server.close()) server.listen(0, () => { const client = new Client(`http://localhost:${server.address().port}`) - t.teardown(client.close.bind(client)) + after(() => client.close()) client.request({ path: '/', method: 'GET' }, (err, { body }) => { - t.error(err) + t.ifError(err) body.once('data', () => { _res.write('asd') body.on('data', (buf) => { @@ -1502,53 +1583,57 @@ test('destroy in push', (t) => { }) client.request({ path: '/', method: 'GET' }, (err, { body }) => { - t.error(err) + t.ifError(err) let buf = '' body.on('data', (chunk) => { buf = chunk.toString() _res.end() }).on('end', () => { - t.equal('asd', buf) + t.strictEqual('asd', buf) }) }) }) + + await t.completed }) -test('non recoverable socket error fails pending request', (t) => { - t.plan(2) +test('non recoverable socket error fails pending request', async (t) => { + t = tspl(t, { plan: 2 }) const server = createServer((req, res) => { res.end() }) - t.teardown(server.close.bind(server)) + after(() => server.close()) server.listen(0, () => { const client = new Client(`http://localhost:${server.address().port}`) - t.teardown(client.close.bind(client)) + after(() => client.close()) client.request({ path: '/', method: 'GET' }, (err, data) => { - t.equal(err.message, 'kaboom') + t.strictEqual(err.message, 'kaboom') }) client.request({ path: '/', method: 'GET' }, (err, data) => { - t.equal(err.message, 'kaboom') + t.strictEqual(err.message, 'kaboom') }) client.on('connect', () => { client[kSocket].destroy(new Error('kaboom')) }) }) + + await t.completed }) -test('POST empty with error', (t) => { - t.plan(1) +test('POST empty with error', async (t) => { + t = tspl(t, { plan: 1 }) const server = createServer((req, res) => { req.pipe(res) }) - t.teardown(server.close.bind(server)) + after(() => server.close()) server.listen(0, () => { const client = new Client(`http://localhost:${server.address().port}`) - t.teardown(client.close.bind(client)) + after(() => client.close()) const body = new Readable({ read () { @@ -1562,110 +1647,118 @@ test('POST empty with error', (t) => { }) client.request({ path: '/', method: 'POST', body }, (err, data) => { - t.equal(err.message, 'asd') + t.strictEqual(err.message, 'asd') }) }) + + await t.completed }) -test('busy', (t) => { - t.plan(2) +test('busy', async (t) => { + t = tspl(t, { plan: 2 }) const server = createServer((req, res) => { req.pipe(res) }) - t.teardown(server.close.bind(server)) + after(() => server.close()) server.listen(0, () => { const client = new Client(`http://localhost:${server.address().port}`, { pipelining: 1 }) - t.teardown(client.close.bind(client)) + after(() => client.close()) client[kConnect](() => { client.request({ path: '/', method: 'GET' }, (err) => { - t.error(err) + t.ifError(err) }) - t.equal(client[kBusy], true) + t.strictEqual(client[kBusy], true) }) }) + + await t.completed }) -test('connected', (t) => { - t.plan(7) +test('connected', async (t) => { + t = tspl(t, { plan: 7 }) const server = createServer((req, res) => { // needed so that disconnect is emitted res.setHeader('connection', 'close') req.pipe(res) }) - t.teardown(server.close.bind(server)) + after(() => server.close()) server.listen(0, () => { const url = new URL(`http://localhost:${server.address().port}`) const client = new Client(url, { pipelining: 1 }) - t.teardown(client.close.bind(client)) + after(() => client.close()) client.on('connect', (origin, [self]) => { - t.equal(origin, url) - t.equal(client, self) + t.strictEqual(origin, url) + t.strictEqual(client, self) }) client.on('disconnect', (origin, [self]) => { - t.equal(origin, url) - t.equal(client, self) + t.strictEqual(origin, url) + t.strictEqual(client, self) }) - t.equal(client[kConnected], false) + t.strictEqual(client[kConnected], false) client[kConnect](() => { client.request({ path: '/', method: 'GET' }, (err) => { - t.error(err) + t.ifError(err) }) - t.equal(client[kConnected], true) + t.strictEqual(client[kConnected], true) }) }) + + await t.completed }) -test('emit disconnect after destroy', t => { - t.plan(4) +test('emit disconnect after destroy', async t => { + t = tspl(t, { plan: 4 }) const server = createServer((req, res) => { req.pipe(res) }) - t.teardown(server.close.bind(server)) + after(() => server.close()) server.listen(0, () => { const url = new URL(`http://localhost:${server.address().port}`) const client = new Client(url) - t.equal(client[kConnected], false) + t.strictEqual(client[kConnected], false) client[kConnect](() => { - t.equal(client[kConnected], true) + t.strictEqual(client[kConnected], true) let disconnected = false client.on('disconnect', () => { disconnected = true t.ok(true, 'pass') }) client.destroy(() => { - t.equal(disconnected, true) + t.strictEqual(disconnected, true) }) }) }) + + await t.completed }) -test('end response before request', t => { - t.plan(2) +test('end response before request', async t => { + t = tspl(t, { plan: 2 }) const server = createServer((req, res) => { res.end() }) - t.teardown(server.close.bind(server)) + after(() => server.close()) server.listen(0, async () => { const client = new Client(`http://localhost:${server.address().port}`) @@ -1688,13 +1781,15 @@ test('end response before request', t => { }) .resume() client.on('disconnect', (url, targets, err) => { - t.equal(err.code, 'UND_ERR_INFO') + t.strictEqual(err.code, 'UND_ERR_INFO') }) }) + + await t.completed }) -test('parser pause with no body timeout', (t) => { - t.plan(2) +test('parser pause with no body timeout', async (t) => { + t = tspl(t, { plan: 2 }) const server = createServer((req, res) => { let counter = 0 const t = setInterval(() => { @@ -1708,67 +1803,71 @@ test('parser pause with no body timeout', (t) => { } }, 20) }) - t.teardown(server.close.bind(server)) + after(() => server.close()) server.listen(0, () => { const client = new Client(`http://localhost:${server.address().port}`, { bodyTimeout: 0 }) - t.teardown(client.close.bind(client)) + after(() => client.close()) client.request({ path: '/', method: 'GET' }, (err, { statusCode, body }) => { - t.error(err) - t.equal(statusCode, 200) + t.ifError(err) + t.strictEqual(statusCode, 200) body.resume() }) }) + + await t.completed }) -test('TypedArray and DataView body', (t) => { - t.plan(3) +test('TypedArray and DataView body', async (t) => { + t = tspl(t, { plan: 3 }) const server = createServer((req, res) => { - t.equal(req.headers['content-length'], '8') + t.strictEqual(req.headers['content-length'], '8') res.end() }) - t.teardown(server.close.bind(server)) + after(() => server.close()) server.listen(0, () => { const client = new Client(`http://localhost:${server.address().port}`, { bodyTimeout: 0 }) - t.teardown(client.close.bind(client)) + after(() => client.close()) const body = Uint8Array.from(Buffer.alloc(8)) client.request({ path: '/', method: 'POST', body }, (err, { statusCode, body }) => { - t.error(err) - t.equal(statusCode, 200) + t.ifError(err) + t.strictEqual(statusCode, 200) body.resume() }) }) + + await t.completed }) -test('async iterator empty chunk continues', (t) => { - t.plan(5) +test('async iterator empty chunk continues', async (t) => { + t = tspl(t, { plan: 5 }) const serverChunks = ['hello', 'world'] const server = createServer((req, res) => { let str = '' let i = 0 req.on('data', (chunk) => { const content = chunk.toString() - t.equal(serverChunks[i++], content) + t.strictEqual(serverChunks[i++], content) str += content }).on('end', () => { - t.equal(str, serverChunks.join('')) + t.strictEqual(str, serverChunks.join('')) res.end() }) }) - t.teardown(server.close.bind(server)) + after(() => server.close()) server.listen(0, () => { const client = new Client(`http://localhost:${server.address().port}`, { bodyTimeout: 0 }) - t.teardown(client.close.bind(client)) + after(() => client.close()) const body = (async function * () { yield serverChunks[0] @@ -1776,27 +1875,29 @@ test('async iterator empty chunk continues', (t) => { yield serverChunks[1] })() client.request({ path: '/', method: 'POST', body }, (err, { statusCode, body }) => { - t.error(err) - t.equal(statusCode, 200) + t.ifError(err) + t.strictEqual(statusCode, 200) body.resume() }) }) + + await t.completed }) -test('async iterator error from server destroys early', (t) => { - t.plan(3) +test('async iterator error from server destroys early', async (t) => { + t = tspl(t, { plan: 3 }) const server = createServer((req, res) => { req.on('data', (chunk) => { res.destroy() }) }) - t.teardown(server.close.bind(server)) + after(() => server.close()) server.listen(0, () => { const client = new Client(`http://localhost:${server.address().port}`, { bodyTimeout: 0 }) - t.teardown(client.close.bind(client)) + after(() => client.close()) let gotDestroyed const body = (async function * () { try { @@ -1813,14 +1914,16 @@ test('async iterator error from server destroys early', (t) => { })() client.request({ path: '/', method: 'POST', body }, (err, { statusCode, body }) => { t.ok(err) - t.equal(statusCode, undefined) + t.strictEqual(statusCode, undefined) gotDestroyed() }) }) + + await t.completed }) -test('regular iterator error from server closes early', (t) => { - t.plan(3) +test('regular iterator error from server closes early', async (t) => { + t = tspl(t, { plan: 3 }) const server = createServer((req, res) => { req.on('data', () => { process.nextTick(() => { @@ -1828,13 +1931,13 @@ test('regular iterator error from server closes early', (t) => { }) }) }) - t.teardown(server.close.bind(server)) + after(() => server.close()) server.listen(0, () => { const client = new Client(`http://localhost:${server.address().port}`, { bodyTimeout: 0 }) - t.teardown(client.close.bind(client)) + after(() => client.close()) let gotDestroyed = false const body = (function * () { try { @@ -1853,27 +1956,28 @@ test('regular iterator error from server closes early', (t) => { })() client.request({ path: '/', method: 'POST', body }, (err, { statusCode, body }) => { t.ok(err) - t.equal(statusCode, undefined) + t.strictEqual(statusCode, undefined) gotDestroyed = true }) }) + await t.completed }) -test('async iterator early return closes early', (t) => { - t.plan(3) +test('async iterator early return closes early', async (t) => { + t = tspl(t, { plan: 3 }) const server = createServer((req, res) => { req.on('data', () => { res.writeHead(200) res.end() }) }) - t.teardown(server.close.bind(server)) + after(() => server.close()) server.listen(0, () => { const client = new Client(`http://localhost:${server.address().port}`, { bodyTimeout: 0 }) - t.teardown(client.close.bind(client)) + after(() => client.close()) let gotDestroyed const body = (async function * () { try { @@ -1889,28 +1993,29 @@ test('async iterator early return closes early', (t) => { } })() client.request({ path: '/', method: 'POST', body }, (err, { statusCode, body }) => { - t.error(err) - t.equal(statusCode, 200) + t.ifError(err) + t.strictEqual(statusCode, 200) gotDestroyed() }) }) + await t.completed }) -test('async iterator yield unsupported TypedArray', (t) => { - t.plan(3) +test('async iterator yield unsupported TypedArray', async (t) => { + t = tspl(t, { plan: 3 }) const server = createServer((req, res) => { req.on('end', () => { res.writeHead(200) res.end() }) }) - t.teardown(server.close.bind(server)) + after(() => server.close()) server.listen(0, () => { const client = new Client(`http://localhost:${server.address().port}`, { bodyTimeout: 0 }) - t.teardown(client.close.bind(client)) + after(() => client.close()) const body = (async function * () { try { yield new Int32Array([1]) @@ -1921,26 +2026,28 @@ test('async iterator yield unsupported TypedArray', (t) => { })() client.request({ path: '/', method: 'POST', body }, (err) => { t.ok(err) - t.equal(err.code, 'ERR_INVALID_ARG_TYPE') + t.strictEqual(err.code, 'ERR_INVALID_ARG_TYPE') }) }) + + await t.completed }) -test('async iterator yield object error', (t) => { - t.plan(3) +test('async iterator yield object error', async (t) => { + t = tspl(t, { plan: 3 }) const server = createServer((req, res) => { req.on('end', () => { res.writeHead(200) res.end() }) }) - t.teardown(server.close.bind(server)) + after(() => server.close()) server.listen(0, () => { const client = new Client(`http://localhost:${server.address().port}`, { bodyTimeout: 0 }) - t.teardown(client.close.bind(client)) + after(() => client.close()) const body = (async function * () { try { yield {} @@ -1951,9 +2058,11 @@ test('async iterator yield object error', (t) => { })() client.request({ path: '/', method: 'POST', body }, (err) => { t.ok(err) - t.equal(err.code, 'ERR_INVALID_ARG_TYPE') + t.strictEqual(err.code, 'ERR_INVALID_ARG_TYPE') }) }) + + await t.completed }) function buildParams (path) { @@ -1979,8 +2088,8 @@ function buildParams (path) { return builtParams } -test('\\r\\n in Headers', (t) => { - t.plan(1) +test('\\r\\n in Headers', async (t) => { + t = tspl(t, { plan: 1 }) const reqHeaders = { bar: '\r\nbar' @@ -1989,19 +2098,19 @@ test('\\r\\n in Headers', (t) => { const client = new Client('http://localhost:4242', { keepAliveTimeout: 300e3 }) - t.teardown(client.close.bind(client)) + after(() => client.close()) client.request({ path: '/', method: 'GET', headers: reqHeaders }, (err) => { - t.equal(err.message, 'invalid bar header') + t.strictEqual(err.message, 'invalid bar header') }) }) -test('\\r in Headers', (t) => { - t.plan(1) +test('\\r in Headers', async (t) => { + t = tspl(t, { plan: 1 }) const reqHeaders = { bar: '\rbar' @@ -2010,19 +2119,19 @@ test('\\r in Headers', (t) => { const client = new Client('http://localhost:4242', { keepAliveTimeout: 300e3 }) - t.teardown(client.close.bind(client)) + after(() => client.close()) client.request({ path: '/', method: 'GET', headers: reqHeaders }, (err) => { - t.equal(err.message, 'invalid bar header') + t.strictEqual(err.message, 'invalid bar header') }) }) -test('\\n in Headers', (t) => { - t.plan(1) +test('\\n in Headers', async (t) => { + t = tspl(t, { plan: 1 }) const reqHeaders = { bar: '\nbar' @@ -2031,19 +2140,19 @@ test('\\n in Headers', (t) => { const client = new Client('http://localhost:4242', { keepAliveTimeout: 300e3 }) - t.teardown(client.close.bind(client)) + after(() => client.close()) client.request({ path: '/', method: 'GET', headers: reqHeaders }, (err) => { - t.equal(err.message, 'invalid bar header') + t.strictEqual(err.message, 'invalid bar header') }) }) -test('\\n in Headers', (t) => { - t.plan(1) +test('\\n in Headers', async (t) => { + t = tspl(t, { plan: 1 }) const reqHeaders = { '\nbar': 'foo' @@ -2052,45 +2161,45 @@ test('\\n in Headers', (t) => { const client = new Client('http://localhost:4242', { keepAliveTimeout: 300e3 }) - t.teardown(client.close.bind(client)) + after(() => client.close()) client.request({ path: '/', method: 'GET', headers: reqHeaders }, (err) => { - t.equal(err.message, 'invalid header key') + t.strictEqual(err.message, 'invalid header key') }) }) -test('\\n in Path', (t) => { - t.plan(1) +test('\\n in Path', async (t) => { + t = tspl(t, { plan: 1 }) const client = new Client('http://localhost:4242', { keepAliveTimeout: 300e3 }) - t.teardown(client.close.bind(client)) + after(() => client.close()) client.request({ path: '/\n', method: 'GET' }, (err) => { - t.equal(err.message, 'invalid request path') + t.strictEqual(err.message, 'invalid request path') }) }) -test('\\n in Method', (t) => { - t.plan(1) +test('\\n in Method', async (t) => { + t = tspl(t, { plan: 1 }) const client = new Client('http://localhost:4242', { keepAliveTimeout: 300e3 }) - t.teardown(client.close.bind(client)) + after(() => client.close()) client.request({ path: '/', method: 'GET\n' }, (err) => { - t.equal(err.message, 'invalid request method') + t.strictEqual(err.message, 'invalid request method') }) }) diff --git a/test/close-and-destroy.js b/test/close-and-destroy.js index b946e3e18b6..5d4f135dcd2 100644 --- a/test/close-and-destroy.js +++ b/test/close-and-destroy.js @@ -1,12 +1,13 @@ 'use strict' -const { test } = require('tap') +const { tspl } = require('@matteo.collina/tspl') +const { test, after } = require('node:test') const { Client, errors } = require('..') const { createServer } = require('node:http') const { kSocket, kSize } = require('../lib/core/symbols') -test('close waits for queued requests to finish', (t) => { - t.plan(16) +test('close waits for queued requests to finish', async (t) => { + t = tspl(t, { plan: 16 }) const server = createServer() @@ -14,11 +15,11 @@ test('close waits for queued requests to finish', (t) => { t.ok(true, 'request received') res.end('hello') }) - t.teardown(server.close.bind(server)) + after(() => server.close()) server.listen(0, () => { const client = new Client(`http://localhost:${server.address().port}`) - t.teardown(client.destroy.bind(client)) + after(() => client.destroy()) client.request({ path: '/', method: 'GET' }, function (err, data) { onRequest(err, data) @@ -36,36 +37,38 @@ test('close waits for queued requests to finish', (t) => { }) function onRequest (err, { statusCode, headers, body }) { - t.error(err) - t.equal(statusCode, 200) + t.ifError(err) + t.strictEqual(statusCode, 200) const bufs = [] body.on('data', (buf) => { bufs.push(buf) }) body.on('end', () => { - t.equal('hello', Buffer.concat(bufs).toString('utf8')) + t.strictEqual('hello', Buffer.concat(bufs).toString('utf8')) }) } + + await t.completed }) -test('destroy invoked all pending callbacks', (t) => { - t.plan(4) +test('destroy invoked all pending callbacks', async (t) => { + t = tspl(t, { plan: 4 }) const server = createServer() server.on('request', (req, res) => { res.write('hello') }) - t.teardown(server.close.bind(server)) + after(() => server.close()) server.listen(0, () => { const client = new Client(`http://localhost:${server.address().port}`, { pipelining: 2 }) - t.teardown(client.destroy.bind(client)) + after(() => client.destroy()) client.request({ path: '/', method: 'GET' }, (err, data) => { - t.error(err) + t.ifError(err) data.body.on('error', (err) => { t.ok(err) }).resume() @@ -78,49 +81,53 @@ test('destroy invoked all pending callbacks', (t) => { t.ok(err instanceof errors.ClientDestroyedError) }) }) + + await t.completed }) -test('destroy invoked all pending callbacks ticked', (t) => { - t.plan(4) +test('destroy invoked all pending callbacks ticked', async (t) => { + t = tspl(t, { plan: 4 }) const server = createServer() server.on('request', (req, res) => { res.write('hello') }) - t.teardown(server.close.bind(server)) + after(() => server.close()) server.listen(0, () => { const client = new Client(`http://localhost:${server.address().port}`, { pipelining: 2 }) - t.teardown(client.destroy.bind(client)) + after(() => client.destroy()) let ticked = false client.request({ path: '/', method: 'GET' }, (err) => { - t.equal(ticked, true) + t.strictEqual(ticked, true) t.ok(err instanceof errors.ClientDestroyedError) }) client.request({ path: '/', method: 'GET' }, (err) => { - t.equal(ticked, true) + t.strictEqual(ticked, true) t.ok(err instanceof errors.ClientDestroyedError) }) client.destroy() ticked = true }) + + await t.completed }) -test('close waits until socket is destroyed', (t) => { - t.plan(4) +test('close waits until socket is destroyed', async (t) => { + t = tspl(t, { plan: 4 }) const server = createServer((req, res) => { res.end(req.url) }) - t.teardown(server.close.bind(server)) + after(() => server.close()) server.listen(0, () => { const client = new Client(`http://localhost:${server.address().port}`) - t.teardown(client.destroy.bind(client)) + after(() => client.destroy()) makeRequest() @@ -130,39 +137,41 @@ test('close waits until socket is destroyed', (t) => { done = true }) client.close((err) => { - t.error(err) - t.equal(client.closed, true) - t.equal(done, true) + t.ifError(err) + t.strictEqual(client.closed, true) + t.strictEqual(done, true) }) }) function makeRequest () { client.request({ path: '/', method: 'GET' }, (err, data) => { - t.error(err) + t.ifError(err) }) return client[kSize] <= client.pipelining } }) + + await t.completed }) -test('close should still reconnect', (t) => { - t.plan(6) +test('close should still reconnect', async (t) => { + t = tspl(t, { plan: 6 }) const server = createServer((req, res) => { res.end(req.url) }) - t.teardown(server.close.bind(server)) + after(() => server.close()) server.listen(0, () => { const client = new Client(`http://localhost:${server.address().port}`) - t.teardown(client.destroy.bind(client)) + after(() => client.destroy()) t.ok(makeRequest()) t.ok(!makeRequest()) client.close((err) => { - t.error(err) - t.equal(client.closed, true) + t.ifError(err) + t.strictEqual(client.closed, true) }) client.once('connect', () => { client[kSocket].destroy() @@ -170,57 +179,61 @@ test('close should still reconnect', (t) => { function makeRequest () { client.request({ path: '/', method: 'GET' }, (err, data) => { - t.error(err) + t.ifError(err) data.body.resume() }) return client[kSize] <= client.pipelining } }) + + await t.completed }) -test('close should call callback once finished', (t) => { - t.plan(6) +test('close should call callback once finished', async (t) => { + t = tspl(t, { plan: 6 }) const server = createServer((req, res) => { setImmediate(function () { res.end(req.url) }) }) - t.teardown(server.close.bind(server)) + after(() => server.close()) server.listen(0, () => { const client = new Client(`http://localhost:${server.address().port}`) - t.teardown(client.destroy.bind(client)) + after(() => client.destroy()) t.ok(makeRequest()) t.ok(!makeRequest()) client.close((err) => { - t.error(err) - t.equal(client.closed, true) + t.ifError(err) + t.strictEqual(client.closed, true) }) function makeRequest () { client.request({ path: '/', method: 'GET' }, (err, data) => { - t.error(err) + t.ifError(err) data.body.resume() }) return client[kSize] <= client.pipelining } }) + + await t.completed }) -test('closed and destroyed errors', (t) => { - t.plan(4) +test('closed and destroyed errors', async (t) => { + t = tspl(t, { plan: 4 }) const client = new Client('http://localhost:4000') - t.teardown(client.destroy.bind(client)) + after(() => client.destroy()) client.request({ path: '/', method: 'GET' }, (err) => { t.ok(err) }) client.close((err) => { - t.error(err) + t.ifError(err) }) client.request({ path: '/', method: 'GET' }, (err) => { t.ok(err instanceof errors.ClientClosedError) @@ -229,13 +242,15 @@ test('closed and destroyed errors', (t) => { t.ok(err instanceof errors.ClientDestroyedError) }) }) + + await t.completed }) -test('close after and destroy should error', (t) => { - t.plan(2) +test('close after and destroy should error', async (t) => { + t = tspl(t, { plan: 2 }) const client = new Client('http://localhost:4000') - t.teardown(client.destroy.bind(client)) + after(() => client.destroy()) client.destroy() client.close((err) => { @@ -244,16 +259,18 @@ test('close after and destroy should error', (t) => { client.close().catch((err) => { t.ok(err instanceof errors.ClientDestroyedError) }) + + await t.completed }) -test('close socket and reconnect after maxRequestsPerClient reached', (t) => { - t.plan(5) +test('close socket and reconnect after maxRequestsPerClient reached', async (t) => { + t = tspl(t, { plan: 1 }) const server = createServer((req, res) => { res.end(req.url) }) - t.teardown(server.close.bind(server)) + after(() => server.close()) server.listen(0, async () => { let connections = 0 @@ -264,28 +281,30 @@ test('close socket and reconnect after maxRequestsPerClient reached', (t) => { `http://localhost:${server.address().port}`, { maxRequestsPerClient: 2 } ) - t.teardown(client.destroy.bind(client)) + after(() => client.destroy()) - await t.resolves(makeRequest()) - await t.resolves(makeRequest()) - await t.resolves(makeRequest()) - await t.resolves(makeRequest()) - t.equal(connections, 2) + await makeRequest() + await makeRequest() + await makeRequest() + await makeRequest() + t.strictEqual(connections, 2) function makeRequest () { return client.request({ path: '/', method: 'GET' }) } }) + + await t.completed }) -test('close socket and reconnect after maxRequestsPerClient reached (async)', (t) => { - t.plan(2) +test('close socket and reconnect after maxRequestsPerClient reached (async)', async (t) => { + t = tspl(t, { plan: 1 }) const server = createServer((req, res) => { res.end(req.url) }) - t.teardown(server.close.bind(server)) + after(() => server.close()) server.listen(0, async () => { let connections = 0 @@ -296,32 +315,32 @@ test('close socket and reconnect after maxRequestsPerClient reached (async)', (t `http://localhost:${server.address().port}`, { maxRequestsPerClient: 2 } ) - t.teardown(client.destroy.bind(client)) - - await t.resolves( - Promise.all([ - makeRequest(), - makeRequest(), - makeRequest(), - makeRequest() - ]) - ) - t.equal(connections, 2) + after(() => client.destroy()) + + await Promise.all([ + makeRequest(), + makeRequest(), + makeRequest(), + makeRequest() + ]) + t.strictEqual(connections, 2) function makeRequest () { return client.request({ path: '/', method: 'GET' }) } }) + + await t.completed }) -test('should not close socket when no maxRequestsPerClient is provided', (t) => { - t.plan(5) +test('should not close socket when no maxRequestsPerClient is provided', async (t) => { + t = tspl(t, { plan: 1 }) const server = createServer((req, res) => { res.end(req.url) }) - t.teardown(server.close.bind(server)) + after(() => server.close()) server.listen(0, async () => { let connections = 0 @@ -329,16 +348,18 @@ test('should not close socket when no maxRequestsPerClient is provided', (t) => connections++ }) const client = new Client(`http://localhost:${server.address().port}`) - t.teardown(client.destroy.bind(client)) + after(() => client.destroy()) - await t.resolves(makeRequest()) - await t.resolves(makeRequest()) - await t.resolves(makeRequest()) - await t.resolves(makeRequest()) - t.equal(connections, 1) + await makeRequest() + await makeRequest() + await makeRequest() + await makeRequest() + t.strictEqual(connections, 1) function makeRequest () { return client.request({ path: '/', method: 'GET' }) } }) + + await t.completed }) diff --git a/test/connect-timeout.js b/test/connect-timeout.js index 5eab8ee1098..d8ff177504c 100644 --- a/test/connect-timeout.js +++ b/test/connect-timeout.js @@ -1,19 +1,22 @@ 'use strict' -const { test } = require('tap') +const { tspl } = require('@matteo.collina/tspl') +const { test, after, describe } = require('node:test') const { Client, Pool, errors } = require('..') const net = require('node:net') +const assert = require('node:assert') const sleep = ms => Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, Number(ms)) -test('prioritize socket errors over timeouts', (t) => { - t.plan(1) +// Using describe instead of test to avoid the timeout +describe('prioritize socket errors over timeouts', () => { + const t = tspl({ ...assert, after: () => {} }, { plan: 1 }) const connectTimeout = 1000 const client = new Pool('http://foobar.bar:1234', { connectTimeout: 2 }) client.request({ method: 'GET', path: '/foobar' }) .then(() => t.fail()) .catch((err) => { - t.equal(err.code, 'ENOTFOUND') + t.strictEqual(err.code, 'ENOTFOUND') }) // block for 1s which is enough for the dns lookup to complete and TO to fire @@ -25,13 +28,13 @@ net.connect = function (options) { return new net.Socket(options) } -test('connect-timeout', t => { - t.plan(1) +test('connect-timeout', async t => { + t = tspl(t, { plan: 1 }) const client = new Client('http://localhost:9000', { connectTimeout: 1e3 }) - t.teardown(client.close.bind(client)) + after(() => client.close()) const timeout = setTimeout(() => { t.fail() @@ -44,15 +47,17 @@ test('connect-timeout', t => { t.ok(err instanceof errors.ConnectTimeoutError) clearTimeout(timeout) }) + + await t.completed }) -test('connect-timeout', t => { - t.plan(1) +test('connect-timeout', async t => { + t = tspl(t, { plan: 1 }) const client = new Pool('http://localhost:9000', { connectTimeout: 1e3 }) - t.teardown(client.close.bind(client)) + after(() => client.close()) const timeout = setTimeout(() => { t.fail() @@ -65,4 +70,6 @@ test('connect-timeout', t => { t.ok(err instanceof errors.ConnectTimeoutError) clearTimeout(timeout) }) + + await t.completed }) diff --git a/test/gc.js b/test/gc.js index ab3b0e83dbf..91ea6ab170c 100644 --- a/test/gc.js +++ b/test/gc.js @@ -1,18 +1,23 @@ 'use strict' /* global WeakRef, FinalizationRegistry */ -const { test } = require('tap') +const { tspl } = require('@matteo.collina/tspl') +const { test, after } = require('node:test') const { createServer } = require('node:net') const { Client, Pool } = require('..') -const SKIP = typeof WeakRef === 'undefined' || typeof FinalizationRegistry === 'undefined' +const SKIP = ( + typeof WeakRef === 'undefined' || + typeof FinalizationRegistry === 'undefined' || + typeof global.gc === 'undefined' +) setInterval(() => { global.gc() }, 100).unref() -test('gc should collect the client if, and only if, there are no active sockets', { skip: SKIP }, t => { - t.plan(4) +test('gc should collect the client if, and only if, there are no active sockets', { skip: SKIP }, async t => { + t = tspl(t, { plan: 4 }) const server = createServer((socket) => { socket.write('HTTP/1.1 200 OK\r\n') @@ -21,15 +26,15 @@ test('gc should collect the client if, and only if, there are no active sockets' socket.write('Connection: keep-alive\r\n') socket.write('\r\n\r\n') }) - t.teardown(server.close.bind(server)) + after(() => server.close()) let weakRef let disconnected = false const registry = new FinalizationRegistry((data) => { - t.equal(data, 'test') - t.equal(disconnected, true) - t.equal(weakRef.deref(), undefined) + t.strictEqual(data, 'test') + t.strictEqual(disconnected, true) + t.strictEqual(weakRef.deref(), undefined) }) server.listen(0, () => { @@ -47,14 +52,16 @@ test('gc should collect the client if, and only if, there are no active sockets' path: '/', method: 'GET' }, (err, { body }) => { - t.error(err) + t.ifError(err) body.resume() }) }) + + await t.completed }) -test('gc should collect the pool if, and only if, there are no active sockets', { skip: SKIP }, t => { - t.plan(4) +test('gc should collect the pool if, and only if, there are no active sockets', { skip: SKIP }, async t => { + t = tspl(t, { plan: 4 }) const server = createServer((socket) => { socket.write('HTTP/1.1 200 OK\r\n') @@ -63,15 +70,15 @@ test('gc should collect the pool if, and only if, there are no active sockets', socket.write('Connection: keep-alive\r\n') socket.write('\r\n\r\n') }) - t.teardown(server.close.bind(server)) + after(() => server.close()) let weakRef let disconnected = false const registry = new FinalizationRegistry((data) => { - t.equal(data, 'test') - t.equal(disconnected, true) - t.equal(weakRef.deref(), undefined) + t.strictEqual(data, 'test') + t.strictEqual(disconnected, true) + t.strictEqual(weakRef.deref(), undefined) }) server.listen(0, () => { @@ -91,8 +98,10 @@ test('gc should collect the pool if, and only if, there are no active sockets', path: '/', method: 'GET' }, (err, { body }) => { - t.error(err) + t.ifError(err) body.resume() }) }) + + await t.completed }) diff --git a/test/issue-2590.js b/test/issue-2590.js index cd4913c642f..c5499bf4513 100644 --- a/test/issue-2590.js +++ b/test/issue-2590.js @@ -1,14 +1,16 @@ 'use strict' -const { test } = require('tap') +const { tspl } = require('@matteo.collina/tspl') +const { test, after } = require('node:test') const { request } = require('..') const { createServer } = require('node:http') const { once } = require('node:events') test('aborting request with custom reason', async (t) => { + t = tspl(t, { plan: 3 }) const server = createServer(() => {}).listen(0) - t.teardown(server.close.bind(server)) + after(() => server.close()) await once(server, 'listening') const timeout = AbortSignal.timeout(0) @@ -25,11 +27,13 @@ test('aborting request with custom reason', async (t) => { await t.rejects( request(`http://localhost:${server.address().port}`, { signal: ac.signal }), - ac.signal.reason + /Request aborted/ ) await t.rejects( request(`http://localhost:${server.address().port}`, { signal: ac2.signal }), { code: 'UND_ERR_ABORTED' } ) + + await t.completed }) diff --git a/test/pool.js b/test/pool.js index af6a019c7a0..4a22aedc84e 100644 --- a/test/pool.js +++ b/test/pool.js @@ -1,5 +1,7 @@ 'use strict' +const { tspl } = require('@matteo.collina/tspl') +const { test, after } = require('node:test') const { EventEmitter } = require('node:events') const { createServer } = require('node:http') const net = require('node:net') @@ -10,7 +12,6 @@ const { } = require('node:stream') const { promisify } = require('node:util') const proxyquire = require('proxyquire') -const { test } = require('tap') const { kBusy, kPending, @@ -24,60 +25,60 @@ const { errors } = require('..') -test('throws when connection is infinite', (t) => { - t.plan(2) +test('throws when connection is infinite', async (t) => { + t = tspl(t, { plan: 2 }) try { new Pool(null, { connections: 0 / 0 }) // eslint-disable-line } catch (e) { t.ok(e instanceof errors.InvalidArgumentError) - t.equal(e.message, 'invalid connections') + t.strictEqual(e.message, 'invalid connections') } }) -test('throws when connections is negative', (t) => { - t.plan(2) +test('throws when connections is negative', async (t) => { + t = tspl(t, { plan: 2 }) try { new Pool(null, { connections: -1 }) // eslint-disable-line no-new } catch (e) { t.ok(e instanceof errors.InvalidArgumentError) - t.equal(e.message, 'invalid connections') + t.strictEqual(e.message, 'invalid connections') } }) -test('throws when connection is not number', (t) => { - t.plan(2) +test('throws when connection is not number', async (t) => { + t = tspl(t, { plan: 2 }) try { new Pool(null, { connections: true }) // eslint-disable-line no-new } catch (e) { t.ok(e instanceof errors.InvalidArgumentError) - t.equal(e.message, 'invalid connections') + t.strictEqual(e.message, 'invalid connections') } }) -test('throws when factory is not a function', (t) => { - t.plan(2) +test('throws when factory is not a function', async (t) => { + t = tspl(t, { plan: 2 }) try { new Pool(null, { factory: '' }) // eslint-disable-line no-new } catch (e) { t.ok(e instanceof errors.InvalidArgumentError) - t.equal(e.message, 'factory must be a function.') + t.strictEqual(e.message, 'factory must be a function.') } }) -test('does not throw when connect is a function', (t) => { - t.plan(1) +test('does not throw when connect is a function', async (t) => { + t = tspl(t, { plan: 1 }) t.doesNotThrow(() => new Pool('http://localhost', { connect: () => {} })) }) -test('connect/disconnect event(s)', (t) => { +test('connect/disconnect event(s)', async (t) => { const clients = 2 - t.plan(clients * 6) + t = tspl(t, { plan: clients * 6 }) const server = createServer((req, res) => { res.writeHead(200, { @@ -86,23 +87,23 @@ test('connect/disconnect event(s)', (t) => { }) res.end('ok') }) - t.teardown(server.close.bind(server)) + after(() => server.close()) server.listen(0, () => { const pool = new Pool(`http://localhost:${server.address().port}`, { connections: clients, keepAliveTimeoutThreshold: 100 }) - t.teardown(pool.close.bind(pool)) + after(() => pool.close()) pool.on('connect', (origin, [pool, client]) => { - t.equal(client instanceof Client, true) + t.strictEqual(client instanceof Client, true) }) pool.on('disconnect', (origin, [pool, client], error) => { t.ok(client instanceof Client) t.ok(error instanceof errors.InformationalError) - t.equal(error.code, 'UND_ERR_INFO') - t.equal(error.message, 'socket idle timeout') + t.strictEqual(error.code, 'UND_ERR_INFO') + t.strictEqual(error.message, 'socket idle timeout') }) for (let i = 0; i < clients; i++) { @@ -110,112 +111,118 @@ test('connect/disconnect event(s)', (t) => { path: '/', method: 'GET' }, (err, { headers, body }) => { - t.error(err) + t.ifError(err) body.resume() }) } }) + + await t.completed }) -test('basic get', (t) => { - t.plan(14) +test('basic get', async (t) => { + t = tspl(t, { plan: 14 }) const server = createServer((req, res) => { - t.equal('/', req.url) - t.equal('GET', req.method) + t.strictEqual('/', req.url) + t.strictEqual('GET', req.method) res.setHeader('content-type', 'text/plain') res.end('hello') }) - t.teardown(server.close.bind(server)) + after(() => server.close()) server.listen(0, async () => { const client = new Pool(`http://localhost:${server.address().port}`) - t.teardown(client.destroy.bind(client)) + after(() => client.destroy()) - t.equal(client[kUrl].origin, `http://localhost:${server.address().port}`) + t.strictEqual(client[kUrl].origin, `http://localhost:${server.address().port}`) client.request({ path: '/', method: 'GET' }, (err, { statusCode, headers, body }) => { - t.error(err) - t.equal(statusCode, 200) - t.equal(headers['content-type'], 'text/plain') + t.ifError(err) + t.strictEqual(statusCode, 200) + t.strictEqual(headers['content-type'], 'text/plain') const bufs = [] body.on('data', (buf) => { bufs.push(buf) }) body.on('end', () => { - t.equal('hello', Buffer.concat(bufs).toString('utf8')) + t.strictEqual('hello', Buffer.concat(bufs).toString('utf8')) }) }) - t.equal(client.destroyed, false) - t.equal(client.closed, false) + t.strictEqual(client.destroyed, false) + t.strictEqual(client.closed, false) client.close((err) => { - t.error(err) - t.equal(client.destroyed, true) + t.ifError(err) + t.strictEqual(client.destroyed, true) client.destroy((err) => { - t.error(err) + t.ifError(err) client.close((err) => { t.ok(err instanceof errors.ClientDestroyedError) }) }) }) - t.equal(client.closed, true) + t.strictEqual(client.closed, true) }) + + await t.completed }) -test('URL as arg', (t) => { - t.plan(9) +test('URL as arg', async (t) => { + t = tspl(t, { plan: 9 }) const server = createServer((req, res) => { - t.equal('/', req.url) - t.equal('GET', req.method) + t.strictEqual('/', req.url) + t.strictEqual('GET', req.method) res.setHeader('content-type', 'text/plain') res.end('hello') }) - t.teardown(server.close.bind(server)) + after(() => server.close()) server.listen(0, async () => { const url = new URL('http://localhost') url.port = server.address().port const client = new Pool(url) - t.teardown(client.destroy.bind(client)) + after(() => client.destroy()) client.request({ path: '/', method: 'GET' }, (err, { statusCode, headers, body }) => { - t.error(err) - t.equal(statusCode, 200) - t.equal(headers['content-type'], 'text/plain') + t.ifError(err) + t.strictEqual(statusCode, 200) + t.strictEqual(headers['content-type'], 'text/plain') const bufs = [] body.on('data', (buf) => { bufs.push(buf) }) body.on('end', () => { - t.equal('hello', Buffer.concat(bufs).toString('utf8')) + t.strictEqual('hello', Buffer.concat(bufs).toString('utf8')) }) }) client.close((err) => { - t.error(err) + t.ifError(err) client.destroy((err) => { - t.error(err) + t.ifError(err) client.close((err) => { t.ok(err instanceof errors.ClientDestroyedError) }) }) }) }) + + await t.completed }) -test('basic get error async/await', (t) => { - t.plan(2) +test('basic get error async/await', async (t) => { + t = tspl(t, { plan: 2 }) const server = createServer((req, res) => { res.destroy() }) - t.teardown(server.close.bind(server)) + after(() => server.close()) server.listen(0, async () => { const client = new Pool(`http://localhost:${server.address().port}`) - t.teardown(client.destroy.bind(client)) + after(() => client.destroy()) await client.request({ path: '/', method: 'GET' }) .catch((err) => { @@ -228,24 +235,28 @@ test('basic get error async/await', (t) => { t.ok(err instanceof errors.ClientDestroyedError) }) }) + + await t.completed }) test('basic get with async/await', async (t) => { + t = tspl(t, { plan: 4 }) + const server = createServer((req, res) => { - t.equal('/', req.url) - t.equal('GET', req.method) + t.strictEqual('/', req.url) + t.strictEqual('GET', req.method) res.setHeader('content-type', 'text/plain') res.end('hello') }) - t.teardown(server.close.bind(server)) + after(() => server.close()) await promisify(server.listen.bind(server))(0) const client = new Pool(`http://localhost:${server.address().port}`) - t.teardown(client.destroy.bind(client)) + after(() => client.destroy()) const { statusCode, headers, body } = await client.request({ path: '/', method: 'GET' }) - t.equal(statusCode, 200) - t.equal(headers['content-type'], 'text/plain') + t.strictEqual(statusCode, 200) + t.strictEqual(headers['content-type'], 'text/plain') body.resume() await promisify(finished)(body) @@ -255,36 +266,40 @@ test('basic get with async/await', async (t) => { }) test('stream get async/await', async (t) => { + t = tspl(t, { plan: 4 }) + const server = createServer((req, res) => { - t.equal('/', req.url) - t.equal('GET', req.method) + t.strictEqual('/', req.url) + t.strictEqual('GET', req.method) res.setHeader('content-type', 'text/plain') res.end('hello') }) - t.teardown(server.close.bind(server)) + after(() => server.close()) await promisify(server.listen.bind(server))(0) const client = new Pool(`http://localhost:${server.address().port}`) - t.teardown(client.destroy.bind(client)) + after(() => client.destroy()) await client.stream({ path: '/', method: 'GET' }, ({ statusCode, headers }) => { - t.equal(statusCode, 200) - t.equal(headers['content-type'], 'text/plain') + t.strictEqual(statusCode, 200) + t.strictEqual(headers['content-type'], 'text/plain') return new PassThrough() }) + + await t.completed }) -test('stream get error async/await', (t) => { - t.plan(1) +test('stream get error async/await', async (t) => { + t = tspl(t, { plan: 1 }) const server = createServer((req, res) => { res.destroy() }) - t.teardown(server.close.bind(server)) + after(() => server.close()) server.listen(0, async () => { const client = new Pool(`http://localhost:${server.address().port}`) - t.teardown(client.destroy.bind(client)) + after(() => client.destroy()) await client.stream({ path: '/', method: 'GET' }, () => { @@ -293,27 +308,29 @@ test('stream get error async/await', (t) => { t.ok(err) }) }) + + await t.completed }) -test('pipeline get', (t) => { - t.plan(5) +test('pipeline get', async (t) => { + t = tspl(t, { plan: 5 }) const server = createServer((req, res) => { - t.equal('/', req.url) - t.equal('GET', req.method) + t.strictEqual('/', req.url) + t.strictEqual('GET', req.method) res.setHeader('content-type', 'text/plain') res.end('hello') }) - t.teardown(server.close.bind(server)) + after(() => server.close()) server.listen(0, async () => { const client = new Pool(`http://localhost:${server.address().port}`) - t.teardown(client.destroy.bind(client)) + after(() => client.destroy()) const bufs = [] client.pipeline({ path: '/', method: 'GET' }, ({ statusCode, headers, body }) => { - t.equal(statusCode, 200) - t.equal(headers['content-type'], 'text/plain') + t.strictEqual(statusCode, 200) + t.strictEqual(headers['content-type'], 'text/plain') return body }) .end() @@ -321,12 +338,16 @@ test('pipeline get', (t) => { bufs.push(buf) }) .on('end', () => { - t.equal('hello', Buffer.concat(bufs).toString('utf8')) + t.strictEqual('hello', Buffer.concat(bufs).toString('utf8')) }) }) + + await t.completed }) -test('backpressure algorithm', (t) => { +test('backpressure algorithm', async (t) => { + t = tspl(t, { plan: 12 }) + const seen = [] let total = 0 @@ -361,11 +382,11 @@ test('backpressure algorithm', (t) => { pool.dispatch({}, noopHandler) const d1 = seen.shift() // d1 = c0 - t.equal(d1.id, 0) + t.strictEqual(d1.id, 0) const d2 = seen.shift() // d2 = c0 - t.equal(d2.id, 0) + t.strictEqual(d2.id, 0) - t.equal(d1.id, d2.id) + t.strictEqual(d1.id, d2.id) writeMore = false @@ -374,12 +395,12 @@ test('backpressure algorithm', (t) => { pool.dispatch({}, noopHandler) // d4 = c1 const d3 = seen.shift() - t.equal(d3.id, 0) + t.strictEqual(d3.id, 0) const d4 = seen.shift() - t.equal(d4.id, 1) + t.strictEqual(d4.id, 1) - t.equal(d3.id, d2.id) - t.not(d3.id, d4.id) + t.strictEqual(d3.id, d2.id) + t.notEqual(d3.id, d4.id) writeMore = true @@ -392,28 +413,28 @@ test('backpressure algorithm', (t) => { pool.dispatch({}, noopHandler) // d6 = c0 const d5 = seen.shift() - t.equal(d5.id, 1) + t.strictEqual(d5.id, 1) const d6 = seen.shift() - t.equal(d6.id, 0) + t.strictEqual(d6.id, 0) - t.equal(d5.id, d4.id) - t.equal(d3.id, d6.id) + t.strictEqual(d5.id, d4.id) + t.strictEqual(d3.id, d6.id) - t.equal(total, 3) + t.strictEqual(total, 3) t.end() }) -test('busy', (t) => { - t.plan(8 * 16 + 2 + 1) +test('busy', async (t) => { + t = tspl(t, { plan: 8 * 16 + 2 + 1 }) const server = createServer((req, res) => { - t.equal('/', req.url) - t.equal('GET', req.method) + t.strictEqual('/', req.url) + t.strictEqual('GET', req.method) res.setHeader('content-type', 'text/plain') res.end('hello') }) - t.teardown(server.close.bind(server)) + after(() => server.close()) const connections = 2 @@ -428,45 +449,47 @@ test('busy', (t) => { client.on('connect', () => { t.ok(true, 'pass') }) - t.teardown(client.destroy.bind(client)) + after(() => client.destroy()) for (let n = 1; n <= 8; ++n) { client.request({ path: '/', method: 'GET' }, (err, { statusCode, headers, body }) => { - t.error(err) - t.equal(statusCode, 200) - t.equal(headers['content-type'], 'text/plain') + t.ifError(err) + t.strictEqual(statusCode, 200) + t.strictEqual(headers['content-type'], 'text/plain') const bufs = [] body.on('data', (buf) => { bufs.push(buf) }) body.on('end', () => { - t.equal('hello', Buffer.concat(bufs).toString('utf8')) + t.strictEqual('hello', Buffer.concat(bufs).toString('utf8')) }) }) - t.equal(client[kPending], n) - t.equal(client[kBusy], n > 1) - t.equal(client[kSize], n) - t.equal(client[kRunning], 0) - - t.equal(client.stats.connected, 0) - t.equal(client.stats.free, 0) - t.equal(client.stats.queued, Math.max(n - connections, 0)) - t.equal(client.stats.pending, n) - t.equal(client.stats.size, n) - t.equal(client.stats.running, 0) + t.strictEqual(client[kPending], n) + t.strictEqual(client[kBusy], n > 1) + t.strictEqual(client[kSize], n) + t.strictEqual(client[kRunning], 0) + + t.strictEqual(client.stats.connected, 0) + t.strictEqual(client.stats.free, 0) + t.strictEqual(client.stats.queued, Math.max(n - connections, 0)) + t.strictEqual(client.stats.pending, n) + t.strictEqual(client.stats.size, n) + t.strictEqual(client.stats.running, 0) } }) + + await t.completed }) -test('invalid pool dispatch options', (t) => { - t.plan(2) +test('invalid pool dispatch options', async (t) => { + t = tspl(t, { plan: 2 }) const pool = new Pool('http://notahost') t.throws(() => pool.dispatch({}), errors.InvalidArgumentError, 'throws on invalid handler') t.throws(() => pool.dispatch({}, {}), errors.InvalidArgumentError, 'throws on invalid handler') }) -test('pool upgrade promise', (t) => { - t.plan(2) +test('pool upgrade promise', async (t) => { + t = tspl(t, { plan: 2 }) const server = net.createServer((c) => { c.on('data', (d) => { @@ -482,11 +505,11 @@ test('pool upgrade promise', (t) => { c.end() }) }) - t.teardown(server.close.bind(server)) + after(() => server.close()) server.listen(0, async () => { const client = new Pool(`http://localhost:${server.address().port}`) - t.teardown(client.close.bind(client)) + after(() => client.close()) const { headers, socket } = await client.upgrade({ path: '/', @@ -500,20 +523,22 @@ test('pool upgrade promise', (t) => { }) socket.on('close', () => { - t.equal(recvData.toString(), 'Body') + t.strictEqual(recvData.toString(), 'Body') }) - t.same(headers, { + t.deepStrictEqual(headers, { hello: 'world', connection: 'upgrade', upgrade: 'websocket' }) socket.end() }) + + await t.completed }) -test('pool connect', (t) => { - t.plan(1) +test('pool connect', async (t) => { + t = tspl(t, { plan: 1 }) const server = createServer((c) => { t.fail() @@ -530,11 +555,11 @@ test('pool connect', (t) => { socket.end(data) }) }) - t.teardown(server.close.bind(server)) + after(() => server.close()) server.listen(0, async () => { const client = new Pool(`http://localhost:${server.address().port}`) - t.teardown(client.close.bind(client)) + after(() => client.close()) const { socket } = await client.connect({ path: '/' @@ -546,25 +571,27 @@ test('pool connect', (t) => { }) socket.on('end', () => { - t.equal(recvData.toString(), 'Body') + t.strictEqual(recvData.toString(), 'Body') }) socket.write('Body') socket.end() }) + + await t.completed }) -test('pool dispatch', (t) => { - t.plan(2) +test('pool dispatch', async (t) => { + t = tspl(t, { plan: 2 }) const server = createServer((req, res) => { res.end('asd') }) - t.teardown(server.close.bind(server)) + after(() => server.close()) server.listen(0, async () => { const client = new Pool(`http://localhost:${server.address().port}`) - t.teardown(client.close.bind(client)) + after(() => client.close()) let buf = '' client.dispatch({ @@ -574,22 +601,24 @@ test('pool dispatch', (t) => { onConnect () { }, onHeaders (statusCode, headers) { - t.equal(statusCode, 200) + t.strictEqual(statusCode, 200) }, onData (chunk) { buf += chunk }, onComplete () { - t.equal(buf, 'asd') + t.strictEqual(buf, 'asd') }, onError () { } }) }) + + await t.completed }) -test('pool pipeline args validation', (t) => { - t.plan(2) +test('pool pipeline args validation', async (t) => { + t = tspl(t, { plan: 2 }) const client = new Pool('http://localhost:5000') @@ -598,40 +627,44 @@ test('pool pipeline args validation', (t) => { t.ok(/opts/.test(err.message)) t.ok(err instanceof errors.InvalidArgumentError) }) + + await t.completed }) -test('300 requests succeed', (t) => { - t.plan(300 * 3) +test('300 requests succeed', async (t) => { + t = tspl(t, { plan: 300 * 3 }) const server = createServer((req, res) => { res.end('asd') }) - t.teardown(server.close.bind(server)) + after(() => server.close()) server.listen(0, () => { const client = new Pool(`http://localhost:${server.address().port}`, { connections: 1 }) - t.teardown(client.destroy.bind(client)) + after(() => client.destroy()) for (let n = 0; n < 300; ++n) { client.request({ path: '/', method: 'GET' }, (err, data) => { - t.error(err) + t.ifError(err) data.body.on('data', (chunk) => { - t.equal(chunk.toString(), 'asd') + t.strictEqual(chunk.toString(), 'asd') }).on('end', () => { t.ok(true, 'pass') }) }) } }) + + await t.completed }) -test('pool connect error', (t) => { - t.plan(1) +test('pool connect error', async (t) => { + t = tspl(t, { plan: 1 }) const server = createServer((c) => { t.fail() @@ -639,11 +672,11 @@ test('pool connect error', (t) => { server.on('connect', (req, socket, firstBodyChunk) => { socket.destroy() }) - t.teardown(server.close.bind(server)) + after(() => server.close()) server.listen(0, async () => { const client = new Pool(`http://localhost:${server.address().port}`) - t.teardown(client.close.bind(client)) + after(() => client.close()) try { await client.connect({ @@ -653,10 +686,12 @@ test('pool connect error', (t) => { t.ok(err) } }) + + await t.completed }) -test('pool upgrade error', (t) => { - t.plan(1) +test('pool upgrade error', async (t) => { + t = tspl(t, { plan: 1 }) const server = net.createServer((c) => { c.on('data', (d) => { @@ -671,11 +706,11 @@ test('pool upgrade error', (t) => { // Ignore error. }) }) - t.teardown(server.close.bind(server)) + after(() => server.close()) server.listen(0, async () => { const client = new Pool(`http://localhost:${server.address().port}`) - t.teardown(client.close.bind(client)) + after(() => client.close()) try { await client.upgrade({ @@ -687,22 +722,24 @@ test('pool upgrade error', (t) => { t.ok(err) } }) + + await t.completed }) -test('pool dispatch error', (t) => { - t.plan(3) +test('pool dispatch error', async (t) => { + t = tspl(t, { plan: 3 }) const server = createServer((req, res) => { res.end('asd') }) - t.teardown(server.close.bind(server)) + after(() => server.close()) server.listen(0, async () => { const client = new Pool(`http://localhost:${server.address().port}`, { connections: 1, pipelining: 1 }) - t.teardown(client.close.bind(client)) + after(() => client.close()) client.dispatch({ path: '/', @@ -711,7 +748,7 @@ test('pool dispatch error', (t) => { onConnect () { }, onHeaders (statusCode, headers) { - t.equal(statusCode, 200) + t.strictEqual(statusCode, 200) }, onData (chunk) { }, @@ -739,26 +776,28 @@ test('pool dispatch error', (t) => { t.fail() }, onError (err) { - t.equal(err.code, 'UND_ERR_INVALID_ARG') + t.strictEqual(err.code, 'UND_ERR_INVALID_ARG') } }) }) + + await t.completed }) -test('pool request abort in queue', (t) => { - t.plan(3) +test('pool request abort in queue', async (t) => { + t = tspl(t, { plan: 3 }) const server = createServer((req, res) => { res.end('asd') }) - t.teardown(server.close.bind(server)) + after(() => server.close()) server.listen(0, async () => { const client = new Pool(`http://localhost:${server.address().port}`, { connections: 1, pipelining: 1 }) - t.teardown(client.close.bind(client)) + after(() => client.close()) client.dispatch({ path: '/', @@ -767,7 +806,7 @@ test('pool request abort in queue', (t) => { onConnect () { }, onHeaders (statusCode, headers) { - t.equal(statusCode, 200) + t.strictEqual(statusCode, 200) }, onData (chunk) { }, @@ -784,26 +823,28 @@ test('pool request abort in queue', (t) => { method: 'GET', signal }, (err) => { - t.equal(err.code, 'UND_ERR_ABORTED') + t.strictEqual(err.code, 'UND_ERR_ABORTED') }) signal.emit('abort') }) + + await t.completed }) -test('pool stream abort in queue', (t) => { - t.plan(3) +test('pool stream abort in queue', async (t) => { + t = tspl(t, { plan: 3 }) const server = createServer((req, res) => { res.end('asd') }) - t.teardown(server.close.bind(server)) + after(() => server.close()) server.listen(0, async () => { const client = new Pool(`http://localhost:${server.address().port}`, { connections: 1, pipelining: 1 }) - t.teardown(client.close.bind(client)) + after(() => client.close()) client.dispatch({ path: '/', @@ -812,7 +853,7 @@ test('pool stream abort in queue', (t) => { onConnect () { }, onHeaders (statusCode, headers) { - t.equal(statusCode, 200) + t.strictEqual(statusCode, 200) }, onData (chunk) { }, @@ -829,26 +870,28 @@ test('pool stream abort in queue', (t) => { method: 'GET', signal }, ({ body }) => body, (err) => { - t.equal(err.code, 'UND_ERR_ABORTED') + t.strictEqual(err.code, 'UND_ERR_ABORTED') }) signal.emit('abort') }) + + await t.completed }) -test('pool pipeline abort in queue', (t) => { - t.plan(3) +test('pool pipeline abort in queue', async (t) => { + t = tspl(t, { plan: 3 }) const server = createServer((req, res) => { res.end('asd') }) - t.teardown(server.close.bind(server)) + after(() => server.close()) server.listen(0, async () => { const client = new Pool(`http://localhost:${server.address().port}`, { connections: 1, pipelining: 1 }) - t.teardown(client.close.bind(client)) + after(() => client.close()) client.dispatch({ path: '/', @@ -857,7 +900,7 @@ test('pool pipeline abort in queue', (t) => { onConnect () { }, onHeaders (statusCode, headers) { - t.equal(statusCode, 200) + t.strictEqual(statusCode, 200) }, onData (chunk) { }, @@ -874,26 +917,28 @@ test('pool pipeline abort in queue', (t) => { method: 'GET', signal }, ({ body }) => body).end().on('error', (err) => { - t.equal(err.code, 'UND_ERR_ABORTED') + t.strictEqual(err.code, 'UND_ERR_ABORTED') }) signal.emit('abort') }) + + await t.completed }) -test('pool stream constructor error destroy body', (t) => { - t.plan(4) +test('pool stream constructor error destroy body', async (t) => { + t = tspl(t, { plan: 4 }) const server = createServer((req, res) => { res.end('asd') }) - t.teardown(server.close.bind(server)) + after(() => server.close()) server.listen(0, async () => { const client = new Pool(`http://localhost:${server.address().port}`, { connections: 1, pipelining: 1 }) - t.teardown(client.close.bind(client)) + after(() => client.close()) { const body = new Readable({ @@ -910,8 +955,8 @@ test('pool stream constructor error destroy body', (t) => { }, () => { t.fail() }, (err) => { - t.equal(err.code, 'UND_ERR_INVALID_ARG') - t.equal(body.destroyed, true) + t.strictEqual(err.code, 'UND_ERR_INVALID_ARG') + t.strictEqual(body.destroyed, true) }) } @@ -927,27 +972,29 @@ test('pool stream constructor error destroy body', (t) => { }, () => { t.fail() }, (err) => { - t.equal(err.code, 'UND_ERR_INVALID_ARG') - t.equal(body.destroyed, true) + t.strictEqual(err.code, 'UND_ERR_INVALID_ARG') + t.strictEqual(body.destroyed, true) }) } }) + + await t.completed }) -test('pool request constructor error destroy body', (t) => { - t.plan(4) +test('pool request constructor error destroy body', async (t) => { + t = tspl(t, { plan: 4 }) const server = createServer((req, res) => { res.end('asd') }) - t.teardown(server.close.bind(server)) + after(() => server.close()) server.listen(0, async () => { const client = new Pool(`http://localhost:${server.address().port}`, { connections: 1, pipelining: 1 }) - t.teardown(client.close.bind(client)) + after(() => client.close()) { const body = new Readable({ @@ -962,8 +1009,8 @@ test('pool request constructor error destroy body', (t) => { 'transfer-encoding': 'fail' } }, (err) => { - t.equal(err.code, 'UND_ERR_INVALID_ARG') - t.equal(body.destroyed, true) + t.strictEqual(err.code, 'UND_ERR_INVALID_ARG') + t.strictEqual(body.destroyed, true) }) } @@ -977,40 +1024,42 @@ test('pool request constructor error destroy body', (t) => { method: 'CONNECT', body }, (err) => { - t.equal(err.code, 'UND_ERR_INVALID_ARG') - t.equal(body.destroyed, true) + t.strictEqual(err.code, 'UND_ERR_INVALID_ARG') + t.strictEqual(body.destroyed, true) }) } }) + + await t.completed }) -test('pool close waits for all requests', (t) => { - t.plan(5) +test('pool close waits for all requests', async (t) => { + t = tspl(t, { plan: 5 }) const server = createServer((req, res) => { res.end('asd') }) - t.teardown(server.close.bind(server)) + after(() => server.close()) server.listen(0, () => { const client = new Pool(`http://localhost:${server.address().port}`, { connections: 1, pipelining: 1 }) - t.teardown(client.destroy.bind(client)) + after(() => client.destroy()) client.request({ path: '/', method: 'GET' }, (err) => { - t.error(err) + t.ifError(err) }) client.request({ path: '/', method: 'GET' }, (err) => { - t.error(err) + t.ifError(err) }) client.close(() => { @@ -1028,22 +1077,24 @@ test('pool close waits for all requests', (t) => { t.ok(err instanceof errors.ClientClosedError) }) }) + + await t.completed }) -test('pool destroyed', (t) => { - t.plan(1) +test('pool destroyed', async (t) => { + t = tspl(t, { plan: 1 }) const server = createServer((req, res) => { res.end('asd') }) - t.teardown(server.close.bind(server)) + after(() => server.close()) server.listen(0, () => { const client = new Pool(`http://localhost:${server.address().port}`, { connections: 1, pipelining: 1 }) - t.teardown(client.destroy.bind(client)) + after(() => client.destroy()) client.destroy() client.request({ @@ -1053,43 +1104,45 @@ test('pool destroyed', (t) => { t.ok(err instanceof errors.ClientDestroyedError) }) }) + + await t.completed }) -test('pool destroy fails queued requests', (t) => { - t.plan(6) +test('pool destroy fails queued requests', async (t) => { + t = tspl(t, { plan: 6 }) const server = createServer((req, res) => { res.end('asd') }) - t.teardown(server.close.bind(server)) + after(() => server.close()) server.listen(0, async () => { const client = new Pool(`http://localhost:${server.address().port}`, { connections: 1, pipelining: 1 }) - t.teardown(client.destroy.bind(client)) + after(() => client.destroy()) const _err = new Error() client.request({ path: '/', method: 'GET' }, (err) => { - t.equal(err, _err) + t.strictEqual(err, _err) }) client.request({ path: '/', method: 'GET' }, (err) => { - t.equal(err, _err) + t.strictEqual(err, _err) }) - t.equal(client.destroyed, false) + t.strictEqual(client.destroyed, false) client.destroy(_err, () => { t.ok(true, 'pass') }) - t.equal(client.destroyed, true) + t.strictEqual(client.destroyed, true) client.request({ path: '/', @@ -1098,4 +1151,5 @@ test('pool destroy fails queued requests', (t) => { t.ok(err instanceof errors.ClientDestroyedError) }) }) + await t.completed }) diff --git a/test/request-timeout.js b/test/request-timeout.js index 0db4417e0d5..f49f6c5bcf3 100644 --- a/test/request-timeout.js +++ b/test/request-timeout.js @@ -1,6 +1,7 @@ 'use strict' -const { test } = require('tap') +const { tspl } = require('@matteo.collina/tspl') +const { test, after } = require('node:test') const { createReadStream, writeFileSync, unlinkSync } = require('node:fs') const { Client, errors } = require('..') const { kConnect } = require('../lib/core/symbols') @@ -16,71 +17,75 @@ const { PassThrough } = require('node:stream') -test('request timeout', (t) => { - t.plan(1) +test('request timeout', async (t) => { + t = tspl(t, { plan: 1 }) const server = createServer((req, res) => { setTimeout(() => { res.end('hello') }, 1000) }) - t.teardown(server.close.bind(server)) + after(() => server.close()) server.listen(0, () => { const client = new Client(`http://localhost:${server.address().port}`, { headersTimeout: 500 }) - t.teardown(client.destroy.bind(client)) + after(() => client.destroy()) client.request({ path: '/', method: 'GET' }, (err, response) => { t.ok(err instanceof errors.HeadersTimeoutError) }) }) + + await t.completed }) -test('request timeout with readable body', (t) => { - t.plan(1) +test('request timeout with readable body', async (t) => { + t = tspl(t, { plan: 1 }) const server = createServer((req, res) => { }) - t.teardown(server.close.bind(server)) + after(() => server.close()) const tempfile = `${__filename}.10mb.txt` writeFileSync(tempfile, Buffer.alloc(10 * 1024 * 1024)) - t.teardown(() => unlinkSync(tempfile)) + after(() => unlinkSync(tempfile)) server.listen(0, () => { const client = new Client(`http://localhost:${server.address().port}`, { headersTimeout: 1e3 }) - t.teardown(client.destroy.bind(client)) + after(() => client.destroy()) const body = createReadStream(tempfile) client.request({ path: '/', method: 'POST', body }, (err, response) => { t.ok(err instanceof errors.HeadersTimeoutError) }) }) + + await t.completed }) -test('body timeout', (t) => { - t.plan(2) +test('body timeout', async (t) => { + t = tspl(t, { plan: 2 }) - const clock = FakeTimers.install() - t.teardown(clock.uninstall.bind(clock)) + const clock = FakeTimers.install({ shouldClearNativeTimers: true }) + after(() => clock.uninstall()) const orgTimers = { ...timers } Object.assign(timers, { setTimeout, clearTimeout }) - t.teardown(() => { + after(() => { Object.assign(timers, orgTimers) }) const server = createServer((req, res) => { res.write('hello') }) - t.teardown(server.close.bind(server)) + after(() => server.close()) server.listen(0, () => { const client = new Client(`http://localhost:${server.address().port}`, { bodyTimeout: 50 }) - t.teardown(client.destroy.bind(client)) + after(() => client.destroy()) client.request({ path: '/', method: 'GET' }, (err, { body }) => { - t.error(err) + t.ifError(err) body.on('data', () => { clock.tick(100) }).on('error', (err) => { @@ -90,17 +95,19 @@ test('body timeout', (t) => { clock.tick(50) }) + + await t.completed }) -test('overridden request timeout', (t) => { - t.plan(1) +test('overridden request timeout', async (t) => { + t = tspl(t, { plan: 1 }) - const clock = FakeTimers.install() - t.teardown(clock.uninstall.bind(clock)) + const clock = FakeTimers.install({ shouldClearNativeTimers: true }) + after(() => clock.uninstall()) const orgTimers = { ...timers } Object.assign(timers, { setTimeout, clearTimeout }) - t.teardown(() => { + after(() => { Object.assign(timers, orgTimers) }) @@ -110,11 +117,11 @@ test('overridden request timeout', (t) => { }, 100) clock.tick(100) }) - t.teardown(server.close.bind(server)) + after(() => server.close()) server.listen(0, () => { const client = new Client(`http://localhost:${server.address().port}`, { headersTimeout: 500 }) - t.teardown(client.destroy.bind(client)) + after(() => client.destroy()) client.request({ path: '/', method: 'GET', headersTimeout: 50 }, (err, response) => { t.ok(err instanceof errors.HeadersTimeoutError) @@ -122,31 +129,33 @@ test('overridden request timeout', (t) => { clock.tick(50) }) + + await t.completed }) -test('overridden body timeout', (t) => { - t.plan(2) +test('overridden body timeout', async (t) => { + t = tspl(t, { plan: 2 }) - const clock = FakeTimers.install() - t.teardown(clock.uninstall.bind(clock)) + const clock = FakeTimers.install({ shouldClearNativeTimers: true }) + after(() => clock.uninstall()) const orgTimers = { ...timers } Object.assign(timers, { setTimeout, clearTimeout }) - t.teardown(() => { + after(() => { Object.assign(timers, orgTimers) }) const server = createServer((req, res) => { res.write('hello') }) - t.teardown(server.close.bind(server)) + after(() => server.close()) server.listen(0, () => { const client = new Client(`http://localhost:${server.address().port}`, { bodyTimeout: 500 }) - t.teardown(client.destroy.bind(client)) + after(() => client.destroy()) client.request({ path: '/', method: 'GET', bodyTimeout: 50 }, (err, { body }) => { - t.error(err) + t.ifError(err) body.on('data', () => { clock.tick(100) }).on('error', (err) => { @@ -156,17 +165,19 @@ test('overridden body timeout', (t) => { clock.tick(50) }) + + await t.completed }) -test('With EE signal', (t) => { - t.plan(1) +test('With EE signal', async (t) => { + t = tspl(t, { plan: 1 }) - const clock = FakeTimers.install() - t.teardown(clock.uninstall.bind(clock)) + const clock = FakeTimers.install({ shouldClearNativeTimers: true }) + after(() => clock.uninstall()) const orgTimers = { ...timers } Object.assign(timers, { setTimeout, clearTimeout }) - t.teardown(() => { + after(() => { Object.assign(timers, orgTimers) }) @@ -176,14 +187,14 @@ test('With EE signal', (t) => { }, 100) clock.tick(100) }) - t.teardown(server.close.bind(server)) + after(() => server.close()) server.listen(0, () => { const client = new Client(`http://localhost:${server.address().port}`, { headersTimeout: 50 }) const ee = new EventEmitter() - t.teardown(client.destroy.bind(client)) + after(() => client.destroy()) client.request({ path: '/', method: 'GET', signal: ee }, (err, response) => { t.ok(err instanceof errors.HeadersTimeoutError) @@ -191,17 +202,19 @@ test('With EE signal', (t) => { clock.tick(50) }) + + await t.completed }) -test('With abort-controller signal', (t) => { - t.plan(1) +test('With abort-controller signal', async (t) => { + t = tspl(t, { plan: 1 }) - const clock = FakeTimers.install() - t.teardown(clock.uninstall.bind(clock)) + const clock = FakeTimers.install({ shouldClearNativeTimers: true }) + after(() => clock.uninstall()) const orgTimers = { ...timers } Object.assign(timers, { setTimeout, clearTimeout }) - t.teardown(() => { + after(() => { Object.assign(timers, orgTimers) }) @@ -211,14 +224,14 @@ test('With abort-controller signal', (t) => { }, 100) clock.tick(100) }) - t.teardown(server.close.bind(server)) + after(() => server.close()) server.listen(0, () => { const client = new Client(`http://localhost:${server.address().port}`, { headersTimeout: 50 }) const abortController = new AbortController() - t.teardown(client.destroy.bind(client)) + after(() => client.destroy()) client.request({ path: '/', method: 'GET', signal: abortController.signal }, (err, response) => { t.ok(err instanceof errors.HeadersTimeoutError) @@ -226,17 +239,19 @@ test('With abort-controller signal', (t) => { clock.tick(50) }) + + await t.completed }) -test('Abort before timeout (EE)', (t) => { - t.plan(1) +test('Abort before timeout (EE)', async (t) => { + t = tspl(t, { plan: 1 }) - const clock = FakeTimers.install() - t.teardown(clock.uninstall.bind(clock)) + const clock = FakeTimers.install({ shouldClearNativeTimers: true }) + after(() => clock.uninstall()) const orgTimers = { ...timers } Object.assign(timers, { setTimeout, clearTimeout }) - t.teardown(() => { + after(() => { Object.assign(timers, orgTimers) }) @@ -248,30 +263,32 @@ test('Abort before timeout (EE)', (t) => { ee.emit('abort') clock.tick(50) }) - t.teardown(server.close.bind(server)) + after(() => server.close()) server.listen(0, () => { const client = new Client(`http://localhost:${server.address().port}`, { headersTimeout: 50 }) - t.teardown(client.destroy.bind(client)) + after(() => client.destroy()) client.request({ path: '/', method: 'GET', signal: ee }, (err, response) => { t.ok(err instanceof errors.RequestAbortedError) clock.tick(100) }) }) + + await t.completed }) -test('Abort before timeout (abort-controller)', (t) => { - t.plan(1) +test('Abort before timeout (abort-controller)', async (t) => { + t = tspl(t, { plan: 1 }) - const clock = FakeTimers.install() - t.teardown(clock.uninstall.bind(clock)) + const clock = FakeTimers.install({ shouldClearNativeTimers: true }) + after(() => clock.uninstall()) const orgTimers = { ...timers } Object.assign(timers, { setTimeout, clearTimeout }) - t.teardown(() => { + after(() => { Object.assign(timers, orgTimers) }) @@ -283,30 +300,32 @@ test('Abort before timeout (abort-controller)', (t) => { abortController.abort() clock.tick(50) }) - t.teardown(server.close.bind(server)) + after(() => server.close()) server.listen(0, () => { const client = new Client(`http://localhost:${server.address().port}`, { headersTimeout: 50 }) - t.teardown(client.destroy.bind(client)) + after(() => client.destroy()) client.request({ path: '/', method: 'GET', signal: abortController.signal }, (err, response) => { t.ok(err instanceof errors.RequestAbortedError) clock.tick(100) }) }) + + await t.completed }) -test('Timeout with pipelining', (t) => { - t.plan(3) +test('Timeout with pipelining', async (t) => { + t = tspl(t, { plan: 3 }) - const clock = FakeTimers.install() - t.teardown(clock.uninstall.bind(clock)) + const clock = FakeTimers.install({ shouldClearNativeTimers: true }) + after(() => clock.uninstall()) const orgTimers = { ...timers } Object.assign(timers, { setTimeout, clearTimeout }) - t.teardown(() => { + after(() => { Object.assign(timers, orgTimers) }) @@ -316,14 +335,14 @@ test('Timeout with pipelining', (t) => { }, 100) clock.tick(50) }) - t.teardown(server.close.bind(server)) + after(() => server.close()) server.listen(0, () => { const client = new Client(`http://localhost:${server.address().port}`, { pipelining: 10, headersTimeout: 50 }) - t.teardown(client.destroy.bind(client)) + after(() => client.destroy()) client.request({ path: '/', method: 'GET' }, (err, response) => { t.ok(err instanceof errors.HeadersTimeoutError) @@ -337,17 +356,19 @@ test('Timeout with pipelining', (t) => { t.ok(err instanceof errors.HeadersTimeoutError) }) }) + + await t.completed }) -test('Global option', (t) => { - t.plan(1) +test('Global option', async (t) => { + t = tspl(t, { plan: 1 }) - const clock = FakeTimers.install() - t.teardown(clock.uninstall.bind(clock)) + const clock = FakeTimers.install({ shouldClearNativeTimers: true }) + after(() => clock.uninstall()) const orgTimers = { ...timers } Object.assign(timers, { setTimeout, clearTimeout }) - t.teardown(() => { + after(() => { Object.assign(timers, orgTimers) }) @@ -357,13 +378,13 @@ test('Global option', (t) => { }, 100) clock.tick(100) }) - t.teardown(server.close.bind(server)) + after(() => server.close()) server.listen(0, () => { const client = new Client(`http://localhost:${server.address().port}`, { headersTimeout: 50 }) - t.teardown(client.destroy.bind(client)) + after(() => client.destroy()) client.request({ path: '/', method: 'GET' }, (err, response) => { t.ok(err instanceof errors.HeadersTimeoutError) @@ -371,17 +392,19 @@ test('Global option', (t) => { clock.tick(50) }) + + await t.completed }) -test('Request options overrides global option', (t) => { - t.plan(1) +test('Request options overrides global option', async (t) => { + t = tspl(t, { plan: 1 }) - const clock = FakeTimers.install() - t.teardown(clock.uninstall.bind(clock)) + const clock = FakeTimers.install({ shouldClearNativeTimers: true }) + after(() => clock.uninstall()) const orgTimers = { ...timers } Object.assign(timers, { setTimeout, clearTimeout }) - t.teardown(() => { + after(() => { Object.assign(timers, orgTimers) }) @@ -391,13 +414,13 @@ test('Request options overrides global option', (t) => { }, 100) clock.tick(100) }) - t.teardown(server.close.bind(server)) + after(() => server.close()) server.listen(0, () => { const client = new Client(`http://localhost:${server.address().port}`, { headersTimeout: 50 }) - t.teardown(client.destroy.bind(client)) + after(() => client.destroy()) client.request({ path: '/', method: 'GET' }, (err, response) => { t.ok(err instanceof errors.HeadersTimeoutError) @@ -405,15 +428,17 @@ test('Request options overrides global option', (t) => { clock.tick(50) }) + + await t.completed }) -test('client.destroy should cancel the timeout', (t) => { - t.plan(2) +test('client.destroy should cancel the timeout', async (t) => { + t = tspl(t, { plan: 2 }) const server = createServer((req, res) => { res.end('hello') }) - t.teardown(server.close.bind(server)) + after(() => server.close()) server.listen(0, () => { const client = new Client(`http://localhost:${server.address().port}`, { @@ -425,39 +450,41 @@ test('client.destroy should cancel the timeout', (t) => { }) client.destroy(err => { - t.error(err) + t.ifError(err) }) }) + + await t.completed }) -test('client.close should wait for the timeout', (t) => { - t.plan(2) +test('client.close should wait for the timeout', async (t) => { + t = tspl(t, { plan: 2 }) const clock = FakeTimers.install({ shouldClearNativeTimers: true }) - t.teardown(clock.uninstall.bind(clock)) + after(() => clock.uninstall()) const orgTimers = { ...timers } Object.assign(timers, { setTimeout, clearTimeout }) - t.teardown(() => { + after(() => { Object.assign(timers, orgTimers) }) const server = createServer((req, res) => { }) - t.teardown(server.close.bind(server)) + after(() => server.close()) server.listen(0, () => { const client = new Client(`http://localhost:${server.address().port}`, { headersTimeout: 100 }) - t.teardown(client.destroy.bind(client)) + after(() => client.destroy()) client.request({ path: '/', method: 'GET' }, (err, response) => { t.ok(err instanceof errors.HeadersTimeoutError) }) client.close((err) => { - t.error(err) + t.ifError(err) }) client.on('connect', () => { @@ -466,16 +493,18 @@ test('client.close should wait for the timeout', (t) => { }) }) }) + + await t.completed }) -test('Validation', (t) => { - t.plan(4) +test('Validation', async (t) => { + t = tspl(t, { plan: 4 }) try { const client = new Client('http://localhost:3000', { headersTimeout: 'foobar' }) - t.teardown(client.destroy.bind(client)) + after(() => client.destroy()) } catch (err) { t.ok(err instanceof errors.InvalidArgumentError) } @@ -484,7 +513,7 @@ test('Validation', (t) => { const client = new Client('http://localhost:3000', { headersTimeout: -1 }) - t.teardown(client.destroy.bind(client)) + after(() => client.destroy()) } catch (err) { t.ok(err instanceof errors.InvalidArgumentError) } @@ -493,7 +522,7 @@ test('Validation', (t) => { const client = new Client('http://localhost:3000', { bodyTimeout: 'foobar' }) - t.teardown(client.destroy.bind(client)) + after(() => client.destroy()) } catch (err) { t.ok(err instanceof errors.InvalidArgumentError) } @@ -502,21 +531,23 @@ test('Validation', (t) => { const client = new Client('http://localhost:3000', { bodyTimeout: -1 }) - t.teardown(client.destroy.bind(client)) + after(() => client.destroy()) } catch (err) { t.ok(err instanceof errors.InvalidArgumentError) } + + await t.completed }) -test('Disable request timeout', (t) => { - t.plan(2) +test('Disable request timeout', async (t) => { + t = tspl(t, { plan: 2 }) - const clock = FakeTimers.install() - t.teardown(clock.uninstall.bind(clock)) + const clock = FakeTimers.install({ shouldClearNativeTimers: true }) + after(() => clock.uninstall()) const orgTimers = { ...timers } Object.assign(timers, { setTimeout, clearTimeout }) - t.teardown(() => { + after(() => { Object.assign(timers, orgTimers) }) @@ -526,39 +557,41 @@ test('Disable request timeout', (t) => { }, 32e3) clock.tick(33e3) }) - t.teardown(server.close.bind(server)) + after(() => server.close()) server.listen(0, () => { const client = new Client(`http://localhost:${server.address().port}`, { headersTimeout: 0, connectTimeout: 0 }) - t.teardown(client.destroy.bind(client)) + after(() => client.destroy()) client.request({ path: '/', method: 'GET' }, (err, response) => { - t.error(err) + t.ifError(err) const bufs = [] response.body.on('data', (buf) => { bufs.push(buf) }) response.body.on('end', () => { - t.equal('hello', Buffer.concat(bufs).toString('utf8')) + t.strictEqual('hello', Buffer.concat(bufs).toString('utf8')) }) }) clock.tick(31e3) }) + + await t.completed }) -test('Disable request timeout for a single request', (t) => { - t.plan(2) +test('Disable request timeout for a single request', async (t) => { + t = tspl(t, { plan: 2 }) - const clock = FakeTimers.install() - t.teardown(clock.uninstall.bind(clock)) + const clock = FakeTimers.install({ shouldClearNativeTimers: true }) + after(() => clock.uninstall()) const orgTimers = { ...timers } Object.assign(timers, { setTimeout, clearTimeout }) - t.teardown(() => { + after(() => { Object.assign(timers, orgTimers) }) @@ -568,39 +601,41 @@ test('Disable request timeout for a single request', (t) => { }, 32e3) clock.tick(33e3) }) - t.teardown(server.close.bind(server)) + after(() => server.close()) server.listen(0, () => { const client = new Client(`http://localhost:${server.address().port}`, { headersTimeout: 0, connectTimeout: 0 }) - t.teardown(client.destroy.bind(client)) + after(() => client.destroy()) client.request({ path: '/', method: 'GET' }, (err, response) => { - t.error(err) + t.ifError(err) const bufs = [] response.body.on('data', (buf) => { bufs.push(buf) }) response.body.on('end', () => { - t.equal('hello', Buffer.concat(bufs).toString('utf8')) + t.strictEqual('hello', Buffer.concat(bufs).toString('utf8')) }) }) clock.tick(31e3) }) + + await t.completed }) -test('stream timeout', (t) => { - t.plan(1) +test('stream timeout', async (t) => { + t = tspl(t, { plan: 1 }) - const clock = FakeTimers.install() - t.teardown(clock.uninstall.bind(clock)) + const clock = FakeTimers.install({ shouldClearNativeTimers: true }) + after(() => clock.uninstall()) const orgTimers = { ...timers } Object.assign(timers, { setTimeout, clearTimeout }) - t.teardown(() => { + after(() => { Object.assign(timers, orgTimers) }) @@ -610,11 +645,11 @@ test('stream timeout', (t) => { }, 301e3) clock.tick(301e3) }) - t.teardown(server.close.bind(server)) + after(() => server.close()) server.listen(0, () => { const client = new Client(`http://localhost:${server.address().port}`, { connectTimeout: 0 }) - t.teardown(client.destroy.bind(client)) + after(() => client.destroy()) client.stream({ path: '/', @@ -626,17 +661,19 @@ test('stream timeout', (t) => { t.ok(err instanceof errors.HeadersTimeoutError) }) }) + + await t.completed }) -test('stream custom timeout', (t) => { - t.plan(1) +test('stream custom timeout', async (t) => { + t = tspl(t, { plan: 1 }) - const clock = FakeTimers.install() - t.teardown(clock.uninstall.bind(clock)) + const clock = FakeTimers.install({ shouldClearNativeTimers: true }) + after(() => clock.uninstall()) const orgTimers = { ...timers } Object.assign(timers, { setTimeout, clearTimeout }) - t.teardown(() => { + after(() => { Object.assign(timers, orgTimers) }) @@ -646,13 +683,13 @@ test('stream custom timeout', (t) => { }, 31e3) clock.tick(31e3) }) - t.teardown(server.close.bind(server)) + after(() => server.close()) server.listen(0, () => { const client = new Client(`http://localhost:${server.address().port}`, { headersTimeout: 30e3 }) - t.teardown(client.destroy.bind(client)) + after(() => client.destroy()) client.stream({ path: '/', @@ -664,17 +701,19 @@ test('stream custom timeout', (t) => { t.ok(err instanceof errors.HeadersTimeoutError) }) }) + + await t.completed }) -test('pipeline timeout', (t) => { - t.plan(1) +test('pipeline timeout', async (t) => { + t = tspl(t, { plan: 1 }) - const clock = FakeTimers.install() - t.teardown(clock.uninstall.bind(clock)) + const clock = FakeTimers.install({ shouldClearNativeTimers: true }) + after(() => clock.uninstall()) const orgTimers = { ...timers } Object.assign(timers, { setTimeout, clearTimeout }) - t.teardown(() => { + after(() => { Object.assign(timers, orgTimers) }) @@ -684,11 +723,11 @@ test('pipeline timeout', (t) => { }, 301e3) clock.tick(301e3) }) - t.teardown(server.close.bind(server)) + after(() => server.close()) server.listen(0, () => { const client = new Client(`http://localhost:${server.address().port}`) - t.teardown(client.destroy.bind(client)) + after(() => client.destroy()) const buf = Buffer.alloc(1e6).toString() pipeline( @@ -719,17 +758,19 @@ test('pipeline timeout', (t) => { } ) }) + + await t.completed }) -test('pipeline timeout', (t) => { - t.plan(1) +test('pipeline timeout', async (t) => { + t = tspl(t, { plan: 1 }) - const clock = FakeTimers.install() - t.teardown(clock.uninstall.bind(clock)) + const clock = FakeTimers.install({ shouldClearNativeTimers: true }) + after(() => clock.uninstall()) const orgTimers = { ...timers } Object.assign(timers, { setTimeout, clearTimeout }) - t.teardown(() => { + after(() => { Object.assign(timers, orgTimers) }) @@ -739,13 +780,13 @@ test('pipeline timeout', (t) => { }, 31e3) clock.tick(31e3) }) - t.teardown(server.close.bind(server)) + after(() => server.close()) server.listen(0, () => { const client = new Client(`http://localhost:${server.address().port}`, { headersTimeout: 30e3 }) - t.teardown(client.destroy.bind(client)) + after(() => client.destroy()) const buf = Buffer.alloc(1e6).toString() pipeline( @@ -776,30 +817,32 @@ test('pipeline timeout', (t) => { } ) }) + + await t.completed }) -test('client.close should not deadlock', (t) => { - t.plan(2) +test('client.close should not deadlock', async (t) => { + t = tspl(t, { plan: 2 }) - const clock = FakeTimers.install() - t.teardown(clock.uninstall.bind(clock)) + const clock = FakeTimers.install({ shouldClearNativeTimers: true }) + after(() => clock.uninstall()) const orgTimers = { ...timers } Object.assign(timers, { setTimeout, clearTimeout }) - t.teardown(() => { + after(() => { Object.assign(timers, orgTimers) }) const server = createServer((req, res) => { }) - t.teardown(server.close.bind(server)) + after(() => server.close()) server.listen(0, () => { const client = new Client(`http://localhost:${server.address().port}`, { bodyTimeout: 200, headersTimeout: 100 }) - t.teardown(client.destroy.bind(client)) + after(() => client.destroy()) client[kConnect](() => { client.request({ @@ -810,10 +853,11 @@ test('client.close should not deadlock', (t) => { }) client.close((err) => { - t.error(err) + t.ifError(err) }) clock.tick(100) }) }) + await t.completed }) diff --git a/test/tls-session-reuse.js b/test/tls-session-reuse.js index 0c784456798..c70578bed1f 100644 --- a/test/tls-session-reuse.js +++ b/test/tls-session-reuse.js @@ -1,10 +1,11 @@ 'use strict' +const { tspl } = require('@matteo.collina/tspl') +const { test, after, describe } = require('node:test') const { readFileSync } = require('node:fs') const { join } = require('node:path') const https = require('node:https') const crypto = require('node:crypto') -const { test, teardown } = require('tap') const { Client, Pool } = require('..') const { kSocket } = require('../lib/core/symbols') @@ -14,12 +15,12 @@ const options = { } const ca = readFileSync(join(__dirname, 'fixtures', 'ca.pem'), 'utf8') -test('A client should disable session caching', t => { +describe('A client should disable session caching', () => { const clientSessions = {} let serverRequests = 0 - t.test('Prepare request', t => { - t.plan(3) + test('Prepare request', async t => { + t = tspl(t, { plan: 3 }) const server = https.createServer(options, (req, res) => { if (req.url === '/drop-key') { server.setTicketKeys(crypto.randomBytes(48)) @@ -40,7 +41,7 @@ test('A client should disable session caching', t => { maxCachedSessions: 0 }) - t.teardown(() => { + after(() => { client.close() server.close() }) @@ -64,7 +65,7 @@ test('A client should disable session caching', t => { delete tls.ciphers } client.request(options, (err, data) => { - t.error(err) + t.ifError(err) clientSessions[options.name] = client[kSocket].getSession() data.body.resume().on('end', () => { if (queue.length !== 0) { @@ -76,28 +77,29 @@ test('A client should disable session caching', t => { } request() }) + + await t.completed }) - t.test('Verify cached sessions', t => { - t.plan(2) - t.equal(serverRequests, 2) - t.not( + test('Verify cached sessions', async t => { + t = tspl(t, { plan: 2 }) + t.strictEqual(serverRequests, 2) + t.notEqual( clientSessions.first.toString('hex'), clientSessions.second.toString('hex') ) + await t.completed }) - - t.end() }) -test('A pool should be able to reuse TLS sessions between clients', t => { +describe('A pool should be able to reuse TLS sessions between clients', () => { let serverRequests = 0 const REQ_COUNT = 10 const ASSERT_PERFORMANCE_GAIN = false - t.test('Prepare request', t => { - t.plan(2 + 1 + (ASSERT_PERFORMANCE_GAIN ? 1 : 0)) + test('Prepare request', async t => { + t = tspl(t, { plan: 2 + 1 + (ASSERT_PERFORMANCE_GAIN ? 1 : 0) }) const server = https.createServer(options, (req, res) => { serverRequests++ res.end() @@ -137,7 +139,7 @@ test('A pool should be able to reuse TLS sessions between clients', t => { numSessions++ }) - t.teardown(() => { + after(() => { poolWithSessionReuse.close() poolWithoutSessionReuse.close() server.close() @@ -168,13 +170,11 @@ test('A pool should be able to reuse TLS sessions between clients', t => { await runRequests(poolWithoutSessionReuse, REQ_COUNT, false) await runRequests(poolWithSessionReuse, REQ_COUNT, true) - t.equal(numSessions, 2) - t.equal(serverRequests, 2 + REQ_COUNT * 2) + t.strictEqual(numSessions, 2) + t.strictEqual(serverRequests, 2 + REQ_COUNT * 2) t.ok(true, 'pass') }) - }) - t.end() + await t.completed + }) }) - -teardown(() => process.exit())