Replace the header "Byt lösenord" link with an Inställningar menu for changing email or password. Email changes are two-step: request with password, confirmation link to the new address, then password again on confirm so a wrong inbox cannot take over the account. - Backend: EmailChangeService, V10 email_change_tokens, confirm API - Frontend: ChangeEmailPage, ConfirmEmailChangePage, header dropdown - E2E: account-settings round-trips, Mailpit verification, wrong-password guard - Flyway: V9 restore for dev DBs, CI migration checks, V10 for email tokens Co-authored-by: Cursor <cursoragent@cursor.com>
89 lines
3 KiB
TypeScript
89 lines
3 KiB
TypeScript
import { test, expect } from '@playwright/test'
|
|
|
|
test.describe('Auth guards', () => {
|
|
test('redirects unauthenticated user from /compose to /logga-in', async ({
|
|
page,
|
|
}) => {
|
|
await page.goto('/compose')
|
|
await expect(page).toHaveURL(/\/logga-in\?redirect=\/compose/)
|
|
await expect(page.getByRole('heading', { name: 'Logga in' })).toBeVisible()
|
|
})
|
|
|
|
test('redirects unauthenticated user from /orders to /logga-in', async ({
|
|
page,
|
|
}) => {
|
|
await page.goto('/orders')
|
|
await expect(page).toHaveURL(/\/logga-in\?redirect=\/orders/)
|
|
await expect(page.getByRole('heading', { name: 'Logga in' })).toBeVisible()
|
|
})
|
|
|
|
test('redirects unauthenticated user from /admin to /logga-in', async ({
|
|
page,
|
|
}) => {
|
|
await page.goto('/admin')
|
|
await expect(page).toHaveURL(/\/logga-in\?redirect=\/admin/)
|
|
await expect(page.getByRole('heading', { name: 'Logga in' })).toBeVisible()
|
|
})
|
|
|
|
test('redirects unauthenticated user from /andra-losenord to /logga-in', async ({
|
|
page,
|
|
}) => {
|
|
await page.goto('/andra-losenord')
|
|
await expect(page).toHaveURL(/\/logga-in\?redirect=\/andra-losenord/)
|
|
await expect(page.getByRole('heading', { name: 'Logga in' })).toBeVisible()
|
|
})
|
|
|
|
test('redirects unauthenticated user from /andra-epost to /logga-in', async ({
|
|
page,
|
|
}) => {
|
|
await page.goto('/andra-epost')
|
|
await expect(page).toHaveURL(/\/logga-in\?redirect=\/andra-epost/)
|
|
await expect(page.getByRole('heading', { name: 'Logga in' })).toBeVisible()
|
|
})
|
|
|
|
test('redirects authenticated user from /logga-in to home', async ({
|
|
page,
|
|
}) => {
|
|
const jwt = makeJwt({ role: 'user' })
|
|
await page.goto('/')
|
|
await page.evaluate((token) => localStorage.setItem('auth_token', token), jwt)
|
|
await page.goto('/logga-in')
|
|
await expect(page).toHaveURL('/')
|
|
})
|
|
|
|
test('redirects authenticated user from /registrera to home', async ({
|
|
page,
|
|
}) => {
|
|
const jwt = makeJwt({ role: 'user' })
|
|
await page.goto('/')
|
|
await page.evaluate((token) => localStorage.setItem('auth_token', token), jwt)
|
|
await page.goto('/registrera')
|
|
await expect(page).toHaveURL('/')
|
|
})
|
|
|
|
test('redirects non-admin user from /admin to home', async ({ page }) => {
|
|
const jwt = makeJwt({ role: 'user' })
|
|
await page.goto('/')
|
|
await page.evaluate((token) => localStorage.setItem('auth_token', token), jwt)
|
|
await page.goto('/admin')
|
|
await expect(page).toHaveURL('/')
|
|
})
|
|
|
|
test('allows admin user to access /admin', async ({ page }) => {
|
|
const jwt = makeJwt({ role: 'admin' })
|
|
await page.goto('/')
|
|
await page.evaluate((token) => localStorage.setItem('auth_token', token), jwt)
|
|
await page.goto('/admin')
|
|
await expect(page).toHaveURL('/admin')
|
|
await expect(
|
|
page.getByRole('heading', { name: 'Administration' }),
|
|
).toBeVisible()
|
|
})
|
|
})
|
|
|
|
function makeJwt(payload: Record<string, unknown>): string {
|
|
const header = btoa(JSON.stringify({ alg: 'HS256', typ: 'JWT' }))
|
|
const body = btoa(JSON.stringify(payload))
|
|
const signature = 'test-sig'
|
|
return `${header}.${body}.${signature}`
|
|
}
|