import TaskRunner from "./taskRunner"; const mockPromise = async (id, ms) => { await new Promise(resolve => setTimeout(resolve, ms)); return id; } const mockPromiseError = async (id, ms) => { await new Promise(resolve => setTimeout(resolve, ms)); return new Error(`Task ${id} had an error`); } const asyncFn1 = () => mockPromise(1, 200); const asyncFn2 = () => mockPromise(2, 100); const asyncFn3 = () => mockPromise(3, 50); describe("TaskRunner", () => { it("runs task added to queue, when space available", () => { const taskRunner = new TaskRunner(2); expect(taskRunner._running).toEqual(0); taskRunner.push(() => mockPromise(1, 300)); expect(taskRunner._running).toEqual(1); }); it("keeps task in queue when at concurrency limit", () => { const taskRunner = new TaskRunner(2); expect(taskRunner._running).toEqual(0); taskRunner.push(() => mockPromise(1, 100)); taskRunner.push(() => mockPromise(2, 25)); taskRunner.push(() => mockPromise(3, 10)); expect(taskRunner._running).toEqual(2); expect(taskRunner._queue.length).toEqual(1); }); it("runs queued tasks as space becomes available", async () => { const taskRunner = new TaskRunner(2); taskRunner.push(() => mockPromise(1, 600)); taskRunner.push(() => mockPromise(2, 300)); taskRunner.push(() => mockPromise(3, 100)); expect(taskRunner._queue.length).toEqual(1); await new Promise(r => setTimeout(r, 301)); expect(taskRunner._queue.length).toEqual(0); }); it("runs tasks in order", async () => { const actual = []; const taskRunner = new TaskRunner(2); taskRunner.push(asyncFn1) .then((id) => { actual.push(id); }); taskRunner.push(asyncFn2) .then((id) => { actual.push(id); }); taskRunner.push(asyncFn3) .then((id) => { actual.push(id); }); await new Promise(resolve => setTimeout(resolve, 500)); expect(actual).toEqual([2, 3, 1]); }); it("resolves a promise when all tasks are complete", async () => { const taskRunner = new TaskRunner(2, 5); taskRunner.push(() => mockPromise(1, 600)); taskRunner.push(() => mockPromise(2, 300)); taskRunner.push(() => mockPromise(3, 200)); taskRunner.push(() => mockPromise(4, 600)); taskRunner.push(() => mockPromise(5, 100)); await taskRunner.onComplete().then((actual) => { expect(actual).toStrictEqual([1, 2, 3, 4, 5]); }); }); it("resolves a promise when all tasks are complete, even if some fail", async () => { const error = new Error(`Task 3 had an error`); const taskRunner = new TaskRunner(2, 5); taskRunner.push(() => mockPromise(1, 600)); taskRunner.push(() => mockPromise(2, 300)); taskRunner.push(() => mockPromiseError(3, 200)); taskRunner.push(() => mockPromise(4, 600)); taskRunner.push(() => mockPromise(5, 100)); await taskRunner.onComplete().then((actual) => { expect(actual).toStrictEqual([1, 2, error, 4, 5]); }); }); it("rejects a promise when the total number of tasks is unknown", async () => { const taskRunner = new TaskRunner(2); taskRunner.push(() => mockPromise(1, 600)); taskRunner.push(() => mockPromise(2, 300)); taskRunner.push(() => mockPromise(3, 200)); taskRunner.push(() => mockPromise(4, 600)); taskRunner.push(() => mockPromise(5, 100)); await taskRunner.onComplete().catch((error) => { expect(error.message).toBe("Total is required to determine onComplete."); }); }); });