skills/qa-testing/SKILL.md
Autonomously QA and verify the application using browser automation. Use when verifying code changes, testing features, validating bug fixes, or confirming any work done on the application. Triggers on requests to "test this", "verify this works", "QA this change", "make sure it works", or after implementing features that need validation.
npx skillsauth add miketromba/skills qa-testingInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Autonomously test and verify the application using browser automation with the QA auth bypass system.
REQUIRED: Read the agent-browser skill first to learn browser automation commands:
./agent-browser/SKILL.md
Do not proceed until you have read and understood the agent-browser skill. It contains essential commands for navigating pages, taking snapshots, interacting with elements, and capturing screenshots.
Warning: Subagent type: Use
generalPurpose, NOTbrowser-use. The QA workflow uses theagent-browserCLI via Shell commands. Thebrowser-usesubagent has its own built-in browser that is completely separate fromagent-browserand does NOT follow this skill's patterns. Always delegate QA tasks to ageneralPurposesubagent, which has Shell access to runagent-browsercommands.
The app uses a QA bypass system that allows automated testing without email verification.
The QA email whitelist is defined in the project's config package. Look for the QA config at:
packages/config/src/qa.ts
Read that file to find the whitelisted emails and the isQaEmail() helper.
Each email creates a distinct auth user with its own session and data. Use different emails when testing multi-user flows (invitations, member management, role changes, etc.).
isQaEmail() from the config package) and calls the QA bypass API endpointThe QA email whitelist is hardcoded in the config package. No QA-specific env vars are required.
Never assume QA accounts have pre-existing data. QA accounts are ephemeral — they may have no prior data or state. Never skip a verification step because the required data doesn't exist. Create the state you need.
Create state through the UI. Use browser automation to perform the actions a real user would — fill out forms, click buttons, and let the app create the data naturally. This tests the full stack (UI -> API -> DB -> side effects) and catches more bugs than testing views in isolation.
Last resort: Seed via database only when no UI or API path exists at all. Write a temporary seed script, run it before browser tests, then clean up after and delete the script.
Check if the server is already running by listing the terminals folder. If not running, start the app's dev server (e.g., bun run dev in the appropriate app directory).
agent-browser open http://localhost:<PORT>
agent-browser snapshot -i
# Find the email input
agent-browser fill @e1 "[email protected]"
# Find and click the submit button
agent-browser click @e2
# Wait for auth to complete and redirect
agent-browser wait 2000
agent-browser snapshot -i
After login, you should see the authenticated view (dashboard, home page, etc.).
Navigate to the relevant part of the app and verify the expected behavior. Take screenshots and read them to document the verification:
agent-browser screenshot --full
# The command prints the saved file path — you MUST read that file
# using the Read tool to actually see the screenshot contents.
# A screenshot you don't read tells you nothing.
agent-browser close
For flows that require multiple authenticated users, use separate browser sessions with --session:
# Session 1: Primary user
agent-browser --session user1 open http://localhost:<PORT>
agent-browser --session user1 snapshot -i
agent-browser --session user1 fill @e1 "[email protected]"
agent-browser --session user1 click @e2
agent-browser --session user1 wait 3000
# Session 2: Secondary user (separate browser, separate auth)
agent-browser --session user2 open http://localhost:<PORT>
agent-browser --session user2 snapshot -i
agent-browser --session user2 fill @e1 "[email protected]"
agent-browser --session user2 click @e2
agent-browser --session user2 wait 3000
# Now you have two authenticated users to test multi-user flows
# Clean up both sessions
agent-browser --session user1 close
agent-browser --session user2 close
Each --session name creates an isolated browser context with its own cookies, localStorage, and auth state.
Reminder: Every
agent-browser screenshotcall saves a file and prints its path. You MUST read that file with the Read tool to see the image. If you skip the read, the screenshot is wasted.
agent-browser open http://localhost:<PORT>
agent-browser snapshot -i
agent-browser fill @e1 "[email protected]"
agent-browser click @e2
agent-browser wait 3000
agent-browser snapshot -i
# Should show the authenticated view
agent-browser screenshot
# Now READ the screenshot file to verify what's on screen
agent-browser close
agent-browser open http://localhost:<PORT>
# Authenticate first...
agent-browser fill @e1 "[email protected]"
agent-browser click @e2
agent-browser wait 3000
# Navigate to the specific route
agent-browser open http://localhost:<PORT>/some-route
agent-browser snapshot -i
agent-browser screenshot
agent-browser open http://localhost:<PORT>
agent-browser snapshot -i
# Look for the specific element
agent-browser get text @eN # Get text content
agent-browser get styles @eN # Check styling
agent-browser screenshot
agent-browser snapshot -i
agent-browser fill @input1 "test value"
agent-browser fill @input2 "another value"
agent-browser click @submit
agent-browser wait --load networkidle
agent-browser snapshot -i
# Check for success/error states
NODE_ENV is not set to "production"packages/config/src/qa.tspackage.json for the correct dev command and portagent-browser snapshot -i after any navigation or DOM changes@e1 are only valid until the page changesIn apps/app/.env:
SUPABASE_SERVICE_ROLE_KEY=<your-service-role-key>
No QA-specific env vars are needed — the email whitelist is hardcoded in packages/config/src/qa.ts.
tools
Vercel Sandbox documentation and guidance for running untrusted code in isolated environments. Use when working with Vercel Sandbox - a compute primitive for safely executing AI-generated code, user-submitted scripts, or developer experiments in Firecracker microVMs. Triggers on questions about Vercel Sandbox SDK, sandbox CLI, @vercel/sandbox, Sandbox.create, snapshots, persistent sandboxes, sandbox authentication, sandbox pricing, sandbox system specs, microVMs, code execution isolation, or ANY Vercel Sandbox-related development tasks.
development
Vercel for Platforms documentation and guidance for building multi-tenant and multi-project applications. Use when working with Vercel Platforms - building SaaS apps serving multiple tenants with custom domains, AI coding platforms, or any platform deploying multiple projects. Triggers on questions about multi-tenant architecture, multi-project platforms, wildcard domains, custom domains on Vercel, tenant middleware, Vercel SDK for platforms, platform elements, deploy actions, vibe coding platforms, or ANY Vercel Platforms-related development tasks.
development
TanStack Query (React Query) documentation and guidance. Use when working with TanStack Query - a powerful async state management library for data fetching, caching, synchronization, and server state management. Triggers on questions about React Query, TanStack Query, useQuery, useMutation, query invalidation, caching strategies, optimistic updates, infinite queries, prefetching, or ANY TanStack Query-related development tasks.
tools
Supabase backend-as-a-service platform documentation and guidance. Use when working with Supabase - an open-source Firebase alternative providing Postgres database, authentication, real-time subscriptions, edge functions, storage, and vector embeddings. Triggers on questions about Supabase setup, database, auth, RLS, edge functions, storage, realtime, pgvector, migrations, CLI, self-hosting, or ANY Supabase-related development tasks.