FN-7457: stabilize plugin runner lifecycle hook tests

Replace real timer waits with a bounded microtask flush for plugin runner lifecycle hook tests.

- Add a shared flushMicrotasks helper for fire-and-forget hook assertions.
- Update task lifecycle hook tests to avoid setTimeout-based settling delays.
- Document the test-settling requirement with an FNXC comment.

Files changed:
 .../engine/src/__tests__/plugin-runner.test.ts     | 23 ++++++++++++++--------
 1 file changed, 15 insertions(+), 8 deletions(-)

Fusion-Task-Id: FN-7457

Fusion-Task-Lineage: 8a4eb36c-4e36-4c97-a88d-d76b8f410dc8

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
This commit is contained in:
gsxdsm
2026-07-02 22:53:51 -07:00
parent f9733341b5
commit f92c255e45

View File

@@ -1428,6 +1428,17 @@ describe("PluginRunner", () => {
});
describe("task lifecycle hooks", () => {
/*
FNXC:PluginRunnerTests 2026-07-02-17:20:
PluginRunner lifecycle handlers intentionally fire-and-forget their hook dispatch, so tests must wait for the mocked invokeHook promise chain to settle before asserting.
Use a bounded microtask flush instead of real wall-clock sleeps because FN-5048 forbids deterministic test settling through setTimeout delays when no production timer behavior is under test.
*/
const flushMicrotasks = async (turns = 4): Promise<void> => {
for (let turn = 0; turn < turns; turn += 1) {
await Promise.resolve();
}
};
it("should invoke onTaskCreated when task:created event fires", async () => {
mockPluginLoader.invokeHook = vi.fn();
await pluginRunner.init();
@@ -1443,8 +1454,7 @@ describe("PluginRunner", () => {
createdHandler(mockTask);
}
// Give async handler time to execute
await new Promise(resolve => setTimeout(resolve, 10));
await flushMicrotasks();
expect(mockPluginLoader.invokeHook).toHaveBeenCalledWith(
"onTaskCreated",
@@ -1467,8 +1477,7 @@ describe("PluginRunner", () => {
movedHandler({ task: mockTask, from: "todo", to: "in-progress" });
}
// Give async handler time to execute
await new Promise(resolve => setTimeout(resolve, 10));
await flushMicrotasks();
expect(mockPluginLoader.invokeHook).toHaveBeenCalledWith(
"onTaskMoved",
@@ -1505,8 +1514,7 @@ describe("PluginRunner", () => {
movedHandler({ task: mockTask, from: "in-progress", to: "done" });
}
// Give async handler time to execute
await new Promise(resolve => setTimeout(resolve, 50));
await flushMicrotasks();
expect(mockPluginLoader.invokeHook).toHaveBeenCalledWith(
"onTaskCompleted",
@@ -1538,8 +1546,7 @@ describe("PluginRunner", () => {
movedHandler({ task: mockTask, from: "todo", to: "in-progress" });
}
// Give async handler time to execute
await new Promise(resolve => setTimeout(resolve, 50));
await flushMicrotasks();
expect(mockPluginLoader.invokeHook).not.toHaveBeenCalledWith(
"onTaskCompleted",