import { test, expect } from './fixtures'; // These edit global settings that other specs depend on — cart expiry above // all — so they run serially and put everything back afterwards. test.describe.configure({ mode: 'serial' }); const DEFAULTS = { cartExpiryHours: 24, verifyTokenHours: 24, passwordResetHours: 1, greetingFormat: 'Hi {{firstName}},', greetingFallback: 'Hi,' }; async function openSettings(page: import('@playwright/test').Page) { await page.goto('/admin'); await page.getByRole('tab', { name: 'Settings' }).click(); await expect(page.getByRole('heading', { name: 'Link lifetimes' })).toBeVisible(); } test.describe('The email settings', () => { test.afterEach(async ({ page }) => { await page.request.put('/api/admin/settings', { data: DEFAULTS }); }); test('offers the link lifetimes and the greeting alongside cart expiry', async ({ page }) => { await openSettings(page); // antd renders a stepped InputNumber to the step's precision, so "24.0". await expect(page.getByLabel('Cart expiry (hours)')).toHaveValue('24.0'); await expect(page.getByLabel('Email verification link (hours)')).toHaveValue('24.0'); await expect(page.getByLabel('Password reset link (hours)')).toHaveValue('1.0'); await expect(page.getByLabel('Greeting format')).toHaveValue('Hi {{firstName}},'); await expect(page.getByLabel('Fallback, when there is no first name')).toHaveValue('Hi,'); }); test('saves a new lifetime, and the server keeps it', async ({ page }) => { await openSettings(page); await page.getByLabel('Password reset link (hours)').fill('3'); await page.getByRole('button', { name: 'Save' }).click(); await expect(page.getByText('Settings saved')).toBeVisible(); const stored = await (await page.request.get('/api/admin/settings')).json(); expect(stored.passwordResetHours).toBe(3); }); // The whole reason the placeholder exists: the sentence in the email is // rendered from the setting rather than written out beside it. test('the password reset preview states the configured lifetime', async ({ page }) => { await page.request.put('/api/admin/settings', { data: { passwordResetHours: 2 } }); await page.goto('/admin'); await page.getByRole('tab', { name: 'Emails' }).click(); await page.getByRole('tab', { name: /Password reset/ }).click(); const preview = page.frameLocator('iframe[title="Password reset preview"]'); await expect(preview.getByText('2 hours')).toBeVisible(); }); test('the preview greets through the configured format', async ({ page }) => { await page.request.put('/api/admin/settings', { data: { greetingFormat: 'Salutations {{firstName}}!' } }); await page.goto('/admin'); await page.getByRole('tab', { name: 'Emails' }).click(); await page.getByRole('tab', { name: /Email verification/ }).click(); const preview = page.frameLocator('iframe[title="Email verification preview"]'); await expect(preview.getByText('Salutations Ada!')).toBeVisible(); }); test('refuses a lifetime of zero rather than reporting a save', async ({ page }) => { await openSettings(page); await page.getByLabel('Password reset link (hours)').fill('0'); await page.getByRole('button', { name: 'Save' }).click(); await expect(page.getByText('Settings saved')).toHaveCount(0); }); });