test(ui): flush passive effects with React act in CompanySkills tests

The local act helper wrapped flushSync, which flushes render work but
not passive effects. The install dialog seeds its state in a useEffect,
so tests added a setTimeout(0) hop to give it a chance to run. A
setTimeout callback and React's own scheduler task queue in a
different order each run, so the hop sometimes lost the race and the
test read stale state.

Delegate the helper to React's own act, which flushes passive effects
before it resolves, and remove the now-unneeded timing hops.

Co-authored-by: Paperclip <noreply@paperclip.ing>
This commit is contained in:
Priya Raman 2026-09-05 08:07:54 +00:00
parent a7ed22e3dd
commit 834f33c31b
No known key found for this signature in database
GPG Key ID: 4861541D36B2037E
1 changed files with 3 additions and 20 deletions

View File

@ -1,7 +1,6 @@
// @vitest-environment jsdom
import type { ComponentProps, ReactNode } from "react";
import { flushSync } from "react-dom";
import { act as reactAct, type ComponentProps, type ReactNode } from "react";
import { createRoot, type Root } from "react-dom/client";
import type { CatalogSkill, CompanySkillDetail, CompanySkillListItem, CompanySkillVersion, FolderListResult } from "@paperclipai/shared";
import { afterEach, describe, expect, it, vi } from "vitest";
@ -104,11 +103,9 @@ let root: Root | null = null;
let container: HTMLDivElement | null = null;
async function act(callback: () => void | Promise<void>) {
let result: void | Promise<void> = undefined;
flushSync(() => {
result = callback();
await reactAct(async () => {
await callback();
});
await result;
}
afterEach(() => {
@ -1043,11 +1040,6 @@ describe("install-time agent enablement", () => {
/>,
);
});
// The dialog seeds its slug/agent state in passive effects; give them a
// macrotask to flush before interacting.
await act(async () => {
await new Promise((resolve) => setTimeout(resolve, 0));
});
const node = container as ParentNode;
expect(node.textContent).toContain("Enable for agents");
@ -1089,15 +1081,9 @@ describe("install-time agent enablement", () => {
// Dialog opens before the agents query resolves: nothing to select yet.
await act(async () => renderDialog([]));
await act(async () => {
await new Promise((resolve) => setTimeout(resolve, 0));
});
// The agents arrive later; the untouched selection must pick them up.
await act(async () => renderDialog(agentOptions));
await act(async () => {
await new Promise((resolve) => setTimeout(resolve, 0));
});
await click(buttonsNamed(container as ParentNode, "Install skill")[0] as HTMLButtonElement);
@ -1129,9 +1115,6 @@ describe("install-time agent enablement", () => {
/>,
);
});
await act(async () => {
await new Promise((resolve) => setTimeout(resolve, 0));
});
const node = container as ParentNode;
expect(node.textContent).not.toContain("Enable for agents");