import { describe, expect, it, vi } from "vitest"; import { createCliProgress, shouldUseInteractiveProgressSpinner } from "./progress.js"; function withStdinIsRaw(isRaw: boolean, run: () => T): T { const original = Object.getOwnPropertyDescriptor(process.stdin, "isRaw"); Object.defineProperty(process.stdin, "isRaw", { configurable: true, value: isRaw, }); try { return run(); } finally { if (original) { Object.defineProperty(process.stdin, "isRaw", original); } else { Reflect.deleteProperty(process.stdin, "isRaw"); } } } describe("cli progress", () => { it("logs progress when non-tty and fallback=log", () => { const writes: string[] = []; const stream = { isTTY: false, write: vi.fn((chunk: string) => { writes.push(chunk); }), } as unknown as NodeJS.WriteStream; const progress = createCliProgress({ label: "Indexing memory...", total: 10, stream, fallback: "log", }); progress.setPercent(50); progress.done(); const output = writes.join(""); expect(output).toContain("Indexing memory... 0%"); expect(output).toContain("Indexing memory... 50%"); }); it("does not log without a tty when fallback is none", () => { const write = vi.fn(); const stream = { isTTY: false, write, } as unknown as NodeJS.WriteStream; const progress = createCliProgress({ label: "Nope", total: 2, stream, fallback: "none", }); progress.setPercent(50); progress.done(); expect(write).not.toHaveBeenCalled(); }); it("does not use readline-backed spinners while raw TUI input is active", () => { expect( shouldUseInteractiveProgressSpinner({ streamIsTty: true, stdinIsRaw: true, }), ).toBe(false); }); it("keeps the normal interactive spinner for regular tty commands", () => { expect( shouldUseInteractiveProgressSpinner({ streamIsTty: true, stdinIsRaw: false, }), ).toBe(true); }); it("does not write terminal controls when raw TUI input suppresses the default spinner", () => { const writes: string[] = []; const stream = { isTTY: true, write: vi.fn((chunk: string) => { writes.push(chunk); }), } as unknown as NodeJS.WriteStream; withStdinIsRaw(true, () => { const progress = createCliProgress({ label: "Scanning", total: 2, stream, }); progress.setLabel("Still scanning"); progress.tick(); progress.done(); }); expect(writes).toEqual([]); }); });