e2e/sidebar-clerk.spec.ts
Linked repository file from this build.
import type { Clerk } from "@clerk/shared/types";
import { expect, test } from "@playwright/test";
type ClerkWindow = Window & { Clerk?: Clerk };
test("authenticated sidebar keeps view picker, notifications and Clerk profile together", async ({
page,
request,
}) => {
test.skip(process.env.QC_E2E_CLERK !== "1", "Requires the provisioned Clerk demo roster");
await page.setViewportSize({ width: 1280, height: 800 });
await page.goto("/dashboard");
const response = await request.post("/api/demo/view-as", { data: { staffId: "601" } });
expect(response.ok()).toBe(true);
const { ticket } = await response.json();
await page.evaluate((value) => sessionStorage.setItem("qccrm.demo-ticket", value), ticket);
await page.goto("/demo-switch");
await page.waitForURL("**/dashboard");
await page.waitForFunction(() => Boolean((window as ClerkWindow).Clerk?.user));
const original = await page.evaluate(() => (window as ClerkWindow).Clerk!.user!.unsafeMetadata);
try {
await page.evaluate(async () =>
(window as ClerkWindow).Clerk!.user!.updateMetadata({
unsafeMetadata: { layout: "workbench", sidebar: "hidden" },
}),
);
await page.reload();
await expect(page.locator("html")).toHaveAttribute("data-layout", "workbench");
const nav = page.locator(".app-nav");
await nav.getByRole("button", { name: "Pin sidebar open" }).hover();
const view = nav.getByRole("button", { name: "View as", exact: true });
await view.hover();
await expect(nav.locator(".app-nav-label").first()).toBeVisible();
await view.click();
const picker = nav.locator('.header-popover-panel[aria-label="View as"]');
await expect(picker.getByLabel("Profile", { exact: true })).toBeVisible();
expect((await picker.boundingBox())!.y).toBeGreaterThanOrEqual(0);
await picker.hover();
await expect(nav.locator(".app-nav-label").first()).toBeVisible();
await page.keyboard.press("Escape");
const bell = nav.getByRole("button", { name: /^Notifications/ });
await bell.hover();
await expect(nav.locator(".app-nav-label").first()).toBeVisible();
const profile = nav.locator(".cl-userButtonTrigger");
await profile.hover();
await expect(nav.locator(".app-nav-label").first()).toBeVisible();
const boxes = await Promise.all([
view.boundingBox(),
bell.boundingBox(),
profile.boundingBox(),
]);
expect(
Math.max(...boxes.map((box) => box!.y + box!.height / 2)) -
Math.min(...boxes.map((box) => box!.y + box!.height / 2)),
).toBeLessThan(2);
await profile.click();
const menu = page.locator(".cl-userButtonPopoverCard");
await expect(menu).toBeVisible();
await menu.hover();
await expect(nav.locator(".app-nav-label").first()).toBeVisible();
const box = (await menu.boundingBox())!;
expect(box.y).toBeGreaterThanOrEqual(0);
expect(box.y + box.height).toBeLessThanOrEqual(800);
await page.keyboard.press("Escape");
await page.evaluate(async () =>
(window as ClerkWindow).Clerk!.user!.updateMetadata({ unsafeMetadata: { sidebar: "icons" } }),
);
await page.reload();
await expect(page.locator("html")).toHaveAttribute("data-sidebar", "icons");
await nav.getByRole("button", { name: "View as", exact: true }).click();
await expect(nav).toHaveCSS("width", "56px");
await expect(nav.getByLabel("Profile", { exact: true })).toBeVisible();
await page.keyboard.press("Escape");
await nav.locator(".cl-userButtonTrigger").click();
await page.locator(".cl-userButtonPopoverCard").hover();
await expect(nav).toHaveCSS("width", "56px");
} finally {
await page.evaluate(async (saved) => {
await (window as ClerkWindow).Clerk!.user!.updateMetadata({
unsafeMetadata: { layout: saved.layout ?? null, sidebar: saved.sidebar ?? null },
});
}, original);
}
});