Spaces:
Paused
Paused
File size: 3,328 Bytes
1da8cb0 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 | import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
import { ProgressDisplay } from "./progress.js";
// Capture stdout writes instead of printing to terminal
let output: string[];
beforeEach(() => {
output = [];
vi.spyOn(process.stdout, "write").mockImplementation((data: string | Uint8Array) => {
output.push(String(data));
return true;
});
vi.useFakeTimers();
});
afterEach(() => {
vi.restoreAllMocks();
vi.useRealTimers();
});
describe("ProgressDisplay", () => {
it("renders pending stages with blank time", () => {
const p = new ProgressDisplay();
p.addStage("Research");
p.addStage("TTS");
// Trigger render by starting stage 0
p.start(0);
const joined = output.join("");
// Pending stage (TTS) should not show a time value
expect(joined).toContain("TTS");
});
it("renders a spinner for running stages", () => {
const p = new ProgressDisplay();
p.addStage("Research");
p.start(0);
// The running stage should include a time like "0.0s"
const joined = output.join("");
expect(joined).toMatch(/\d+\.\d+s/);
});
it("starts a tick interval on start() and clears on complete()", () => {
const p = new ProgressDisplay();
const idx = p.addStage("Research");
p.start(idx);
// Advance fake timers — spinner should update
const beforeLen = output.length;
vi.advanceTimersByTime(160); // 2 ticks at 80ms
expect(output.length).toBeGreaterThan(beforeLen);
// Complete the stage — interval should stop
p.complete(idx, "done");
const afterComplete = output.length;
vi.advanceTimersByTime(160);
// No more renders after completion
expect(output.length).toBe(afterComplete);
});
it("shows checkmark and duration for completed stages", () => {
const p = new ProgressDisplay();
const idx = p.addStage("Research");
p.start(idx);
p.complete(idx, "8 facts");
const joined = output.join("");
expect(joined).toContain("\u2714"); // checkmark
expect(joined).toContain("8 facts");
});
it("shows X mark for failed stages", () => {
const p = new ProgressDisplay();
const idx = p.addStage("TTS");
p.start(idx);
p.fail(idx, "API error");
const joined = output.join("");
expect(joined).toContain("\u2718"); // X mark
expect(joined).toContain("API error");
});
it("summary clears the interval and prints totals", () => {
const logSpy = vi.spyOn(console, "log").mockImplementation(() => {});
const p = new ProgressDisplay();
const idx = p.addStage("Research");
p.start(idx);
p.complete(idx);
p.summary();
expect(logSpy).toHaveBeenCalledWith(expect.stringContaining("Completed 1/1 stages"));
});
it("keeps ticking if one stage completes but another is still running", () => {
const p = new ProgressDisplay();
const a = p.addStage("Research");
const b = p.addStage("TTS");
p.start(a);
p.start(b);
p.complete(a, "done");
// Stage b still running — ticks should continue
const beforeLen = output.length;
vi.advanceTimersByTime(160);
expect(output.length).toBeGreaterThan(beforeLen);
p.complete(b, "done");
const afterComplete = output.length;
vi.advanceTimersByTime(160);
expect(output.length).toBe(afterComplete);
});
});
|