import { test, expect, type Locator, type Page } from '@playwright/test'; import { TEST_USERS } from './setup/test-users.js'; const LOGIN_URL = '/trips/login'; const ADMIN_USERS_URL = '/trips/admin/users'; async function loginAsLocalUser(page: Page, username: string, password: string): Promise { await page.goto(LOGIN_URL); await page.fill('input[name="identifier"]', username); await page.fill('input[name="password"]', password); await page.click('button[type="submit"]:has-text("Sign in locally")'); await page.waitForURL('**/trips/dashboard', { timeout: 15_000 }); } function rowForUser(page: Page, username: string): Locator { return page.getByRole('cell', { name: username }).locator('..'); } test.beforeEach(async ({ context }) => { await context.clearCookies(); }); test('admin sees auth source and can set local password', async ({ page }) => { const suffix = Date.now(); const username = `e2e_auth_source_${suffix}`; const fullName = `E2E Auth Source ${suffix}`; const email = `e2e_auth_source_${suffix}@test.local`; const password = `InitPass-${suffix}-123`; await loginAsLocalUser(page, TEST_USERS.admin.username, TEST_USERS.admin.password); await page.goto(ADMIN_USERS_URL); await expect(page.getByRole('heading', { name: 'Users' })).toBeVisible(); const regularRow = rowForUser(page, TEST_USERS.regular.username); await expect(regularRow.getByText('Local', { exact: true })).toBeVisible(); const adminRow = rowForUser(page, TEST_USERS.admin.username); await expect(adminRow.getByText('Local', { exact: true })).toBeVisible(); await page.getByRole('button', { name: 'Add User' }).click(); const addDialog = page.getByRole('dialog', { name: 'Add user' }); await expect(addDialog).toBeVisible(); await addDialog.locator('input[type="text"]').nth(0).fill(username); await addDialog.locator('input[type="text"]').nth(1).fill(fullName); await addDialog.locator('input[type="email"]').fill(email); await addDialog.locator('input[type="password"]').nth(0).fill(password); await addDialog.locator('input[type="password"]').nth(1).fill(password); await addDialog.getByRole('button', { name: 'Create user' }).click(); const disposableUserRow = rowForUser(page, username); await expect(disposableUserRow.getByText('Local', { exact: true })).toBeVisible(); await disposableUserRow.getByRole('button', { name: 'Set local password' }).click(); const dialog = page.getByRole('dialog', { name: 'Set local password' }); await expect(dialog).toBeVisible(); await dialog.getByRole('button', { name: 'Save password' }).click(); await expect(dialog.getByText('Password is required')).toBeVisible(); await dialog.locator('input[type="password"]').nth(0).fill('short'); await dialog.locator('input[type="password"]').nth(1).fill('short'); await dialog.getByRole('button', { name: 'Save password' }).click(); await expect(dialog.getByText('Password must be at least 12 characters')).toBeVisible(); await dialog.locator('input[type="password"]').nth(0).fill('long-enough-password'); await dialog.locator('input[type="password"]').nth(1).fill('long-enough-password-mismatch'); await dialog.getByRole('button', { name: 'Save password' }).click(); await expect(dialog.getByText('Passwords do not match')).toBeVisible(); await dialog.locator('input[type="password"]').nth(0).fill('local-password-123'); await dialog.locator('input[type="password"]').nth(1).fill('local-password-123'); await dialog.getByRole('button', { name: 'Save password' }).click(); await expect(dialog).toBeHidden(); });