Playwright api fixtures cleanup
Skill kjuhwa/skills-hub/skills/testing/playwright-api-fixtures-cleanup
Self-contained Playwright E2E tests using a TestApiClient fixture that creates entities over HTTP and tears them down in afterEach — no shared DB seed, no cross-test pollution.From its SKILL.md
npx -y skills add kjuhwa/skills-hub --skill playwright-api-fixtures-cleanupAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
One thing to look at
- 0 stars0 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
SKILL.md
3.4 KB, 707 tokens by cl100k_base, as published. Nobody here has run it
When to use
- Multi-user / multi-tenant app with an HTTP API.
- You want E2E tests to run against a real backend, in parallel, without step-on-toes failures.
- You're tired of
beforeAllmigration/seed scripts that get out of sync with app behavior.
Steps
- Build a
TestApiClientclass that:- Logs in as a fixed test user (dev verification code in non-prod).
- Tracks every entity it creates (issues, workspaces, comments).
- Exposes
cleanup()to delete them all.
export class TestApiClient { private token: string | null = null; private createdIssues: string[] = []; async login(email: string, name: string) { await fetch(`${API}/auth/send-code`, { method: "POST", body: JSON.stringify({ email }) }); const r = await fetch(`${API}/auth/verify-code`, { method: "POST", body: JSON.stringify({ email, code: "888888" }) }); this.token = (await r.json()).token; } async createIssue(title: string): Promise<Issue> { const r = await fetch(`${API}/api/issues`, { method: "POST", headers: { Authorization: `Bearer ${this.token}` }, body: JSON.stringify({ title }) }); const issue = await r.json(); this.createdIssues.push(issue.id); return issue; } async cleanup() { for (const id of this.createdIssues) { await fetch(`${API}/api/issues/${id}`, { method: "DELETE", headers: { Authorization: `Bearer ${this.token}` } }); } } getToken() { return this.token!; } } - Expose helpers that combine login + workspace scaffolding:
export async function loginAsDefault(page: Page): Promise<string> { const api = new TestApiClient(); await api.login(E2E_EMAIL, E2E_NAME); const ws = await api.ensureWorkspace("E2E Workspace", "e2e-workspace"); await page.goto("/login"); await page.evaluate(t => localStorage.setItem("app_token", t), api.getToken()); await page.goto(`/${ws.slug}/issues`); return ws.slug; } - Use in each spec:
let api: TestApiClient; test.beforeEach(async ({ page }) => { api = await createTestApi(); await loginAsDefault(page); }); test.afterEach(() => api.cleanup()); test("create and view issue", async ({ page }) => { const issue = await api.createIssue("Test Issue"); await page.goto(`/issues/${issue.id}`); await expect(page.getByText("Test Issue")).toBeVisible(); });
Example
See the source repo's e2e/helpers.ts and e2e/fixtures.ts.
Caveats
cleanup()should tolerate already-deleted entities (404s from earlier cleanup paths or cascading deletes are fine).- Don't share the
TestApiClientacross parallel tests — each gets its own viabeforeEach. - The dev-master verification code (e.g.
888888) must only work in non-production builds; see the "verification-code-dev-master" knowledge entry.
What ships with it
Read from the repository
Just SKILL.md. No reference files, no scripts.