diff --git a/extensions/cli/src/ui/__tests__/TUIChat.editMessage.test.tsx b/extensions/cli/src/ui/__tests__/TUIChat.editMessage.test.tsx index 73af37d509..2a537cf3d4 100644 --- a/extensions/cli/src/ui/__tests__/TUIChat.editMessage.test.tsx +++ b/extensions/cli/src/ui/__tests__/TUIChat.editMessage.test.tsx @@ -1,18 +1,5 @@ import { renderInMode, testBothModes } from "./TUIChat.dualModeHelper.js"; - -async function waitForCondition( - conditionFn: () => boolean, - timeoutMs = 2000, - intervalMs = 50, -): Promise { - const startTime = Date.now(); - while (Date.now() - startTime < timeoutMs) { - if (conditionFn()) { - return; - } - await new Promise((resolve) => setTimeout(resolve, intervalMs)); - } -} +import { waitForCondition } from "./TUIChat.testHelper.js"; /** * Integration tests for the message edit feature in TUIChat diff --git a/extensions/cli/src/ui/__tests__/TUIChat.fileSearch.test.tsx b/extensions/cli/src/ui/__tests__/TUIChat.fileSearch.test.tsx index b38a90cb62..b469b27255 100644 --- a/extensions/cli/src/ui/__tests__/TUIChat.fileSearch.test.tsx +++ b/extensions/cli/src/ui/__tests__/TUIChat.fileSearch.test.tsx @@ -1,5 +1,5 @@ import { renderInMode, testSingleMode } from "./TUIChat.dualModeHelper.js"; -import { waitForNextRender } from "./TUIChat.testHelper.js"; +import { waitForCondition } from "./TUIChat.testHelper.js"; describe("TUIChat - @ File Search Tests", () => { testSingleMode("shows @ character when user types @", "local", async () => { @@ -34,17 +34,20 @@ describe("TUIChat - @ File Search Tests", () => { // Type @ followed by text to filter files stdin.write("@READ"); - // Wait for file search to filter and display results - await new Promise((resolve) => setTimeout(resolve, 500)); + let frame = lastFrame(); - const frame = lastFrame()!; + await waitForCondition(() => { + frame = lastFrame(); + return frame?.includes("@READ") ?? false; + }); + expect(frame).toBeDefined(); // Should show the typed text expect(frame).toContain("@READ"); // Should show either navigation hints or at least indicate file search is working - const hasNavigationHints = frame.includes("↑/↓ to navigate"); - const hasFileSearch = frame.includes("@READ"); + const hasNavigationHints = frame!.includes("↑/↓ to navigate"); + const hasFileSearch = frame!.includes("@READ"); expect(hasNavigationHints || hasFileSearch).toBe(true); // Local mode specific UI expectations @@ -57,10 +60,13 @@ describe("TUIChat - @ File Search Tests", () => { // Type multiple @ characters stdin.write("@@test"); - // Wait for UI update - await waitForNextRender(); - const frame = lastFrame(); + let frame = lastFrame(); + + await waitForCondition(() => { + frame = lastFrame(); + return frame?.includes("@@test") ?? false; + }); // Should handle multiple @ without crashing expect(frame).toBeDefined(); diff --git a/extensions/cli/src/ui/__tests__/TUIChat.slashCommands.test.tsx b/extensions/cli/src/ui/__tests__/TUIChat.slashCommands.test.tsx index 1f63f3814b..6f44933b64 100644 --- a/extensions/cli/src/ui/__tests__/TUIChat.slashCommands.test.tsx +++ b/extensions/cli/src/ui/__tests__/TUIChat.slashCommands.test.tsx @@ -1,5 +1,5 @@ import { renderInMode, testBothModes } from "./TUIChat.dualModeHelper.js"; -import { waitForNextRender } from "./TUIChat.testHelper.js"; +import { waitForCondition, waitForNextRender } from "./TUIChat.testHelper.js"; describe("TUIChat - Slash Commands Tests", () => { testBothModes("shows slash when user types /", async (mode) => { @@ -28,9 +28,13 @@ describe("TUIChat - Slash Commands Tests", () => { // Type /exi to trigger slash command filtering stdin.write("/exi"); - await waitForNextRender(); - const frame = lastFrame(); + let frame = lastFrame(); + + await waitForCondition(() => { + frame = lastFrame(); + return frame?.includes("/exi") ?? false; + }); // Should show the typed command expect(frame).toContain("/exi"); diff --git a/extensions/cli/src/ui/__tests__/TUIChat.testHelper.ts b/extensions/cli/src/ui/__tests__/TUIChat.testHelper.ts index 37ebb5c3ee..00a0e16a32 100644 --- a/extensions/cli/src/ui/__tests__/TUIChat.testHelper.ts +++ b/extensions/cli/src/ui/__tests__/TUIChat.testHelper.ts @@ -458,6 +458,24 @@ export function expectNormalMode(frame: string | undefined) { expect(frame).toContain("Continue CLI"); } +/** + * Helper to wait for a condition to be true + * similar to `waitFor` in testing libraries + */ +export async function waitForCondition( + conditionFn: () => boolean, + timeoutMs = 2000, + intervalMs = 50, +): Promise { + const startTime = Date.now(); + while (Date.now() - startTime < timeoutMs) { + if (conditionFn()) { + return; + } + await new Promise((resolve) => setTimeout(resolve, intervalMs)); + } +} + // Make runTest available globally for test files declare global { var runTest: (