diff --git a/package.json b/package.json index c715e566dba..c2fb6d7ce7a 100644 --- a/package.json +++ b/package.json @@ -114,7 +114,6 @@ "@metcoder95/https-pem": "^1.0.0", "@sinonjs/fake-timers": "^12.0.0", "@types/node": "^22.0.0", - "abort-controller": "^3.0.0", "borp": "^0.20.0", "c8": "^10.0.0", "cross-env": "^10.0.0", diff --git a/test/node-test/abort-controller.js b/test/node-test/abort-controller.js index f8249c13039..7d95d6e67d8 100644 --- a/test/node-test/abort-controller.js +++ b/test/node-test/abort-controller.js @@ -1,7 +1,6 @@ 'use strict' const { test } = require('node:test') -const { AbortController: NPMAbortController } = require('abort-controller') const { Client, errors } = require('../..') const { createServer } = require('node:http') const { createReadStream } = require('node:fs') @@ -9,84 +8,148 @@ const { wrapWithAsyncIterable } = require('../utils/async-iterators') const { tspl } = require('@matteo.collina/tspl') const { closeServerAsPromise } = require('../utils/node-http') -const controllers = [{ - AbortControllerImpl: NPMAbortController, - controllerName: 'npm-abortcontroller-shim' -}] +test('Abort AbortController before creating request', async (t) => { + const p = tspl(t, { plan: 1 }) -if (global.AbortController) { - controllers.push({ - AbortControllerImpl: global.AbortController, - controllerName: 'native-abortcontroller' + const server = createServer({ joinDuplicateHeaders: true }, (req, res) => { + p.fail() }) -} -for (const { AbortControllerImpl, controllerName } of controllers) { - test(`Abort ${controllerName} before creating request`, async (t) => { - const p = tspl(t, { plan: 1 }) + t.after(closeServerAsPromise(server)) - const server = createServer({ joinDuplicateHeaders: true }, (req, res) => { - p.fail() + server.listen(0, () => { + const client = new Client(`http://localhost:${server.address().port}`) + const abortController = new AbortController() + t.after(client.destroy.bind(client)) + + abortController.abort() + + client.request({ path: '/', method: 'GET', signal: abortController.signal }, (err, response) => { + p.ok(err instanceof errors.RequestAbortedError || err instanceof DOMException) }) - t.after(closeServerAsPromise(server)) + }) - server.listen(0, () => { - const client = new Client(`http://localhost:${server.address().port}`) - const abortController = new AbortControllerImpl() - t.after(client.destroy.bind(client)) + await p.completed +}) - abortController.abort() +test('Abort AbortController before sending request (no body)', async (t) => { + const p = tspl(t, { plan: 3 }) - client.request({ path: '/', method: 'GET', signal: abortController.signal }, (err, response) => { - p.ok(err instanceof errors.RequestAbortedError || err instanceof DOMException) + let count = 0 + const server = createServer({ joinDuplicateHeaders: true }, (req, res) => { + if (count === 1) { + p.fail('The second request should never be executed') + } + count += 1 + res.end('hello') + }) + t.after(closeServerAsPromise(server)) + + server.listen(0, () => { + const client = new Client(`http://localhost:${server.address().port}`) + const abortController = new AbortController() + t.after(client.destroy.bind(client)) + + client.request({ path: '/', method: 'GET' }, (err, response) => { + p.ifError(err) + const bufs = [] + response.body.on('data', (buf) => { + bufs.push(buf) + }) + response.body.on('end', () => { + p.strictEqual('hello', Buffer.concat(bufs).toString('utf8')) }) }) - await p.completed + client.request({ path: '/', method: 'GET', signal: abortController.signal }, (err, response) => { + p.ok(err instanceof errors.RequestAbortedError || err instanceof DOMException) + }) + + abortController.abort() }) - test(`Abort ${controllerName} before sending request (no body)`, async (t) => { - const p = tspl(t, { plan: 3 }) + await p.completed +}) - let count = 0 - const server = createServer({ joinDuplicateHeaders: true }, (req, res) => { - if (count === 1) { - p.fail('The second request should never be executed') - } - count += 1 - res.end('hello') +test('Abort AbortController while waiting response (no body)', async (t) => { + const p = tspl(t, { plan: 1 }) + + const abortController = new AbortController() + const server = createServer({ joinDuplicateHeaders: true }, (req, res) => { + abortController.abort() + res.setHeader('content-type', 'text/plain') + res.end('hello world') + }) + t.after(closeServerAsPromise(server)) + + 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) => { + p.ok(err instanceof errors.RequestAbortedError || err instanceof DOMException) }) - t.after(closeServerAsPromise(server)) + }) - server.listen(0, () => { - const client = new Client(`http://localhost:${server.address().port}`) - const abortController = new AbortControllerImpl() - t.after(client.destroy.bind(client)) + await p.completed +}) - client.request({ path: '/', method: 'GET' }, (err, response) => { - p.ifError(err) - const bufs = [] - response.body.on('data', (buf) => { - bufs.push(buf) - }) - response.body.on('end', () => { - p.strictEqual('hello', Buffer.concat(bufs).toString('utf8')) - }) - }) +test('Abort AbortController while waiting response (write headers started) (no body)', async (t) => { + const p = tspl(t, { plan: 1 }) - client.request({ path: '/', method: 'GET', signal: abortController.signal }, (err, response) => { - p.ok(err instanceof errors.RequestAbortedError || err instanceof DOMException) - }) + const abortController = new AbortController() + const server = createServer({ joinDuplicateHeaders: true }, (req, res) => { + res.writeHead(200, { 'content-type': 'text/plain' }) + res.flushHeaders() + abortController.abort() + res.end('hello world') + }) + t.after(closeServerAsPromise(server)) - abortController.abort() + 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) => { + p.ok(err instanceof errors.RequestAbortedError || err instanceof DOMException) }) + }) - await p.completed + await p.completed +}) + +test('Abort AbortController while waiting response (write headers and write body started) (no body)', async (t) => { + const p = tspl(t, { plan: 2 }) + + const abortController = new AbortController() + const server = createServer({ joinDuplicateHeaders: true }, (req, res) => { + res.writeHead(200, { 'content-type': 'text/plain' }) + res.write('hello') + }) + t.after(closeServerAsPromise(server)) + + 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) => { + p.ifError(err) + response.body.on('data', () => { + abortController.abort() + }) + response.body.on('error', err => { + p.ok(err instanceof errors.RequestAbortedError || err instanceof DOMException) + }) + }) }) - test(`Abort ${controllerName} while waiting response (no body)`, async (t) => { + await p.completed +}) + +function waitingWithBody (body, type) { + test(`Abort AbortController while waiting response (with body ${type})`, async (t) => { const p = tspl(t, { plan: 1 }) - const abortController = new AbortControllerImpl() + const abortController = new AbortController() const server = createServer({ joinDuplicateHeaders: true }, (req, res) => { abortController.abort() res.setHeader('content-type', 'text/plain') @@ -98,18 +161,24 @@ for (const { AbortControllerImpl, controllerName } of controllers) { 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) => { + client.request({ path: '/', method: 'POST', body, signal: abortController.signal }, (err, response) => { p.ok(err instanceof errors.RequestAbortedError || err instanceof DOMException) }) }) - await p.completed }) +} + +waitingWithBody('hello', 'string') +waitingWithBody(createReadStream(__filename), 'stream') +waitingWithBody(new Uint8Array([42]), 'Uint8Array') +waitingWithBody(wrapWithAsyncIterable(createReadStream(__filename)), 'async-iterator') - test(`Abort ${controllerName} while waiting response (write headers started) (no body)`, async (t) => { +function writeHeadersStartedWithBody (body, type) { + test(`Abort AbortController while waiting response (write headers started) (with body ${type})`, async (t) => { const p = tspl(t, { plan: 1 }) - const abortController = new AbortControllerImpl() + const abortController = new AbortController() const server = createServer({ joinDuplicateHeaders: true }, (req, res) => { res.writeHead(200, { 'content-type': 'text/plain' }) res.flushHeaders() @@ -122,18 +191,24 @@ for (const { AbortControllerImpl, controllerName } of controllers) { 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) => { + client.request({ path: '/', method: 'POST', body, signal: abortController.signal }, (err, response) => { p.ok(err instanceof errors.RequestAbortedError || err instanceof DOMException) }) }) - await p.completed }) +} - test(`Abort ${controllerName} while waiting response (write headers and write body started) (no body)`, async (t) => { +writeHeadersStartedWithBody('hello', 'string') +writeHeadersStartedWithBody(createReadStream(__filename), 'stream') +writeHeadersStartedWithBody(new Uint8Array([42]), 'Uint8Array') +writeHeadersStartedWithBody(wrapWithAsyncIterable(createReadStream(__filename)), 'async-iterator') + +function writeBodyStartedWithBody (body, type) { + test(`Abort AbortController 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 abortController = new AbortController() const server = createServer({ joinDuplicateHeaders: true }, (req, res) => { res.writeHead(200, { 'content-type': 'text/plain' }) res.write('hello') @@ -144,7 +219,7 @@ for (const { AbortControllerImpl, controllerName } of controllers) { 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) => { + client.request({ path: '/', method: 'POST', body, signal: abortController.signal }, (err, response) => { p.ifError(err) response.body.on('data', () => { abortController.abort() @@ -154,100 +229,11 @@ for (const { AbortControllerImpl, controllerName } of controllers) { }) }) }) - await p.completed }) - - function waitingWithBody (body, type) { - test(`Abort ${controllerName} while waiting response (with body ${type})`, async (t) => { - const p = tspl(t, { plan: 1 }) - - const abortController = new AbortControllerImpl() - const server = createServer({ joinDuplicateHeaders: true }, (req, res) => { - abortController.abort() - res.setHeader('content-type', 'text/plain') - res.end('hello world') - }) - t.after(closeServerAsPromise(server)) - - 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) => { - p.ok(err instanceof errors.RequestAbortedError || err instanceof DOMException) - }) - }) - await p.completed - }) - } - - waitingWithBody('hello', 'string') - waitingWithBody(createReadStream(__filename), 'stream') - waitingWithBody(new Uint8Array([42]), 'Uint8Array') - waitingWithBody(wrapWithAsyncIterable(createReadStream(__filename)), 'async-iterator') - - function writeHeadersStartedWithBody (body, type) { - 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({ joinDuplicateHeaders: true }, (req, res) => { - res.writeHead(200, { 'content-type': 'text/plain' }) - res.flushHeaders() - abortController.abort() - res.end('hello world') - }) - t.after(closeServerAsPromise(server)) - - 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) => { - p.ok(err instanceof errors.RequestAbortedError || err instanceof DOMException) - }) - }) - await p.completed - }) - } - - writeHeadersStartedWithBody('hello', 'string') - writeHeadersStartedWithBody(createReadStream(__filename), 'stream') - writeHeadersStartedWithBody(new Uint8Array([42]), 'Uint8Array') - writeHeadersStartedWithBody(wrapWithAsyncIterable(createReadStream(__filename)), 'async-iterator') - - function writeBodyStartedWithBody (body, type) { - 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({ joinDuplicateHeaders: true }, (req, res) => { - res.writeHead(200, { 'content-type': 'text/plain' }) - res.write('hello') - }) - t.after(closeServerAsPromise(server)) - - 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) => { - p.ifError(err) - response.body.on('data', () => { - abortController.abort() - }) - response.body.on('error', err => { - p.ok(err instanceof errors.RequestAbortedError || err instanceof DOMException) - }) - }) - }) - await p.completed - }) - } - - writeBodyStartedWithBody('hello', 'string') - writeBodyStartedWithBody(createReadStream(__filename), 'stream') - writeBodyStartedWithBody(new Uint8Array([42]), 'Uint8Array') - writeBodyStartedWithBody(wrapWithAsyncIterable(createReadStream(__filename), 'async-iterator')) } + +writeBodyStartedWithBody('hello', 'string') +writeBodyStartedWithBody(createReadStream(__filename), 'stream') +writeBodyStartedWithBody(new Uint8Array([42]), 'Uint8Array') +writeBodyStartedWithBody(wrapWithAsyncIterable(createReadStream(__filename), 'async-iterator')) diff --git a/test/request-timeout.js b/test/request-timeout.js index d56d2a9c14a..f98fd088cc4 100644 --- a/test/request-timeout.js +++ b/test/request-timeout.js @@ -9,7 +9,6 @@ const { kConnect } = require('../lib/core/symbols') const { createServer } = require('node:http') const EventEmitter = require('node:events') const FakeTimers = require('@sinonjs/fake-timers') -const { AbortController } = require('abort-controller') const { pipeline, Readable, @@ -210,7 +209,7 @@ test('With EE signal', async (t) => { await t.completed }) -test('With abort-controller signal', async (t) => { +test('With AbortController signal', async (t) => { t = tspl(t, { plan: 1 }) const clock = FakeTimers.install({ @@ -282,7 +281,7 @@ test('Abort before timeout (EE)', async (t) => { await t.completed }) -test('Abort before timeout (abort-controller)', async (t) => { +test('Abort before timeout (AbortController)', async (t) => { t = tspl(t, { plan: 1 }) const clock = FakeTimers.install({ @@ -309,7 +308,7 @@ test('Abort before timeout (abort-controller)', async (t) => { after(() => client.destroy()) client.request({ path: '/', method: 'GET', signal: abortController.signal }, (err, response) => { - t.ok(err instanceof errors.RequestAbortedError) + t.ok(err instanceof DOMException) clock.tick(100) fastTimersTick(100) })