Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -2,34 +2,38 @@ import { expect, test } from "@playwright/test";

test.describe("Smoke: Advanced Draft Persistence", () => {
test.beforeEach(async ({ page }) => {
// Drafts from prior specs/sessions must not leak in.
await page.addInitScript(() => window.localStorage.clear());
// Drafts from prior specs/sessions must not leak in. Clear storage ONCE —
// NOT via page.addInitScript(), which re-runs on every navigation including
// the page.reload() these tests depend on, wiping the draft mid-test.
await page.goto("/advanced");
await page.evaluate(() => window.localStorage.clear());
});

test("wizard edits survive a reload and show the restore notice", async ({ page }) => {
await page.goto("/advanced?step=1");

const entityName = page.getByDisplayValue("Product");
const entityName = page.getByPlaceholder("EntityName");
await expect(entityName).toHaveValue("Product");
await entityName.fill("Subscription");
// Outlive the 800ms persist debounce before reloading.
await page.waitForTimeout(1200);

await page.reload();

await expect(page.getByDisplayValue("Subscription")).toBeVisible();
await expect(page.getByPlaceholder("EntityName")).toHaveValue("Subscription");
await expect(page.getByTestId("advanced-draft-restored")).toBeVisible();
});

test("start fresh discards the draft", async ({ page }) => {
await page.goto("/advanced?step=1");
await page.getByDisplayValue("Product").fill("Subscription");
await page.getByPlaceholder("EntityName").fill("Subscription");
await page.waitForTimeout(1200);
await page.reload();
await expect(page.getByTestId("advanced-draft-restored")).toBeVisible();

await page.getByRole("button", { name: "start fresh" }).click();

await expect(page.getByDisplayValue("Product")).toBeVisible();
await expect(page.getByPlaceholder("EntityName")).toHaveValue("Product");
await page.reload();
await expect(page.getByTestId("advanced-draft-restored")).not.toBeVisible();
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,17 @@ test.describe("Smoke: Personalization modal keyboard a11y", () => {
await page.getByTestId("advanced-personalize-button").click();
await expect(page.getByRole("dialog")).toBeVisible();

// Tab through all focusable elements — focus must not escape to the page behind.
// Tab through focusable elements — focus must stay trapped inside the dialog,
// not escape to the page behind. Assert containment directly: comparing the
// focused element's innerText (CSS-uppercased) against the dialog's textContent
// (raw, mixed-case) was brittle and never matched — the original bug.
for (let i = 0; i < 10; i++) {
await page.keyboard.press("Tab");
const focused = page.locator(":focus");
const dialogHandle = page.getByRole("dialog");
await expect(dialogHandle).toContainText(await focused.innerText().catch(() => ""));
const trapped = await page.evaluate(() => {
const dialog = document.querySelector('[role="dialog"]');
return !!dialog && dialog.contains(document.activeElement);
});
expect(trapped, `focus escaped the dialog after Tab #${i + 1}`).toBe(true);
}

// Confirm: after Escape, some element on the page (opener button) receives focus.
Expand Down
Loading