diff --git a/test/parallel/test-abortsignal-cloneable.js b/test/parallel/test-abortsignal-cloneable.js index a5061a7b81b..ffffcc5f43f 100644 --- a/test/parallel/test-abortsignal-cloneable.js +++ b/test/parallel/test-abortsignal-cloneable.js @@ -1,83 +1,91 @@ 'use strict'; -const common = require('../common'); +require('../common'); const { ok, strictEqual } = require('assert'); -const { setImmediate: pause } = require('timers/promises'); +const { setImmediate: sleep } = require('timers/promises'); const { transferableAbortSignal, transferableAbortController, } = require('util'); +const { + test, + mock, +} = require('node:test'); - -function deferred() { - let res; - const promise = new Promise((resolve) => res = resolve); - return { res, promise }; -} - -(async () => { +test('Can create a transferable abort controller', async () => { const ac = transferableAbortController(); const mc = new MessageChannel(); - const deferred1 = deferred(); - const deferred2 = deferred(); - const resolvers = [deferred1, deferred2]; + const setup1 = Promise.withResolvers(); + const setup2 = Promise.withResolvers(); + const setupResolvers = [setup1, setup2]; - mc.port1.onmessage = common.mustCall(({ data }) => { - data.addEventListener('abort', common.mustCall(() => { + const abort1 = Promise.withResolvers(); + const abort2 = Promise.withResolvers(); + const abort3 = Promise.withResolvers(); + const abortResolvers = [abort1, abort2, abort3]; + + mc.port1.onmessage = ({ data }) => { + data.addEventListener('abort', () => { strictEqual(data.reason, 'boom'); - })); - resolvers.shift().res(); - }, 2); + abortResolvers.shift().resolve(); + }); + setupResolvers.shift().resolve(); + }; mc.port2.postMessage(ac.signal, [ac.signal]); // Can be cloned/transferd multiple times and they all still work mc.port2.postMessage(ac.signal, [ac.signal]); - mc.port2.close(); - // Although we're using transfer semantics, the local AbortSignal // is still usable locally. - ac.signal.addEventListener('abort', common.mustCall(() => { + ac.signal.addEventListener('abort', () => { strictEqual(ac.signal.reason, 'boom'); - })); + abortResolvers.shift().resolve(); + }); - await Promise.all([ deferred1.promise, deferred2.promise ]); + await Promise.all([ setup1.promise, setup2.promise ]); ac.abort('boom'); + await Promise.all([ abort1.promise, abort2.promise, abort3.promise ]); + + mc.port2.close(); + +}); + +test('Can create a transferable abort signal', async () => { + const signal = transferableAbortSignal(AbortSignal.abort('boom')); + ok(signal.aborted); + strictEqual(signal.reason, 'boom'); + const mc = new MessageChannel(); + const { promise, resolve } = Promise.withResolvers(); + mc.port1.onmessage = ({ data }) => { + ok(data instanceof AbortSignal); + ok(data.aborted); + strictEqual(data.reason, 'boom'); + resolve(); + }; + mc.port2.postMessage(signal, [signal]); + await promise; + mc.port1.close(); +}); + +test('A cloned AbortSignal does not keep the event loop open', async () => { + const ac = transferableAbortController(); + const mc = new MessageChannel(); + const fn = mock.fn(); + mc.port1.onmessage = fn; + mc.port2.postMessage(ac.signal, [ac.signal]); // Because the postMessage used by the underlying AbortSignal // takes at least one turn of the event loop to be processed, // and because it is unref'd, it won't, by itself, keep the // event loop open long enough for the test to complete, so // we schedule two back to back turns of the event to ensure // the loop runs long enough for the test to complete. - await pause(); - await pause(); - -})().then(common.mustCall()); - -{ - const signal = transferableAbortSignal(AbortSignal.abort('boom')); - ok(signal.aborted); - strictEqual(signal.reason, 'boom'); - const mc = new MessageChannel(); - mc.port1.onmessage = common.mustCall(({ data }) => { - ok(data instanceof AbortSignal); - ok(data.aborted); - strictEqual(data.reason, 'boom'); - mc.port1.close(); - }); - mc.port2.postMessage(signal, [signal]); -} - -{ - // The cloned AbortSignal does not keep the event loop open - // waiting for the abort to be triggered. - const ac = transferableAbortController(); - const mc = new MessageChannel(); - mc.port1.onmessage = common.mustCall(); - mc.port2.postMessage(ac.signal, [ac.signal]); + await sleep(); + await sleep(); + strictEqual(fn.mock.calls.length, 1); mc.port2.close(); -} +});