Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 1 addition & 14 deletions extensions/cli/src/ui/__tests__/TUIChat.editMessage.test.tsx
Original file line number Diff line number Diff line change
@@ -1,18 +1,5 @@
import { renderInMode, testBothModes } from "./TUIChat.dualModeHelper.js";

async function waitForCondition(
conditionFn: () => boolean,
timeoutMs = 2000,
intervalMs = 50,
): Promise<void> {
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
Expand Down
24 changes: 15 additions & 9 deletions extensions/cli/src/ui/__tests__/TUIChat.fileSearch.test.tsx
Original file line number Diff line number Diff line change
@@ -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 () => {
Expand Down Expand Up @@ -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
Expand All @@ -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();
Expand Down
10 changes: 7 additions & 3 deletions extensions/cli/src/ui/__tests__/TUIChat.slashCommands.test.tsx
Original file line number Diff line number Diff line change
@@ -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) => {
Expand Down Expand Up @@ -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");
Expand Down
18 changes: 18 additions & 0 deletions extensions/cli/src/ui/__tests__/TUIChat.testHelper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<void> {
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: (
Expand Down
Loading