repositories / pi-ext
pi-ext
bugabingas pi extensions
owned by admin
extensions/nushell/__serial__/runtime.test.ts
Rawimport type { ChildProcess } from "node:child_process";
import { EventEmitter } from "node:events";
import { afterEach, describe, expect, it, vi } from "vitest";
const { spawnMock } = vi.hoisted(() => ({ spawnMock: vi.fn() }));
vi.mock("node:child_process", () => ({ spawn: spawnMock }));
vi.mock("node:fs/promises", () => ({
access: vi.fn().mockResolvedValue(undefined),
}));
import { freshOperations } from "../runtime.ts";
afterEach(() => {
vi.useRealTimers();
vi.clearAllMocks();
});
function childProcess(): ChildProcess {
const child = new EventEmitter() as unknown as ChildProcess;
Object.defineProperty(child, "stdout", { value: new EventEmitter() });
Object.defineProperty(child, "stderr", { value: new EventEmitter() });
Object.defineProperty(child, "pid", { value: undefined });
Object.defineProperty(child, "unref", { value: vi.fn() });
return child;
}
describe("fresh Nushell process completion", () => {
it("waits for close and forwards final stdout/stderr chunks after exit", async () => {
const child = childProcess();
spawnMock.mockReturnValue(child);
const chunks: Buffer[] = [];
let completed = false;
const resultPromise = freshOperations("nu").exec("true", process.cwd(), {
onData: (chunk) => chunks.push(chunk),
});
await Promise.resolve();
void resultPromise.then(() => {
completed = true;
});
child.emit("exit", 0, null);
await Promise.resolve();
await Promise.resolve();
expect(completed).toBe(false);
const stdout = Buffer.from("stdout-tail");
const stderr = Buffer.from("stderr-tail");
child.stdout?.emit("data", stdout);
child.stderr?.emit("data", stderr);
child.emit("close", 0, null);
await expect(resultPromise).resolves.toEqual({ exitCode: 0 });
expect(chunks).toEqual([stdout, stderr]);
});
it("rejects spawn errors", async () => {
const child = childProcess();
spawnMock.mockReturnValue(child);
const resultPromise = freshOperations("nu").exec("true", process.cwd(), {
onData: () => {},
});
await Promise.resolve();
child.emit("error", new Error("spawn failed"));
await expect(resultPromise).rejects.toThrow("spawn failed");
});
it("rejects aborted executions after process close", async () => {
const child = childProcess();
spawnMock.mockReturnValue(child);
const controller = new AbortController();
const resultPromise = freshOperations("nu").exec("true", process.cwd(), {
onData: () => {},
signal: controller.signal,
});
await Promise.resolve();
controller.abort();
child.emit("close", null, "SIGKILL");
await expect(resultPromise).rejects.toThrow("aborted");
});
it("rejects timed-out executions after process close", async () => {
vi.useFakeTimers();
const child = childProcess();
spawnMock.mockReturnValue(child);
const resultPromise = freshOperations("nu").exec("true", process.cwd(), {
onData: () => {},
timeout: 0.01,
});
await Promise.resolve();
await vi.advanceTimersByTimeAsync(10);
child.emit("close", null, "SIGKILL");
await expect(resultPromise).rejects.toThrow("timeout:0.01");
});
});