From 620593d1e97c63602da38eccf91e31f2f8e7c68d Mon Sep 17 00:00:00 2001 From: Sosuke Suzuki Date: Sun, 31 Dec 2023 01:12:54 +0900 Subject: [PATCH 1/9] Add `test:node-test` script --- package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/package.json b/package.json index 56d6207f9c0..4b5a8cf1538 100644 --- a/package.json +++ b/package.json @@ -81,6 +81,7 @@ "test:fetch": "npm run build:node && tap --expose-gc test/fetch/*.js && borp --coverage -p \"test/webidl/*.js\"", "test:jest": "jest", "test:tap": "tap test/*.js test/diagnostics-channel/*.js", + "test:node-test": "borp --coverage -p \"test/node-test/*.js\"", "test:tdd": "tap test/*.js test/diagnostics-channel/*.js -w", "test:typescript": "tsd && tsc --skipLibCheck test/imports/undici-import.ts", "test:websocket": "borp --coverage -p \"test/websocket/*.js\"", From 5cf60b789d417aad76fe4ac7f55f262625417163 Mon Sep 17 00:00:00 2001 From: Sosuke Suzuki Date: Sun, 31 Dec 2023 01:13:09 +0900 Subject: [PATCH 2/9] Move `test/abort-controller.js` to `test/node-test` --- test/{ => node-test}/abort-controller.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) rename test/{ => node-test}/abort-controller.js (98%) diff --git a/test/abort-controller.js b/test/node-test/abort-controller.js similarity index 98% rename from test/abort-controller.js rename to test/node-test/abort-controller.js index 4658686657a..04e6c41acf6 100644 --- a/test/abort-controller.js +++ b/test/node-test/abort-controller.js @@ -2,10 +2,10 @@ const { test } = require('tap') const { AbortController: NPMAbortController } = require('abort-controller') -const { Client, errors } = require('..') +const { Client, errors } = require('../..') const { createServer } = require('http') const { createReadStream } = require('fs') -const { wrapWithAsyncIterable } = require('./utils/async-iterators') +const { wrapWithAsyncIterable } = require('../utils/async-iterators') const controllers = [{ AbortControllerImpl: NPMAbortController, From 3abcc63b5750015bfde763f763e43d7c137c3acd Mon Sep 17 00:00:00 2001 From: Sosuke Suzuki Date: Sun, 31 Dec 2023 02:41:25 +0900 Subject: [PATCH 3/9] Migrate all tests to use `node:test` --- test/node-test/abort-controller.js | 202 ++++++++++++++++++++++------- 1 file changed, 155 insertions(+), 47 deletions(-) diff --git a/test/node-test/abort-controller.js b/test/node-test/abort-controller.js index 04e6c41acf6..bfc371a9a52 100644 --- a/test/node-test/abort-controller.js +++ b/test/node-test/abort-controller.js @@ -1,11 +1,82 @@ 'use strict' -const { test } = require('tap') +const { test } = require('node:test') const { AbortController: NPMAbortController } = require('abort-controller') const { Client, errors } = require('../..') const { createServer } = require('http') const { createReadStream } = require('fs') const { wrapWithAsyncIterable } = require('../utils/async-iterators') +const { tspl } = require('@matteo.collina/tspl') + +/** + * A port of tap's `t.type` that can be used with `node:assert` + * https://github.com/tapjs/tapjs/blob/511019b2ac0fa014370154c3a341a0e632f50b19/src/asserts/src/index.ts#L199 + */ +function ttype (plan, obj, klass) { + const name = + typeof klass === 'function' + ? klass.name || '(anonymous constructor)' + : klass + + if (obj === klass) { + return plan.ok(1) + } + + const tof = typeof obj + const type = + !obj && tof === 'object' + ? 'null' + // treat as object, but not Object + // t.type(() => {}, Function) + : tof === 'function' && + typeof klass === 'function' && + klass !== Object + ? 'object' + : tof + + if ( + (type === 'number' && klass === Number) || + (type === 'string' && klass === String) || + (type === 'bigint' && klass === BigInt) || + (klass === 'array' && Array.isArray(obj)) || + (type === 'symbol' && klass === Symbol) + ) { + return plan.ok(1) + } + + // simplest case, it literally is the same thing + if (type === 'object' && klass !== 'object') { + if (typeof klass === 'function') { + return plan.ok(obj instanceof klass) + } + + // check prototype chain for name + // at this point, we already know klass is not a function + // if the klass specified is an obj in the proto chain, pass + // if the name specified is the name of a ctor in the chain, pass + for (let p = obj; p; p = Object.getPrototypeOf(p)) { + const ctor = p.constructor && p.constructor.name + if (p === klass || ctor === name) { + return plan.ok(1) + } + } + } + + return plan.strictEqual(type, name) +} + +/** + * The helper function to create a promise with resolvers. + * Please see https://github.com/tc39/proposal-promise-with-resolvers for more details. + */ +function promiseWithResolvers () { + let _resolve, _reject + const promise = new Promise((resolve, reject) => { + _resolve = resolve + _reject = reject + }) + return { promise, resolve: _resolve, reject: _reject } +} const controllers = [{ AbortControllerImpl: NPMAbortController, @@ -19,66 +90,78 @@ if (global.AbortController) { }) } for (const { AbortControllerImpl, controllerName } of controllers) { - test(`Abort ${controllerName} before creating request`, (t) => { - t.plan(1) + test(`Abort ${controllerName} before creating request`, async (t) => { + const p = tspl(t, { plan: 1 }) const server = createServer((req, res) => { - t.fail() + p.fail() }) - t.teardown(server.close.bind(server)) + t.after(server.close.bind(server)) + + const { promise, resolve } = promiseWithResolvers() server.listen(0, () => { const client = new Client(`http://localhost:${server.address().port}`) const abortController = new AbortControllerImpl() - t.teardown(client.destroy.bind(client)) + t.after(client.destroy.bind(client)) abortController.abort() client.request({ path: '/', method: 'GET', signal: abortController.signal }, (err, response) => { - t.type(err, errors.RequestAbortedError) + ttype(p, err, errors.RequestAbortedError) + resolve() }) }) + + await promise }) - test(`Abort ${controllerName} before sending request (no body)`, (t) => { - t.plan(3) + test(`Abort ${controllerName} before sending request (no body)`, async (t) => { + const p = tspl(t, { plan: 3 }) let count = 0 const server = createServer((req, res) => { if (count === 1) { - t.fail('The second request should never be executed') + p.fail('The second request should never be executed') } count += 1 res.end('hello') }) - t.teardown(server.close.bind(server)) + t.after(server.close.bind(server)) + + const { promise: promise1, resolve: resolve1 } = promiseWithResolvers() + const { promise: promise2, resolve: resolve2 } = promiseWithResolvers() server.listen(0, () => { const client = new Client(`http://localhost:${server.address().port}`) const abortController = new AbortControllerImpl() - t.teardown(client.destroy.bind(client)) + t.after(client.destroy.bind(client)) client.request({ path: '/', method: 'GET' }, (err, response) => { - t.error(err) + p.ifError(err) const bufs = [] response.body.on('data', (buf) => { bufs.push(buf) }) response.body.on('end', () => { - t.equal('hello', Buffer.concat(bufs).toString('utf8')) + p.strictEqual('hello', Buffer.concat(bufs).toString('utf8')) + resolve1() }) }) client.request({ path: '/', method: 'GET', signal: abortController.signal }, (err, response) => { - t.type(err, errors.RequestAbortedError) + ttype(p, err, errors.RequestAbortedError) + resolve2() }) abortController.abort() }) + + await Promise.all([promise1, promise2]) }) - test(`Abort ${controllerName} while waiting response (no body)`, (t) => { - t.plan(1) + test(`Abort ${controllerName} while waiting response (no body)`, async (t) => { + const p = tspl(t, { plan: 1 }) const abortController = new AbortControllerImpl() const server = createServer((req, res) => { @@ -86,20 +169,25 @@ for (const { AbortControllerImpl, controllerName } of controllers) { res.setHeader('content-type', 'text/plain') res.end('hello world') }) - t.teardown(server.close.bind(server)) + t.after(server.close.bind(server)) + + const { promise, resolve } = promiseWithResolvers() server.listen(0, () => { const client = new Client(`http://localhost:${server.address().port}`) - t.teardown(client.destroy.bind(client)) + t.after(client.destroy.bind(client)) client.request({ path: '/', method: 'GET', signal: abortController.signal }, (err, response) => { - t.type(err, errors.RequestAbortedError) + ttype(p, err, errors.RequestAbortedError) + resolve() }) }) + + await promise }) - test(`Abort ${controllerName} while waiting response (write headers started) (no body)`, (t) => { - t.plan(1) + test(`Abort ${controllerName} while waiting response (write headers started) (no body)`, async (t) => { + const p = tspl(t, { plan: 1 }) const abortController = new AbortControllerImpl() const server = createServer((req, res) => { @@ -108,47 +196,57 @@ for (const { AbortControllerImpl, controllerName } of controllers) { abortController.abort() res.end('hello world') }) - t.teardown(server.close.bind(server)) + t.after(server.close.bind(server)) + + const { promise, resolve } = promiseWithResolvers() server.listen(0, () => { const client = new Client(`http://localhost:${server.address().port}`) - t.teardown(client.destroy.bind(client)) + t.after(client.destroy.bind(client)) client.request({ path: '/', method: 'GET', signal: abortController.signal }, (err, response) => { - t.type(err, errors.RequestAbortedError) + ttype(p, err, errors.RequestAbortedError) + resolve() }) }) + + await promise }) - test(`Abort ${controllerName} while waiting response (write headers and write body started) (no body)`, (t) => { - t.plan(2) + test(`Abort ${controllerName} while waiting response (write headers and write body started) (no body)`, async (t) => { + const p = tspl(t, { plan: 2 }) const abortController = new AbortControllerImpl() const server = createServer((req, res) => { res.writeHead(200, { 'content-type': 'text/plain' }) res.write('hello') }) - t.teardown(server.close.bind(server)) + t.after(server.close.bind(server)) + + const { promise, resolve } = promiseWithResolvers() server.listen(0, () => { const client = new Client(`http://localhost:${server.address().port}`) - t.teardown(client.destroy.bind(client)) + t.after(client.destroy.bind(client)) client.request({ path: '/', method: 'GET', signal: abortController.signal }, (err, response) => { - t.error(err) + p.ifError(err) response.body.on('data', () => { abortController.abort() }) response.body.on('error', err => { - t.type(err, errors.RequestAbortedError) + ttype(p, err, errors.RequestAbortedError) + resolve() }) }) }) + + await promise }) function waitingWithBody (body, type) { // eslint-disable-line - test(`Abort ${controllerName} while waiting response (with body ${type})`, (t) => { - t.plan(1) + test(`Abort ${controllerName} while waiting response (with body ${type})`, async (t) => { + const p = tspl(t, { plan: 1 }) const abortController = new AbortControllerImpl() const server = createServer((req, res) => { @@ -156,16 +254,20 @@ for (const { AbortControllerImpl, controllerName } of controllers) { res.setHeader('content-type', 'text/plain') res.end('hello world') }) - t.teardown(server.close.bind(server)) + t.after(server.close.bind(server)) + const { promise, resolve } = promiseWithResolvers() server.listen(0, () => { const client = new Client(`http://localhost:${server.address().port}`) - t.teardown(client.destroy.bind(client)) + t.after(client.destroy.bind(client)) client.request({ path: '/', method: 'POST', body, signal: abortController.signal }, (err, response) => { - t.type(err, errors.RequestAbortedError) + ttype(p, err, errors.RequestAbortedError) + resolve() }) }) + + await promise }) } @@ -175,8 +277,8 @@ for (const { AbortControllerImpl, controllerName } of controllers) { waitingWithBody(wrapWithAsyncIterable(createReadStream(__filename)), 'async-iterator') function writeHeadersStartedWithBody (body, type) { // eslint-disable-line - test(`Abort ${controllerName} while waiting response (write headers started) (with body ${type})`, (t) => { - t.plan(1) + test(`Abort ${controllerName} while waiting response (write headers started) (with body ${type})`, async (t) => { + const p = tspl(t, { plan: 1 }) const abortController = new AbortControllerImpl() const server = createServer((req, res) => { @@ -185,16 +287,19 @@ for (const { AbortControllerImpl, controllerName } of controllers) { abortController.abort() res.end('hello world') }) - t.teardown(server.close.bind(server)) + t.after(server.close.bind(server)) + const { promise, resolve } = promiseWithResolvers() server.listen(0, () => { const client = new Client(`http://localhost:${server.address().port}`) - t.teardown(client.destroy.bind(client)) + t.after(client.destroy.bind(client)) client.request({ path: '/', method: 'POST', body, signal: abortController.signal }, (err, response) => { - t.type(err, errors.RequestAbortedError) + ttype(p, err, errors.RequestAbortedError) + resolve() }) }) + await promise }) } @@ -204,30 +309,33 @@ for (const { AbortControllerImpl, controllerName } of controllers) { writeHeadersStartedWithBody(wrapWithAsyncIterable(createReadStream(__filename)), 'async-iterator') function writeBodyStartedWithBody (body, type) { // eslint-disable-line - test(`Abort ${controllerName} while waiting response (write headers and write body started) (with body ${type})`, (t) => { - t.plan(2) + test(`Abort ${controllerName} while waiting response (write headers and write body started) (with body ${type})`, async (t) => { + const p = tspl(t, { plan: 2 }) const abortController = new AbortControllerImpl() const server = createServer((req, res) => { res.writeHead(200, { 'content-type': 'text/plain' }) res.write('hello') }) - t.teardown(server.close.bind(server)) + t.after(server.close.bind(server)) + const { promise, resolve } = promiseWithResolvers() server.listen(0, () => { const client = new Client(`http://localhost:${server.address().port}`) - t.teardown(client.destroy.bind(client)) + t.after(client.destroy.bind(client)) client.request({ path: '/', method: 'POST', body, signal: abortController.signal }, (err, response) => { - t.error(err) + p.ifError(err) response.body.on('data', () => { abortController.abort() }) response.body.on('error', err => { - t.type(err, errors.RequestAbortedError) + ttype(p, err, errors.RequestAbortedError) + resolve() }) }) }) + await promise }) } From db57315aa8e45714d3b3b9754bd408fa66229e0d Mon Sep 17 00:00:00 2001 From: Sosuke Suzuki Date: Sun, 31 Dec 2023 02:47:48 +0900 Subject: [PATCH 4/9] Update `test` script --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 4b5a8cf1538..7c1475f0e14 100644 --- a/package.json +++ b/package.json @@ -75,7 +75,7 @@ "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:wpt && npm run test:websocket && npm run test:jest && npm run test:typescript", + "test": "node scripts/generate-pem && npm run test:tap && npm run test:node-fetch && npm run test:fetch && npm run test:cookies && npm run test:wpt && npm run test:websocket && npm run test:jest && npm run test:typescript && npm run test:node-test", "test:cookies": "borp --coverage -p \"test/cookie/*.js\"", "test:node-fetch": "mocha --exit test/node-fetch", "test:fetch": "npm run build:node && tap --expose-gc test/fetch/*.js && borp --coverage -p \"test/webidl/*.js\"", From 7b7b865a4aa91f0d41ea4b80f7b274b343ef5337 Mon Sep 17 00:00:00 2001 From: Sosuke Suzuki Date: Sun, 31 Dec 2023 03:00:02 +0900 Subject: [PATCH 5/9] Move utils to `/test/utils` --- test/node-test/abort-controller.js | 72 +----------------------------- test/utils/node-test.js | 60 +++++++++++++++++++++++++ test/utils/promise.js | 16 +++++++ 3 files changed, 78 insertions(+), 70 deletions(-) create mode 100644 test/utils/node-test.js create mode 100644 test/utils/promise.js diff --git a/test/node-test/abort-controller.js b/test/node-test/abort-controller.js index bfc371a9a52..1f7171afe18 100644 --- a/test/node-test/abort-controller.js +++ b/test/node-test/abort-controller.js @@ -7,76 +7,8 @@ const { createServer } = require('http') const { createReadStream } = require('fs') const { wrapWithAsyncIterable } = require('../utils/async-iterators') const { tspl } = require('@matteo.collina/tspl') - -/** - * A port of tap's `t.type` that can be used with `node:assert` - * https://github.com/tapjs/tapjs/blob/511019b2ac0fa014370154c3a341a0e632f50b19/src/asserts/src/index.ts#L199 - */ -function ttype (plan, obj, klass) { - const name = - typeof klass === 'function' - ? klass.name || '(anonymous constructor)' - : klass - - if (obj === klass) { - return plan.ok(1) - } - - const tof = typeof obj - const type = - !obj && tof === 'object' - ? 'null' - // treat as object, but not Object - // t.type(() => {}, Function) - : tof === 'function' && - typeof klass === 'function' && - klass !== Object - ? 'object' - : tof - - if ( - (type === 'number' && klass === Number) || - (type === 'string' && klass === String) || - (type === 'bigint' && klass === BigInt) || - (klass === 'array' && Array.isArray(obj)) || - (type === 'symbol' && klass === Symbol) - ) { - return plan.ok(1) - } - - // simplest case, it literally is the same thing - if (type === 'object' && klass !== 'object') { - if (typeof klass === 'function') { - return plan.ok(obj instanceof klass) - } - - // check prototype chain for name - // at this point, we already know klass is not a function - // if the klass specified is an obj in the proto chain, pass - // if the name specified is the name of a ctor in the chain, pass - for (let p = obj; p; p = Object.getPrototypeOf(p)) { - const ctor = p.constructor && p.constructor.name - if (p === klass || ctor === name) { - return plan.ok(1) - } - } - } - - return plan.strictEqual(type, name) -} - -/** - * The helper function to create a promise with resolvers. - * Please see https://github.com/tc39/proposal-promise-with-resolvers for more details. - */ -function promiseWithResolvers () { - let _resolve, _reject - const promise = new Promise((resolve, reject) => { - _resolve = resolve - _reject = reject - }) - return { promise, resolve: _resolve, reject: _reject } -} +const { promiseWithResolvers } = require('../utils/promise') +const { ttype } = require('../utils/node-test') const controllers = [{ AbortControllerImpl: NPMAbortController, diff --git a/test/utils/node-test.js b/test/utils/node-test.js new file mode 100644 index 00000000000..549fab32369 --- /dev/null +++ b/test/utils/node-test.js @@ -0,0 +1,60 @@ +/** + * A port of tap's `t.type` that can be used with `node:assert` + * https://github.com/tapjs/tapjs/blob/511019b2ac0fa014370154c3a341a0e632f50b19/src/asserts/src/index.ts#L199 + */ +function ttype (plan, obj, klass) { + const name = + typeof klass === 'function' + ? klass.name || '(anonymous constructor)' + : klass + + if (obj === klass) { + return plan.ok(1) + } + + const tof = typeof obj + const type = + !obj && tof === 'object' + ? 'null' + // treat as object, but not Object + // t.type(() => {}, Function) + : tof === 'function' && + typeof klass === 'function' && + klass !== Object + ? 'object' + : tof + + if ( + (type === 'number' && klass === Number) || + (type === 'string' && klass === String) || + (type === 'bigint' && klass === BigInt) || + (klass === 'array' && Array.isArray(obj)) || + (type === 'symbol' && klass === Symbol) + ) { + return plan.ok(1) + } + + // simplest case, it literally is the same thing + if (type === 'object' && klass !== 'object') { + if (typeof klass === 'function') { + return plan.ok(obj instanceof klass) + } + + // check prototype chain for name + // at this point, we already know klass is not a function + // if the klass specified is an obj in the proto chain, pass + // if the name specified is the name of a ctor in the chain, pass + for (let p = obj; p; p = Object.getPrototypeOf(p)) { + const ctor = p.constructor && p.constructor.name + if (p === klass || ctor === name) { + return plan.ok(1) + } + } + } + + return plan.strictEqual(type, name) +} + +module.exports = { + ttype +} diff --git a/test/utils/promise.js b/test/utils/promise.js new file mode 100644 index 00000000000..5e16a803630 --- /dev/null +++ b/test/utils/promise.js @@ -0,0 +1,16 @@ +/** + * The helper function to create a promise with resolvers. + * Please see https://github.com/tc39/proposal-promise-with-resolvers for more details. + */ +function promiseWithResolvers () { + let _resolve, _reject + const promise = new Promise((resolve, reject) => { + _resolve = resolve + _reject = reject + }) + return { promise, resolve: _resolve, reject: _reject } +} + +module.exports = { + promiseWithResolvers +} From 17163248740469b11c2880c3b1dcf6d89a1fea84 Mon Sep 17 00:00:00 2001 From: Sosuke Suzuki Date: Sun, 31 Dec 2023 06:38:11 +0900 Subject: [PATCH 6/9] Use `p.completed` --- test/node-test/abort-controller.js | 41 ++++++------------------------ test/utils/promise.js | 16 ------------ 2 files changed, 8 insertions(+), 49 deletions(-) delete mode 100644 test/utils/promise.js diff --git a/test/node-test/abort-controller.js b/test/node-test/abort-controller.js index 1f7171afe18..f43f14321d5 100644 --- a/test/node-test/abort-controller.js +++ b/test/node-test/abort-controller.js @@ -7,7 +7,6 @@ const { createServer } = require('http') const { createReadStream } = require('fs') const { wrapWithAsyncIterable } = require('../utils/async-iterators') const { tspl } = require('@matteo.collina/tspl') -const { promiseWithResolvers } = require('../utils/promise') const { ttype } = require('../utils/node-test') const controllers = [{ @@ -30,8 +29,6 @@ for (const { AbortControllerImpl, controllerName } of controllers) { }) t.after(server.close.bind(server)) - const { promise, resolve } = promiseWithResolvers() - server.listen(0, () => { const client = new Client(`http://localhost:${server.address().port}`) const abortController = new AbortControllerImpl() @@ -41,11 +38,10 @@ for (const { AbortControllerImpl, controllerName } of controllers) { client.request({ path: '/', method: 'GET', signal: abortController.signal }, (err, response) => { ttype(p, err, errors.RequestAbortedError) - resolve() }) }) - await promise + await p.completed }) test(`Abort ${controllerName} before sending request (no body)`, async (t) => { @@ -61,9 +57,6 @@ for (const { AbortControllerImpl, controllerName } of controllers) { }) t.after(server.close.bind(server)) - const { promise: promise1, resolve: resolve1 } = promiseWithResolvers() - const { promise: promise2, resolve: resolve2 } = promiseWithResolvers() - server.listen(0, () => { const client = new Client(`http://localhost:${server.address().port}`) const abortController = new AbortControllerImpl() @@ -77,19 +70,17 @@ for (const { AbortControllerImpl, controllerName } of controllers) { }) response.body.on('end', () => { p.strictEqual('hello', Buffer.concat(bufs).toString('utf8')) - resolve1() }) }) client.request({ path: '/', method: 'GET', signal: abortController.signal }, (err, response) => { ttype(p, err, errors.RequestAbortedError) - resolve2() }) abortController.abort() }) - await Promise.all([promise1, promise2]) + await p.completed }) test(`Abort ${controllerName} while waiting response (no body)`, async (t) => { @@ -103,19 +94,16 @@ for (const { AbortControllerImpl, controllerName } of controllers) { }) t.after(server.close.bind(server)) - const { promise, resolve } = promiseWithResolvers() - server.listen(0, () => { const client = new Client(`http://localhost:${server.address().port}`) t.after(client.destroy.bind(client)) client.request({ path: '/', method: 'GET', signal: abortController.signal }, (err, response) => { ttype(p, err, errors.RequestAbortedError) - resolve() }) }) - await promise + await p.completed }) test(`Abort ${controllerName} while waiting response (write headers started) (no body)`, async (t) => { @@ -130,19 +118,16 @@ for (const { AbortControllerImpl, controllerName } of controllers) { }) t.after(server.close.bind(server)) - const { promise, resolve } = promiseWithResolvers() - server.listen(0, () => { const client = new Client(`http://localhost:${server.address().port}`) t.after(client.destroy.bind(client)) client.request({ path: '/', method: 'GET', signal: abortController.signal }, (err, response) => { ttype(p, err, errors.RequestAbortedError) - resolve() }) }) - await promise + await p.completed }) test(`Abort ${controllerName} while waiting response (write headers and write body started) (no body)`, async (t) => { @@ -155,8 +140,6 @@ for (const { AbortControllerImpl, controllerName } of controllers) { }) t.after(server.close.bind(server)) - const { promise, resolve } = promiseWithResolvers() - server.listen(0, () => { const client = new Client(`http://localhost:${server.address().port}`) t.after(client.destroy.bind(client)) @@ -168,12 +151,11 @@ for (const { AbortControllerImpl, controllerName } of controllers) { }) response.body.on('error', err => { ttype(p, err, errors.RequestAbortedError) - resolve() }) }) }) - await promise + await p.completed }) function waitingWithBody (body, type) { // eslint-disable-line @@ -188,18 +170,15 @@ for (const { AbortControllerImpl, controllerName } of controllers) { }) t.after(server.close.bind(server)) - const { promise, resolve } = promiseWithResolvers() server.listen(0, () => { const client = new Client(`http://localhost:${server.address().port}`) t.after(client.destroy.bind(client)) client.request({ path: '/', method: 'POST', body, signal: abortController.signal }, (err, response) => { ttype(p, err, errors.RequestAbortedError) - resolve() }) }) - - await promise + await p.completed }) } @@ -221,17 +200,15 @@ for (const { AbortControllerImpl, controllerName } of controllers) { }) t.after(server.close.bind(server)) - const { promise, resolve } = promiseWithResolvers() server.listen(0, () => { const client = new Client(`http://localhost:${server.address().port}`) t.after(client.destroy.bind(client)) client.request({ path: '/', method: 'POST', body, signal: abortController.signal }, (err, response) => { ttype(p, err, errors.RequestAbortedError) - resolve() }) }) - await promise + await p.completed }) } @@ -251,7 +228,6 @@ for (const { AbortControllerImpl, controllerName } of controllers) { }) t.after(server.close.bind(server)) - const { promise, resolve } = promiseWithResolvers() server.listen(0, () => { const client = new Client(`http://localhost:${server.address().port}`) t.after(client.destroy.bind(client)) @@ -263,11 +239,10 @@ for (const { AbortControllerImpl, controllerName } of controllers) { }) response.body.on('error', err => { ttype(p, err, errors.RequestAbortedError) - resolve() }) }) }) - await promise + await p.completed }) } diff --git a/test/utils/promise.js b/test/utils/promise.js deleted file mode 100644 index 5e16a803630..00000000000 --- a/test/utils/promise.js +++ /dev/null @@ -1,16 +0,0 @@ -/** - * The helper function to create a promise with resolvers. - * Please see https://github.com/tc39/proposal-promise-with-resolvers for more details. - */ -function promiseWithResolvers () { - let _resolve, _reject - const promise = new Promise((resolve, reject) => { - _resolve = resolve - _reject = reject - }) - return { promise, resolve: _resolve, reject: _reject } -} - -module.exports = { - promiseWithResolvers -} From a874a48881c518f3d59b51a626603a445485a0e1 Mon Sep 17 00:00:00 2001 From: Sosuke Suzuki Date: Sun, 31 Dec 2023 19:32:34 +0900 Subject: [PATCH 7/9] Make `ttype` return `boolean` --- test/node-test/abort-controller.js | 16 ++++++++-------- test/utils/node-test.js | 12 ++++++------ 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/test/node-test/abort-controller.js b/test/node-test/abort-controller.js index f43f14321d5..fceb6bc272d 100644 --- a/test/node-test/abort-controller.js +++ b/test/node-test/abort-controller.js @@ -37,7 +37,7 @@ for (const { AbortControllerImpl, controllerName } of controllers) { abortController.abort() client.request({ path: '/', method: 'GET', signal: abortController.signal }, (err, response) => { - ttype(p, err, errors.RequestAbortedError) + p.ok(ttype(err, errors.RequestAbortedError)) }) }) @@ -74,7 +74,7 @@ for (const { AbortControllerImpl, controllerName } of controllers) { }) client.request({ path: '/', method: 'GET', signal: abortController.signal }, (err, response) => { - ttype(p, err, errors.RequestAbortedError) + p.ok(ttype(err, errors.RequestAbortedError)) }) abortController.abort() @@ -99,7 +99,7 @@ for (const { AbortControllerImpl, controllerName } of controllers) { t.after(client.destroy.bind(client)) client.request({ path: '/', method: 'GET', signal: abortController.signal }, (err, response) => { - ttype(p, err, errors.RequestAbortedError) + p.ok(ttype(err, errors.RequestAbortedError)) }) }) @@ -123,7 +123,7 @@ for (const { AbortControllerImpl, controllerName } of controllers) { t.after(client.destroy.bind(client)) client.request({ path: '/', method: 'GET', signal: abortController.signal }, (err, response) => { - ttype(p, err, errors.RequestAbortedError) + p.ok(ttype(err, errors.RequestAbortedError)) }) }) @@ -150,7 +150,7 @@ for (const { AbortControllerImpl, controllerName } of controllers) { abortController.abort() }) response.body.on('error', err => { - ttype(p, err, errors.RequestAbortedError) + p.ok(ttype(err, errors.RequestAbortedError)) }) }) }) @@ -175,7 +175,7 @@ for (const { AbortControllerImpl, controllerName } of controllers) { t.after(client.destroy.bind(client)) client.request({ path: '/', method: 'POST', body, signal: abortController.signal }, (err, response) => { - ttype(p, err, errors.RequestAbortedError) + p.ok(ttype(err, errors.RequestAbortedError)) }) }) await p.completed @@ -205,7 +205,7 @@ for (const { AbortControllerImpl, controllerName } of controllers) { t.after(client.destroy.bind(client)) client.request({ path: '/', method: 'POST', body, signal: abortController.signal }, (err, response) => { - ttype(p, err, errors.RequestAbortedError) + p.ok(ttype(err, errors.RequestAbortedError)) }) }) await p.completed @@ -238,7 +238,7 @@ for (const { AbortControllerImpl, controllerName } of controllers) { abortController.abort() }) response.body.on('error', err => { - ttype(p, err, errors.RequestAbortedError) + p.ok(ttype(err, errors.RequestAbortedError)) }) }) }) diff --git a/test/utils/node-test.js b/test/utils/node-test.js index 549fab32369..250fd0b19c2 100644 --- a/test/utils/node-test.js +++ b/test/utils/node-test.js @@ -2,14 +2,14 @@ * A port of tap's `t.type` that can be used with `node:assert` * https://github.com/tapjs/tapjs/blob/511019b2ac0fa014370154c3a341a0e632f50b19/src/asserts/src/index.ts#L199 */ -function ttype (plan, obj, klass) { +function ttype (obj, klass) { const name = typeof klass === 'function' ? klass.name || '(anonymous constructor)' : klass if (obj === klass) { - return plan.ok(1) + return true } const tof = typeof obj @@ -31,13 +31,13 @@ function ttype (plan, obj, klass) { (klass === 'array' && Array.isArray(obj)) || (type === 'symbol' && klass === Symbol) ) { - return plan.ok(1) + return true } // simplest case, it literally is the same thing if (type === 'object' && klass !== 'object') { if (typeof klass === 'function') { - return plan.ok(obj instanceof klass) + return obj instanceof klass } // check prototype chain for name @@ -47,12 +47,12 @@ function ttype (plan, obj, klass) { for (let p = obj; p; p = Object.getPrototypeOf(p)) { const ctor = p.constructor && p.constructor.name if (p === klass || ctor === name) { - return plan.ok(1) + return true } } } - return plan.strictEqual(type, name) + return type === name } module.exports = { From 88d2c96c101ae83455a94752b93f5eabd59aeaaa Mon Sep 17 00:00:00 2001 From: Sosuke Suzuki Date: Mon, 1 Jan 2024 12:15:31 +0900 Subject: [PATCH 8/9] Add LICENSE comment for `t.type` --- test/utils/node-test.js | 58 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) diff --git a/test/utils/node-test.js b/test/utils/node-test.js index 250fd0b19c2..958db2e96ea 100644 --- a/test/utils/node-test.js +++ b/test/utils/node-test.js @@ -1,6 +1,64 @@ /** * A port of tap's `t.type` that can be used with `node:assert` * https://github.com/tapjs/tapjs/blob/511019b2ac0fa014370154c3a341a0e632f50b19/src/asserts/src/index.ts#L199 + * + * LICENSE(https://github.com/tapjs/tapjs/blob/511019b2ac0fa014370154c3a341a0e632f50b19/src/asserts/LICENSE.md): + +# Blue Oak Model License + +Version 1.0.0 + +## Purpose + +This license gives everyone as much permission to work with +this software as possible, while protecting contributors +from liability. + +## Acceptance + +In order to receive this license, you must agree to its +rules. The rules of this license are both obligations +under that agreement and conditions to your license. +You must not do anything with this software that triggers +a rule that you cannot or will not follow. + +## Copyright + +Each contributor licenses you to do everything with this +software that would otherwise infringe that contributor's +copyright in it. + +## Notices + +You must ensure that everyone who gets a copy of +any part of this software from you, with or without +changes, also gets the text of this license or a link to +. + +## Excuse + +If anyone notifies you in writing that you have not +complied with [Notices](#notices), you can keep your +license by taking all practical steps to comply within 30 +days after the notice. If you do not do so, your license +ends immediately. + +## Patent + +Each contributor licenses you to do everything with this +software that would otherwise infringe any patent claims +they can license or become able to license. + +## Reliability + +No contributor can revoke this license. + +## No Liability + +***As far as the law allows, this software comes as is, +without any warranty or condition, and no contributor +will be liable to anyone for any damages related to this +software or this license, under any kind of legal claim.*** */ function ttype (obj, klass) { const name = From bc062c1c762dfdca51bffb9fca33ee404432573d Mon Sep 17 00:00:00 2001 From: Sosuke Suzuki Date: Tue, 2 Jan 2024 19:21:38 +0900 Subject: [PATCH 9/9] Remove `ttype` --- test/node-test/abort-controller.js | 17 ++--- test/utils/node-test.js | 118 ----------------------------- 2 files changed, 8 insertions(+), 127 deletions(-) delete mode 100644 test/utils/node-test.js diff --git a/test/node-test/abort-controller.js b/test/node-test/abort-controller.js index fceb6bc272d..d4d9a588df6 100644 --- a/test/node-test/abort-controller.js +++ b/test/node-test/abort-controller.js @@ -7,7 +7,6 @@ const { createServer } = require('http') const { createReadStream } = require('fs') const { wrapWithAsyncIterable } = require('../utils/async-iterators') const { tspl } = require('@matteo.collina/tspl') -const { ttype } = require('../utils/node-test') const controllers = [{ AbortControllerImpl: NPMAbortController, @@ -37,7 +36,7 @@ for (const { AbortControllerImpl, controllerName } of controllers) { abortController.abort() client.request({ path: '/', method: 'GET', signal: abortController.signal }, (err, response) => { - p.ok(ttype(err, errors.RequestAbortedError)) + p.ok(err instanceof errors.RequestAbortedError) }) }) @@ -74,7 +73,7 @@ for (const { AbortControllerImpl, controllerName } of controllers) { }) client.request({ path: '/', method: 'GET', signal: abortController.signal }, (err, response) => { - p.ok(ttype(err, errors.RequestAbortedError)) + p.ok(err instanceof errors.RequestAbortedError) }) abortController.abort() @@ -99,7 +98,7 @@ for (const { AbortControllerImpl, controllerName } of controllers) { t.after(client.destroy.bind(client)) client.request({ path: '/', method: 'GET', signal: abortController.signal }, (err, response) => { - p.ok(ttype(err, errors.RequestAbortedError)) + p.ok(err instanceof errors.RequestAbortedError) }) }) @@ -123,7 +122,7 @@ for (const { AbortControllerImpl, controllerName } of controllers) { t.after(client.destroy.bind(client)) client.request({ path: '/', method: 'GET', signal: abortController.signal }, (err, response) => { - p.ok(ttype(err, errors.RequestAbortedError)) + p.ok(err instanceof errors.RequestAbortedError) }) }) @@ -150,7 +149,7 @@ for (const { AbortControllerImpl, controllerName } of controllers) { abortController.abort() }) response.body.on('error', err => { - p.ok(ttype(err, errors.RequestAbortedError)) + p.ok(err instanceof errors.RequestAbortedError) }) }) }) @@ -175,7 +174,7 @@ for (const { AbortControllerImpl, controllerName } of controllers) { t.after(client.destroy.bind(client)) client.request({ path: '/', method: 'POST', body, signal: abortController.signal }, (err, response) => { - p.ok(ttype(err, errors.RequestAbortedError)) + p.ok(err instanceof errors.RequestAbortedError) }) }) await p.completed @@ -205,7 +204,7 @@ for (const { AbortControllerImpl, controllerName } of controllers) { t.after(client.destroy.bind(client)) client.request({ path: '/', method: 'POST', body, signal: abortController.signal }, (err, response) => { - p.ok(ttype(err, errors.RequestAbortedError)) + p.ok(err instanceof errors.RequestAbortedError) }) }) await p.completed @@ -238,7 +237,7 @@ for (const { AbortControllerImpl, controllerName } of controllers) { abortController.abort() }) response.body.on('error', err => { - p.ok(ttype(err, errors.RequestAbortedError)) + p.ok(err instanceof errors.RequestAbortedError) }) }) }) diff --git a/test/utils/node-test.js b/test/utils/node-test.js deleted file mode 100644 index 958db2e96ea..00000000000 --- a/test/utils/node-test.js +++ /dev/null @@ -1,118 +0,0 @@ -/** - * A port of tap's `t.type` that can be used with `node:assert` - * https://github.com/tapjs/tapjs/blob/511019b2ac0fa014370154c3a341a0e632f50b19/src/asserts/src/index.ts#L199 - * - * LICENSE(https://github.com/tapjs/tapjs/blob/511019b2ac0fa014370154c3a341a0e632f50b19/src/asserts/LICENSE.md): - -# Blue Oak Model License - -Version 1.0.0 - -## Purpose - -This license gives everyone as much permission to work with -this software as possible, while protecting contributors -from liability. - -## Acceptance - -In order to receive this license, you must agree to its -rules. The rules of this license are both obligations -under that agreement and conditions to your license. -You must not do anything with this software that triggers -a rule that you cannot or will not follow. - -## Copyright - -Each contributor licenses you to do everything with this -software that would otherwise infringe that contributor's -copyright in it. - -## Notices - -You must ensure that everyone who gets a copy of -any part of this software from you, with or without -changes, also gets the text of this license or a link to -. - -## Excuse - -If anyone notifies you in writing that you have not -complied with [Notices](#notices), you can keep your -license by taking all practical steps to comply within 30 -days after the notice. If you do not do so, your license -ends immediately. - -## Patent - -Each contributor licenses you to do everything with this -software that would otherwise infringe any patent claims -they can license or become able to license. - -## Reliability - -No contributor can revoke this license. - -## No Liability - -***As far as the law allows, this software comes as is, -without any warranty or condition, and no contributor -will be liable to anyone for any damages related to this -software or this license, under any kind of legal claim.*** - */ -function ttype (obj, klass) { - const name = - typeof klass === 'function' - ? klass.name || '(anonymous constructor)' - : klass - - if (obj === klass) { - return true - } - - const tof = typeof obj - const type = - !obj && tof === 'object' - ? 'null' - // treat as object, but not Object - // t.type(() => {}, Function) - : tof === 'function' && - typeof klass === 'function' && - klass !== Object - ? 'object' - : tof - - if ( - (type === 'number' && klass === Number) || - (type === 'string' && klass === String) || - (type === 'bigint' && klass === BigInt) || - (klass === 'array' && Array.isArray(obj)) || - (type === 'symbol' && klass === Symbol) - ) { - return true - } - - // simplest case, it literally is the same thing - if (type === 'object' && klass !== 'object') { - if (typeof klass === 'function') { - return obj instanceof klass - } - - // check prototype chain for name - // at this point, we already know klass is not a function - // if the klass specified is an obj in the proto chain, pass - // if the name specified is the name of a ctor in the chain, pass - for (let p = obj; p; p = Object.getPrototypeOf(p)) { - const ctor = p.constructor && p.constructor.name - if (p === klass || ctor === name) { - return true - } - } - } - - return type === name -} - -module.exports = { - ttype -}