Skip to content
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
93 changes: 64 additions & 29 deletions test/parallel/test-aborted-util.js
Original file line number Diff line number Diff line change
@@ -1,59 +1,94 @@
// Flags: --expose-gc
'use strict';

const common = require('../common');
require('../common');
const { aborted } = require('util');
const assert = require('assert');
const {
match,
rejects,
strictEqual,
} = require('assert');
const { getEventListeners } = require('events');
const { spawn } = require('child_process');
const { inspect } = require('util');

{
// Test aborted works when provided a resource
const {
test,
} = require('node:test');

test('Aborted works when provided a resource', async () => {
const ac = new AbortController();
aborted(ac.signal, {}).then(common.mustCall());
const promise = aborted(ac.signal, {});
ac.abort();
assert.strictEqual(ac.signal.aborted, true);
assert.strictEqual(getEventListeners(ac.signal, 'abort').length, 0);
}
await promise;
strictEqual(ac.signal.aborted, true);
strictEqual(getEventListeners(ac.signal, 'abort').length, 0);
});

{
test('Aborted with gc cleanup', async () => {
// Test aborted with gc cleanup
const ac = new AbortController();
aborted(ac.signal, {}).then(common.mustNotCall());

const abortedPromise = aborted(ac.signal, {});
const { promise, resolve } = Promise.withResolvers();

setImmediate(() => {
global.gc();
ac.abort();
assert.strictEqual(ac.signal.aborted, true);
assert.strictEqual(getEventListeners(ac.signal, 'abort').length, 0);
strictEqual(ac.signal.aborted, true);
strictEqual(getEventListeners(ac.signal, 'abort').length, 0);
resolve();
});
}

{
// Fails with error if not provided abort signal
Promise.all([{}, null, undefined, Symbol(), [], 1, 0, 1n, true, false, 'a', () => {}].map((sig) =>
assert.rejects(aborted(sig, {}), {
await promise;

// Ensure that the promise is still pending
match(inspect(abortedPromise), /<pending>/);
});

test('Fails with error if not provided AbortSignal', async () => {
await Promise.all([{}, null, undefined, Symbol(), [], 1, 0, 1n, true, false, 'a', () => {}].map((sig) =>
rejects(aborted(sig, {}), {
code: 'ERR_INVALID_ARG_TYPE',
})
)).then(common.mustCall());
}
));
});

{
test('Fails if not provided a resource', async () => {
// Fails if not provided a resource
const ac = new AbortController();
Promise.all([null, undefined, 0, 1, 0n, 1n, Symbol(), '', 'a'].map((resource) =>
assert.rejects(aborted(ac.signal, resource), {
await Promise.all([null, undefined, 0, 1, 0n, 1n, Symbol(), '', 'a'].map((resource) =>
rejects(aborted(ac.signal, resource), {
code: 'ERR_INVALID_ARG_TYPE',
})
)).then(common.mustCall());
));
});

// To allow this case to be more flexibly tested on runtimes that do not have
// child_process.spawn, we lazily require it and skip the test if it is not
// present.

let spawn;
function lazySpawn() {
if (spawn === undefined) {
try {
spawn = require('child_process').spawn;
} catch {
// Ignore if spawn does not exist.
}
}
return spawn;
}

{
test('Does not hang forever', { skip: !lazySpawn() }, async () => {
const { promise, resolve } = Promise.withResolvers();
const childProcess = spawn(process.execPath, ['--input-type=module']);
childProcess.on('exit', common.mustCall((code) => {
assert.strictEqual(code, 13);
}));
childProcess.on('exit', (code) => {
strictEqual(code, 13);
resolve();
});
childProcess.stdin.end(`
import { aborted } from 'node:util';
await aborted(new AbortController().signal, {});
`);
}
await promise;
});