import { test, expect, Page } from './fixtures'; const PASSWORD = 'supersecret123'; const uniqueEmail = () => `account-${Date.now().toString(36)}${Math.random().toString(36).slice(2, 7)}@example.com`; // Registering closes the auth modal and returns to the storefront, signed in. // Returns the address so a test can assert the right account is shown. // // The wait is generous because registration is a bcrypt round-trip rather than // a render: about half a second unloaded, and past Playwright's 5s default when // the suite's workers all register at once. async function registerCustomer(page: Page): Promise { const email = uniqueEmail(); await page.goto('/register'); await page.getByRole('textbox', { name: 'Email' }).fill(email); await page.getByRole('textbox', { name: 'First name' }).fill('Test'); await page.getByRole('textbox', { name: 'Last name' }).fill('Customer'); await page.getByLabel('Password').fill(PASSWORD); await page.getByRole('button', { name: 'Create account' }).click(); await expect(page.getByRole('button', { name: 'My Account' })).toBeVisible({ timeout: 20000 }); return email; } const accountModal = (page: Page) => page.getByRole('dialog', { name: 'My Account' }); async function closeAccount(page: Page) { await accountModal(page).getByRole('button', { name: 'Close' }).click(); await expect(accountModal(page)).toBeHidden(); } test.describe('My Account opens as a modal', () => { test('opens over the storefront and closes back to it, filters and all', async ({ page }) => { await registerCustomer(page); // A filtered view, to prove closing restores where the customer actually // was rather than a bare storefront. await page.goto('/?max_price=50000'); await expect(page.getByRole('button', { name: 'My Account' })).toBeVisible(); await page.getByRole('button', { name: 'My Account' }).click(); await expect(accountModal(page)).toBeVisible(); // Still a real, linkable URL rather than hidden view state. await expect(page).toHaveURL(/\/account/); await closeAccount(page); await expect(page).toHaveURL(/max_price=50000/); }); test('the browser back button closes it, the same as the close control', async ({ page }) => { await registerCustomer(page); await page.goto('/?max_price=50000'); await page.getByRole('button', { name: 'My Account' }).click(); await expect(accountModal(page)).toBeVisible(); await page.goBack(); await expect(accountModal(page)).toBeHidden(); await expect(page).toHaveURL(/max_price=50000/); }); test('a direct visit renders the storefront behind it, so closing lands somewhere real', async ({ page }) => { await registerCustomer(page); // A bookmark, or the link in a verification email. There is no page behind // in this case, which is what used to make /account a dead end. await page.goto('/account'); await expect(accountModal(page)).toBeVisible(); await expect(page.getByRole('heading', { name: 'Redefined Designs' })).toBeVisible(); await closeAccount(page); await expect(page).toHaveURL(/\/$/); await expect(page.getByRole('button', { name: 'My Account' })).toBeVisible(); }); test('survives a reload, since it is a route rather than view state', async ({ page }) => { const email = await registerCustomer(page); await page.goto('/?max_price=50000'); await page.getByRole('button', { name: 'My Account' }).click(); await expect(accountModal(page)).toBeVisible(); await page.reload(); await expect(accountModal(page)).toBeVisible(); await expect(accountModal(page)).toContainText(email); }); test('shows the signed-in account and its settings', async ({ page }) => { const email = await registerCustomer(page); await page.goto('/account'); const modal = accountModal(page); await expect(modal).toContainText(email); // The orders table lives at /orders now. What the account view still owes // the customer is a way to reach it. await expect(modal.getByRole('button', { name: 'View order history' })).toBeVisible(); // Scoped to the modal: the storefront behind it has a theme switch of its // own, so an unscoped switch locator would be ambiguous. await expect(modal.getByRole('switch')).toHaveCount(2); }); test('deleting the account does not leave the page behind it looking signed in', async ({ page }) => { await registerCustomer(page); await page.goto('/account'); await accountModal(page).getByRole('button', { name: 'Delete my account' }).click(); await page.getByRole('dialog', { name: 'Delete your account?' }) .getByRole('button', { name: 'Delete my account' }).click(); // The storefront is rendered behind the modal, so a session left in place // would visibly go on offering My Account for an account that is gone. await expect(page.getByRole('button', { name: 'Sign up' })).toBeVisible(); await expect(page.getByRole('button', { name: 'My Account' })).toBeHidden(); await expect(page).toHaveURL(/\/$/); }); test('stays usable on a phone, with the close control in reach', async ({ page }) => { await registerCustomer(page); await page.setViewportSize({ width: 390, height: 664 }); await page.goto('/account'); const modal = accountModal(page); await expect(modal).toBeVisible(); // The view is taller than the viewport, so the body scrolls rather than // pushing the title and close control off-screen. await expect(modal.getByRole('button', { name: 'Close' })).toBeInViewport(); await expect(modal.getByRole('button', { name: 'View order history' })).toBeVisible(); await closeAccount(page); await expect(page).toHaveURL(/\/$/); }); });