test: add full-stack Playwright integration test infrastructure
Sprint 12 Phase 2: Real integration tests with seed DB - R__seed_test_data.sql (Flyway repeatable, 7 members, strains, batches, docs, board, events) - TestResetController (profile-gated per-test DB reset) - docker-compose.test.yml (self-contained, tmpfs Postgres) - Dockerfile.playwright (v1.60.0, pre-installed deps) - 13 integration spec files, 70+ test cases (@smoke + @full) - seed-constants.ts, selectors.ts, api-client.ts test helpers
This commit is contained in:
@@ -0,0 +1,101 @@
|
||||
import { expect, test } from "@playwright/test"
|
||||
|
||||
import { ApiClient } from "../api-client"
|
||||
import { SEED } from "../seed-constants"
|
||||
|
||||
const apiClient = new ApiClient()
|
||||
|
||||
test.describe("Forum Page @full", () => {
|
||||
test.beforeEach(async () => {
|
||||
await apiClient.login(SEED.admin.email, SEED.admin.password)
|
||||
await apiClient.resetDb()
|
||||
})
|
||||
|
||||
test("lists seed topics", async ({ page }) => {
|
||||
await page.goto("/forum")
|
||||
await expect(
|
||||
page.getByText("Neue Sorten für Sommer")
|
||||
).toBeVisible()
|
||||
await expect(page.getByText("Bewässerungssystem")).toBeVisible()
|
||||
})
|
||||
|
||||
test("topics show reply counts", async ({ page }) => {
|
||||
await page.goto("/forum")
|
||||
// Reply counts should be visible as numbers near topics
|
||||
await expect(
|
||||
page
|
||||
.getByText(/antwort|repl/i)
|
||||
.first()
|
||||
.or(page.locator("[data-testid*='reply-count']").first())
|
||||
).toBeVisible()
|
||||
})
|
||||
|
||||
test("new topic button opens create form", async ({ page }) => {
|
||||
await page.goto("/forum")
|
||||
const newBtn = page
|
||||
.getByRole("button", { name: /neues thema|new topic|erstellen/i })
|
||||
.or(page.locator('[data-testid="forum-new-topic"]'))
|
||||
|
||||
await expect(newBtn).toBeVisible()
|
||||
await newBtn.click()
|
||||
|
||||
// Form should appear with title + content fields
|
||||
await expect(
|
||||
page
|
||||
.getByRole("dialog")
|
||||
.or(page.locator("form"))
|
||||
.or(page.getByLabel(/titel|title/i))
|
||||
).toBeVisible()
|
||||
})
|
||||
|
||||
test("create topic submits and shows new topic", async ({ page }) => {
|
||||
await page.goto("/forum")
|
||||
|
||||
const newBtn = page
|
||||
.getByRole("button", { name: /neues thema|new topic|erstellen/i })
|
||||
.or(page.locator('[data-testid="forum-new-topic"]'))
|
||||
await newBtn.click()
|
||||
|
||||
// Fill title
|
||||
const titleInput = page
|
||||
.getByLabel(/titel|title|thema/i)
|
||||
.or(page.locator("input[name*='title']"))
|
||||
await titleInput.fill("E2E Test Topic")
|
||||
|
||||
// Fill content
|
||||
const contentInput = page
|
||||
.getByLabel(/inhalt|content|nachricht|text/i)
|
||||
.or(page.locator("textarea"))
|
||||
await contentInput.fill("This is an integration test topic body.")
|
||||
|
||||
// Submit
|
||||
const submitBtn = page.getByRole("button", {
|
||||
name: /erstellen|submit|speichern|post/i,
|
||||
})
|
||||
await submitBtn.click()
|
||||
|
||||
// New topic should appear
|
||||
await expect(page.getByText("E2E Test Topic")).toBeVisible({
|
||||
timeout: 5000,
|
||||
})
|
||||
})
|
||||
|
||||
test("pin and lock buttons visible on topics", async ({ page }) => {
|
||||
await page.goto("/forum")
|
||||
|
||||
// Admin should see pin/lock action buttons
|
||||
const pinBtn = page
|
||||
.getByRole("button", { name: /pin|anheften/i })
|
||||
.first()
|
||||
.or(page.locator("[data-testid*='pin']").first())
|
||||
const lockBtn = page
|
||||
.getByRole("button", { name: /lock|sperren/i })
|
||||
.first()
|
||||
.or(page.locator("[data-testid*='lock']").first())
|
||||
|
||||
// At least one should be visible for admin user
|
||||
const pinVisible = await pinBtn.isVisible()
|
||||
const lockVisible = await lockBtn.isVisible()
|
||||
expect(pinVisible || lockVisible).toBeTruthy()
|
||||
})
|
||||
})
|
||||
Reference in New Issue
Block a user