| name | test-qa |
| description | Generic webapp QA fallback — use only when no project-specific QA skill applies (project-local QA skills take precedence; use mobile-emulator-test for native builds). For unit tests use test-unit. Drives a visible (headed) browser manually through playwright-cli like a real user — clicking and typing one action at a time, never via scripts or test runners. Auto-discovers pages, entities, and auth from the codebase, generates user stories, performs real CRUD with data-pipeline verification (FE -> API -> DB -> FE), audits UX quality, tests edge cases, and produces a pass/fail report. Use when asked to "QA the app", "test the app", "find bugs", "run QA", "test CRUD", "smoke test", "check for dead buttons", or "test like a real user" AND no project-specific QA skill matches the repo.
|
| license | MIT |
QA Testing Skill
Perform full QA testing of any webapp through playwright-cli, adopting the
mindset of a senior QA engineer preparing an app for production release. This is NOT a
simple page-navigation monkey test — it is controlled, intelligent, user-story-driven
testing that covers CRUD operations, data pipeline integrity, UX quality, and edge cases.
Before ANY browser interaction, read the protocol-browser-anti-stall skill and apply its
rules to every step — especially Rule 0 (manual & headed, never scripted). That skill lives
at ~/.cursor/skills/protocol-browser-anti-stall/SKILL.md. Also read
references/playwright-session-coordination.md in that folder — named sessions, auth profiles,
persisted login.
Critical Rules
Manual & headed, never scripted.
Drive a visible browser one real action at a time with individual playwright-cli commands.
eval / run-code are inspection-only — never use them to click,
type, or navigate. Do not write *.spec.ts or run npx playwright test; experience the app,
don't automate past it.
Test as a real user, think as an engineer.
Navigate like someone who just opened the app for the first time.
Inspect like someone who knows what's under the hood.
Every mutation must be verified end-to-end.
Creating, updating, or deleting something is not "tested" until you confirm the
change persisted in the UI after a page refresh AND (if DB access available) in the database.
Evidence for every finding.
Every bug report needs: screenshot, console output, network request, and reproduction steps.
"It looked broken" is not a finding.
Clean up after yourself.
If you created test data during CRUD testing, delete it at the end. Leave the app in the
state you found it.
No hardcoded assumptions.
Read the codebase to discover pages, entities, and features. Never assume a route
exists without confirming it in the source code.
Phase 0: Codebase Discovery
Before opening the browser, understand the app from its source code.
0a. Detect Tech Stack
Read the dependency manifest:
package.json → Node/JS/TS (framework, UI lib, auth, ORM, state mgmt)
requirements.txt → Python
pyproject.toml → Python
Cargo.toml → Rust
go.mod → Go
Extract and record:
- Framework: Next.js, Remix, SvelteKit, Nuxt, Django, Rails, etc.
- UI library: React, Vue, Svelte, Angular
- Auth: Supabase Auth, NextAuth, Clerk, Auth0, Passport, custom
- Database/ORM: Supabase, Prisma, Drizzle, Sequelize, SQLAlchemy
- State management: TanStack Query, Zustand, Redux, Pinia
- CSS: Tailwind, CSS Modules, Styled Components, Chakra, Shadcn
- Dev server port: Read from
scripts.dev in package.json (usually 3000, 3001, 5173, 5174)
0b. Discover Routes
Scan the file system for page/route definitions:
| Framework | Scan Pattern |
|---|
| Next.js App Router | app/**/page.tsx or app/**/page.js |
| Next.js Pages | pages/**/*.tsx (excluding _app, _document) |
| Remix | app/routes/**/*.tsx |
| SvelteKit | src/routes/**/+page.svelte |
| Nuxt | pages/**/*.vue |
| React Router (SPA) | Grep for <Route or createBrowserRouter in source |
| Django | urls.py files |
| Rails | config/routes.rb |
For each route, note:
- Path (e.g.,
/words, /profile, /settings)
- Dynamic segments (e.g.,
/grammar/[slug], /culture/[id])
- Layout nesting (which layout wraps which pages)
- Auth requirements (is the page behind a guard/middleware?)
0c. Discover Data Model
Look for entity definitions:
| Source | Where |
|---|
| Supabase migrations | supabase/migrations/*.sql — table definitions, RLS policies |
| Prisma schema | prisma/schema.prisma — models, relations |
| Drizzle schema | drizzle/schema.ts or src/db/schema.ts |
| TypeScript types | types/*.ts, **/types.ts — interfaces for data entities |
| API routes | app/api/** — what CRUD endpoints exist |
| Feature files | features/*/ — feature-specific services, hooks, components |
For each entity, note: name, key fields, CRUD capabilities, relationships.
0d. Discover Auth Pattern
Search for:
- Auth provider config (
createClient for Supabase, NextAuth, ClerkProvider, Auth0Provider)
- Login page/component (grep for
signIn, login, authenticate)
- Test account credentials (check
.env.local, .env.test, .env.example, README)
- Protected routes (middleware files, auth guards, route wrappers)
0e. Read Feature Documentation
If the project has README files in feature directories (@_*-README.md, docs/, etc.),
read them to understand expected behavior and business rules.
0f. Record Discovery Results
Produce a structured summary before proceeding:
APP DISCOVERY:
- Framework: [name + version]
- Dev server: http://localhost:[port]
- Auth: [provider + method]
- Test account: [email / password, or "none found — ask user"]
- Routes discovered: [count]
- Public: [list]
- Auth-required: [list]
- Dynamic: [list with param patterns]
- Data entities: [list with CRUD capabilities]
- API endpoints: [count]
Phase 1: Environment Verification
1a. Verify Dev Server Running
Check the terminals folder for active dev server processes:
- Read terminal files to find running
npm run dev, pnpm dev, next dev, etc.
- If no dev server found, inform the user and stop.
1b. Load the app (own your session)
- Pick a session name for this run (
-s=qa-<app>); never reuse another agent's name.
- Open your own isolated browser — add
--persistent --profile if the app needs a login:
PW="npx --yes @playwright/cli@latest"
$PW -s=qa-<app> open --headed http://localhost:3000
sleep 2
$PW -s=qa-<app> snapshot
$PW -s=qa-<app> screenshot --filename .playwright-mcp/qa-baseline.png
$PW -s=qa-<app> console
$PW -s=qa-<app> requests
If the page is blank after 3 incremental wait cycles (6s total), report a blocker.
1c. Authenticate (reuse session — do not re-login every run)
Follow protocol-browser-anti-stall/references/playwright-session-coordination.md.
- Navigate to a protected route — if already signed in, skip to 1d.
state-load .playwright-mcp/auth/<host>.json if that file exists (or reuse the
--persistent --profile directory, which keeps you signed in automatically).
- If still logged out:
- Email/password: use test credentials from
.env.test / README (never paste secrets in chat).
- OAuth / SSO: complete sign-in in the visible window; wait with incremental
snapshots; then
state-save .playwright-mcp/auth/<host>.json.
- Google accounts cannot be signed into from a Playwright-launched browser — use the
one-time real-Chrome profile login in the coordination reference.
- Verify auth (avatar, dashboard, protected pages load).
- Do not log out at cleanup unless explicitly testing the logout flow.
If auth is impossible, mark auth-required pages as BLOCKED and test only public pages.
1d. Capture Baseline
After login (or on the public home page):
BASELINE:
- URL: [current URL]
- Console errors: [count — list if any]
- Network failures: [count — list if any]
- Visible content: [brief description]
- Screenshot: [reference]
Phase 2: Intelligent Page Crawl
For EVERY route discovered in Phase 0b, do the following:
2a. Navigate and Capture
goto to the page
- Apply anti-stall protocol (2s wait → snapshot → verify)
screenshot for visual evidence
console — record errors and warnings
requests — record API calls, failures, timing
2b. Classify the Page
| Classification | Signals |
|---|
| CRUD page | Has forms, edit buttons, delete buttons, data tables |
| Display page | Shows data but no mutation controls (dashboards, profiles) |
| Settings page | Has toggles, selects, save buttons for preferences |
| Auth page | Login, register, forgot password forms |
| Static page | No dynamic data (about, terms, privacy) |
| Navigation hub | Links to child pages (home, index pages) |
2c. Detect Issues During Crawl
For each page, immediately flag:
| Check | What to Look For |
|---|
| Dead page | Page returns 404, error boundary, or blank screen |
| Console errors | JavaScript errors, failed assertions, React errors |
| Network failures | 4xx/5xx responses, CORS errors, timeouts |
| Missing content | "undefined", "null", "NaN", "[object Object]" visible in text |
| Mock data | Placeholder text ("Lorem ipsum", "TODO", "test", "example@") that should be real |
| Dead buttons | Buttons that have no onClick or navigate nowhere (detect via snapshot inspection) |
| Missing metadata | No page title (document.title empty or generic), no description |
| Loading stuck | Spinner or skeleton that never resolves (after 6s) |
| Empty state | No data AND no helpful empty-state message |
| Broken images | Image elements with no src, broken src, or error fallback showing |
| Overflow | Text or elements overflowing their containers (visible in screenshot) |
2d. Build Feature Map
After crawling all pages, produce:
FEATURE MAP:
- CRUD pages: [list — with which entity and which operations]
- Forms found: [list — page + form purpose]
- Data displays: [list — tables, lists, cards, charts]
- Interactive elements: [buttons, toggles, dropdowns per page]
- Search/filter: [which pages have search or filter controls]
- Settings: [which preferences are configurable]
- Dead buttons found: [list with page + element description]
- Pages with errors: [list]
Phase 3: Dynamic User Story Generation
Based on the feature map, generate user stories. These are NOT predefined — they are
derived from what the app actually contains.
Story Categories
Category A: First Impression
"As a first-time visitor, I open the app and try to understand what it does."
Steps:
- Navigate to home page
- Assess: Is the value proposition clear within 3 seconds?
- Assess: Is there a clear call-to-action?
- Assess: Can I navigate without signing up?
- Assess: Does the app look professional and trustworthy?
Category B: Core User Journey
Identify the app's primary purpose from Phase 0 (e.g., language learning, project management,
e-commerce, social network). Generate a story that walks through the main flow:
"As a [user type], I want to [primary action] so that [value]."
Steps: Follow the app's main flow from start to finish.
Category C: CRUD Lifecycle (per entity)
For each data entity discovered:
"As a user, I create a [entity], verify it appears, edit it, verify changes, delete it, verify removal."
Steps:
- Navigate to the creation form
- Fill with realistic test data (prefix with
QA-TEST- for easy cleanup)
- Submit and verify success feedback
- Navigate to the list view and verify the item appears
- Open the item and verify all fields match what was entered
- Edit one or more fields
- Save and verify the changes appear
- Delete the item
- Verify it's gone from the list
- If DB access available: verify the row was created, updated, and deleted
Category D: Navigation Completeness
"As a user, I can reach every page from the navigation and never hit a dead end."
Steps:
- From home, find and click every navigation link
- On each page, verify back navigation works
- Verify breadcrumbs or location indicators are correct
- Check that all bottom nav / sidebar nav items lead somewhere
- Try browser back/forward buttons between pages
Category E: Search and Filter (if applicable)
"As a user, I search for something and get relevant results."
Steps:
- Find search input
- Search for a known item
- Verify results contain the item
- Search for something that doesn't exist
- Verify empty results have a helpful message
- Test filters if available
Category F: Error Handling
"As a user, I make mistakes and the app guides me."
Steps:
- Submit a form with empty required fields → expect inline validation errors
- Enter invalid data (wrong format, too long, negative numbers) → expect helpful error messages
- Navigate to a non-existent URL → expect a proper 404 page
- If possible, trigger a network error → expect a user-friendly error state
Category G: Settings and Preferences
"As a user, I change my preferences and they persist."
Steps:
- Navigate to settings
- Change a preference
- Navigate away
- Come back to settings
- Verify the preference persisted
Phase 4: CRUD Testing
For each CRUD-capable entity, execute the lifecycle test.
4a. Create
- Navigate to the creation page/form
- Identify all form fields via
snapshot
- Fill each field with realistic test data:
- Text fields:
QA-TEST-[field]-[timestamp]
- Numbers: reasonable values for the domain
- Dates: today or near-future
- Selects: pick a valid option
- Toggles: set to non-default
screenshot before submitting (evidence of input)
- Submit the form
requests — verify the API call succeeded (2xx response)
snapshot — verify success feedback (toast, redirect, confirmation)
screenshot — evidence of success state
Record the created item's identifying info (ID, name, URL) for subsequent steps.
4b. Read
- Navigate to the list view containing the entity
snapshot — find the created item in the list
- Verify all displayed fields match what was entered
- Click into the detail view (if available)
- Verify detail fields match
screenshot — evidence
4c. Update
- Navigate to the edit form for the created item
- Change 1-2 fields to new values
screenshot — evidence of changes before save
- Save the changes
requests — verify the update API call succeeded
- Verify the UI reflects the updated values
- Hard-refresh the page (
goto to same URL) and verify changes persisted
4d. Delete
- Find the delete action for the item
screenshot — evidence before deletion
- Trigger deletion (click delete button, confirm dialog if present)
requests — verify the delete API call succeeded
- Verify the item is gone from the list view
- If the item had a detail URL, navigate to it and verify 404 or redirect
4e. Validation Testing
For each form, also test:
- Empty submission: Clear all fields, submit → expect validation errors
- Invalid data: Wrong format (email without @, text in number field) → expect specific error messages
- Boundary values: Very long strings (500+ chars), zero, negative numbers, past dates
- Special characters:
<script>alert('xss')</script>, '; DROP TABLE, emoji, Unicode
- Duplicate prevention: Try to create the same item twice → expect duplicate handling
4f. Data Pipeline Verification
After each mutation (create/update/delete):
- Network check:
requests — was the API call made? What status code?
- Response check: Did the response body contain the expected data?
- UI check: Does the UI reflect the mutation without manual refresh?
- Refresh check: After
goto to the same page, is the mutation still visible?
- DB check (if Supabase MCP or DB access available):
supabase:execute_sql
{
"project_id": "<PROJECT_ID>",
"query": "SELECT * FROM <table> WHERE <identifying_column> LIKE 'QA-TEST-%' ORDER BY created_at DESC LIMIT 5"
}
Pipeline failures to detect:
- Optimistic update that never confirms (UI shows change but API failed)
- Stale cache (mutation succeeded but list view shows old data)
- Missing cache invalidation (created item doesn't appear until page refresh)
- Ghost data (deleted item reappears after refresh)
- Silent failures (no error shown to user but API returned 4xx/5xx)
Phase 5: UX Quality Audit
Assess each page against design-award quality standards.
5a. Visual Quality
| Check | How to Verify |
|---|
| Consistent spacing | Screenshot — no irregular gaps or cramped areas |
| Typography | No mixed font sizes where they should match, no orphaned headings |
| Truncation | Text truncated with ellipsis where appropriate, not clipped |
| Image loading | All images render, no broken image icons |
| Icons | All icons render (no missing icon squares or fallback text) |
| Dark mode | If supported: toggle and verify all components adapt, no white flashes |
| Responsive | Test at 1280px, 768px, 375px — layout adapts without breaking |
5b. Interaction Quality
| Check | How to Verify |
|---|
| Dead buttons | Click every button. Does it do something? |
| Form labels | Every input has a visible label or accessible name |
| Loading states | Trigger data fetches — is a loading indicator shown? |
| Success feedback | After mutations — toast, confirmation, or visual change? |
| Error feedback | After failures — is the error message helpful and visible? |
| Disabled states | Are disabled elements visually distinct? Is the reason clear? |
| Focus management | After modal close or form submit, is focus moved appropriately? |
5c. Information Architecture
| Check | How to Verify |
|---|
| Page titles | document.title — is it descriptive and unique per page? |
| Active nav state | Current page highlighted in navigation? |
| Dead ends | Any page with no way to navigate forward or back? |
| Empty states | Pages with no data — do they show a helpful message? |
| 404 page | Navigate to /nonexistent-page — is the 404 page helpful? |
Further reading