Skip to main content

e2e-testing

Writing, running, and debugging Playwright E2E tests in coding-tool.

来源信息

仓库
jdelfino/coding-tool
最近来源活动
2026年6月22日 21:13
检测到的 SKILL.md 语言
英语
星标
0
分支
20

安装方式

默认使用会先检查来源的 Prompt;你也可以切换为直接命令,或下载本地副本。

检查来源文件

决定是否安装前,请先阅读 SKILL.md,以及 SkillsMP 当前展示的配套文件。

正在显示 SKILL.md

SKILL.md
来源说明 · 只读预览
name
e2e-testing
description
Writing, running, and debugging Playwright E2E tests in coding-tool.
# E2E Testing Guide for writing, running, and debugging Playwright E2E tests. Tests run against the real Next.js app (auto-started via `webServer`) and a local Supabase stack. ## Core Principles 1. **Failing tests indicate real bugs.** The tests drive the real app. If a test fails, investigate the app, not the test. 2. **Debug locally first.** Read the error, then the page-structure dump, screenshots/video, and console logs. Most failures are obvious once you look at the artifacts. Never debug by pushing to CI. 3. **Fix the app, not the test.** Only change the test if the test itself is wrong (bad selector, wrong expectation, race in the test). Never "fix" a test by bumping timeouts. 4. **Tests must be independent.** Each test creates its own namespace and cleans up after itself. `helpers/setup.ts` also clears test data before each test. ## Debugging Approach When a test fails, in order: ### 1. Read the error message Playwright says exactly which selector failed and why. Start there. ### 2. Check the page-structure dump Failed tests write `test-results/<test-name>/error-context.md` — a YAML snapshot of the DOM at failure time (roles, labels, disabled states). Often more useful than a screenshot for seeing what actually rendered. ### 3. Check artifacts (screenshot / video / trace) Config captures **screenshot** `only-on-failure`, **video** `retain-on-failure`, and **trace** `on-first-retry`. Open the report: ```bash npx playwright show-report ``` ### 4. Check API responses / email Look for non-200s or unexpected bodies in the captured console logs. For auth/MFA/invitation flows, inspect sent email in the local **Mailpit UI at http://localhost:54324** (the `helpers/inbucket-client.ts` helpers read from it). ### 5. Trace back to the bug Common patterns: - **Element not found / timeout** — selector changed, or the page never loaded (API error, auth/RLS issue). - **Text mismatch** — the API/DB returned unexpected data. - **Setup failure** — a `getSupabaseAdmin()` insert or sign-in helper threw; check Supabase is running and migrations are applied (`npx supabase db reset`). ### 6. Run in headed / debug mode ```bash npx playwright test e2e/your-test.spec.ts --headed # watch the browser npx playwright test e2e/your-test.spec.ts --debug # Playwright Inspector, step through ``` ## Running Tests Prerequisite: local Supabase running and `.env.local` present (the devcontainer does this on boot; otherwise `npx supabase start`). `SUPABASE_SECRET_KEY` must be set — specs are **skipped** without it (`hasSupabaseCredentials()`). ```bash npm run test:e2e # full suite (auto-starts the app) npx playwright test e2e/your-test.spec.ts # single file npx playwright test -g "substring" # single test by name ``` ## Writing Tests ### Structure Import the extended `test`/`expect` from `helpers/setup` (it clears test data before each test): ```typescript import { test, expect } from './helpers/setup'; import { hasSupabaseCredentials, getTestUserEmail } from './helpers/db-helpers'; import { loginAsInstructor, loginAsStudent, generateTestNamespaceId, createTestNamespace, cleanupNamespace, } from './fixtures/auth-helpers'; import { getSupabaseAdmin, createTestClass, createTestSection } from './helpers/test-data'; const describeE2E = hasSupabaseCredentials() ? test.describe : test.describe.skip; describeE2E('Feature', () => { test('does the thing', async ({ page, browser }) => { const namespaceId = generateTestNamespaceId(); await createTestNamespace(namespaceId); try { // 1. DATA SETUP via Supabase service role (fast, no UI) const supabase = getSupabaseAdmin(); // ... createTestClass / createTestSection / createTestProblem ... // 2. AUTH + UI await loginAsInstructor(page, `instructor-${namespaceId}`, namespaceId); await page.goto('/instructor'); // 3. ASSERT await expect(page.locator('h2:has-text("Dashboard")')).toBeVisible(); } finally { await cleanupNamespace(namespaceId); } }); }); ``` ### Key patterns - **Set up data via Supabase, not UI clicks.** Use `getSupabaseAdmin()` + the `helpers/test-data.ts` helpers (`createTestClass`, `createTestSection`, `createTestProblem`, `createInstructorForSection`, `setupTestNamespaceWithSection`, `createTestInvitation`). Only drive the UI for the flow you're actually verifying. - **Namespace isolation.** Every test gets a unique `namespaceId` (`generateTestNamespaceId()`); pass it to the login/data helpers and `cleanupNamespace()` in `finally`. - **Auth helpers** create the user (Supabase admin) then sign in through the UI: `loginAsInstructor`/`loginAsStudent`/`loginAsSystemAdmin`, or `signInAs(page, username, role, namespaceId)`. **system-admin** triggers an MFA OTP — the helper reads it from Mailpit automatically; if it hangs, check http://localhost:54324. - **Multi-actor tests** (instructor + student): use a separate `browser.newContext()` per user; close extra contexts in `finally`. - **Waiting:** rely on auto-waiting (`expect(...).toBeVisible()`, `page.waitForURL()`). Avoid `waitForTimeout` except a brief settle for the debounced code sync. ### Monaco editor The code editor is Monaco. There is no test hook — interact through the rendered editor: ```typescript const editor = page.locator('.monaco-editor').first(); await editor.click(); await page.keyboard.press('ControlOrMeta+a'); await page.keyboard.press('Backspace'); await page.keyboard.type('print("hello")', { delay: 50 }); // delay lets Monaco capture keystrokes await page.waitForTimeout(300); // settle for debounced sync ``` Monaco splits text across DOM nodes — assert on the `.monaco-editor` text content (partial match), not a single element. ## Key Files | File | Purpose | |------|---------| | `e2e/helpers/setup.ts` | Extended `test`/`expect`; clears test data before each test | | `e2e/helpers/db-helpers.ts` | `createTestUser`, namespace create/cleanup, `hasSupabaseCredentials`, test email/password | | `e2e/helpers/test-data.ts` | `getSupabaseAdmin()` + class/section/problem/invitation setup helpers | | `e2e/helpers/inbucket-client.ts` | Read email/OTP from Mailpit (localhost:54324) | | `e2e/fixtures/auth-helpers.ts` | `signInAs`, `loginAs*`, sidebar navigation helpers | | `playwright.config.ts` | `testDir: e2e/`, Chromium, 2 workers (non-CI), retries 0, 30s timeout, auto `webServer`, baseURL `localhost:3000` |
在 GitHub 查看