repositories / pi-ext
pi-ext
bugabingas pi extensions
owned by admin
extensions/masks/__tests__/debug.test.ts
Rawimport { readdirSync, readFileSync } from "node:fs";
import path from "node:path";
import { afterEach, describe, expect, it, vi } from "vitest";
import {
createPiSession,
type PiSession,
} from "../../../test/fixture/create-pi-session.ts";
const extensionPath = path.resolve(import.meta.dirname, "../index.ts");
describe("masks debug interface", () => {
let session: PiSession | undefined;
afterEach(async () => {
await session?.dispose();
session = undefined;
});
it("writes lifecycle records in the isolated sandbox", async () => {
session = await createPiSession({
env: { PI_MASKS_DEBUG: "1" },
extensionPaths: [extensionPath],
});
await session.session.extensionRunner.emit({
type: "session_start",
reason: "startup",
});
await session.session.extensionRunner.emit({
type: "session_shutdown",
reason: "quit",
});
const stateHome = session.env["XDG_STATE_HOME"];
if (!stateHome) throw new Error("missing sandbox state home");
const directory = path.join(stateHome, "pi-ext", "debug", "masks");
// Debug records flush asynchronously; poll until both events appear.
const records = await vi.waitFor(
() => {
const parsed = readdirSync(directory).flatMap((file) =>
readFileSync(path.join(directory, file), "utf8")
.trim()
.split("\n")
.filter(Boolean)
.map(
(line) =>
JSON.parse(line) as { event: string; extension: string },
),
);
const events = parsed.map((record) => record.event);
if (
!events.includes("session.start") ||
!events.includes("session.shutdown")
)
throw new Error("lifecycle events not flushed yet");
return parsed;
},
{ timeout: 2_000, interval: 20 },
);
expect(records).toContainEqual(
expect.objectContaining({ event: "session.start", extension: "masks" }),
);
expect(records).toContainEqual(
expect.objectContaining({
event: "session.shutdown",
extension: "masks",
}),
);
});
});