// The worker's one rule: one frame at a time, in arrival order. The bug this // guards against is an `async` listener, which does not serialize. import { test } from "node:test"; import assert from "node:assert/strict"; import { serialize } from "../serial.js"; const tick = (n) => new Promise((resolve) => setTimeout(resolve, n)); test("a slow frame does not let a later one overtake it", async () => { const posted = []; // The first frame suspends for longer than the second: an `async` listener // would post B's replies while A is still awaiting. const handler = async (frame) => { await tick(frame === "A" ? 20 : 0); posted.push(frame); }; const onMessage = serialize(Promise.resolve(), handler, () => {}); onMessage("A"); await onMessage("B"); assert.deepEqual(posted, ["A", "B"]); }); test("the same interleaving without the chain is what this rules out", async () => { const posted = []; const listener = async (frame) => { await tick(frame === "A" ? 20 : 0); posted.push(frame); }; listener("A"); await listener("B"); await tick(30); assert.deepEqual(posted, ["B", "A"]); }); test("frames that arrive before startup finishes are held, not dropped", async () => { const posted = []; let ready; const head = new Promise((resolve) => { ready = resolve; }); const onMessage = serialize(head, (f) => posted.push(f), () => {}); onMessage("first"); onMessage("second"); assert.deepEqual(posted, [], "nothing runs before startup settles"); ready(); await onMessage("third"); assert.deepEqual(posted, ["first", "second", "third"]); }); test("a startup that failed still lets the chain run, so the handler can decline", async () => { const seen = []; const head = Promise.reject(new Error("no bundle")); const onMessage = serialize(head, (f) => seen.push(f), () => {}); await onMessage("frame"); assert.deepEqual(seen, ["frame"]); }); test("one bad frame does not poison the frames after it", async () => { const posted = []; const errors = []; const onMessage = serialize( Promise.resolve(), (frame) => { if (frame === "bad") throw new Error("rejected"); posted.push(frame); }, (err, frame) => errors.push([frame, err.message]), ); onMessage("good"); onMessage("bad"); await onMessage("later"); assert.deepEqual(posted, ["good", "later"]); assert.deepEqual(errors, [["bad", "rejected"]]); });