mirror of
https://github.com/Buriburizaem0n/admin-frontend-domain.git
synced 2026-09-19 09:40:13 +00:00
Covers the security fixes that landed across both repos: - auth.spec.ts: login persists nz-jwt cookie and getProfile succeeds; password change bumps TokenVersion + revokes the old cookie so the pre-change JWT can no longer auth (regression guard for the keyId+session backend rewrite). - cron-csrf.spec.ts: POST /api/v1/cron/:id/manual succeeds while GET is no longer routable (regression guard for the cron CSRF fix). - fm-csrf.spec.ts: POST /api/v1/file is reachable while GET is no longer routable (regression guard for the FM CSRF fix). - visibility.spec.ts: an anonymous caller cannot see a server-group that contains zero guest-visible servers (regression guard for the server-group leak fix). Fixtures wrap the noisy login + cleanup boilerplate. tsconfig is scoped to tests/e2e so the suite stays out of the production tsc project graph. Playwright config starts the Vite dev server (npm run dev) and expects a backend reachable at the URL Vite proxies to. CI workflow follow-up commit wires the backend up. Co-authored-by: cloudcode <cloudcode@users.noreply.github.com>
57 lines
1.9 KiB
TypeScript
57 lines
1.9 KiB
TypeScript
import { Page, Request, expect, test as base } from "@playwright/test"
|
|
|
|
export type LoginContext = {
|
|
username: string
|
|
password: string
|
|
}
|
|
|
|
export const defaultAdmin: LoginContext = {
|
|
username: process.env.E2E_ADMIN_USER || "admin",
|
|
password: process.env.E2E_ADMIN_PASS || "admin",
|
|
}
|
|
|
|
export async function loginAs(page: Page, creds: LoginContext) {
|
|
await page.goto("/dashboard/login")
|
|
await page.locator('input[autocomplete="username"]').fill(creds.username)
|
|
await page.locator('input[autocomplete="current-password"]').fill(creds.password)
|
|
await page.locator('button[type="submit"]').click()
|
|
await page.waitForURL(/\/dashboard\/?(?:$|\?|#)/, { timeout: 10_000 })
|
|
}
|
|
|
|
export async function logout(page: Page) {
|
|
await page.context().clearCookies()
|
|
}
|
|
|
|
export async function expectAuthenticated(page: Page) {
|
|
const resp = await page.request.get("/api/v1/profile")
|
|
expect(resp.status(), "profile must respond 2xx while authenticated").toBeLessThan(400)
|
|
const body = await resp.json()
|
|
expect(body.success, "profile.success must be true").toBe(true)
|
|
expect(body.data?.id, "profile.data.id must be present").toBeTruthy()
|
|
}
|
|
|
|
export async function expectUnauthenticated(page: Page) {
|
|
const resp = await page.request.get("/api/v1/profile")
|
|
const body = await resp.json()
|
|
expect(body.success, "profile must NOT be authorized after revoke").not.toBe(true)
|
|
expect(body.error, "profile must surface an error after revoke").toBeTruthy()
|
|
}
|
|
|
|
export async function findRequest(
|
|
page: Page,
|
|
matcher: (req: Request) => boolean,
|
|
trigger: () => Promise<void>,
|
|
timeoutMs = 5000,
|
|
): Promise<Request> {
|
|
const waiter = page.waitForRequest(matcher, { timeout: timeoutMs })
|
|
await trigger()
|
|
return await waiter
|
|
}
|
|
|
|
export const test = base.extend<{ adminPage: Page }>({
|
|
adminPage: async ({ page }, use) => {
|
|
await loginAs(page, defaultAdmin)
|
|
await use(page)
|
|
},
|
|
})
|