Files
codex/codex-cli/tests/attachment-preview.test.tsx
Eason Goodale 5481bf0cb4 update
2025-04-30 11:45:29 -07:00

93 lines
2.5 KiB
TypeScript

// Attachment preview shows selected images and clears with Ctrl+U
import fs from "node:fs";
import path from "node:path";
import React from "react";
import { beforeAll, afterAll, describe, expect, it, vi } from "vitest";
import { renderTui } from "./ui-test-helpers.js";
vi.mock("../src/utils/input-utils.js", () => ({
createInputItem: vi.fn(async () => ({})),
imageFilenameByDataUrl: new Map(),
}));
// mock external deps used inside chat input
// Mock approval helper used by TerminalChatInput
vi.mock("../src/approvals.js", () => ({ isSafeCommand: () => null }));
vi.mock("../src/format-command.js", () => ({
// Accept an array of command tokens and join them with spaces for display.
formatCommandForDisplay: (c: Array<string>): string => c.join(" "),
}));
import TerminalChatInput from "../src/components/chat/terminal-chat-input.js";
async function type(
stdin: NodeJS.WritableStream & { write(str: string): void },
text: string,
flush: () => Promise<void>,
): Promise<void> {
stdin.write(text);
await flush();
}
function props() {
return {
isNew: true,
loading: false,
submitInput: () => {},
confirmationPrompt: null,
submitConfirmation: () => {},
setLastResponseId: () => {},
setItems: () => {},
contextLeftPercent: 100,
openOverlay: () => {},
openModelOverlay: () => {},
openApprovalOverlay: () => {},
openHelpOverlay: () => {},
interruptAgent: () => {},
active: true,
onCompact: () => {},
openDiffOverlay: () => {},
thinkingSeconds: 0,
};
}
describe("Chat input attachment preview", () => {
const TMP = path.join(process.cwd(), "attachment-preview-test");
const IMG = path.join(TMP, "foo.png");
beforeAll(() => {
fs.mkdirSync(TMP, { recursive: true });
fs.writeFileSync(IMG, "");
});
afterAll(() => {
fs.rmSync(TMP, { recursive: true, force: true });
});
it("shows image then clears with Ctrl+U", async () => {
const orig = process.cwd();
process.chdir(TMP);
const { stdin, flush, lastFrameStripped, cleanup } = renderTui(
React.createElement(TerminalChatInput, props()),
);
await flush();
await type(stdin, "@", flush);
await type(stdin, "\r", flush); // choose first
const frame1 = lastFrameStripped();
expect(frame1.match(/foo\.png/g)?.length ?? 0).toBe(1);
await type(stdin, "\x07", flush); // Ctrl+G (clear images only)
expect(lastFrameStripped()).not.toContain("foo.png");
cleanup();
process.chdir(orig);
});
});