diff options
Diffstat (limited to 'test/js/node/events/node-events.node.test.ts')
-rw-r--r-- | test/js/node/events/node-events.node.test.ts | 305 |
1 files changed, 160 insertions, 145 deletions
diff --git a/test/js/node/events/node-events.node.test.ts b/test/js/node/events/node-events.node.test.ts index 6a1fd5f2a..c086aa0b7 100644 --- a/test/js/node/events/node-events.node.test.ts +++ b/test/js/node/events/node-events.node.test.ts @@ -1,10 +1,10 @@ import { EventEmitter, on } from "node:events"; import { createTest } from "node-harness"; -const { expect, assert, describe, it, createCallCheckCtx, createDoneDotAll } = createTest(import.meta.path); +const { beforeAll, expect, assert, describe, it, createCallCheckCtx, createDoneDotAll } = createTest(import.meta.path); // const NodeEventTarget = globalThis.EventTarget; -describe("node:events.on (EE async iterator)", () => { +describe("node:events.on (EventEmitter AsyncIterator)", () => { it("should return an async iterator", async () => { const ee = new EventEmitter(); const iterable = on(ee, "foo"); @@ -192,106 +192,174 @@ describe("node:events.on (EE async iterator)", () => { done(); }); - it("should throw a `TypeError` when calling throw without args", async () => { + describe(".throw()", () => { + let ee: EventEmitter; + let iterable: AsyncIterableIterator<any>; + + beforeAll(() => { + ee = new EventEmitter(); + iterable = on(ee, "foo"); + }); + + it("should throw a `TypeError` when calling without args", async () => { + expect(() => { + iterable.throw!(); + }).toThrow(TypeError); + + assert.strictEqual(ee.listenerCount("foo"), 1); + assert.strictEqual(ee.listenerCount("error"), 1); + }); + + it("should throw when called with an error", async () => { + const _err = new Error("kaboom"); + + ee.emit("foo", "bar"); + ee.emit("foo", 42); + iterable.throw!(_err); + + const expected = [["bar"], [42]]; + + let thrown = false; + let looped = false; + + try { + for await (const event of iterable) { + assert.deepStrictEqual(event, expected.shift()); + looped = true; + } + } catch (err) { + thrown = true; + assert.strictEqual(err, _err); + } + + assert.strictEqual(looped, true); + assert.strictEqual(thrown, true); + assert.strictEqual(ee.listenerCount("foo"), 0); + assert.strictEqual(ee.listenerCount("error"), 0); + }); + }); + + it("should add an error listener when the iterable is created", () => { const ee = new EventEmitter(); - const iterable = on(ee, "foo"); + on(ee, "foo"); + assert.strictEqual(ee.listenerCount("error"), 1); + }); - expect(() => { - // @ts-ignore - iterable.throw(); - }).toThrow(TypeError); + it("should throw when called with an aborted signal", () => { + const ee = new EventEmitter(); + const abortedSignal = AbortSignal.abort(); + [1, {}, null, false, "hi"].forEach((signal: any) => { + assert.throws(() => on(ee, "foo", { signal }), Error); + }); + assert.throws(() => on(ee, "foo", { signal: abortedSignal }), { + name: "AbortError", + }); }); - // async function iterableThrow() { - // const ee = new EventEmitter(); - // const iterable = on(ee, "foo"); + it("should NOT THROW an `AbortError` AFTER done iterating over events", async _done => { + let _doneCalled = false; + const done = (err?: Error) => { + if (_doneCalled) return; + _doneCalled = true; + _done(err); + }; - // process.nextTick(() => { - // ee.emit("foo", "bar"); - // ee.emit("foo", 42); // lost in the queue - // iterable.throw(_err); - // }); + const ee = new EventEmitter(); + const ac = new AbortController(); + + const i = setInterval(() => ee.emit("foo", "foo"), 1); + let count = 0; + + async function foo() { + for await (const f of on(ee, "foo", { signal: ac.signal })) { + assert.strictEqual(f[0], "foo"); + if (++count === 5) break; + } + ac.abort(); // No error will occur + } + + foo() + .catch(err => done(err)) + .finally(() => { + clearInterval(i); + if (!_doneCalled) expect(true).toBe(true); + done(); + }); + }); + + it("should THROW an `AbortError` BEFORE done iterating over events", async _done => { + let _doneCalled = false; + const done = (err?: Error) => { + if (_doneCalled) return; + _doneCalled = true; + _done(err); + }; + + let count = 0; + + const createDone = createDoneDotAll(done); + const { mustCall, closeTimers } = createCallCheckCtx(createDone()); + const finalDone = createDone(); + + const ee = new EventEmitter(); + const ac = new AbortController(); + + const i = setInterval(() => ee.emit("foo", "foo"), 10); + + setTimeout(() => ac.abort(), 50); + + async function foo() { + for await (const f of on(ee, "foo", { signal: ac.signal })) { + assert.deepStrictEqual(f, ["foo"]); + } + } + + foo() + .then(() => done(new Error("Should not be called"))) + .catch( + mustCall(error => { + assert.strictEqual(error.name, "AbortError"); + }), + ) + .finally(() => { + clearInterval(i); + closeTimers(); + if (!_doneCalled) finalDone(); + }); + }); - // const _err = new Error("kaboom"); - // let thrown = false; - - // assert.throws( - // () => { - // // No argument - // iterable.throw(); - // }, - // { - // message: 'The "EventEmitter.AsyncIterator" property must be' + " an instance of Error. Received undefined", - // name: "TypeError", - // }, - // ); - - // const expected = [["bar"], [42]]; - - // try { - // for await (const event of iterable) { - // assert.deepStrictEqual(event, expected.shift()); + // TODO: Uncomment tests for NodeEventTarget and Web EventTarget + + // async function eventTarget() { + // const et = new EventTarget(); + // const tick = () => et.dispatchEvent(new Event("tick")); + // const interval = setInterval(tick, 0); + // let count = 0; + // for await (const [event] of on(et, "tick")) { + // count++; + // assert.strictEqual(event.type, "tick"); + // if (count >= 5) { + // break; // } - // } catch (err) { - // thrown = true; - // assert.strictEqual(err, _err); // } - // assert.strictEqual(thrown, true); - // assert.strictEqual(expected.length, 0); - // assert.strictEqual(ee.listenerCount("foo"), 0); - // assert.strictEqual(ee.listenerCount("error"), 0); + // assert.strictEqual(count, 5); + // clearInterval(interval); // } - // // async function eventTarget() { - // // const et = new EventTarget(); - // // const tick = () => et.dispatchEvent(new Event("tick")); - // // const interval = setInterval(tick, 0); - // // let count = 0; - // // for await (const [event] of on(et, "tick")) { - // // count++; - // // assert.strictEqual(event.type, "tick"); - // // if (count >= 5) { - // // break; - // // } - // // } - // // assert.strictEqual(count, 5); - // // clearInterval(interval); - // // } - - // async function errorListenerCount() { - // const et = new EventEmitter(); - // on(et, "foo"); - // assert.strictEqual(et.listenerCount("error"), 1); - // } - - // // async function nodeEventTarget() { - // // const et = new NodeEventTarget(); - // // const tick = () => et.dispatchEvent(new Event("tick")); - // // const interval = setInterval(tick, 0); - // // let count = 0; - // // for await (const [event] of on(et, "tick")) { - // // count++; - // // assert.strictEqual(event.type, "tick"); - // // if (count >= 5) { - // // break; - // // } - // // } - // // assert.strictEqual(count, 5); - // // clearInterval(interval); - // // } - - // async function abortableOnBefore() { - // it("should "); - // const ee = new EventEmitter(); - // const abortedSignal = AbortSignal.abort(); - // [1, {}, null, false, "hi"].forEach((signal: any) => { - // assert.throws(() => on(ee, "foo", { signal }), { - // code: "ERR_INVALID_ARG_TYPE", - // }); - // }); - // assert.throws(() => on(ee, "foo", { signal: abortedSignal }), { - // name: "AbortError", - // }); + // async function nodeEventTarget() { + // const et = new NodeEventTarget(); + // const tick = () => et.dispatchEvent(new Event("tick")); + // const interval = setInterval(tick, 0); + // let count = 0; + // for await (const [event] of on(et, "tick")) { + // count++; + // assert.strictEqual(event.type, "tick"); + // if (count >= 5) { + // break; + // } + // } + // assert.strictEqual(count, 5); + // clearInterval(interval); // } // async function eventTargetAbortableOnBefore() { @@ -307,59 +375,6 @@ describe("node:events.on (EE async iterator)", () => { // }); // } - // it("should NOT throw an `AbortError` when done iterating over events", async done => { - // const ee = new EventEmitter(); - // const ac = new AbortController(); - - // const i = setInterval(() => ee.emit("foo", "foo"), 1); - // let count = 0; - - // async function foo() { - // for await (const f of on(ee, "foo", { signal: ac.signal })) { - // assert.strictEqual(f[0], "foo"); - // if (++count === 5) break; - // } - // ac.abort(); // No error will occur - // } - - // foo().finally(() => { - // clearInterval(i); - // expect(true).toBe(true); - // done(); - // }); - // }); - - // it("should throw an `AbortError` when NOT done iterating over events", async done => { - // const createDone = createDoneDotAll(done); - // const { mustCall, closeTimers } = createCallCheckCtx(createDone()); - // const finalDone = createDone(); - - // const ee = new EventEmitter(); - // const ac = new AbortController(); - - // const i = setInterval(() => ee.emit("foo", "foo"), 10); - - // async function foo() { - // for await (const f of on(ee, "foo", { signal: ac.signal })) { - // assert.strictEqual(f, "foo"); - // } - // } - - // foo() - // .catch( - // mustCall(error => { - // assert.strictEqual(error.name, "AbortError"); - // }), - // ) - // .finally(() => { - // clearInterval(i); - // finalDone(); - // closeTimers(); - // }); - - // process.nextTick(() => ac.abort()); - // }); - // async function eventTargetAbortableOnAfter() { // const et = new EventTarget(); // const ac = new AbortController(); |