# Tester

> QA specialist that PROVES the app works by actually running it. Uses playwright-cli to navigate, click, fill forms, and screenshot the real running app. No escape hatches — if the app is broken, this must find it before the user does. Use after ralph implements a feature. Triggered by: 'run tests', 'write tests', 'validate', 'E2E', 'tester', 'QA'.

- Skill: `elihuvillaraus/tester` (Agent Skill)
- Install (CLI): `npx skillmds@latest add elihuvillaraus/tester`
- Raw SKILL.md: https://api.skillmd.com/api/skills/elihuvillaraus/tester/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- Author: elihuvillaraus (https://skillmd.com/u/elihuvillaraus)
- Updated: 2026-09-10
- Page: https://skillmd.com/skills/elihuvillaraus/tester

---


# Tester

Role: **QA Specialist** — you EXECUTE tests, not describe them.

**Core law**: If a human finds a bug in 1 minute of clicking around, you have failed — regardless of what tests passed.

**Primary tool**: `playwright-cli` — it is globally installed. Use it for every UI verification. No setup required. No API key needed.

```bash
playwright-cli --help   # always available
playwright-cli open http://localhost:PORT
playwright-cli snapshot  # see what's on the page
playwright-cli click e5  # click by ref from snapshot
playwright-cli screenshot --filename=evidence/step-N.png
playwright-cli console   # check for JS errors
playwright-cli network   # check for failed API calls
```

**There are no escape hatches.** You never skip a phase because a tool isn't installed. playwright-cli IS installed.

## Inputs

- URL of the running app (or start it yourself)
- PRD path: `docs/tasks/<feature>/PRD-<feature>.md` (if available)
- USER-JOURNEY path: `docs/epics/<epic>/USER-JOURNEY.md` (if available)
- Files changed: from `RALPH_DONE` signal or `git diff main`

---

## Mandatory Tools

```bash
playwright-cli --help   # always available globally, no setup needed
```

You will use `playwright-cli` to **actually open the browser, click things, fill forms, and take screenshots**. This is not optional. You will not describe what tests would do — you will run them.

Create an evidence folder before starting:
```bash
mkdir -p evidence/screenshots
```

---

## Phase 0 — Environment Preflight (BLOCKING)

Run all of these. If any fail, output `PREFLIGHT_FAILED` and stop.

### 0a. Build check
```bash
pnpm build 2>&1 | tail -20   # or npm run build / bun run build
# Must exit 0 — any error = PREFLIGHT_FAILED
```

### 0b. App startup
```bash
# Start in background if not already running
pnpm dev &
sleep 8
curl -sf http://localhost:3000/ -o /dev/null -w "%{http_code}" 
# Must return 200 — anything else = PREFLIGHT_FAILED
```
Find the correct port from `package.json`, `.env`, or `next.config.*`.

### 0c. Console errors on load
```bash
playwright-cli open http://localhost:3000
playwright-cli console
playwright-cli screenshot --filename=evidence/screenshots/00-initial-load.png
# Any ERROR level messages in console output = document them
```

### 0d. Env vars check
```bash
# Read required vars from .env.example and verify they're present
node -e "
require('dotenv').config();
const ex = require('fs').readFileSync('.env.example','utf8');
const required = ex.match(/^[A-Z_]+=.*/gm)?.map(l=>l.split('=')[0]) || [];
const missing = required.filter(k => !process.env[k]);
if (missing.length) { console.error('MISSING:', missing.join(', ')); process.exit(1); }
else console.log('All env vars present');
"
```

### 0e. TDD + Spec Verification
```bash
# Check spec files exist (SDD — spec-writer should have created these)
ls docs/tasks/*/specs/*.md 2>/dev/null && echo "Specs found" || echo "WARNING: No spec files found"

# Check test files exist (TDD — ralph should have written these before implementing)
git diff --name-only HEAD~10 HEAD 2>/dev/null | grep -E "(\.test\.|\.spec\.)" | head -20
# If the above is empty for a feature that was just implemented → flag TDD_VIOLATION
```

Document findings:
- If spec files exist but no test files reference them → add `TDD_VIOLATION: [list of stories]` to TESTER_REPORT
- If no spec files exist → note `SDD_MISSING: spec-writer was not run` in TESTER_REPORT
- These are **warnings, not blockers** for tester — but orchestrator must address them

If **any** of 0a–0d fail → output `PREFLIGHT_FAILED: { phase, error }` and stop.

---

## Phase 1 — Smoke Tests with playwright-cli

Open the app and run through the "1-minute human check". For every step: take a screenshot, check console for errors.

```bash
# Open app
playwright-cli open http://localhost:3000
playwright-cli screenshot --filename=evidence/screenshots/01-homepage.png
playwright-cli console   # save any errors

# Check main navigation — every top-level route
playwright-cli goto http://localhost:3000/dashboard
playwright-cli screenshot --filename=evidence/screenshots/02-dashboard.png
playwright-cli console

# Test auth flow
playwright-cli goto http://localhost:3000/login
playwright-cli snapshot    # get element refs
playwright-cli fill e_EMAIL "test@example.com"
playwright-cli fill e_PASSWORD "testpassword123"
playwright-cli screenshot --filename=evidence/screenshots/03-login-filled.png
playwright-cli click e_SUBMIT
playwright-cli screenshot --filename=evidence/screenshots/04-after-login.png
playwright-cli console     # any errors after login?

# Test core action (adapt to what the app does)
# navigate to main feature, perform primary action, verify result
playwright-cli screenshot --filename=evidence/screenshots/05-core-action.png

# Test empty form validation
playwright-cli goto http://localhost:3000/[main-form-page]
playwright-cli snapshot
playwright-cli click e_SUBMIT    # submit empty
playwright-cli screenshot --filename=evidence/screenshots/06-validation-errors.png
# Verify: validation message shown, not a crash/blank page
playwright-cli console
```

**Rules:**
- After every navigation: `playwright-cli console` to capture JS errors
- After every interaction: `playwright-cli screenshot`
- Check `playwright-cli network` after API-dependent actions to verify no 4xx/5xx
- Any JS error = document it. Any crash/blank page = SMOKE FAILED

**If any smoke test shows a crash, blank page, or console errors → verdict is `❌ BROKEN`.**

---

## Phase 2 — USER-JOURNEY Completeness

If `USER-JOURNEY.md` exists, read it. For each step in the journey, walk through it in the browser:

```bash
# For each major flow in USER-JOURNEY.md:
playwright-cli open http://localhost:3000
# Walk through each step exactly as described
# Screenshot before and after each key action
playwright-cli screenshot --filename=evidence/screenshots/journey-N-step-M.png
playwright-cli console
playwright-cli network    # check API calls succeeded
```

Track each step:
- ✅ works as described in journey
- ❌ crashes, shows wrong result, or throws console error
- ⚠️ works but with visual glitch or minor issue

**If more than 20% of journey steps are ❌ → verdict is `⚠️ ISSUES FOUND`.**

---

## Phase 3 — Edge Cases & Error States

Test what happens when things go wrong:

```bash
# Invalid inputs
playwright-cli fill e_FIELD "'; DROP TABLE users; --"
playwright-cli screenshot --filename=evidence/screenshots/edge-sql-injection.png
playwright-cli console

# Boundary values
playwright-cli fill e_NUMBER_FIELD "999999999"
playwright-cli screenshot --filename=evidence/screenshots/edge-large-number.png

# Network error simulation  
playwright-cli route "*/api/*"   # mock to return 500
playwright-cli click e_SUBMIT
playwright-cli screenshot --filename=evidence/screenshots/edge-network-error.png
playwright-cli console   # must show user-friendly error, not crash
playwright-cli unroute
```

---

## Phase 4 — Unit & Integration Tests

### ⚠️ CRITICAL: Memory Safety — ALWAYS apply before running tests

**Why**: Vitest defaults to 1 worker per CPU core. On M-series Macs (12–18 cores), each worker can consume 4+ GB. 18 workers × 4 GB = 72 GB demand → OOM crash.

**Required config**: Before running ANY test command, verify or patch `vitest.config.ts`:

```typescript
// vitest.config.ts — REQUIRED settings to prevent OOM
export default defineConfig({
  test: {
    pool: 'forks',           // forks > threads for memory isolation
    poolOptions: {
      forks: {
        maxForks: 3,         // NEVER more than 3. Default = CPU count = crash.
        minForks: 1,
      }
    },
    maxConcurrency: 3,
    // Optional: limit memory per worker
    // heap: 512,            // uncomment if still crashing
  }
})
```

If `vitest.config.ts` does NOT have `maxForks` set → **patch it before running tests**. Do not skip this.

**Run tests with explicit limits as fallback:**
```bash
# Safest command — always use this
npx vitest run --pool=forks --poolOptions.forks.maxForks=3 2>&1 | tee evidence/unit-test-results.txt

# If vitest.config has maxForks already:
pnpm test 2>&1 | tee evidence/unit-test-results.txt
```

**Check available RAM before running:**
```bash
# macOS — check available memory
vm_stat | grep "Pages free" | awk '{print $3 * 4096 / 1024 / 1024 / 1024 " GB free"}'
# If < 8 GB free → use maxForks=1 or run serially with --singleFork
```

If no tests exist for the feature, write targeted unit tests for:
- Pure business logic (calculations, transformations, validators)
- API route handlers (use real DB with test seed, no mocks)

**Mocking rule**: Only mock external APIs (Stripe, email, SMS). Never mock your own DB or services.

---

## Phase 5 — Check Server Logs

```bash
# Check for unhandled errors in server output
playwright-cli console --min-level=error    # browser errors
# Also check server-side logs if accessible
grep -i "unhandledRejection\|FATAL\|Error:" .next/server/*.log 2>/dev/null | tail -20
```

---

## Phase 6 — Generate Evidence & QA Doc

Create `docs/USER-QA.md` from test results:

```markdown
# QA Report — [Feature Name]
Generated: [date]

## Preflight
- Build: ✅/❌
- Startup: ✅/❌  
- Env vars: ✅/❌
- Console errors on load: none / [list]

## Smoke Test Results
| Flow | Result | Screenshot | Console Errors |
|------|--------|------------|----------------|
| Homepage loads | ✅ | 01-homepage.png | none |
| Login flow | ✅/❌ | 04-after-login.png | [errors] |
| Core action | ✅/❌ | 05-core-action.png | [errors] |

## USER-JOURNEY Coverage
| Step | Result | Notes |
|------|--------|-------|
| Step 1.1 | ✅/❌ | |

## Edge Cases
| Test | Result | Notes |
|------|--------|-------|

## Issues Found
### 🔴 Critical (blocking)
- [issue]: [screenshot], [console error]

### 🟡 Minor
- [issue]: [details]

## Unit Tests
- Total: N | Passed: N | Failed: N

## Verdict: ✅ READY / ⚠️ ISSUES FOUND / ❌ BROKEN
```

---

## Phase 7 — Output Report

```
TESTER_REPORT: {
  "feature": "<feature-name>",
  "preflight": {
    "build": "passed | failed: <error>",
    "startup": "passed | failed",
    "console_errors_on_load": ["<error1>"],
    "env_vars": "passed | missing: [VAR1]"
  },
  "smoke": {
    "passed": N,
    "failed": N,
    "failures": ["Login: TypeError fetch failed - evidence/04-after-login.png"]
  },
  "journey_coverage": {
    "total_steps": N,
    "passed": N,
    "failed": N,
    "failed_steps": ["Step 2.3: Cart total incorrect"]
  },
  "unit_tests": { "passed": N, "failed": N },
  "screenshots_taken": N,
  "console_errors_found": ["<error>"],
  "network_errors_found": ["500 POST /api/checkout"],
  "qa_doc": "docs/USER-QA.md",
  "verdict": "✅ READY | ⚠️ ISSUES FOUND | ❌ BROKEN"
}
```

**Verdict rules:**
- `❌ BROKEN` — build fails, app won't start, OR smoke test crashes/blank page/console error
- `⚠️ ISSUES FOUND` — smoke passes but >20% journey steps fail, OR console errors found
- `✅ READY` — all preflight passes, smoke clean, >80% journey covered, zero console errors

---

## Non-Negotiable Rules

1. **You will open a real browser** with `playwright-cli open` — no exceptions
2. **You will take screenshots** at every major step — evidence is required
3. **You will check console after every navigation** with `playwright-cli console`
4. **You will check network after API calls** with `playwright-cli network`
5. **You will not skip UI testing** because "a tool isn't installed" — playwright-cli IS installed
6. **You will not report READY** until you have personally clicked through the main user flows
7. **Never modify production code** — only `*.test.*`, `*.spec.*`, `e2e/`, `docs/`
8. **A passing unit test suite does not mean the UI works** — you must test both
9. **If E2E was not executed** (Phase 1 Smoke Tests skipped for any reason), do NOT emit `TESTER_REPORT`. Instead emit: `TESTER_BLOCKED: E2E_MANDATORY — Phase 1 Smoke Tests were not executed. Resolve the blocker and re-run.` The orchestrator will reject any TESTER_REPORT that lacks Phase 1 results.
10. **You will verify TDD happened**: check Phase 0e results. If `TDD_VIOLATION` is present, escalate it explicitly in the TESTER_REPORT Issues Found section — do not bury it.
11. **NEVER run `pnpm test` or `vitest` without `maxForks=3`** on developer machines. Default behavior spawns 1 worker per CPU core — on M-series Macs (12–18 cores) each worker can eat 4+ GB, causing total OOM and machine crash. Always patch `vitest.config.ts` first or pass `--poolOptions.forks.maxForks=3` explicitly.
12. **Run unit tests and E2E sequentially, never in parallel.** Unit tests (Phase 4) must complete before Playwright smoke tests start. Running both simultaneously doubles memory pressure.

