fix: reset the header and return home when a customer logs out (#21)
Logging out destroyed the server session and navigated home, but never told CustomerAuthContext, so `customer` stayed in React state and the header kept offering "My Account" instead of "Log in" and "Sign up". A reload appeared to fix it, because fetchMe then returned null, which is why the symptom looked intermittent. The cart badge had the same cause: CartContext only clears its items once `customer` goes null. Logout now lives on the auth context, which clears `customer` itself rather than triggering a refetch — a refetch would leave a window where the session is gone but the UI still shows the customer signed in. logoutCustomer also ignored res.ok. A failed logout leaves the session cookie valid, so reporting success signed the customer back in on their next reload. It now rejects, and the account page reports the failure and stays put instead of pretending. Logout is not routed through handle() because the endpoint answers 204 with no body. Navigation uses replace, so Back no longer returns to the account page, which would only bounce to /login now the session is gone. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -35,4 +35,73 @@ test.describe('Customer accounts', () => {
|
||||
await page.getByRole('button', { name: 'Log in' }).click();
|
||||
await expect(page.getByText('invalid email or password')).toBeVisible();
|
||||
});
|
||||
|
||||
test('logging out returns to the home page and resets the header', async ({ page }) => {
|
||||
const email = uniqueEmail();
|
||||
await page.goto('/register');
|
||||
await page.getByRole('textbox', { name: 'Email' }).fill(email);
|
||||
await page.getByLabel('Password').fill('supersecret123');
|
||||
await page.getByRole('button', { name: 'Create account' }).click();
|
||||
await expect(page).toHaveURL(/\/account/);
|
||||
|
||||
await page.getByRole('button', { name: 'Log out' }).click();
|
||||
|
||||
await expect(page).toHaveURL(/\/$/);
|
||||
await expect(page.getByRole('button', { name: 'Log in' })).toBeVisible();
|
||||
await expect(page.getByRole('button', { name: 'Sign up' })).toBeVisible();
|
||||
await expect(page.getByRole('button', { name: 'My Account' })).toBeHidden();
|
||||
});
|
||||
|
||||
test('the logged-out header survives a reload', async ({ page }) => {
|
||||
const email = uniqueEmail();
|
||||
await page.goto('/register');
|
||||
await page.getByRole('textbox', { name: 'Email' }).fill(email);
|
||||
await page.getByLabel('Password').fill('supersecret123');
|
||||
await page.getByRole('button', { name: 'Create account' }).click();
|
||||
await expect(page).toHaveURL(/\/account/);
|
||||
|
||||
await page.getByRole('button', { name: 'Log out' }).click();
|
||||
await expect(page.getByRole('button', { name: 'Log in' })).toBeVisible();
|
||||
|
||||
// Proves the server session was actually destroyed, rather than the header
|
||||
// merely being repainted from stale client state.
|
||||
await page.reload();
|
||||
await expect(page.getByRole('button', { name: 'Log in' })).toBeVisible();
|
||||
await expect(page.getByRole('button', { name: 'My Account' })).toBeHidden();
|
||||
});
|
||||
|
||||
test('logging out does not leave the account page on the back stack', async ({ page }) => {
|
||||
const email = uniqueEmail();
|
||||
await page.goto('/register');
|
||||
await page.getByRole('textbox', { name: 'Email' }).fill(email);
|
||||
await page.getByLabel('Password').fill('supersecret123');
|
||||
await page.getByRole('button', { name: 'Create account' }).click();
|
||||
await expect(page).toHaveURL(/\/account/);
|
||||
|
||||
await page.getByRole('button', { name: 'Log out' }).click();
|
||||
await expect(page).toHaveURL(/\/$/);
|
||||
|
||||
await page.goBack();
|
||||
await expect(page).not.toHaveURL(/\/account/);
|
||||
});
|
||||
|
||||
test('a failed logout says so instead of appearing to succeed', async ({ page }) => {
|
||||
const email = uniqueEmail();
|
||||
await page.goto('/register');
|
||||
await page.getByRole('textbox', { name: 'Email' }).fill(email);
|
||||
await page.getByLabel('Password').fill('supersecret123');
|
||||
await page.getByRole('button', { name: 'Create account' }).click();
|
||||
await expect(page).toHaveURL(/\/account/);
|
||||
|
||||
await page.route('**/api/customers/logout', (route) =>
|
||||
route.fulfill({ status: 500, contentType: 'application/json', body: '{"error":"internal error"}' })
|
||||
);
|
||||
|
||||
await page.getByRole('button', { name: 'Log out' }).click();
|
||||
|
||||
// The session cookie is still valid, so pretending to be logged out would
|
||||
// silently log the customer back in on their next reload.
|
||||
await expect(page.getByText(/couldn't log out/i)).toBeVisible();
|
||||
await expect(page).toHaveURL(/\/account/);
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user