mirror of
https://github.com/block/buzz.git
synced 2026-08-18 06:50:31 +02:00
Fix agent panel desktop e2e expectations
This commit is contained in:
@@ -30,11 +30,8 @@ async function gotoApp(page: import("@playwright/test").Page) {
|
||||
}
|
||||
|
||||
async function openPersonaCatalog(page: import("@playwright/test").Page) {
|
||||
await page
|
||||
.getByTestId("agents-library-personas")
|
||||
.getByRole("button", { name: "New", exact: true })
|
||||
.click();
|
||||
await page.getByText("Choose from Catalog...").click();
|
||||
await page.getByTestId("new-agent-card").click();
|
||||
await page.getByRole("menuitem", { name: "Choose from Catalog..." }).click();
|
||||
}
|
||||
|
||||
async function getCatalogOrder(page: import("@playwright/test").Page) {
|
||||
@@ -184,23 +181,11 @@ test("built-in personas are chosen from the dialog and can be selected", async (
|
||||
);
|
||||
const fizzCard = page.getByTestId("persona-agent-row-builtin:fizz");
|
||||
await expect(fizzCard).toContainText("Fizz");
|
||||
await expect(fizzCard).toContainText("Built-in Agent");
|
||||
await expect(fizzCard).toContainText("Auto");
|
||||
await expect(
|
||||
page.getByTestId("persona-catalog-card-target-builtin:fizz"),
|
||||
).toHaveAttribute("aria-pressed", "true");
|
||||
await expect.poll(() => getCatalogOrder(page)).toEqual(initialCatalogOrder);
|
||||
|
||||
await page.getByTestId("persona-catalog-card-target-builtin:fizz").click();
|
||||
await expect(
|
||||
page
|
||||
.locator("[data-sonner-toast]")
|
||||
.filter({ hasText: "Deselected Fizz from My Agents." }),
|
||||
).toBeVisible();
|
||||
await expect(
|
||||
page.getByTestId("persona-catalog-card-target-builtin:fizz"),
|
||||
).toHaveAttribute("aria-pressed", "false");
|
||||
await expect.poll(() => getCatalogOrder(page)).toEqual(initialCatalogOrder);
|
||||
});
|
||||
|
||||
test("persona catalog can reopen from the populated library header", async ({
|
||||
|
||||
@@ -48,6 +48,23 @@ async function commands(page: import("@playwright/test").Page) {
|
||||
return page.evaluate(() => (window as E2eWindow).__BUZZ_E2E_COMMANDS__ ?? []);
|
||||
}
|
||||
|
||||
async function managedAgentStatus(
|
||||
page: import("@playwright/test").Page,
|
||||
pubkey: string,
|
||||
) {
|
||||
return page.evaluate(async (agentPubkey) => {
|
||||
const invoke = (window as E2eWindow).__BUZZ_E2E_INVOKE_MOCK_COMMAND__ as
|
||||
| ((
|
||||
command: string,
|
||||
payload?: Record<string, unknown>,
|
||||
) => Promise<Array<{ pubkey: string; status: string }>>)
|
||||
| undefined;
|
||||
if (!invoke) throw new Error("Mock invoke bridge is unavailable.");
|
||||
const agents = await invoke("list_managed_agents");
|
||||
return agents.find((agent) => agent.pubkey === agentPubkey)?.status ?? null;
|
||||
}, pubkey);
|
||||
}
|
||||
|
||||
/** Signed event templates the bridge recorded so far. */
|
||||
async function signedEvents(page: import("@playwright/test").Page) {
|
||||
return page.evaluate(
|
||||
@@ -57,29 +74,19 @@ async function signedEvents(page: import("@playwright/test").Page) {
|
||||
|
||||
async function setMesh(
|
||||
page: import("@playwright/test").Page,
|
||||
mesh: { admitted?: boolean; denyReason?: string },
|
||||
mesh: {
|
||||
admitted?: boolean;
|
||||
denyReason?: string;
|
||||
models?: Array<{ id: string; name: string | null }>;
|
||||
},
|
||||
) {
|
||||
await page.evaluate((m) => {
|
||||
(window as E2eWindow).__BUZZ_E2E_SET_MESH__?.(m);
|
||||
}, mesh);
|
||||
}
|
||||
|
||||
async function openManagedAgentActions(
|
||||
page: import("@playwright/test").Page,
|
||||
pubkey: string,
|
||||
) {
|
||||
const trigger = page.getByTestId(`managed-agent-actions-${pubkey}`);
|
||||
await trigger.scrollIntoViewIfNeeded();
|
||||
await trigger.focus();
|
||||
await trigger.press("Enter");
|
||||
await expect(trigger).toHaveAttribute("data-state", "open");
|
||||
}
|
||||
|
||||
async function openNewAgentMenu(page: import("@playwright/test").Page) {
|
||||
await page
|
||||
.getByTestId("agents-library-personas")
|
||||
.getByRole("button", { name: "New", exact: true })
|
||||
.click();
|
||||
await page.getByTestId("new-agent-card").click();
|
||||
}
|
||||
|
||||
test.beforeEach(async ({ page }) => {
|
||||
@@ -324,44 +331,56 @@ test("saved relay-mesh agents restart via the backend serve-target preflight", a
|
||||
|
||||
const row = page.getByTestId(`managed-agent-${pubkey}`);
|
||||
await expect(row).toContainText("Saved relay mesh agent");
|
||||
await expect(row).toContainText("running");
|
||||
await expect
|
||||
.poll(async () => managedAgentStatus(page, pubkey))
|
||||
.toBe("running");
|
||||
await page.getByRole("button", { name: "Done" }).click();
|
||||
await expect(page.getByRole("dialog", { name: "Agent created" })).toHaveCount(
|
||||
0,
|
||||
);
|
||||
|
||||
await openManagedAgentActions(page, pubkey);
|
||||
await page.getByRole("menuitem", { name: "Stop" }).click();
|
||||
await row.click();
|
||||
const primaryAction = page.getByTestId("user-profile-agent-primary-action");
|
||||
await expect(primaryAction).toContainText("Stop");
|
||||
await primaryAction.click();
|
||||
await expect
|
||||
.poll(async () => await commands(page))
|
||||
.toContain("stop_managed_agent");
|
||||
await expect(row).toContainText("stopped");
|
||||
await expect
|
||||
.poll(async () => managedAgentStatus(page, pubkey))
|
||||
.toBe("stopped");
|
||||
await expect(primaryAction).toContainText("Start agent");
|
||||
|
||||
// With a live serve target for the model, manual restart goes through:
|
||||
// the backend preflight re-resolves the target and the agent starts.
|
||||
await openManagedAgentActions(page, pubkey);
|
||||
await page.getByRole("menuitem", { name: "Spawn" }).click();
|
||||
await primaryAction.click();
|
||||
await expect
|
||||
.poll(async () => await commands(page))
|
||||
.toContain("start_managed_agent");
|
||||
await expect(row).toContainText("running");
|
||||
await expect
|
||||
.poll(async () => managedAgentStatus(page, pubkey))
|
||||
.toBe("running");
|
||||
await expect(primaryAction).toContainText("Stop");
|
||||
|
||||
await openManagedAgentActions(page, pubkey);
|
||||
await page.getByRole("menuitem", { name: "Stop" }).click();
|
||||
await expect(row).toContainText("stopped");
|
||||
await primaryAction.click();
|
||||
await expect
|
||||
.poll(async () => managedAgentStatus(page, pubkey))
|
||||
.toBe("stopped");
|
||||
await expect(primaryAction).toContainText("Start agent");
|
||||
|
||||
// Without a live serve target, the backend preflight rejects the start
|
||||
// with an actionable error, surfaced as a toast; the agent stays stopped.
|
||||
await setMesh(page, { models: [] });
|
||||
await openManagedAgentActions(page, pubkey);
|
||||
await page.getByRole("menuitem", { name: "Spawn" }).click();
|
||||
await primaryAction.click();
|
||||
|
||||
await expect(
|
||||
page
|
||||
.locator("[data-sonner-toast]")
|
||||
.filter({ hasText: "no live serve target is available" }),
|
||||
).toBeVisible();
|
||||
await expect(row).toContainText("stopped");
|
||||
await expect
|
||||
.poll(async () => managedAgentStatus(page, pubkey))
|
||||
.toBe("stopped");
|
||||
|
||||
await expect(
|
||||
page.evaluate(async (agentPubkey) => {
|
||||
@@ -380,5 +399,7 @@ test("saved relay-mesh agents restart via the backend serve-target preflight", a
|
||||
}
|
||||
}, pubkey),
|
||||
).resolves.toContain("no live serve target is available");
|
||||
await expect(row).toContainText("stopped");
|
||||
await expect
|
||||
.poll(async () => managedAgentStatus(page, pubkey))
|
||||
.toBe("stopped");
|
||||
});
|
||||
|
||||
@@ -293,10 +293,35 @@ async function expectWelcomeComposerBannerCompletesAfterPersonaMention(
|
||||
).toBeVisible();
|
||||
await expect(banner).toContainText("Nice work.");
|
||||
await expect(banner).not.toContainText("Try mentioning");
|
||||
await expect(banner).toHaveAttribute("data-state", "dismissing", {
|
||||
timeout: 5_000,
|
||||
});
|
||||
await expect(channelIntro).toBeVisible();
|
||||
const introBoxBeforeDismiss = await channelIntro.boundingBox();
|
||||
if (!introBoxBeforeDismiss) {
|
||||
throw new Error("Could not measure welcome intro before banner dismiss");
|
||||
}
|
||||
|
||||
await page.waitForFunction(
|
||||
({ beforeY }) => {
|
||||
const introElement = document.querySelector(
|
||||
'[data-testid="message-channel-intro"]',
|
||||
);
|
||||
if (!(introElement instanceof HTMLElement)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const bannerElement = document.querySelector(
|
||||
'[data-testid="welcome-composer-guide-banner"]',
|
||||
);
|
||||
const introMoved = introElement.getBoundingClientRect().y > beforeY + 4;
|
||||
if (!introMoved) {
|
||||
return false;
|
||||
}
|
||||
return (
|
||||
!(bannerElement instanceof HTMLElement) ||
|
||||
bannerElement.dataset.state === "dismissing"
|
||||
);
|
||||
},
|
||||
{ beforeY: introBoxBeforeDismiss.y },
|
||||
{ polling: "raf", timeout: 10_000 },
|
||||
);
|
||||
await expect(banner).toHaveCount(0, { timeout: 7_000 });
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user