tests/e2e/flows-pane-theme-sidebar.spec.ts
Rama main · réplica de lectura del repositorio original.
import { expect, test } from "@playwright/test";
import {
fulfillJson,
setupWorkflowsPage,
} from "./helpers/flows-pane-theme-fixtures";
test("app sidebar owns primary navigation and supports drag and keyboard resize", async ({
page,
}) => {
await setupWorkflowsPage(page, "light");
await page.route("**/api/memberships", (route) =>
fulfillJson(route, {
personal: { slug: "alex", name: "Alex", avatarUrl: null },
teams: [],
})
);
await page.route("**/api/billing/capacity", (route) =>
fulfillJson(route, {
version: "capacity_v2",
plan: { name: "Plus" },
account: { canManageBilling: true },
hostedUsage: {
includedRemainingCents: 0,
purchasedRemainingCents: 2_500,
spendableCents: 1_250,
},
})
);
await page.setViewportSize({ width: 1600, height: 900 });
await page.goto("/alex/workflows");
await page.waitForLoadState("networkidle");
const sidebar = page.getByTestId("app-sidebar");
await expect(sidebar).toBeVisible();
await expect(sidebar.getByText("Plus", { exact: true })).toBeVisible();
await expect(sidebar.getByText("$25.00 inference")).toBeVisible();
await expect(
sidebar.getByRole("link", { name: "Manage billing" })
).toBeVisible();
for (const destination of [
"control",
"automations",
"delivery",
"observe",
"agents",
"models",
"settings",
]) {
await expect(page.getByTestId(`app-nav-${destination}`)).toBeVisible();
}
// /workflows is a legacy subpath of the Automations nav item.
await expect(page.getByTestId("app-nav-automations")).toHaveAttribute(
"aria-current",
"page"
);
const initialBox = await sidebar.boundingBox();
expect(initialBox).not.toBeNull();
expect(initialBox!.width).toBeGreaterThan(120);
await expect(page.getByTestId("app-sidebar-toggle")).toHaveCount(0);
const resizer = page.getByTestId("app-sidebar-resizer");
await expect(resizer).toBeVisible();
const widthBeforeKeyboardResize = (await sidebar.boundingBox())!.width;
await resizer.press("ArrowRight");
const widthAfterKeyboardResize = (await sidebar.boundingBox())!.width;
expect(widthAfterKeyboardResize).toBe(widthBeforeKeyboardResize + 8);
const resizerBox = await resizer.boundingBox();
expect(resizerBox).not.toBeNull();
await page.mouse.move(
resizerBox!.x + resizerBox!.width / 2,
resizerBox!.y + 80
);
await page.mouse.down();
await page.mouse.move(56, resizerBox!.y + 80, { steps: 8 });
await page.mouse.up();
const widthAfterDrag = (await sidebar.boundingBox())!.width;
expect(widthAfterDrag).toBe(64);
await expect(sidebar).toHaveAttribute("data-compact", "true");
await expect(page.getByTestId("app-nav-automations")).toHaveAttribute(
"aria-label",
"Automations"
);
for (const compactLabel of [
".app-sidebar-section-label",
".app-sidebar-link-label",
".app-sidebar-footer-label",
]) {
await expect(sidebar.locator(compactLabel)).toHaveCount(0);
}
// The brand mark lives in the window chrome above the sidebar and stays
// visible there when the sidebar is compact.
const compactSidebarBox = await sidebar.boundingBox();
const brandLink = page.locator(
'.app-window-chrome a[aria-label="Mogplex home"]'
);
await expect(brandLink).toBeVisible();
const brandLinkBox = await brandLink.boundingBox();
expect(compactSidebarBox).not.toBeNull();
expect(brandLinkBox).not.toBeNull();
expect(brandLinkBox!.y + brandLinkBox!.height).toBeLessThanOrEqual(
compactSidebarBox!.y
);
});