diff --git a/src/effected.ts b/src/effected.ts index 3b1bc99..40dd549 100644 --- a/src/effected.ts +++ b/src/effected.ts @@ -497,7 +497,7 @@ export class Effected implements Iterable implements Iterable { describe("Effected.all", () => { const delay = effect("delay")<[ms: number, label: string], string>; + function deferred() { + let resolve!: (value: T | PromiseLike) => void; + const promise = new Promise((complete) => { + resolve = complete; + }); + return { promise, resolve }; + } + it("should run effects in parallel rather than sequentially", async () => { const executeOrder: string[] = []; const startTime = Date.now(); @@ -1382,6 +1390,53 @@ describe("Effected.all", () => { expect(seqResult).toEqual(result); }); + it("should complete nested effects resolved in reverse order in the same turn", async () => { + const first = deferred(); + const second = deferred(); + const firstTask = effected(function* () { + return yield* effectify(first.promise); + }); + const secondTask = effected(function* () { + return yield* effectify(second.promise); + }); + const result = Effected.all([Effected.all([firstTask, secondTask])]).runAsync(); + + second.resolve("second"); + first.resolve("first"); + + await expect(result).resolves.toEqual([["first", "second"]]); + }); + + it("should complete the ready first effect while the second effect waits again", async () => { + const first = deferred(); + const second = deferred(); + const third = deferred(); + const firstCompleted = deferred(); + const secondWaiting = deferred(); + + const firstTask = effected(function* () { + const value = yield* effectify(first.promise); + firstCompleted.resolve(value); + return value; + }); + const secondTask = effected(function* () { + const value = yield* effectify(second.promise); + secondWaiting.resolve(); + yield* effectify(third.promise); + return value; + }); + const result = Effected.all([Effected.all([firstTask, secondTask])]).runAsync(); + + second.resolve("second"); + first.resolve("first"); + + await secondWaiting.promise; + await expect(firstCompleted.promise).resolves.toBe("first"); + third.resolve(); + + await expect(result).resolves.toEqual([["first", "second"]]); + }); + it("should handle empty input correctly", () => { expect(Effected.all([]).runSync()).toEqual([]); expect(Effected.all({}).runSync()).toEqual({});