repositories / pi-ext
pi-ext
bugabingas pi extensions
owned by admin
extensions/notes/__tests__/debug.test.ts
Rawimport { readdirSync, readFileSync } from "node:fs";
import { join } from "node:path";
import { fileURLToPath } from "node:url";
import { afterEach, expect, it, vi } from "vitest";
import {
createPiSession,
type PiSession,
} from "../../../test/fixture/create-pi-session.ts";
const extensionPath = fileURLToPath(new URL("../index.ts", import.meta.url));
let session: PiSession | undefined;
afterEach(async () => {
await session?.dispose();
session = undefined;
vi.restoreAllMocks();
});
it("records a terminal transition after session shutdown", async () => {
session = await createPiSession({
extensionPaths: [extensionPath],
env: { PI_NOTES_DEBUG: "1" },
});
const runner = session.session.extensionRunner;
await runner.emit({ type: "session_start", reason: "startup" });
const command = session.extensions[0]!.commands.get("note");
if (!command) throw new Error("missing note command");
await command.handler("add failed delivery", runner.createCommandContext());
const ctx = runner.createCommandContext() as any;
const manager = session.session.sessionManager as any;
ctx.newSession = vi.fn(async (options) => {
await runner.emit({
type: "session_shutdown",
reason: "new",
});
manager.newSession();
await runner.emit({
type: "session_start",
reason: "new",
});
await options.withSession({
...ctx,
sendUserMessage: async () => {
throw new Error("delivery failed");
},
});
return { cancelled: false };
});
await command.handler("new 1", ctx);
await command.handler("add later", runner.createCommandContext());
await command.handler("add", runner.createCommandContext());
const directory = join(
session.env["XDG_STATE_HOME"] as string,
"pi-ext",
"debug",
"notes",
);
const files = readdirSync(directory);
expect(files).toHaveLength(2);
const events = files.flatMap((file) =>
readFileSync(join(directory, file), "utf8")
.trim()
.split("\n")
.map((line) => JSON.parse(line)),
);
const starts = events.filter(
(event) => event.event === "note.session_transition.start",
);
const terminals = events.filter(
(event) =>
event.event === "note.session_transition.finish" ||
event.event === "note.session_transition.error",
);
expect(starts).toHaveLength(1);
expect(events).toEqual(
expect.arrayContaining([
expect.objectContaining({
event: "note.change",
kind: "add",
outcome: "applied",
}),
expect.objectContaining({
event: "note.change",
kind: "add",
outcome: "invalid",
}),
]),
);
expect(terminals).toEqual([
expect.objectContaining({
extension: "notes",
event: "note.session_transition.finish",
kind: "new",
outcome: "delivery_failed",
spanId: starts[0]?.spanId,
durationMs: expect.any(Number),
}),
]);
});