Files
jb fd63b0ccec
fast-browser scenarios / Offline scenario contract tests (push) Failing after 44s
fast-browser scenarios / Local Chromium headless scenarios (push) Failing after 23s
fast-browser-with-jev
2026-09-20 12:24:08 -04:00

139 lines
5.1 KiB
TypeScript

import assert from "node:assert/strict";
import test from "node:test";
import { getSettingsListTheme, initTheme } from "@earendil-works/pi-coding-agent";
import { SettingsList, visibleWidth } from "@earendil-works/pi-tui";
import {
FAST_BROWSER_SETTING_IDS,
FAST_BROWSER_SETTING_LABELS,
FastBrowserSettingsView,
buildFastBrowserSettingItems,
fastBrowserSettingValue,
} from "./settings-view.ts";
const stripAnsi = (value: string): string => value.replace(/\u001b\[[0-9;]*m/g, "");
test.before(() => initTheme("dark", false));
function options(
draft: Record<string, unknown> = {},
inherited: Record<string, unknown> = {},
onEvent: (event: any) => void = () => {},
) {
return {
scope: "project" as const,
draft,
inherited,
onEvent,
};
}
test("renders native SettingsList values subdued on the right", () => {
const view = new FastBrowserSettingsView(options(
{ cdpUrl: "http://127.0.0.1:9333" },
{ allowedOrigins: ["https://example.test"], textModel: "fixture/small" },
));
const lines = view.render(80);
const endpoint = lines.find((line) => stripAnsi(line).includes("CDP endpoint"));
assert(endpoint);
assert.match(stripAnsi(endpoint), /CDP endpoint\s+http:\/\/127\.0\.0\.1:9333/);
// The native theme wraps an unselected value in its muted ANSI color.
assert.match(endpoint, /\u001b\[[0-9;]*mhttp:\/\/127\.0\.0\.1:9333\u001b\[[0-9;]*m/);
const inherited = fastBrowserSettingValue(
FAST_BROWSER_SETTING_IDS.textModel,
{},
{ textModel: "fixture/small" },
);
assert.equal(inherited, "(inherited) fixture/small");
});
test("displays unrestricted origin policy and inherited default values", () => {
assert.equal(fastBrowserSettingValue(
FAST_BROWSER_SETTING_IDS.allowedOrigins,
{ allowedOrigins: "*" },
{},
), "All web origins");
assert.equal(fastBrowserSettingValue(
FAST_BROWSER_SETTING_IDS.allowedOrigins,
{},
{ allowedOrigins: "*" },
), "(inherited) All web origins");
});
test("shows named profiles as explicit or inherited browser settings", () => {
const explicit = fastBrowserSettingValue(
FAST_BROWSER_SETTING_IDS.browserProfile,
{ browser: { mode: "launch", profile: "evebot" } },
{},
);
const inherited = fastBrowserSettingValue(
FAST_BROWSER_SETTING_IDS.browserProfile,
{},
{ browser: { mode: "launch", profile: "global-profile" } },
);
assert.equal(explicit, "evebot");
assert.equal(inherited, "(inherited) global-profile");
});
test("updates displayed rows with the latest draft after an edit", () => {
const draft: Record<string, unknown> = {};
const inherited = { textModel: "global/model" };
const view = new FastBrowserSettingsView(options(draft, inherited));
const before = view.render(80).join("\n");
assert.match(stripAnsi(before), /Auxiliary text model\s+\(inherited\) global\/model/);
draft.textModel = "project/model";
view.updateValues(draft, inherited);
const after = view.render(80).join("\n");
assert.match(stripAnsi(after), /Auxiliary text model\s+project\/model/);
});
test("keeps long URLs, paths, and CJK labels within narrow terminal widths", () => {
const view = new FastBrowserSettingsView(options(
{
cdpUrl: "http://127.0.0.1:9222",
python: "/very/long/path/项目/with/a/credential-free/python-executable",
browser: {
mode: "launch",
product: "chromium",
executablePath: "/very/long/path/项目/with/a/browser-executable",
startUrl: "https://example.test/非常長い開始URL/with/more/path",
},
},
{ allowedOrigins: ["https://example.test/非常長い起点"] },
));
for (const width of [60, 80, 120]) {
for (const line of view.render(width)) assert(visibleWidth(line) <= width, `${width}: ${stripAnsi(line)}`);
}
});
test("dispatches by stable id even when a displayed label changes", () => {
const events: any[] = [];
const items = buildFastBrowserSettingItems(options({}, {}, (event) => events.push(event)));
const first = items.find((item) => item.id === FAST_BROWSER_SETTING_IDS.cdpUrl);
assert(first);
first.label = "Endpoint label changed";
const list = new SettingsList(items, 10, getSettingsListTheme(), (id) => {
events.push({ kind: "edit", id });
}, () => {});
list.handleInput("\r");
assert.deepEqual(events, [{ kind: "edit", id: FAST_BROWSER_SETTING_IDS.cdpUrl }]);
assert.equal(FAST_BROWSER_SETTING_LABELS.cdpUrl, "CDP endpoint");
});
test("does not render explicit save or discard actions", () => {
const labels = buildFastBrowserSettingItems(options()).map((item) => item.label);
assert(!labels.includes("Save settings"));
assert(!labels.includes("Cancel"));
const view = new FastBrowserSettingsView(options());
assert.match(stripAnsi(view.render(120).join("\n")), /Changes save automatically/);
});
test("Escape dispatches cancel without mutating the draft", () => {
const draft = { textModel: "keep-me" };
const events: any[] = [];
const view = new FastBrowserSettingsView(options(draft, {}, (event) => events.push(event)));
view.handleInput("\u001b");
assert.deepEqual(events, [{ kind: "cancel" }]);
assert.deepEqual(draft, { textModel: "keep-me" });
});