e2e/auth.spec.ts
Rama main · réplica de lectura del repositorio original.
import { test, expect } from '@playwright/test'
const ADMIN_EMAIL = process.env.DEFAULT_ADMIN_EMAIL ?? 'admin@flagraft.local'
const ADMIN_PASSWORD = process.env.DEFAULT_ADMIN_PASSWORD ?? 'flagraft-admin'
/** Signing in is the preamble to most of these tests; keep the selectors in one place. */
async function signIn(page: import('@playwright/test').Page) {
await page.goto('/login')
await page.getByLabel(/^email/i).fill(ADMIN_EMAIL)
await page.getByLabel(/^password/i).fill(ADMIN_PASSWORD)
await page.getByRole('button', { name: /sign in/i }).click()
await expect(page).toHaveURL(/\/flags/)
}
// ---------------------------------------------------------------------------
// 2. Unauthenticated Redirect
// ---------------------------------------------------------------------------
test.describe('Unauthenticated redirect', () => {
test('visiting / redirects to /login', async ({ page }) => {
await page.goto('/')
await expect(page).toHaveURL(/\/login/)
})
test('visiting /flags redirects to /login', async ({ page }) => {
await page.goto('/flags')
await expect(page).toHaveURL(/\/login/)
})
test('visiting /users redirects to /login', async ({ page }) => {
await page.goto('/users')
await expect(page).toHaveURL(/\/login/)
})
test('visiting /settings redirects to /login', async ({ page }) => {
await page.goto('/settings')
await expect(page).toHaveURL(/\/login/)
})
})
// ---------------------------------------------------------------------------
// 3. Login Screen UI
// ---------------------------------------------------------------------------
test.describe('Login screen UI', () => {
test.beforeEach(async ({ page }) => {
await page.goto('/login')
})
test('shows two-column layout with brand panel and form', async ({ page }) => {
await expect(page.locator('.auth-brand')).toBeVisible()
await expect(page.locator('.auth-main')).toBeVisible()
})
test('email field has a label and type email', async ({ page }) => {
const input = page.getByLabel(/^email/i)
await expect(input).toBeVisible()
await expect(input).toHaveAttribute('type', 'email')
})
test('password field has type password by default', async ({ page }) => {
const input = page.getByLabel(/^password/i)
await expect(input).toHaveAttribute('type', 'password')
})
test('show password toggle switches type to text and back', async ({ page }) => {
const input = page.getByLabel(/^password/i)
await page.getByRole('button', { name: /show password/i }).click()
await expect(input).toHaveAttribute('type', 'text')
await page.getByRole('button', { name: /hide password/i }).click()
await expect(input).toHaveAttribute('type', 'password')
})
})
// ---------------------------------------------------------------------------
// 4. Login — Wrong Credentials
// ---------------------------------------------------------------------------
test.describe('Login with wrong credentials', () => {
test('shows error alert and no cookie is set', async ({ page }) => {
await page.goto('/login')
await page.getByLabel(/^email/i).fill(ADMIN_EMAIL)
await page.getByLabel(/^password/i).fill('wrongpassword')
await page.getByRole('button', { name: /sign in/i }).click()
await expect(page.getByRole('alert')).toBeVisible()
const cookies = await page.context().cookies()
expect(cookies.find((c) => c.name === 'flagraft_session')).toBeUndefined()
})
test('submit button is disabled during request', async ({ page }) => {
await page.goto('/login')
await page.getByLabel(/^email/i).fill(ADMIN_EMAIL)
await page.getByLabel(/^password/i).fill('wrongpassword')
const btn = page.getByRole('button', { name: /sign in/i })
await btn.click()
// Button should briefly show "Signing in..." and be disabled
await expect(page.getByRole('button', { name: /signing in/i })).toBeDisabled()
})
})
// ---------------------------------------------------------------------------
// 5. Login — Correct Credentials
// ---------------------------------------------------------------------------
test.describe('Login with correct credentials', () => {
test('redirects to /flags after successful login', async ({ page }) => {
await signIn(page)
})
test('sets an HttpOnly flagraft_session cookie', async ({ page }) => {
await signIn(page)
const cookies = await page.context().cookies()
const session = cookies.find((c) => c.name === 'flagraft_session')
expect(session).toBeDefined()
expect(session?.httpOnly).toBe(true)
expect(session?.sameSite).toBe('Strict')
expect(session?.path).toBe('/')
})
test('session cookie is NOT accessible via document.cookie', async ({ page }) => {
await signIn(page)
const cookieStr = await page.evaluate(() => document.cookie)
expect(cookieStr).not.toContain('flagraft_session')
})
})
// ---------------------------------------------------------------------------
// 6. Authenticated State
// ---------------------------------------------------------------------------
test.describe('Authenticated state', () => {
test.beforeEach(async ({ page }) => {
await signIn(page)
})
test('SideNav footer shows logged-in user name and role', async ({ page }) => {
await expect(page.locator('.sidenav-user-name')).toContainText('Admin')
await expect(page.locator('.sidenav-user-role')).toContainText('owner')
})
test('refreshing the page keeps you logged in', async ({ page }) => {
await page.reload()
await expect(page).toHaveURL(/\/flags/)
await expect(page.locator('.sidenav-user-name')).toBeVisible()
})
})
// ---------------------------------------------------------------------------
// 7. Protected Routes
// ---------------------------------------------------------------------------
test.describe('Protected routes work when logged in', () => {
test.beforeEach(async ({ page }) => {
await signIn(page)
})
test('/flags loads the flags screen', async ({ page }) => {
await page.goto('/flags')
await expect(page.getByRole('heading', { name: /feature flags/i })).toBeVisible()
})
test('/users loads the users screen', async ({ page }) => {
await page.goto('/users')
await expect(page).toHaveURL(/\/users/)
})
test('/settings loads the settings screen', async ({ page }) => {
await page.goto('/settings')
await expect(page.getByRole('heading', { name: /project settings/i })).toBeVisible()
})
test('navigating between routes does not log you out', async ({ page }) => {
await page.goto('/users')
await page.goto('/settings')
await page.goto('/flags')
await expect(page).toHaveURL(/\/flags/)
await expect(page.locator('.sidenav-user-name')).toBeVisible()
})
})
// ---------------------------------------------------------------------------
// 11. Sign Out
// ---------------------------------------------------------------------------
test.describe('Sign out', () => {
test.beforeEach(async ({ page }) => {
await signIn(page)
})
test('clicking sign out redirects to /login and clears the session cookie', async ({ page }) => {
await page.getByRole('button', { name: /sign out/i }).click()
await expect(page).toHaveURL(/\/login/)
const cookies = await page.context().cookies()
expect(cookies.find((c) => c.name === 'flagraft_session')).toBeUndefined()
})
test('pressing back after logout and visiting /flags redirects to /login', async ({ page }) => {
await page.getByRole('button', { name: /sign out/i }).click()
await expect(page).toHaveURL(/\/login/)
await page.goto('/flags')
await expect(page).toHaveURL(/\/login/)
})
})
// ---------------------------------------------------------------------------
// 12. Already Logged In Redirect
// ---------------------------------------------------------------------------
test.describe('Already logged-in redirect', () => {
test('visiting /login while authenticated redirects to /flags', async ({ page }) => {
await signIn(page)
await page.goto('/login')
await expect(page).toHaveURL(/\/flags/)
})
})