Skip to content
This repository was archived by the owner on Jul 29, 2026. It is now read-only.

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

15 Commits
 
 
 
 
 
 
 
 
 
 

Repository files navigation

QA Plugin for Claude Code

A column of checks with one gone, and nothing else pointing at the gap

Autonomous QA testing for web applications. Analyzes your source code, identifies user personas, tests through a real browser, tracks assertion coverage across runs, and crystallizes passing tests to Playwright for CI.

/qa

That's it. One command. Claude reads your code, finds vulnerabilities and bugs, figures out who your users are, simulates their journeys through your app, and produces a full report with actionable fixes — each issue in its own Jira-ready file.

How It Works

flowchart TD
    A["/qa"] --> B["Route Discovery"]
    B --> C["Code Analysis\n(security + functional)"]
    C --> P["Persona Identification\n(roles, guards, UI)"]
    P --> D{"Crystallized\nPlaywright exists?"}

    D -- "Yes" --> E["Run Playwright\n(fast CI path)"]
    D -- "No" --> F["Chrome Extension\n+ dynamic scenarios\n+ persona journeys"]

    E -- "Pass" --> BL["Baseline Diff\n(coverage drift)"]
    E -- "Fail" --> G["Fallback to Chrome"]

    F -- "Pass" --> H["Crystallize to\nPlaywright"]
    H --> BL

    G -- "Pass" --> I["Re-crystallize"]
    G -- "Fail" --> BL
    I --> BL

    BL --> R["Report\n(enriched bugs + personas\n+ coverage trend\n+ Jira-ready issue files)"]
Loading

The Nine Phases

Phase What happens
0. Baseline Load Loads assertion baseline from previous runs to track coverage drift
0b. Run Directory Creates timestamped run folder (qa-reports/runs/2026-03-21_14-30-00/) to preserve history
1. Route Discovery Scans your Next.js project for all page and API routes
2. Code Analysis + Personas Static analysis for security/functional issues, identifies user persona types from code, generates 3 persona instances per type
3. Browser Testing Playwright-first for crystallized flows, Chrome extension for new/failed flows
4. Persona Simulation Executes persona journeys — methodical admins, impatient editors, confused visitors
5. Crystallization Converts passing Chrome tests to Playwright scripts with dynamic data-aware assertions
6. Baseline Update Diffs assertions against baseline, detects regression coverage drift
7. Reporting Generates enriched bug reports, persona insights, coverage trends, individual issue files
8. Finalize Updates run metadata, writes latest-run.json pointer

Installation

/plugin marketplace add EvolvingAgentsLabs/qa
/plugin install qa-plugin@EvolvingAgentsLabs-qa
/reload-plugins

Prerequisites

Quick Start

# 1. Start your dev server
npm run dev

# 2. Launch Claude Code with Chrome
claude --chrome

# 3. Run QA
/qa

Usage Examples

Run the full test suite

/qa

Runs everything: code analysis, persona detection, all standard flows (navigation, forms, auth, responsive), all persona journeys, crystallization, and baseline tracking. Every run is preserved in a timestamped folder.

Example output:

QA Testing Complete
===================
Overall Status: FAIL
Pass Rate: 91.2%
Run #3 | Coverage Score: 100.0%

Code Analysis:
  Security: 2 findings (1 high, 1 medium)
  Functional: 3 findings (1 high, 2 low)
  Dynamic E2E scenarios: 3 generated, 2 passed, 1 failed

Flows:
  Navigation: PASS (8/8 steps) [crystallized]
  Forms:      FAIL (6/7 steps — email validation missing) [chrome]
  Auth:       PASS (5/5 steps) [crystallized]
  Responsive: PASS (9/9 steps) [crystallized]

Personas (3 types, 9 instances):
  admin:   2/3 passed — Jake Torres (impatient) failed on user creation form
  editor:  3/3 passed
  visitor: 3/3 passed
  Key insight: Impatient personas expose missing client-side validation

Assertion Baseline:
  Tracked assertions: 47 (+5 added, -0 dropped, ~0 changed)
  Coverage score: 100.0% (no drift)

Crystallization:
  Playwright scripts: qa-reports/playwright/ (4 flows)
  Dynamic data: 3 assertions use pattern matchers (uuid, timestamp)
  Run in CI: npx playwright test qa-reports/playwright/

Reports:
  Run Directory:  qa-reports/runs/2026-03-21_14-30-00/
  Summary:        qa-reports/runs/2026-03-21_14-30-00/summary.md
  Issue Index:    qa-reports/runs/2026-03-21_14-30-00/issues/INDEX.md
  Issue Files:    qa-reports/runs/2026-03-21_14-30-00/issues/ (8 files)
  Baseline:       qa-reports/baseline.json (persistent)

Critical Issues:
  1. [SEC-001] XSS via dangerouslySetInnerHTML in CommentSection.tsx:42
  2. [E2E-forms-003] Email field accepts invalid format on /contact
  3. [PERSONA-admin-2-003] User creation submits without required fields

Test a specific flow

/qa navigation     # Just page load tests
/qa forms          # Just form tests
/qa auth           # Just auth flow tests
/qa responsive     # Just responsive layout tests

Example — testing only forms:

/qa forms
QA Testing Complete
===================
Overall Status: FAIL
Pass Rate: 85.7%

Flows:
  Forms: FAIL (6/7 steps + 1 dynamic scenario)
    Step 5 FAIL: Email input accepts "not-an-email" without validation
    Dynamic SEC-001 PASS: XSS payload escaped correctly in comment field

Assertion Baseline:
  Partial run — only forms flow was tested
  Forms assertions: 12 (+0 added, -0 dropped)

Test only persona journeys

/qa personas          # All persona types
/qa persona-admin     # Only admin persona instances

Example:

/qa personas
Persona Testing
================
3 types identified (role-based detection: UserRole enum + middleware guards)

admin-1 Maria Chen (methodical):    PASS (4/4 steps)
  -> Dashboard loaded, user list visible, created user, settings saved

admin-2 Jake Torres (impatient):    FAIL (2/4 steps)
  -> Clicked "Create User" before page loaded — form submitted empty
  -> Key finding: No client-side validation on admin user creation form

admin-3 Priya Sharma (exploratory): PASS (6/6 steps)
  -> Tested URL manipulation /admin/users/99999 — got proper 404
  -> Tried SQL-like input in search — properly escaped

editor-1 Sam Wilson (cautious):     PASS (5/5 steps)
  -> Read all tooltips, checked confirmation on delete — dialog present

editor-2 Alex Rivera (power_user):  PASS (5/5 steps)
  -> Navigated via direct URLs, used Tab/Enter for forms — all worked

editor-3 Jordan Lee (confused):     FAIL (3/5 steps)
  -> Went to /settings instead of /posts — no breadcrumb to navigate back
  -> Used browser back 3 times — landed on blank state page

visitor-1 Casey Smith (methodical):  PASS (4/4 steps)
visitor-2 Dana Park (impatient):     PASS (4/4 steps)
visitor-3 Riley Jones (exploratory): PASS (5/5 steps)

Cross-Persona Insights:
  - Impatient personas fail on forms without client-side validation (2 instances)
  - Confused personas get lost when breadcrumbs are missing (1 instance)
  - All exploratory personas successfully handled — error pages work well

Run in CI with crystallized tests

After the first /qa run crystallizes tests, you can run them headlessly:

npx playwright test qa-reports/playwright/

If a Playwright test fails in CI (e.g., after a UI change), run /qa locally — Claude re-tests with Chrome and re-crystallizes with updated selectors.

Track coverage over time

The plugin tracks every assertion across runs. On run #5:

Assertion Baseline Updated
==========================
Run #5 | Assertions: 47 (+2 new, -3 dropped, ~1 changed)
Coverage Score: 93.6% (drift detected!)

DROPPED ASSERTIONS (regressions):
  - forms:step-3:element_visible:button[type=submit] — Submit button check
  - forms:step-5:input_validation:email — Email validation check
  - auth:step-7:redirect:/dashboard — Post-login redirect check

These checks were previously passing but are no longer being tested.

This answers the question every QA tool misses: "what did we stop checking for?"

What It Detects

Code Analysis (Static)

Category Examples
XSS dangerouslySetInnerHTML without sanitization, innerHTML assignments
Injection Raw SQL with string interpolation, unsanitized exec() calls
Auth bypass API routes without auth checks, missing middleware coverage
Secrets Hardcoded API keys, AWS credentials, database passwords in source
Null refs Unguarded .map() on undefined, destructuring without defaults
Race conditions Stale closures in setState, missing AbortController in useEffect
Missing validation Form submission without checks, API routes without schema validation

Browser Testing (E2E)

Flow What it checks
Navigation Every page loads, no console errors, 404 page works, internal links work
Forms Empty submission shows validation, required fields enforced, valid submit works
Auth Login/signup pages render, validation works, wrong credentials handled, protected routes redirect
Responsive Pages render at mobile/tablet/desktop, hamburger menu works at mobile
Dynamic scenarios Code analysis findings verified in browser (XSS payloads escaped, null refs don't crash)

Persona Simulation

What it catches Example
Missing validation Impatient user submits form before client-side validation runs
Dead-end states Confused user navigates to wrong section, no way back
Permission gaps Admin can't access feature their role should allow
Onboarding failures First-time visitor can't figure out what to do
Keyboard inaccessibility Power user can't tab through form fields
Error recovery Exploratory user enters garbage data, app crashes instead of showing error

Dynamic Data Handling

The plugin detects dynamic values (UUIDs, timestamps, JWTs, session tokens) and uses pattern matchers instead of exact values. This means crystallized Playwright tests don't break when IDs change between runs.

// Without dynamic data handling (breaks on next run):
await expect(page.getByTestId('order-id')).toHaveText('Order #550e8400-e29b-41d4-a716-446655440000');

// With dynamic data handling (stable across runs):
// [DYNAMIC: uuid_v4] Order ID generated per-creation
await expect(page.getByTestId('order-id')).toHaveText(/Order #[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}/);

Detected patterns: UUID v4, ISO timestamps, Unix timestamps, JWT tokens, hex tokens, MongoDB ObjectIDs, numeric IDs in URLs, relative times ("5 minutes ago"), and more.

Report Structure

Every run gets its own timestamped folder. Persistent files (baseline, Playwright scripts) stay at the root so they accumulate across runs.

qa-reports/
├── baseline.json              # PERSISTENT — assertion baseline across runs
├── crystallization.json       # PERSISTENT — crystallization state
├── latest-run.json            # Points to the most recent run
├── playwright/                # PERSISTENT — crystallized Playwright scripts for CI
│   ├── playwright.config.ts
│   ├── navigation.spec.ts
│   ├── forms.spec.ts
│   └── ...
└── runs/
    ├── 2026-03-21_14-30-00/   # Each run is preserved
    │   ├── run-metadata.json  # Run context (timestamp, args, duration, status)
    │   ├── routes.json
    │   ├── code-analysis.json
    │   ├── personas.json
    │   ├── summary.md
    │   ├── screenshots/
    │   ├── flows/
    │   │   ├── code-analysis.md
    │   │   ├── personas.md
    │   │   ├── navigation.md
    │   │   └── ...
    │   └── issues/            # Jira-ready individual issue files
    │       ├── INDEX.md       # Sortable table with quick filters
    │       ├── SEC-001.md
    │       ├── E2E-forms-002.md
    │       └── ...
    └── 2026-03-20_09-15-00/   # Previous runs are preserved
        └── ...

Individual Issue Files

Every issue gets its own standalone markdown file designed for Jira import and team sharing:

---
id: SEC-001
title: "Unsanitized HTML rendering in blog comments"
severity: high
category: xss
source: code-analysis
location: "components/CommentSection.tsx:42"
status: open
e2e_verified: confirmed
run: "2026-03-21_14-30-00"
run_number: 6
---

# SEC-001 — Unsanitized HTML rendering in blog comments

**Severity**: High
**Source**: Code Analysis (confirmed via E2E)
**Location**: `components/CommentSection.tsx:42`

## Steps to Reproduce
1. Navigate to /blog/test-post
2. Enter `<img src=x onerror=alert(1)>` in the comment textarea
3. Click Submit
4. Observe: payload executes as HTML

## Evidence
- **Code Snippet**: `dangerouslySetInnerHTML={{ __html: comment.body }}`
- **Screenshot**: [XSS payload rendered](../screenshots/forms-xss-sec001-001.png)

## Technical Analysis
User-submitted comment body is rendered as raw HTML without sanitization.

## Remediation
import DOMPurify from 'dompurify'
<div dangerouslySetInnerHTML={{ __html: DOMPurify.sanitize(comment.body) }} />

## Verification Steps
1. Re-run `/qa` — SEC-001 should no longer appear
2. Submit `<script>alert(1)</script>` and verify it renders as text

The INDEX.md provides summary-by-severity, summary-by-source tables, and quick filter sections (critical issues, unverified high-severity, E2E-confirmed code issues).

Enriched Bug Reports

Every issue — code analysis, E2E failure, or persona finding — uses a 5-section format:

  1. Steps to Reproduce — How to trigger the issue
  2. Evidence — Code snippet, screenshot, or console log
  3. Technical Analysis — Root cause explanation
  4. Remediation — Specific fix with before/after code
  5. Verification Steps — How to confirm the fix

Persona Detection — How It Identifies Users

The plugin scans your code for signals that reveal user types:

Signal (strongest first) What it looks for Example
Role definitions Enums, types, permission checks enum UserRole { ADMIN, EDITOR, VIEWER }
Route guards Middleware, auth HOCs, redirects requireRole('admin') in middleware.ts
UI conditionals Components rendered by role/plan {isAdmin && <AdminPanel />}
Data models User schema with role fields Prisma User model with role enum
Navigation Sidebar items filtered by role Admin nav vs user nav
API permissions Different behavior per role Rate limiting tiers, data scoping

If no role system is found (public site), it falls back to universal personas: first-time visitor, returning user, power user.

The 3-Instance Rule

Each persona type gets 3 instances with different behavioral profiles:

admin-1: Maria Chen    (methodical)  — follows every step carefully
admin-2: Jake Torres   (impatient)   — clicks before pages load
admin-3: Priya Sharma  (exploratory) — tries to break things

The 6 profiles: methodical, impatient, exploratory, confused, power_user, cautious. Each profile changes HOW the persona interacts — impatient personas submit forms before validation, confused personas navigate to wrong sections, exploratory personas enter emoji and SQL fragments.

Assertion Baseline — Tracking What You Test

The plugin fingerprints every assertion and tracks them in qa-reports/baseline.json across runs. Each baseline history entry includes a run_dir linking back to the specific run for full traceability. This enables:

  • Added assertions: New checks you started making (coverage growth)
  • Dropped assertions: Checks that disappeared between runs (coverage drift)
  • Coverage score: current / peak * 100 — drops when you stop checking things
  • Trend history: Last 50 runs for spotting gradual coverage erosion
  • Run traceability: Every baseline change links to the specific run that caused it
Coverage Trend (Last 5 Runs)
| Run | Date   | Assertions | Added | Dropped | Score  |
|-----|--------|------------|-------|---------|--------|
| #5  | Mar 21 | 47         | +2    | -0      | 100.0% |
| #4  | Mar 20 | 45         | +3    | -0      | 100.0% |
| #3  | Mar 19 | 42         | +0    | -2      | 95.5%  |
| #2  | Mar 18 | 44         | +10   | -0      | 100.0% |
| #1  | Mar 17 | 34         | +34   | -0      | 100.0% |

Adding Custom Test Flows

Copy system_files/TestFlowTemplate.md to skills/test-your-flow.md and customize. Each skill is a markdown file with step-by-step instructions that Claude executes through the Chrome extension.

Requirements

  • Claude Code with --chrome flag
  • Claude in Chrome extension v1.0.36+
  • Google Chrome or Microsoft Edge
  • A running dev server for the target application
  • (Optional) @playwright/test for running crystallized scripts in CI

About

[ARCHIVED]

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors