e2e/clerk-appearance.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 };
// Opt in because this exercises the real Clerk development service and temporarily
// changes a synthetic demo account's preferences, which are restored afterward.
test("Clerk appearance stays in view when layouts change", async ({ page, request }) => {
test.skip(process.env.QC_E2E_CLERK !== "1", "Requires the provisioned Clerk demo roster");
await page.setViewportSize({ width: 1440, height: 1000 });
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.locator(".cl-userButtonTrigger").click();
await page.getByText("Manage account", { exact: true }).click();
await page.getByRole("button", { name: "Appearance", exact: true }).click();
const settings = page.locator(".appearance-settings-page");
await settings
.getByRole("radiogroup", { name: "Mode", exact: true })
.getByText("Dark", { exact: true })
.click();
const backdrop = page.locator(".cl-modalBackdrop");
await expect(backdrop).toHaveCSS("background-color", "rgba(0, 0, 0, 0.6)");
const layoutGroup = settings.getByRole("radiogroup", { name: "Layout", exact: true });
for (const layout of ["Sidebar", "Queue", "Navigation bar"]) {
// Click the visible label, just as a user does. Do not scroll again after the
// change: that could conceal the outer-container focus-scroll regression.
const label = layoutGroup.locator("label").filter({ hasText: layout });
await label.click();
await expect
.poll(() => page.evaluate(() => (window as ClerkWindow).Clerk!.user!.unsafeMetadata.layout))
.toBe(
(
{ Sidebar: "workbench", Queue: "desk", "Navigation bar": "classic" } as Record<
string,
string
>
)[layout],
);
await expect(label).toBeInViewport();
expect(await page.locator(".cl-scrollBox").evaluate((element) => element.scrollTop)).toBe(0);
}
await layoutGroup.getByRole("radio", { checked: true }).press("ArrowRight");
await expect
.poll(() => page.evaluate(() => (window as ClerkWindow).Clerk!.user!.unsafeMetadata.layout))
.toBe("workbench");
await expect(layoutGroup.locator("label").filter({ hasText: "Sidebar" })).toBeInViewport();
await settings
.getByRole("radiogroup", { name: "Mode", exact: true })
.getByText("Light", { exact: true })
.click();
await expect
.poll(() => page.evaluate(() => (window as ClerkWindow).Clerk!.user!.unsafeMetadata.theme))
.toBe("light");
await expect(backdrop).toHaveCSS("background-color", "rgba(0, 0, 0, 0.6)");
} finally {
await page.evaluate(async (saved) => {
await (window as ClerkWindow).Clerk!.user!.updateMetadata({
unsafeMetadata: Object.fromEntries(
["theme", "palette", "layout", "vision", "sidebar", "fontSize", "font"].map((key) => [
key,
saved[key] ?? null,
]),
),
});
}, original);
}
});