This commit is contained in:
Eason Goodale
2025-04-30 11:45:29 -07:00
parent 41ef530683
commit 5481bf0cb4
10 changed files with 174 additions and 41 deletions
+4 -4
View File
@@ -87,10 +87,10 @@ import { loadConfig } from "../src/utils/config.js";
let projectDir: string;
# beforeEach runs once per test; when the sandbox blocks mkdtemp under the OS
# tmp directory (e.g. GitHub Codespaces or certain container runtimes) fall
# back to creating the directory under the current working directory so the
# suite can still run.
// beforeEach runs once per test; when the sandbox blocks mkdtemp under the OS
// tmp directory (e.g. GitHub Codespaces or certain container runtimes) falls
// back to creating the directory under the current working directory so the
// suite can still run.
beforeEach(() => {
try {
projectDir = mkdtempSync(join(tmpdir(), "codex-proj-"));
@@ -48,6 +48,8 @@ function props() {
interruptAgent: () => {},
active: true,
onCompact: () => {},
openDiffOverlay: () => {},
thinkingSeconds: 0,
};
}
@@ -44,6 +44,8 @@ function props() {
interruptAgent: () => {},
active: true,
onCompact: () => {},
openDiffOverlay: () => {},
thinkingSeconds: 0,
};
}
+7 -6
View File
@@ -6,8 +6,7 @@ import {
} from "../src/utils/check-updates.js";
import { execFile } from "node:child_process";
import { join } from "node:path";
import { CONFIG_DIR } from "src/utils/config.js";
import { beforeEach } from "node:test";
import { CONFIG_DIR } from "../src/utils/config.js";
vi.mock("which", () => ({
default: vi.fn(() => "/usr/local/bin/npm"),
@@ -36,6 +35,9 @@ vi.mock("node:fs/promises", async (importOriginal) => ({
}
return memfs[path];
},
writeFile: async (path: string, data: string) => {
memfs[path] = data;
},
}));
beforeEach(() => {
@@ -88,8 +90,9 @@ describe("Check for updates", () => {
memfs[codexStatePath] = JSON.stringify({
lastUpdateCheck: new Date("2000-01-01T00:00:00Z").toUTCString(),
});
await checkForUpdates();
// Spy on console.log to capture output
// Spy on console.log to capture output BEFORE calling the checker so we
// capture the very first message that is printed when an update is
// detected.
const logSpy = vi.spyOn(console, "log").mockImplementation(() => {});
await checkForUpdates();
expect(logSpy).toHaveBeenCalled();
@@ -107,8 +110,6 @@ describe("Check for updates", () => {
memfs[codexStatePath] = JSON.stringify({
lastUpdateCheck: new Date().toUTCString(),
});
await checkForUpdates();
// Spy on console.log to capture output
const logSpy = vi.spyOn(console, "log").mockImplementation(() => {});
await checkForUpdates();
expect(logSpy).not.toHaveBeenCalled();
+32 -12
View File
@@ -13,13 +13,32 @@ import { renderTui } from "./ui-test-helpers.js";
// Mocks – keep in sync with other TerminalChatInput UI tests
// ---------------------------------------------------------------------------
// mock without type annotations to avoid Vitest transform TS errors in JS test
const createInputItemMock = vi.fn(async () => ({}));
// We need to capture a reference to the mocked `createInputItem` function so we
// can make assertions later in the test, _and_ respect Vitest’s requirement
// that any variables used inside the `vi.mock` factory are already defined at
// the time the factory is hoisted. To satisfy both constraints we:
// 1. Declare the variable with `let` (so it’s hoisted), **without** assigning
// a value yet.
// 2. Inside the factory, create the mock with `vi.fn()` and assign it to the
// outer-scoped variable before returning it.
// This avoids the “there was an error when mocking a module” failure that
// occurs when a factory closes over an uninitialised top-level `const`.
vi.mock("../src/utils/input-utils.js", () => ({
createInputItem: createInputItemMock,
imageFilenameByDataUrl: new Map(),
}));
// Using `var` ensures the binding is hoisted, so it exists (as `undefined`) at
// the time the `vi.mock` factory runs. We re-assign it inside the factory.
// eslint-disable-next-line no-var
var createInputItemMock!: ReturnType<typeof vi.fn>;
vi.mock("../src/utils/input-utils.js", () => {
// Initialise the mock lazily inside the factory so the reference is valid
// when the module is evaluated.
createInputItemMock = vi.fn(async () => ({}));
return {
createInputItem: createInputItemMock,
imageFilenameByDataUrl: new Map(),
};
});
vi.mock("../src/approvals.js", () => ({ isSafeCommand: () => null }));
vi.mock("../src/format-command.js", () => ({
formatCommandForDisplay: (c: Array<string>): string => c.join(" "),
@@ -53,6 +72,8 @@ function props() {
interruptAgent: () => {},
active: true,
onCompact: () => {},
openDiffOverlay: () => {},
thinkingSeconds: 0,
};
}
@@ -70,7 +91,7 @@ describe("Drag-and-drop image attachment", () => {
});
it("moves pasted path to attachment preview", async () => {
process.env.DEBUG_TCI = "1";
process.env["DEBUG_TCI"] = "1";
const orig = process.cwd();
process.chdir(TMP);
@@ -90,8 +111,7 @@ describe("Drag-and-drop image attachment", () => {
// setState inside the onChange handler.
await flush();
let frame = lastFrameStripped();
const frame = lastFrameStripped();
expect(frame.match(/dropped\.png/g)?.length ?? 0).toBe(1);
@@ -101,9 +121,9 @@ describe("Drag-and-drop image attachment", () => {
// createInputItem should have been called with the dropped image path
expect(createInputItemMock).toHaveBeenCalled();
const calls = createInputItemMock.mock.calls;
const lastCall = calls[calls.length - 1];
expect(lastCall?.[1]).toEqual(["dropped.png"]);
const calls: Array<Array<unknown>> = createInputItemMock.mock.calls as any;
const lastCall = calls[calls.length - 1] as Array<unknown>;
expect(lastCall?.[1 as number]).toEqual(["dropped.png"]);
cleanup();
process.chdir(orig);
+1 -1
View File
@@ -12,7 +12,7 @@ describe("extractImagePaths", () => {
});
it("detects quoted image", () => {
const { paths, text } = extractImagePaths("drag \"baz.jpg\" here");
const { paths, text } = extractImagePaths('drag "baz.jpg" here');
expect(paths).toEqual(["baz.jpg"]);
expect(text).toBe("drag here");
});
+1 -1
View File
@@ -8,7 +8,7 @@ let projectDir: string;
let configPath: string;
let instructionsPath: string;
# Use OS tmpdir unless blocked; fallback to cwd.
// Use OS tmpdir unless blocked; fallback to cwd.
beforeEach(() => {
try {
projectDir = mkdtempSync(join(tmpdir(), "codex-proj-"));