Luigit
repositories / pi-ext

pi-ext

bugabingas pi extensions

owned by admin

extensions/strata/__tests__/widget.test.ts

Raw
import type { Theme } from "@earendil-works/pi-coding-agent";
import {
	getOsc8LinkAtColumn,
	stripTerminalSequences,
	visibleWidth,
} from "@earendil-works/pi-tui";
import { describe, expect, it } from "vitest";
import {
	createStrataWidget,
	renderStrataWidget,
	STRATA_ICON,
	type StrataPhase,
	type StrataWidgetState,
} from "../widget.js";

function testTheme() {
	let generation = 0;
	const calls: Array<{ color: string; text: string }> = [];
	const theme = {
		bold: (text: string) => `\x1b[1m${text}\x1b[22m`,
		fg: (color: string, text: string) => {
			calls.push({ color, text });
			return `\x1b[${31 + generation}m${text}\x1b[39m`;
		},
	} as Theme;
	return { theme, calls, change: () => generation++ };
}

function readyState(): StrataWidgetState {
	return {
		phase: "Ready",
		source: { kind: "base", ref: "trunk" },
		url: "http://127.0.0.1:43210/?token=trusted",
		reviewed: 8,
		totalHunks: 24,
		layers: 4,
		comments: 2,
	};
}

describe("Strata Pi widget", () => {
	it("renders the verified icon, semantic state, counts, action, and full link target", () => {
		const { theme } = testTheme();
		const lines = renderStrataWidget(readyState(), theme, 160);
		const visible = lines.map(stripTerminalSequences);
		expect(visible).toEqual([
			`▏ ${STRATA_ICON} STRATA  ● Ready  · base trunk  · 8/24 reviewed  · 4 layers  · 2 comments`,
			"▏ http://127.0.0.1:43210  /strata cancel",
		]);
		expect(lines[1]).toContain("\x1b]8;;http://127.0.0.1:43210/?token=trusted");
		expect(visible.join("\n")).not.toContain("full-authentication-token");
	});

	it("bounds every row and drops secondary details before state and access", () => {
		const { theme } = testTheme();
		for (const width of [1, 4, 12, 24, 36, 48, 80, 160]) {
			const lines = renderStrataWidget(readyState(), theme, width);
			expect(lines).toHaveLength(2);
			for (const line of lines)
				expect(visibleWidth(line)).toBeLessThanOrEqual(width);
		}
		const narrow = renderStrataWidget(readyState(), theme, 36).map(
			stripTerminalSequences,
		);
		expect(narrow[0]).toContain("Ready");
		expect(narrow[0]).not.toContain("comments");
		expect(narrow[1]).toContain("http://127.0.0.1:43210");
	});

	it("renders every lifecycle state with semantic color and its contextual action", () => {
		const { theme, calls } = testTheme();
		const cases: Array<[StrataPhase, string, string]> = [
			["Collecting", "Capturing Git snapshot · /strata cancel", "accent"],
			["Planning", "Organizing review layers · /strata cancel", "accent"],
			["Ready", "/strata cancel", "success"],
			["Answering", "Answering browser question", "accent"],
			["Refreshing", "Refreshing snapshot", "accent"],
			["Stale", "Refresh in browser", "warning"],
			["Feedback sent", "Feedback queued for Pi", "success"],
			["Error", "provider failed", "error"],
			["Closed", "Run /strata to reopen", "muted"],
		];
		for (const [phase, action, color] of cases) {
			calls.length = 0;
			const lines = renderStrataWidget(
				{
					...readyState(),
					phase,
					...(phase === "Error" ? { error: "provider failed" } : {}),
					...(phase === "Closed" ? { url: undefined } : {}),
				},
				theme,
				160,
			).map(stripTerminalSequences);
			expect(lines[0]).toContain(phase);
			expect(lines[1]).toContain(action);
			expect(calls).toContainEqual({ color, text: `● ${phase}` });
		}
	});

	it("drops the collecting and planning cancel hint when width is tight", () => {
		const { theme } = testTheme();
		for (const phase of ["Collecting", "Planning"] as const) {
			const wide = renderStrataWidget({ phase }, theme, 80).map(
				stripTerminalSequences,
			);
			const narrow = renderStrataWidget({ phase }, theme, 28).map(
				stripTerminalSequences,
			);
			expect(wide[1]).toContain("/strata cancel");
			expect(narrow[1]).not.toContain("/strata cancel");
		}
	});

	it("neutralizes terminal controls without changing the trusted authenticated target", () => {
		const { theme } = testTheme();
		const trusted = "http://127.0.0.1:43210/?token=trusted";
		const lines = renderStrataWidget(
			{
				...readyState(),
				phase: "Error",
				url: trusted,
				source: { kind: "base", ref: "bad\x1b]8;;https://evil.example\x07ref" },
				error: "failed\r\n\x1b]8;;https://evil.example\x07click\x1b]8;;\x07",
			},
			theme,
			240,
		);
		const links = lines.flatMap((line) =>
			Array.from({ length: visibleWidth(line) }, (_, column) =>
				getOsc8LinkAtColumn(line, column),
			).filter((value): value is string => value !== undefined),
		);
		expect(new Set(links)).toEqual(new Set([trusted]));
		expect(stripTerminalSequences(lines.join("\n"))).not.toMatch(
			/[\r\n].*[\r\n]/,
		);
	});

	it("recomputes theme styling after invalidation", () => {
		const { theme, change } = testTheme();
		const widget = createStrataWidget(readyState(), theme);
		const before = widget.render(120);
		change();
		widget.invalidate();
		const after = widget.render(120);
		expect(after).not.toEqual(before);
		expect(after.map(stripTerminalSequences)).toEqual(
			before.map(stripTerminalSequences),
		);
	});
});