Files
buzz/desktop/tests/e2e/persona-model-combobox-screenshots.spec.ts
cls 9dfa06ffee
Docker image / Build (linux/amd64) (push) Has been cancelled
Docker image / Build (linux/arm64) (push) Has been cancelled
Docker image / Merge release multi-arch manifest (push) Has been cancelled
Docker image / Merge debug multi-arch manifest (push) Has been cancelled
Docker image / Build public push gateway (linux/amd64) (push) Has been cancelled
Docker image / Build public push gateway (linux/arm64) (push) Has been cancelled
Docker image / Publish public push gateway image (push) Has been cancelled
Sprig image / Build (linux/amd64) (push) Has been cancelled
Sprig image / Build (linux/arm64) (push) Has been cancelled
Sprig image / Merge multi-arch manifest (push) Has been cancelled
Harbor Buzz Orchestra / Python tests and lint (push) Has been cancelled
CI / Detect Changed Paths (push) Has been cancelled
CI / Rust Lint (push) Has been cancelled
CI / Unit Tests (push) Has been cancelled
CI / Desktop Core (push) Has been cancelled
CI / Desktop Smoke E2E (1) (push) Has been cancelled
CI / Desktop Smoke E2E (2) (push) Has been cancelled
CI / Desktop Smoke E2E (3) (push) Has been cancelled
CI / Desktop Smoke E2E (4) (push) Has been cancelled
CI / Desktop (push) Has been cancelled
CI / Desktop E2E Relay (push) Has been cancelled
CI / Desktop E2E Integration (1/2) (push) Has been cancelled
CI / Desktop E2E Integration (2/2) (push) Has been cancelled
CI / Desktop E2E Integration (push) Has been cancelled
CI / Backend Integration (relay e2e) (push) Has been cancelled
CI / Relay E2E (push) Has been cancelled
CI / Web (push) Has been cancelled
CI / Mobile (push) Has been cancelled
CI / Security (push) Has been cancelled
CI / Dead Token Reference Guard (push) Has been cancelled
CI / Server Cross-Compile (aarch64-unknown-linux-musl) (push) Has been cancelled
CI / Server Cross-Compile (x86_64-unknown-linux-musl) (push) Has been cancelled
CI / Windows Rust (x86_64-pc-windows-msvc) (push) Has been cancelled
CI / Desktop Build (macOS) (push) Has been cancelled
helm chart / lint + unittest + render matrix (push) Has been cancelled
helm chart / install on kind (gated) (push) Has been cancelled
helm chart / publish chart to GHCR (push) Has been cancelled
Mesh Lifecycle / Relay-Driven Mesh Lifecycle Smoke (push) Has been cancelled
Sprig / Build (aarch64-unknown-linux-musl) (push) Has been cancelled
Sprig / Build (x86_64-unknown-linux-musl) (push) Has been cancelled
Sprig / Publish rolling release (push) Has been cancelled
Sprig / Publish tagged release (push) Has been cancelled
feat: import Chinese-localized Buzz source snapshot
Signed-off-by: cls_宁波本机 <908705107@qq.com>
2026-08-13 18:34:25 +08:00

152 lines
4.9 KiB
TypeScript

import { expect, test } from "@playwright/test";
import { installMockBridge } from "../helpers/bridge";
import { waitForAnimations } from "../helpers/animations";
const SHOTS = "test-results/persona-model-combobox";
async function waitForInvokeBridge(page: import("@playwright/test").Page) {
await page.waitForFunction(
() => {
const w = window as Window & {
__BUZZ_E2E_INVOKE_MOCK_COMMAND__?: unknown;
__TAURI_INTERNALS__?: { invoke?: unknown };
};
return (
typeof w.__BUZZ_E2E_INVOKE_MOCK_COMMAND__ === "function" ||
typeof w.__TAURI_INTERNALS__?.invoke === "function"
);
},
null,
{ timeout: 8_000 },
);
}
/**
* Open the Agents view, click "New agent", and open the persona create dialog.
* Returns the dialog locator.
*/
async function openNewPersonaDialog(page: import("@playwright/test").Page) {
await page.goto("/", { waitUntil: "domcontentloaded" });
await waitForInvokeBridge(page);
await page.getByTestId("open-agents-view").click();
await expect(page.getByTestId("agents-library-personas")).toBeVisible({
timeout: 8_000,
});
await page.getByTestId("new-agent-card").click();
const dialog = page.getByTestId("persona-dialog");
await expect(dialog).toBeVisible({ timeout: 8_000 });
await dialog.getByRole("tab", { name: "Customize for this agent" }).click();
return dialog;
}
/**
* The mock bridge selects Goose as the default runtime (available + preferred).
* Wait for model discovery to populate the combobox options so the list is
* non-trivial before opening the popover.
*/
async function waitForModelCombobox(
dialog: import("@playwright/test").Locator,
) {
// The model field only appears after a runtime is selected. Goose is the
// mock default; the field should appear without manual interaction.
const trigger = dialog.getByRole("combobox", { name: /model/i });
await expect(trigger).toBeVisible({ timeout: 8_000 });
return trigger;
}
test.describe("persona model combobox screenshots", () => {
test.use({ viewport: { width: 1280, height: 900 } });
test.beforeEach(async ({ page }) => {
page.on("pageerror", (err) => {
console.error(
"PAGE ERROR:",
err.message,
err.stack?.split("\n").slice(0, 5).join("\n"),
);
});
page.on("console", (msg) => {
if (msg.type() === "error") {
console.error("CONSOLE ERROR:", msg.text().slice(0, 500));
}
});
await installMockBridge(page);
});
test("01 — closed trigger (model not yet selected)", async ({ page }) => {
const dialog = await openNewPersonaDialog(page);
await waitForModelCombobox(dialog);
await waitForAnimations(page);
await dialog.screenshot({ path: `${SHOTS}/01-closed-trigger.png` });
});
test("02 — open popover with full model list", async ({ page }) => {
const dialog = await openNewPersonaDialog(page);
const trigger = await waitForModelCombobox(dialog);
await trigger.click();
// Wait for the search input to appear (popover is open).
await expect(page.getByPlaceholder("Search models…")).toBeVisible({
timeout: 5_000,
});
// Wait for model discovery to populate at least one non-loading row.
await expect(
page.getByRole("button", { name: /claude|gpt|default/i }).first(),
).toBeVisible({ timeout: 8_000 });
await waitForAnimations(page);
await dialog.screenshot({ path: `${SHOTS}/02-open-full-list.png` });
});
test("03 — filtered results (query: gpt)", async ({ page }) => {
const dialog = await openNewPersonaDialog(page);
const trigger = await waitForModelCombobox(dialog);
await trigger.click();
const searchInput = page.getByPlaceholder("Search models…");
await expect(searchInput).toBeVisible({ timeout: 5_000 });
await expect(
page.getByRole("button", { name: /claude|gpt|default/i }).first(),
).toBeVisible({ timeout: 8_000 });
await searchInput.fill("gpt");
// At least one GPT option should be visible; Claude options gone.
await expect(
page.getByRole("button", { name: /gpt/i }).first(),
).toBeVisible({ timeout: 3_000 });
await waitForAnimations(page);
await dialog.screenshot({ path: `${SHOTS}/03-filtered-gpt.png` });
});
test("04 — empty state (no models match)", async ({ page }) => {
const dialog = await openNewPersonaDialog(page);
const trigger = await waitForModelCombobox(dialog);
await trigger.click();
const searchInput = page.getByPlaceholder("Search models…");
await expect(searchInput).toBeVisible({ timeout: 5_000 });
await expect(
page.getByRole("button", { name: /claude|gpt|default/i }).first(),
).toBeVisible({ timeout: 8_000 });
await searchInput.fill("zzznomatch");
await expect(page.getByText("No models match")).toBeVisible({
timeout: 3_000,
});
await waitForAnimations(page);
await dialog.screenshot({ path: `${SHOTS}/04-empty-state.png` });
});
});