Stable twin of #1071. Three specs acquire an admin token with `const body = await res.json(); return body.token`. On this branch too the admin login sets the JWT as the httpOnly `admin_token` cookie and responds with `res.json({ user })` — verified in auth.js on stable, not assumed from main — so the token is undefined and each spec fails at its first assertion, before exercising anything it was written to cover. Cookie and Authorization: Bearer are interchangeable server-side, so the helpers read the value back out of the context cookie jar and keep threading it as a Bearer. Every downstream call is unchanged. Verification is weaker than the main twin's, deliberately: the three spec files are byte-identical to the ones measured there (0 passed / 6 failed before, 3 passed / 3 failed after, against a live stack), and they compile and enumerate on this branch. Standing up a full stable compose stack to re-measure test-only changes was not worth it — say the word if you want that done before merge. The remaining failures are UI staleness, not auth, and are not addressed here. No CI workflow runs tests/e2e on this branch either, which is why this rotted unnoticed. Claude-Session: https://claude.ai/code/session_01Ra4hcsYiKuQLbbRsg6EjAc Co-authored-by: Paul Nothaft <[email protected]>
157 lines
5.3 KiB
TypeScript
157 lines
5.3 KiB
TypeScript
import { test, expect, Page } from '@playwright/test';
|
|
|
|
const ADMIN_EMAIL = process.env.ADMIN_EMAIL || '[email protected]';
|
|
const ADMIN_PASSWORD = process.env.ADMIN_PASSWORD || 'Admin!234';
|
|
|
|
async function getAdminToken(page: Page): Promise<string> {
|
|
const res = await page.request.post('/api/auth/admin/login', {
|
|
data: { username: ADMIN_EMAIL, password: ADMIN_PASSWORD },
|
|
});
|
|
expect(res.ok()).toBeTruthy();
|
|
// The admin JWT is delivered as the httpOnly `admin_token` cookie, not in
|
|
// the response body. Server-side the cookie and an Authorization: Bearer
|
|
// header are interchangeable, so read it back out of the context jar and
|
|
// keep threading it as a Bearer — every downstream call stays as it was.
|
|
const cookies = await page.context().cookies();
|
|
const token = cookies.find((c) => c.name === 'admin_token')?.value;
|
|
expect(token, 'admin_token cookie missing from the login response').toBeTruthy();
|
|
return token as string;
|
|
}
|
|
|
|
async function updateEventSettings(
|
|
page: Page,
|
|
token: string,
|
|
settings: Record<string, boolean>
|
|
) {
|
|
const res = await page.request.put('/api/admin/settings/general', {
|
|
headers: {
|
|
Authorization: `Bearer ${token}`,
|
|
'Content-Type': 'application/json',
|
|
},
|
|
data: settings,
|
|
});
|
|
expect(res.ok()).toBeTruthy();
|
|
}
|
|
|
|
test.describe('Optional email fields in event creation (#217)', () => {
|
|
test('event creation succeeds with empty emails when set to optional', async ({ page }) => {
|
|
const token = await getAdminToken(page);
|
|
|
|
// Disable email requirements
|
|
await updateEventSettings(page, token, {
|
|
event_require_customer_email: false,
|
|
event_require_admin_email: false,
|
|
});
|
|
|
|
try {
|
|
// Create event with empty email fields
|
|
const eventRes = await page.request.post('/api/admin/events', {
|
|
headers: {
|
|
Authorization: `Bearer ${token}`,
|
|
'Content-Type': 'application/json',
|
|
},
|
|
data: {
|
|
event_type: 'wedding',
|
|
event_name: `E2E Optional Emails ${Date.now()}`,
|
|
event_date: new Date(Date.now() + 7 * 86400000).toISOString().slice(0, 10),
|
|
customer_name: 'Test Host',
|
|
customer_email: '',
|
|
admin_email: '',
|
|
password: 'TestPass123!',
|
|
expiration_days: 30,
|
|
},
|
|
});
|
|
|
|
const body = await eventRes.json();
|
|
expect(eventRes.ok(), `Expected 200 but got ${eventRes.status()}: ${JSON.stringify(body)}`).toBeTruthy();
|
|
expect(body.id).toBeTruthy();
|
|
|
|
// Cleanup: delete the created event
|
|
await page.request.delete(`/api/admin/events/${body.id}`, {
|
|
headers: { Authorization: `Bearer ${token}` },
|
|
});
|
|
} finally {
|
|
// Revert settings to required
|
|
await updateEventSettings(page, token, {
|
|
event_require_customer_email: true,
|
|
event_require_admin_email: true,
|
|
});
|
|
}
|
|
});
|
|
|
|
test('event creation still fails with empty emails when set to required', async ({ page }) => {
|
|
const token = await getAdminToken(page);
|
|
|
|
// Ensure email requirements are enabled
|
|
await updateEventSettings(page, token, {
|
|
event_require_customer_email: true,
|
|
event_require_admin_email: true,
|
|
});
|
|
|
|
const eventRes = await page.request.post('/api/admin/events', {
|
|
headers: {
|
|
Authorization: `Bearer ${token}`,
|
|
'Content-Type': 'application/json',
|
|
},
|
|
data: {
|
|
event_type: 'wedding',
|
|
event_name: `E2E Required Emails ${Date.now()}`,
|
|
event_date: new Date(Date.now() + 7 * 86400000).toISOString().slice(0, 10),
|
|
customer_name: 'Test Host',
|
|
customer_email: '',
|
|
admin_email: '',
|
|
password: 'TestPass123!',
|
|
expiration_days: 30,
|
|
},
|
|
});
|
|
|
|
expect(eventRes.status()).toBe(400);
|
|
const body = await eventRes.json();
|
|
const paths = body.errors.map((e: { path: string }) => e.path);
|
|
expect(paths).toContain('customer_email');
|
|
expect(paths).toContain('admin_email');
|
|
});
|
|
|
|
test('event creation succeeds with missing email fields when optional', async ({ page }) => {
|
|
const token = await getAdminToken(page);
|
|
|
|
// Disable email requirements
|
|
await updateEventSettings(page, token, {
|
|
event_require_customer_email: false,
|
|
event_require_admin_email: false,
|
|
});
|
|
|
|
try {
|
|
// Create event without email fields at all (undefined, not empty string)
|
|
const eventRes = await page.request.post('/api/admin/events', {
|
|
headers: {
|
|
Authorization: `Bearer ${token}`,
|
|
'Content-Type': 'application/json',
|
|
},
|
|
data: {
|
|
event_type: 'wedding',
|
|
event_name: `E2E Missing Emails ${Date.now()}`,
|
|
event_date: new Date(Date.now() + 7 * 86400000).toISOString().slice(0, 10),
|
|
customer_name: 'Test Host',
|
|
password: 'TestPass123!',
|
|
expiration_days: 30,
|
|
},
|
|
});
|
|
|
|
const body = await eventRes.json();
|
|
expect(eventRes.ok(), `Expected 200 but got ${eventRes.status()}: ${JSON.stringify(body)}`).toBeTruthy();
|
|
expect(body.id).toBeTruthy();
|
|
|
|
// Cleanup
|
|
await page.request.delete(`/api/admin/events/${body.id}`, {
|
|
headers: { Authorization: `Bearer ${token}` },
|
|
});
|
|
} finally {
|
|
await updateEventSettings(page, token, {
|
|
event_require_customer_email: true,
|
|
event_require_admin_email: true,
|
|
});
|
|
}
|
|
});
|
|
});
|