test(app): verify terminal profile artwork in the launch menu

Exercise the rendered SVG, dimensions, theme color, catalog artwork and fallback through the real browser app instead of inspecting hook results in JSDOM. The browser regression fails on main before the lookup fix.
This commit is contained in:
paseo-bot[bot]
2026-10-15 01:46:53 +02:00
parent d2b53ad263
commit cd7a396ac5
2 changed files with 71 additions and 31 deletions
@@ -0,0 +1,71 @@
import { ACP_PROVIDER_ICON_SVGS } from "../../src/assets/acp-provider-icons";
import { expect, test, type Page } from "../support/fixtures";
import { gotoAppShell } from "../support/helpers/app";
import { openNewWorkspaceComposer } from "../support/helpers/new-workspace";
import { openLaunchMenu } from "../support/helpers/new-workspace-launch";
import { seedWorkspace } from "../support/helpers/seed-client";
import { waitForSidebarHydration } from "../support/helpers/workspace-ui";
// Harmless commands: this journey opens the profile menu without launching them.
test.use({
e2eDaemonConfig: {
version: 1,
daemon: {
terminalProfiles: [
{ id: "antigravity", name: "Antigravity artwork", command: "/bin/sh", icon: "agy" },
{ id: "cursor", name: "Cursor artwork", command: "/bin/sh", icon: "cursor" },
{ id: "unknown", name: "Unknown artwork", command: "/bin/sh", icon: "unknown-icon" },
],
},
},
});
function profileIcon(page: Page, name: string) {
return page.getByRole("menuitem", { name: new RegExp(`^${name} artwork`) }).locator("svg");
}
async function expectBundledArtwork(page: Page, name: string, artwork: string) {
const icon = profileIcon(page, name);
await expect(icon).toBeVisible();
const expectedPaths = await page.evaluate((xml) => {
const document = new DOMParser().parseFromString(xml, "image/svg+xml");
return Array.from(document.querySelectorAll("path"), (path) => path.getAttribute("d")!);
}, artwork);
await expect(icon.locator("path")).toHaveCount(expectedPaths.length);
for (const [index, path] of expectedPaths.entries()) {
await expect(icon.locator("path").nth(index)).toHaveAttribute("d", path);
}
await expect(icon).toHaveAttribute("width", "14");
await expect(icon).toHaveAttribute("height", "14");
const terminalColor = await page
.getByRole("menuitem", { name: "Terminal", exact: true })
.locator("svg")
.evaluate((element) => getComputedStyle(element).stroke);
await expect(icon.locator("path").first()).toHaveCSS("fill", terminalColor);
}
async function expectUnknownArtworkFallback(page: Page) {
const icon = profileIcon(page, "Unknown");
await expect(icon).toBeVisible();
await expect(icon.locator('path[d="M12 8V4H8"]')).toHaveCount(1);
}
test("terminal profiles show bundled artwork while unknown icons keep the Bot fallback", async ({
page,
}) => {
const workspace = await seedWorkspace({ repoPrefix: "terminal-icons-" });
try {
await gotoAppShell(page);
await waitForSidebarHydration(page);
await openNewWorkspaceComposer(page, {
projectKey: workspace.projectKey,
projectDisplayName: workspace.projectDisplayName,
});
await openLaunchMenu(page);
await expectBundledArtwork(page, "Antigravity", ACP_PROVIDER_ICON_SVGS.agy);
await expectBundledArtwork(page, "Cursor", ACP_PROVIDER_ICON_SVGS.cursor);
await expectUnknownArtworkFallback(page);
} finally {
await workspace.cleanup();
}
});
@@ -1,7 +1,5 @@
// @vitest-environment jsdom
import { act, cleanup, renderHook } from "@testing-library/react";
import { TERMINAL_PROFILE_ICON_NAMES } from "@getpaseo/protocol/provider-icon-names";
import { ACP_PROVIDER_ICON_SVGS } from "@/assets/acp-provider-icons";
import { Bot } from "lucide-react-native";
import { SvgXml } from "react-native-svg";
import { afterEach, describe, expect, it } from "vitest";
@@ -86,32 +84,3 @@ it("updates collection consumers when their host snapshot arrives", () => {
act(() => replaceProviderSnapshotIcons(serverId, [{ provider, iconSvg: svg }]));
expect(renderIcon(result.current(provider))).toMatchObject({ props: { xml: svg } });
});
it("renders the shipped Antigravity SVG for a terminal profile icon", () => {
const { result } = renderHook(() => useProviderIcon("agy"));
expect(result.current).not.toBe(Bot);
expect(renderIcon(result.current)).toMatchObject({
type: SvgXml,
props: { xml: ACP_PROVIDER_ICON_SVGS.agy, width: 18, height: 18, color: "#123456" },
});
});
it.each(TERMINAL_PROFILE_ICON_NAMES)(
"renders terminal icon %s through collection consumers",
(name) => {
const { result } = renderHook(() => useProviderIcons());
expect(renderIcon(result.current(name))).toMatchObject({
type: SvgXml,
props: { xml: ACP_PROVIDER_ICON_SVGS[name as keyof typeof ACP_PROVIDER_ICON_SVGS] },
});
},
);
it("preserves catalog icons and the unknown icon fallback", () => {
const catalog = renderHook(() => useProviderIcon("cursor"));
expect(renderIcon(catalog.result.current)).toMatchObject({
type: SvgXml,
props: { xml: ACP_PROVIDER_ICON_SVGS.cursor },
});
expect(renderHook(() => useProviderIcon("definitely-not-a-real-icon")).result.current).toBe(Bot);
});