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:
@@ -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",
|
||||
|
||||
Reference in New Issue
Block a user