pytest was deleting every user on teardown against the development database. The engine is built at import time, so tests/__init__.py pins POSTGRES_DB before app.core.config loads; the fixture creates the schema and drops the database again, guarded against a name that is not _test. Playwright now defaults at the integrated stack, which is the origin the API allows, so a bare `bunx playwright test` works without a dev server. The four template specs that asserted copy we no longer ship are gone, along with the helpers they were the last callers of. The admin edit assertion was page-wide and only ever passed on a fresh database. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KkmeRiyeYmVZqJVwuyHq9o
207 lines
7.1 KiB
TypeScript
207 lines
7.1 KiB
TypeScript
import { expect, test } from "@playwright/test"
|
|
import { firstSuperuser, firstSuperuserPassword } from "./config.ts"
|
|
import { createUser } from "./utils/privateApi"
|
|
import { randomEmail, randomPassword } from "./utils/random"
|
|
import { logInUser } from "./utils/user"
|
|
|
|
test("Admin page is accessible and shows correct title", async ({ page }) => {
|
|
await page.goto("/admin")
|
|
await expect(page.getByRole("heading", { name: "Users" })).toBeVisible()
|
|
await expect(
|
|
page.getByText("Manage user accounts and permissions"),
|
|
).toBeVisible()
|
|
})
|
|
|
|
test("Add User button is visible", async ({ page }) => {
|
|
await page.goto("/admin")
|
|
await expect(page.getByRole("button", { name: "Add User" })).toBeVisible()
|
|
})
|
|
|
|
test.describe("Admin user management", () => {
|
|
test("Create a new user successfully", async ({ page }) => {
|
|
await page.goto("/admin")
|
|
|
|
const email = randomEmail()
|
|
const password = randomPassword()
|
|
const fullName = "Test User Admin"
|
|
|
|
await page.getByRole("button", { name: "Add User" }).click()
|
|
|
|
await page.getByPlaceholder("Email").fill(email)
|
|
await page.getByPlaceholder("Full name").fill(fullName)
|
|
await page.getByPlaceholder("Password").first().fill(password)
|
|
await page.getByPlaceholder("Password").last().fill(password)
|
|
|
|
await page.getByRole("button", { name: "Save" }).click()
|
|
|
|
await expect(page.getByText("User created successfully")).toBeVisible()
|
|
|
|
await expect(page.getByRole("dialog")).not.toBeVisible()
|
|
|
|
const userRow = page.getByRole("row").filter({ hasText: email })
|
|
await expect(userRow).toBeVisible()
|
|
})
|
|
|
|
test("Create a superuser", async ({ page }) => {
|
|
await page.goto("/admin")
|
|
|
|
const email = randomEmail()
|
|
const password = randomPassword()
|
|
|
|
await page.getByRole("button", { name: "Add User" }).click()
|
|
|
|
await page.getByPlaceholder("Email").fill(email)
|
|
await page.getByPlaceholder("Password").first().fill(password)
|
|
await page.getByPlaceholder("Password").last().fill(password)
|
|
await page.getByLabel("Is superuser?").check()
|
|
await page.getByLabel("Is active?").check()
|
|
|
|
await page.getByRole("button", { name: "Save" }).click()
|
|
|
|
await expect(page.getByText("User created successfully")).toBeVisible()
|
|
|
|
await expect(page.getByRole("dialog")).not.toBeVisible()
|
|
|
|
const userRow = page.getByRole("row").filter({ hasText: email })
|
|
await expect(userRow.getByText("Superuser")).toBeVisible()
|
|
})
|
|
|
|
test("Edit a user successfully", async ({ page }) => {
|
|
await page.goto("/admin")
|
|
|
|
const email = randomEmail()
|
|
const password = randomPassword()
|
|
const originalName = "Original Name"
|
|
const updatedName = "Updated Name"
|
|
|
|
await page.getByRole("button", { name: "Add User" }).click()
|
|
await page.getByPlaceholder("Email").fill(email)
|
|
await page.getByPlaceholder("Full name").fill(originalName)
|
|
await page.getByPlaceholder("Password").first().fill(password)
|
|
await page.getByPlaceholder("Password").last().fill(password)
|
|
await page.getByRole("button", { name: "Save" }).click()
|
|
|
|
await expect(page.getByText("User created successfully")).toBeVisible()
|
|
await expect(page.getByRole("dialog")).not.toBeVisible()
|
|
|
|
const userRow = page.getByRole("row").filter({ hasText: email })
|
|
await userRow.getByRole("button").click()
|
|
|
|
await page.getByRole("menuitem", { name: "Edit User" }).click()
|
|
|
|
await page.getByPlaceholder("Full name").fill(updatedName)
|
|
await page.getByRole("button", { name: "Save" }).click()
|
|
|
|
await expect(page.getByText("User updated successfully")).toBeVisible()
|
|
// Scoped to this run's row: earlier runs leave their own "Updated Name".
|
|
await expect(userRow.getByText(updatedName)).toBeVisible()
|
|
})
|
|
|
|
test("Delete a user successfully", async ({ page }) => {
|
|
await page.goto("/admin")
|
|
|
|
const email = randomEmail()
|
|
const password = randomPassword()
|
|
|
|
await page.getByRole("button", { name: "Add User" }).click()
|
|
await page.getByPlaceholder("Email").fill(email)
|
|
await page.getByPlaceholder("Password").first().fill(password)
|
|
await page.getByPlaceholder("Password").last().fill(password)
|
|
await page.getByRole("button", { name: "Save" }).click()
|
|
|
|
await expect(page.getByText("User created successfully")).toBeVisible()
|
|
|
|
await expect(page.getByRole("dialog")).not.toBeVisible()
|
|
|
|
const userRow = page.getByRole("row").filter({ hasText: email })
|
|
await userRow.getByRole("button").click()
|
|
|
|
await page.getByRole("menuitem", { name: "Delete User" }).click()
|
|
|
|
await page.getByRole("button", { name: "Delete" }).click()
|
|
|
|
await expect(
|
|
page.getByText("The user was deleted successfully"),
|
|
).toBeVisible()
|
|
|
|
await expect(
|
|
page.getByRole("row").filter({ hasText: email }),
|
|
).not.toBeVisible()
|
|
})
|
|
|
|
test("Cancel user creation", async ({ page }) => {
|
|
await page.goto("/admin")
|
|
|
|
await page.getByRole("button", { name: "Add User" }).click()
|
|
await page.getByPlaceholder("Email").fill("test@example.com")
|
|
|
|
await page.getByRole("button", { name: "Cancel" }).click()
|
|
|
|
await expect(page.getByRole("dialog")).not.toBeVisible()
|
|
})
|
|
|
|
test("Email is required and must be valid", async ({ page }) => {
|
|
await page.goto("/admin")
|
|
|
|
await page.getByRole("button", { name: "Add User" }).click()
|
|
|
|
await page.getByPlaceholder("Email").fill("invalid-email")
|
|
await page.getByPlaceholder("Email").blur()
|
|
|
|
await expect(page.getByText("Invalid email address")).toBeVisible()
|
|
})
|
|
|
|
test("Password must be at least 8 characters", async ({ page }) => {
|
|
await page.goto("/admin")
|
|
|
|
await page.getByRole("button", { name: "Add User" }).click()
|
|
|
|
await page.getByPlaceholder("Email").fill(randomEmail())
|
|
await page.getByPlaceholder("Password").first().fill("short")
|
|
await page.getByPlaceholder("Password").last().fill("short")
|
|
await page.getByRole("button", { name: "Save" }).click()
|
|
|
|
await expect(
|
|
page.getByText("Password must be at least 8 characters"),
|
|
).toBeVisible()
|
|
})
|
|
|
|
test("Passwords must match", async ({ page }) => {
|
|
await page.goto("/admin")
|
|
|
|
await page.getByRole("button", { name: "Add User" }).click()
|
|
|
|
await page.getByPlaceholder("Email").fill(randomEmail())
|
|
await page.getByPlaceholder("Password").first().fill(randomPassword())
|
|
await page.getByPlaceholder("Password").last().fill("different12345")
|
|
await page.getByPlaceholder("Password").last().blur()
|
|
|
|
await expect(page.getByText("The passwords don't match")).toBeVisible()
|
|
})
|
|
})
|
|
|
|
test.describe("Admin page access control", () => {
|
|
test.use({ storageState: { cookies: [], origins: [] } })
|
|
|
|
test("Non-superuser cannot access admin page", async ({ page }) => {
|
|
const email = randomEmail()
|
|
const password = randomPassword()
|
|
|
|
await createUser({ email, password })
|
|
await logInUser(page, email, password)
|
|
|
|
await page.goto("/admin")
|
|
|
|
await expect(page.getByRole("heading", { name: "Users" })).not.toBeVisible()
|
|
await expect(page).not.toHaveURL(/\/admin/)
|
|
})
|
|
|
|
test("Superuser can access admin page", async ({ page }) => {
|
|
await logInUser(page, firstSuperuser, firstSuperuserPassword)
|
|
|
|
await page.goto("/admin")
|
|
|
|
await expect(page.getByRole("heading", { name: "Users" })).toBeVisible()
|
|
})
|
|
})
|