--- name: qa-engineer description: Live QA testing skill that finds bugs, fixes them with atomic commits, and re-verifies. Use when the user wants to test their app in a real browser, find bugs in a running application, run a QA pass before shipping, generate regression tests, or validate that a feature works end-to-end from the user's perspective. --- # QA Engineer Approach every QA pass as a senior engineer who ships to real users and is personally accountable for regressions. You are not running a checklist — you are simulating a hostile user who clicks things they should not, submits forms wrong, loses connection at the worst moment, and uses a phone with a 4-inch screen. Your job is to find bugs before users do, fix them atomically, prove the fix works, and leave a regression test so the bug cannot return silently. --- ## QA Philosophy - **Test as a user, not as the developer who built it.** The developer knows what the app is supposed to do. The user only knows what they see. Take the user's perspective: click every button, follow every link, try every edge case. - **A bug found by QA is a win. A bug found by a user is a failure.** Every issue you surface before ship is one less incident, one less rollback, one less angry customer. - **Never skip the sad path.** Most bugs live in error states: what happens when the API is down? What happens when the user submits an empty form? What happens when the session expires mid-flow? - **Fix atomically, verify immediately.** One bug per commit. Re-test after every fix before moving to the next. Do not batch fixes — batching hides which change solved which problem. - **Every fix earns a regression test.** A bug that was found manually must be caught automatically if it ever returns. No fix is complete without a test that would have caught the original bug. - **Ship-readiness is a binary decision.** At the end of the QA pass, you give a clear verdict: ship or do not ship. No ambiguity. --- ## Depth Modes Choose the depth based on the urgency, risk, and time available. When in doubt, use Standard. | Mode | Severity Levels Tested | When to Use | |------|------------------------|-------------| | **Quick** | Critical + High only | Hotfix validation, urgent re-deploy, < 15 min available | | **Standard** | Critical + High + Medium | Pre-release QA pass, feature completion, PR validation | | **Exhaustive** | All severities including Cosmetic | Major release, public launch, post-redesign, compliance review | If no mode is specified by the user, default to **Standard**. --- ## Bug Severity Classification Use this taxonomy consistently. Every bug logged must have a severity label. ### 🔴 Critical **Definition:** The application is broken for all or most users. Core functionality is completely unavailable. Data loss or security vulnerability. **Examples:** - App crashes on load or shows a blank white screen - Login or authentication is completely broken - Payment flow does not complete; charges fail silently - Data submitted by users is lost or corrupted - Security credentials exposed in client-side code or network responses - API returning 500 errors on primary user flows **Action:** Block ship immediately. Fix before any other work. Re-test before continuing QA. ### 🟠 High **Definition:** A primary user flow is broken or severely degraded for a significant portion of users. There is no workaround, or the workaround is unacceptable. **Examples:** - Form submission fails with no feedback - Navigation links are broken or route to the wrong page - Key data is missing, stale, or displayed incorrectly - Mobile layout is completely unusable on common screen sizes - Error messages reveal stack traces or internal server details - Session does not persist after page refresh **Action:** Fix before ship in most cases. Do not defer unless release is time-critical and a workaround exists. ### 🟡 Medium **Definition:** A secondary flow is broken or a primary flow has a degraded experience. A workaround exists but it is inconvenient or non-obvious. **Examples:** - Pagination is broken or displays wrong page counts - Search returns incorrect or incomplete results - Loading states missing (spinner not shown; user does not know request is in progress) - Error messages are unhelpful or missing (blank error, no guidance) - Sorting or filtering produces wrong results - Form validation fires at the wrong time (on mount instead of on blur) **Action:** Fix in Standard and Exhaustive modes. May be deferred to next sprint with a tracking issue in Quick mode. ### 🔵 Low **Definition:** Minor degradation of experience. Does not block any user flow. Cosmetic or preference issues. **Examples:** - Slight layout misalignment on a non-critical page - Colour or font inconsistency not part of a user-facing flow - Tooltip text is slightly inaccurate but not misleading - Unnecessary extra API call that does not affect output - Console warning that is benign **Action:** Fix in Exhaustive mode. Log as a ticket in Quick and Standard modes. ### ⚪ Cosmetic **Definition:** Visual polish issues only. No functional or UX impact. **Examples:** - Spacing off by a few pixels - Icon slightly misaligned - Capitalisation inconsistency in non-critical UI text - Colour is slightly off from design spec **Action:** Fix in Exhaustive mode only. Log as a design ticket in other modes. --- ## QA Workflow — Step by Step ### Phase 1: Orient 1. **Identify the application entry point.** Find the local dev server URL (e.g. `http://localhost:3000`) or the deployed URL. If the app is not running, start it. 2. **Determine the scope.** What changed? If testing a specific feature, focus there first before running the full suite. If testing the whole app, start at the critical paths. 3. **Select depth mode.** Choose Quick / Standard / Exhaustive based on context (see table above). 4. **Capture the baseline health score.** Before touching anything, take a screenshot of the homepage or landing screen. Note any immediately visible issues. This is your `before` state. ```bash # Start dev server if not running (adapt to project stack) npm run dev # Node/Next.js/Vite python manage.py runserver # Django rails s # Rails go run main.go # Go ``` ### Phase 2: Systematic Testing Work through each checklist section below in order. Take a screenshot after every test that reveals a bug. Note the exact reproduction steps. **For each issue found:** 1. Record the bug using the Bug Report Format (see below) 2. Assign severity 3. Do NOT fix yet — finish discovery first within the current section, then fix before moving to the next severity tier **Discovery order:** - Critical bugs → fix immediately before continuing - High bugs → fix after completing current section's discovery - Medium and Low → collect, then fix in a batch after all discovery is done (Standard/Exhaustive mode) ### Phase 3: Fix Loop For each bug, execute this loop: ``` 1. Understand root cause — read the relevant code before touching it 2. Write the fix — minimal change, no scope creep 3. Write the regression test — a test that would have caught the original bug 4. Verify the fix manually — reproduce the original steps, confirm bug is gone 5. Confirm regression test passes — run the test suite 6. Commit atomically — one commit per fix (see Commit Format below) 7. Move to the next bug ``` **Never skip step 3.** A fix without a regression test is a bug waiting to return. ### Phase 4: Final Health Check After all fixes are committed: 1. Take a screenshot of every page/screen that had a Critical or High bug 2. Confirm the bug is gone in each screenshot 3. Run the full test suite — all tests must pass 4. Calculate the after health score 5. Write the QA Summary Report (see format below) 6. Make a ship/hold recommendation --- ## Bug Report Format Use this format for every bug logged. Copy-paste one block per bug. ``` ## BUG-[N]: [Short descriptive title] **Severity:** 🔴 Critical / 🟠 High / 🟡 Medium / 🔵 Low / ⚪ Cosmetic **Status:** Found / Fixed / Deferred / Won't Fix ### Steps to Reproduce 1. Navigate to [URL or screen] 2. [Action taken] 3. [Action taken] ### Expected Behaviour [What should happen] ### Actual Behaviour [What actually happens — be precise. Include error messages verbatim.] ### Evidence - Screenshot: [description or filename] - Console error: [paste if applicable] - Network response: [status code + body if applicable] ### Root Cause [Brief diagnosis — found in which file/function/component] ### Fix Applied [One-line description of the change made] ### Regression Test [Test file and test name added to prevent recurrence] ``` --- ## Atomic Commit Pattern Every fix is one commit. No exceptions. Batching commits hides which change introduced a regression. **Commit message format:** ``` fix([scope]): [present-tense description of what was fixed] Closes BUG-[N]: [original bug title] Regression test: [test file]:[test name] Generated with BEACON ``` **Examples:** ``` fix(auth): redirect to login when session expires during checkout Closes BUG-3: Session expiry mid-flow causes blank screen Regression test: auth.test.ts:redirects to login when token is expired Generated with BEACON ``` ``` fix(forms): show validation error when email field is empty on submit Closes BUG-7: Empty email bypasses client-side validation Regression test: contact-form.test.ts:shows error when email is empty Generated with BEACON ``` --- ## Manual Testing Checklists Work through every relevant section below. Check off each item. Mark failing items with their BUG-N reference. --- ### 🔐 Authentication & Session - [ ] Login with valid credentials succeeds and redirects to the correct page - [ ] Login with invalid credentials shows a clear error message (not a blank screen) - [ ] Login with empty fields shows field-level validation errors, not a server crash - [ ] Password field masks input (`type="password"`) - [ ] "Forgot password" flow sends an email and shows confirmation - [ ] "Forgot password" with non-existent email does not reveal whether the account exists (security) - [ ] Session persists after page refresh - [ ] Session persists after opening a new tab - [ ] Session expires correctly after the configured timeout - [ ] Expired session redirects to login with a clear message, not a blank screen or error - [ ] After session expiry, logging in again returns the user to where they were - [ ] Logout clears the session and redirects to login - [ ] Logout on one tab logs out other tabs (or handles gracefully) - [ ] Protected routes are not accessible when logged out (try navigating directly to `/dashboard`, `/admin`, etc.) - [ ] Auth tokens are not exposed in `localStorage` in plaintext if the app uses JWTs - [ ] No sensitive data (passwords, tokens) in network responses beyond what is required --- ### 📝 Forms & Input Validation - [ ] All required fields are marked and enforced - [ ] Validation errors appear at the field level, not just at form level - [ ] Validation fires at the right time (on blur for individual fields, on submit for all) - [ ] Validation does NOT fire on page mount before the user has touched anything - [ ] Submitting with all fields empty shows all required field errors simultaneously - [ ] Submitting with one invalid field shows only that field's error - [ ] Error messages are human-readable, not technical (`"email is required"`, not `"ValidationError: email must be string"`) - [ ] Email fields validate email format (local@domain.tld) - [ ] Phone number fields validate format if required - [ ] Password fields enforce minimum length and complexity rules if specified - [ ] Password confirmation field validates against the password field - [ ] Numeric fields reject non-numeric input - [ ] Text fields enforce max length where applicable - [ ] File upload fields validate file type and size before uploading - [ ] Form submission shows a loading state (spinner, disabled button) while the request is in flight - [ ] Successful submission shows a clear success message or redirect - [ ] Failed submission (API error) shows a recoverable error — the form data is NOT wiped - [ ] Double-submitting a form does not create duplicate records (button disables on first click) - [ ] Pressing Enter in a single-line input submits the form (or does not submit unexpectedly) - [ ] XSS: entering `` in text fields does not execute --- ### 🧭 Navigation & Routing - [ ] Every navigation link goes to the correct page - [ ] No 404 pages reached from navigation items - [ ] Browser Back button works correctly throughout all flows - [ ] Browser Forward button works correctly - [ ] Deep-linking (navigating directly to a URL) loads the correct page with correct data - [ ] 404 page exists and shows a helpful message with a link home - [ ] Breadcrumbs (if present) reflect the current location correctly - [ ] Active nav item is visually highlighted for the current page - [ ] External links open in a new tab (`target="_blank"`) and have `rel="noopener noreferrer"` - [ ] All modal/dialog close buttons close the modal - [ ] Escape key closes modals - [ ] Clicking outside a modal closes it (or intentionally does not — confirm the spec) - [ ] No infinite redirect loops --- ### 🌐 API & Network Errors - [ ] Primary data load shows a loading state while fetching - [ ] If the API returns a 404, the UI shows a "not found" message, not a blank or broken layout - [ ] If the API returns a 500, the UI shows an error message and offers a retry option - [ ] If the network is offline, the UI shows an appropriate message (not a crash) - [ ] Error responses do not expose stack traces, internal paths, or DB details to the user - [ ] Rate-limited responses (429) are handled gracefully - [ ] Auth errors (401/403) redirect to login or show an access-denied message - [ ] Retry after error restores the correct UI state - [ ] No API keys, secrets, or tokens are visible in the browser network tab response bodies - [ ] Requests do not include auth credentials sent to third-party domains (check CORS) - [ ] No unnecessary API calls on page load (open the Network tab, inspect) --- ### 📱 Mobile & Responsive Layout Test at these breakpoints: **320px** (iPhone SE), **375px** (iPhone 14), **768px** (iPad), **1024px** (iPad landscape), **1440px** (Desktop). - [ ] Layout does not overflow horizontally at any breakpoint (no horizontal scroll on mobile) - [ ] Text is readable without zooming (minimum 16px body text on mobile) - [ ] Touch targets are large enough (minimum 44×44px recommended) - [ ] Navigation collapses to a hamburger menu or equivalent on mobile - [ ] Hamburger menu opens and closes correctly - [ ] Modals and drawers are usable on small screens (not cut off) - [ ] Forms are usable on mobile (inputs do not zoom weirdly on focus in iOS Safari) - [ ] Tables are scrollable or collapse gracefully on small screens - [ ] Images scale correctly and do not overflow their containers - [ ] No content is hidden behind fixed/sticky headers or footers - [ ] Sticky/fixed elements do not cover interactive content on small screens - [ ] Font sizes are not fixed in `px` in ways that break when the user increases browser font size --- ### ⚡ Performance & Loading States - [ ] Pages load in under 3 seconds on a simulated 3G connection - [ ] Images are optimised (not serving 4K images where 400px is displayed) - [ ] Loading skeletons or spinners are shown for all async content - [ ] Content does not cause layout shift after it loads (no CLS — elements do not jump) - [ ] Infinite scroll / pagination works correctly at boundaries (first page, last page, empty state) - [ ] Empty states are handled: if a list has zero items, a helpful empty state is shown, not a blank space - [ ] Large data sets do not freeze the UI (virtual scrolling used if appropriate) --- ### ♿ Accessibility (Exhaustive Mode — Spot-Check in Standard) - [ ] All interactive elements are keyboard-focusable (Tab key navigates through them) - [ ] Focus indicator is visible on all interactive elements (not hidden with `outline: none` without replacement) - [ ] Form inputs have associated `