Playwright Tests / test-playwright (1, 2) (push) Canceled after 0s
Playwright Tests / test-playwright (2, 2) (push) Canceled after 0s
pre-commit / pre-commit (push) Canceled after 0s
Compose Smoke Test / test-compose (push) Canceled after 0s
Playwright Tests / merge-reports (push) Canceled after 0s
`tests/utils/api.ts` took the API origin from `VITE_API_URL`, which `tests/config.ts` loads out of `app/.env`. In a checkout configured for a deployment that names the deployment — so the browser went to the local stack while every setup and teardown call, `deleteAll` included, went to the live one. `privateApi.ts` had the same reading, and it creates users. Both origins now come from one place: `PLAYWRIGHT_BASE_URL`, with the API derived from it (`app.<domain>` → `api.<domain>`) or named outright by `PLAYWRIGHT_API_URL`, which is what CI and the compose service set. Nothing in the suite reads `VITE_API_URL` any more. Belt and braces, since a stack served under a real domain answers to the same names its production instance does: a global setup resolves both origins and refuses anything that is not loopback or a private range, before a test runs. `PLAYWRIGHT_ALLOW_PUBLIC=1` says you meant it. `make test-frontend` is now that safe run — the Playwright image on the proxy network with both names mapped onto Traefik by address, as the host user so it does not leave root-owned results behind. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NUb8YpL2s3gmN9WTACTt4q
43 lines
1.3 KiB
TypeScript
43 lines
1.3 KiB
TypeScript
import type { Browser, Page } from "@playwright/test"
|
|
|
|
/**
|
|
* Talking to the API directly, for the setup and teardown around a spec.
|
|
*
|
|
* The specs run against a development stack, so whatever they create has to go
|
|
* again — the same bargain the backend suite strikes with its throwaway
|
|
* database. What a spec leaves behind is in someone's flow list tomorrow.
|
|
*/
|
|
|
|
import { apiUrl } from "../config.ts"
|
|
|
|
const authFile = "playwright/.auth/user.json"
|
|
|
|
/** Call the API as the logged-in user of *page*. */
|
|
export async function api(
|
|
page: Page,
|
|
path: string,
|
|
init: Record<string, unknown> = {},
|
|
) {
|
|
const token = await page.evaluate(() => localStorage.getItem("access_token"))
|
|
return page.request.fetch(`${apiUrl}/api/v1${path}`, {
|
|
...init,
|
|
headers: { Authorization: `Bearer ${token}` },
|
|
})
|
|
}
|
|
|
|
/** An authenticated page for a `beforeAll`/`afterAll`, which get no `page`. */
|
|
export async function apiPage(browser: Browser) {
|
|
const page = await browser.newPage({ storageState: authFile })
|
|
await page.goto("/")
|
|
return page
|
|
}
|
|
|
|
/** Delete the given API paths, whether or not they are still there. */
|
|
export async function deleteAll(browser: Browser, paths: string[]) {
|
|
const page = await apiPage(browser)
|
|
for (const path of paths) {
|
|
await api(page, path, { method: "DELETE" })
|
|
}
|
|
await page.close()
|
|
}
|