Code-aware browser testing for AI coding agents

Vibe testing

by AishwaryShrivastav · MIT license · ★ 18 on GitHub · updated Nov 13

Vibe testing cover

Code-aware browser testing for AI coding agents. 14 MCP tools, CLI workflows, regression memory, and human-readable QA reports.

# vibe-testing

[![npm version](https://img.shields.io/npm/v/vibe-testing.svg)](https://www.npmjs.com/package/vibe-testing)
[![npm downloads](https://img.shields.io/npm/dt/vibe-testing?label=npm%20downloads)](https://www.npmjs.com/package/vibe-testing)
[![GitHub stars](https://img.shields.io/github/stars/AishwaryShrivastav/vibe-testing?style=flat)](https://github.com/AishwaryShrivastav/vibe-testing/stargazers)
[![Node.js](https://img.shields.io/badge/node-%3E%3D20-brightgreen.svg)](https://nodejs.org)
[![MCP](https://img.shields.io/badge/MCP-compatible-blue.svg)](https://modelcontextprotocol.io)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
[![CI](https://github.com/AishwaryShrivastav/vibe-testing/actions/workflows/ci.yml/badge.svg)](https://github.com/AishwaryShrivastav/vibe-testing/actions)

**Code-aware browser testing for AI coding agents.**

[Product site](https://testing.tfgstudio.com/) · [npm](https://www.npmjs.com/package/vibe-testing) · [MCP Registry](https://registry.modelcontextprotocol.io/?q=io.github.AishwaryShrivastav%2Fvibe-testing) · [Smithery](https://smithery.ai/servers/aish/vibe-testing) · [Privacy](PRIVACY.md) · [Launch status](https://github.com/AishwaryShrivastav/vibe-testing/blob/main/docs/distribution/launch-status.md)

Listed in [Awesome MCP Servers](https://github.com/punkpeye/awesome-mcp-servers/pull/14575). The download badge shows npm's cumulative package downloads; `npx` package fetches contribute to that total.

vibe-testing reads your codebase so tests use your real routes and field names, runs them in a real Playwright browser, remembers what broke, and tells you what your last change fixed or regressed. It works as an MCP server that gives your editor (Claude Code, Cursor, Windsurf, VS Code Copilot, Roo Code) 14 testing tools, or as a standalone CLI.

Overview

[](https://www.npmjs.com/package/vibe-testing) [](https://www.npmjs.com/package/vibe-testing) [](https://github.com/AishwaryShrivastav/vibe-testing/stargazers) [](https://nodejs.org) [](https://modelcontextprotocol.io) [](https://opensource.org/licenses/MIT) [](https://github.com/AishwaryShrivastav/vibe-testing/actions)

Connects with Agent Alley MCP · agentalley.io/mcp

Files included

  • README.md34.8 KB
Read README.md here
AishwaryShrivastav/main1 file
README.md
Show the full text856 lines

vibe-testing

npm version npm downloads GitHub stars Node.js MCP License: MIT CI

Code-aware browser testing for AI coding agents.

Product site · npm · MCP Registry · Smithery · Privacy · Launch status

Listed in Awesome MCP Servers. The download badge shows npm's cumulative package downloads; npx package fetches contribute to that total.

vibe-testing reads your codebase so tests use your real routes and field names, runs them in a real Playwright browser, remembers what broke, and tells you what your last change fixed or regressed. It works as an MCP server that gives your editor (Claude Code, Cursor, Windsurf, VS Code Copilot, Roo Code) 14 testing tools, or as a standalone CLI.

The repository is also an Agent Plugin with a release-qa skill. Compatible agents get both the testing tools and a senior-QA workflow for coverage, evidence, regression checks, and a clear release verdict.

cd /path/to/your/project
npx vibe-testing@latest init

Then open your editor and say:

"Scan this codebase and test it against http://localhost:3000"

No source code? Point it at a URL from an empty folder and it tests the app black-box:

npx vibe-testing@latest run https://staging.example.com

It finds bugs you didn't write a test for

While it explores, vibe-testing checks for server crashes, console errors, broken values (NaN, [object Object], Invalid Date), totals that don't match their line items, saved values that never appear, a logout that doesn't end the session, and one user opening another user's pages. No scenarios to write.

Measured on intentionally buggy apps (0.5.0, details in #13):

App Mode Before 0.5.0
react-simple-project (7 planted functional bugs) with source code 1 of 7 7 of 7
react-simple-project URL only 0 of 7 7 of 7
OWASP NodeGoat with source code 0 issues /contributions crash, /allocations 500s, a redirect to /undefined
restful-booker-platform (no planted bugs) both 3 pages, 4 false errors 8+ pages, 1 real bug: /api/room/:id returns 500

No false findings on these three apps in either mode. Run it against a test environment: exploration creates records and lists every change it made.

Using it on your project? Add the badge:

[![tested with vibe-testing](https://img.shields.io/badge/tested%20with-vibe--testing-7c3aed)](https://github.com/AishwaryShrivastav/vibe-testing)

What code-aware testing adds

Playwright MCP gives your agent hands. vibe-testing gives it a testing workflow: code-derived scenarios, memory across runs, and a report. Two things a stateless browser tool cannot do:

1. Run it twice and it tells you what you broke. Every run writes .vibe/run-snapshot.json and diffs it against the previous run. Every scan writes .vibe/route-manifest.json and diffs your routes. The second run prints regressions and fixes instead of a wall of results:

Changes since last run
  Fixed:      /login
  Regression: /checkout
  New:        /admin/users

The same diff reaches your editor as snapshot_diff on run_full_test and run_converge, and as route_changes on scan_codebase, so the agent can flag "checkout broke after that commit" without anyone scrolling a report. Flaky routes, working selectors, and measured timeouts are also remembered between runs.

2. Zero LLM calls inside the tool. Pass/fail verification is heuristic: URL changes, toast detection, API errors. Your editor's model decides what to test; vibe-testing does the browsing and checking. No API key, no per-run cost beyond the editor subscription you already pay for.


Contents


How it works

npx vibe-testing@latest init
        |
Registers 14 MCP tools in your editor
        |
You ask: "Test the checkout flow"
        |
AI calls: scan_codebase -> get_context("checkout") -> login -> explore_page -> execute_scenario -> generate_report
        |
HTML report opens in browser with screenshots of every step

No test cases to write. The AI reads your source code to understand real field names and routes, opens a browser, tests everything, and shows you what's broken.

init also:

  • Detects which AI editors you have installed
  • Registers vibe-test in global editor configs (~/.claude.json, ~/.cursor/mcp.json, ~/.codex/config.toml, and so on) so the tools are available in every project, every session
  • Creates project-level MCP configs and AI instruction files
  • Auto-detects your app's URL (reads .env, vite.config, framework defaults)
  • Creates VIBE.md (edit with your test credentials) and vibe.config.json
  • Installs the matching Playwright Chromium build

MCP setup

Agent Plugin

Install this repository as a plugin when your agent supports the Agent Plugins standard. It includes the portable release-qa skill and starts the published npm MCP server with no API key.

  • Cursor: submit or install https://github.com/AishwaryShrivastav/vibe-testing as an Agent Plugin.

  • Claude Code:

    claude plugin marketplace add AishwaryShrivastav/vibe-testing
    claude plugin install vibe-testing@vibe-testing
    
  • Other compatible agents: load the repository root containing plugin.json, skills/, and mcp.json.

The direct MCP and CLI setup below remains available for editors without plugin support.

MCPB bundle

Claude Desktop and other MCPB hosts can install one local bundle. Build and validate it from this repository:

npm ci
npm run build:mcpb

The artifact is written to artifacts/vibe-testing-<version>.mcpb. See the MCPB distribution guide for the bundle contents, validation steps, Smithery handoff, and the one-time Playwright Chromium prerequisite.

npx vibe-testing@latest init

Detects Claude Code, Cursor, Codex, Windsurf, VS Code and Roo Code, registers vibe-test in each, and prints what to do next in each editor. It never overwrites a config file it cannot parse, and running it twice changes nothing.

Option 2: one command per editor
Editor Run this Then
Claude Code claude mcp add --scope user vibe-test -- npx -y vibe-testing@latest --mcp Start a new claude session. /mcp shows vibe-test as connected.
Codex (CLI, IDE extension, desktop app) codex mcp add vibe-test -- npx -y vibe-testing@latest --mcp Start a new codex session. /mcp lists vibe-test.
VS Code (Copilot) code --add-mcp '{"name":"vibe-test","type":"stdio","command":"npx","args":["-y","vibe-testing@latest","--mcp"]}' Use Agent mode in Copilot Chat.
Cursor Add the JSON below to ~/.cursor/mcp.json Cursor Settings > MCP: check vibe-test is switched on.
Windsurf Add the JSON below to ~/.codeium/windsurf/mcp_config.json Press Refresh in the Cascade MCP panel.

Then say to your agent:

"Scan this codebase and test it against http://localhost:3000"

The first run downloads a Chromium build (one-time, roughly 150 MB). npx vibe-testing@latest install-browser does it ahead of time.

Option 3: edit the config file yourself
Claude Code

For every project, the user-scope config is ~/.claude.json (top-level mcpServers). Claude Code does not read MCP servers from ~/.claude/settings.json. For one project, use .mcp.json in the project root, which you can commit for your team:

{
  "mcpServers": {
    "vibe-test": {
      "type": "stdio",
      "command": "npx",
      "args": ["-y", "vibe-testing@latest", "--mcp"]
    }
  }
}

Claude Code asks you to approve a project-scoped server the first time it sees it.

Codex

Add to ~/.codex/config.toml. The Codex CLI, IDE extension and desktop app share this file:

[mcp_servers.vibe-test]
command = "npx"
args = ["-y", "vibe-testing@latest", "--mcp"]

init also writes AGENTS.md, which Codex reads for project instructions.

Cursor

Add to ~/.cursor/mcp.json (global) or .cursor/mcp.json (project):

{
  "mcpServers": {
    "vibe-test": {
      "command": "npx",
      "args": ["-y", "vibe-testing@latest", "--mcp"]
    }
  }
}
Windsurf

Add to ~/.codeium/windsurf/mcp_config.json:

{
  "mcpServers": {
    "vibe-test": {
      "command": "npx",
      "args": ["-y", "vibe-testing@latest", "--mcp"]
    }
  }
}
VS Code (GitHub Copilot)

Add to .vscode/mcp.json in your project:

{
  "servers": {
    "vibe-test": {
      "type": "stdio",
      "command": "npx",
      "args": ["-y", "vibe-testing@latest", "--mcp"]
    }
  }
}
Roo Code / Cline

Add to .roo/mcp.json:

{
  "mcpServers": {
    "vibe-test": {
      "command": "npx",
      "args": ["-y", "vibe-testing@latest", "--mcp"]
    }
  }
}
From local build (development)
{
  "mcpServers": {
    "vibe-test": {
      "command": "node",
      "args": ["/path/to/vibe-testing/dist/mcp-server.js"]
    }
  }
}

MCP tools reference

14 tools available to your AI editor after setup:

Tool When to call Returns
configure Start here on a new project. Detects framework, server, and authentication Structured setup result and idempotent project files
scan_codebase Always first. Reads source code, finds routes/forms/tests/gaps Routes, forms, coverage map, generated scenarios, route_changes since last scan
get_context Before writing test steps. Returns source files for a feature Actual source code with real field names and selectors
login When app requires authentication Post-login screenshot, token state, API calls observed
scan_page_elements To see all interactive elements on a page Element list with selectors plus page screenshot
explore_page Broad "does everything work?" testing Interaction results, API calls, problems, diagnostics, warnings, changes_made_to_app, screenshot. isError when problems is non-empty
execute_scenario Run specific test steps Step-by-step logs plus screenshots
get_coverage View coverage map and untested routes Coverage entries, gaps, available scenarios
suggest_tests Find coverage gaps after exploration Prioritized, ready-to-run scenarios with steps
take_screenshot Quick visual verification Screenshot of any URL
generate_report Build HTML report (auto-opens) Report path plus summary
run_full_test One-shot: scan, execute, explore, report Full results, summary.failed_scenarios (name, route, reason) plus snapshot_diff vs last run
run_converge Iterative testing until thresholds Summary across all rounds (incl. summary.failed_scenarios) plus snapshot_diff vs last run
cleanup Close browsers, free resources -

explore_page replaces the old errors field with problems (real app failures: server errors, console errors, broken values, functional failures) and diagnostics (vibe-test's own notes, such as navigation or discovery issues). It also returns warnings (possible missing data such as "Category: Unknown"; not failures) and changes_made_to_app (data-changing requests it sent, per explore.writes), and sets isError when there are problems.

Run results (run_full_test, run_converge, generate_report) carry summary.failed_scenarios, a list of { name, route, status, reason } for every failed or errored scenario, alongside explorer_failures, explorer_warnings, retry_findings and app_changes. The Markdown and HTML reports list the same findings.

Tool inputs

scan_codebase

{
  "codebase_path": "/path/to/project",
  "url": "http://localhost:3000",
  "mode": "deep"
}

get_context

{ "feature": "login" }
{ "feature": "/checkout" }
{ "feature": "user profile form" }

login

{
  "email": "[email protected]",
  "password": "TestPass123!",
  "login_url": "/login"
}

scan_page_elements / explore_page

{
  "route": "/dashboard",
  "authenticated": true
}

execute_scenario

{
  "scenario": {
    "id": "create-item",
    "name": "Create a new item",
    "route": "/items",
    "steps": [
      { "action": "navigate", "url": "/items", "description": "Open items page" },
      { "action": "click", "selector": "text=Add Item", "description": "Open create form" },
      { "action": "fill", "selector": "[name='title']", "value": "Test Item", "description": "Fill title" },
      { "action": "fill", "selector": "[name='description']", "value": "Test description", "description": "Fill description" },
      { "action": "click", "selector": "button[type='submit']", "description": "Submit form" }
    ],
    "expected_outcome": "New item appears in the list",
    "requires_auth": true
  }
}

Step actions: navigate, fill, click, select, wait, assert, upload

CLI and MCP use the same scenario runner. An assert step evaluates every supplied condition:

  • selector: the target must be visible. CSS, text=, label=, and placeholder= are supported; the named locators match exactly.
  • value: visible text must contain this string, on the selected element or on the page body when no selector is supplied.
  • url: the current URL must exactly match this absolute URL or path resolved against the configured base URL, including query and fragment.

For example:

{ "action": "assert", "selector": "#confirmation", "value": "Saved", "url": "/settings", "timeout": 5000, "description": "Check saved settings" }

These checks wait up to the step timeout (default 15000 ms per check). A failed assertion stops the scenario, records a failed step and reason, and returns status: "fail"; MCP also sets isError: true. Explicit conditions are used as the verdict after the existing authentication and form API checks. The description and expected_outcome prose are not executable assertions. Without selector, value, or url, assert only checks page health: at least 10 characters of visible body text and no nonempty visible error indicators. This compatibility check does not prove a described business outcome.

upload requires a file-input selector and a nonempty file path in value. Relative paths resolve against the codebase root. Hidden file inputs are supported. A missing file, directory, missing target, or target that is not a file input returns status: "error". The action selects one file using Playwright; add an assertion of the resulting UI to verify application-side processing. It does not automate native file-picker dialogs.

Scenarios must contain at least one step. Unknown actions are errors.

take_screenshot

{ "url": "/settings", "authenticated": true, "full_page": false }

run_full_test

{ "url": "http://localhost:3000", "codebase_path": "/path/to/project", "mode": "deep" }

run_converge

{
  "url": "http://localhost:3000",
  "max_followup_rounds": 4,
  "target_pass_rate": 0.92,
  "max_high_severity_gaps": 2
}

Full test session

Tell your AI editor:

Scan this codebase and test it against http://localhost:3000.
Log in with [email protected] / pass123. Explore the dashboard and
settings pages, run the suggested tests, and generate a report.

The AI will:

  1. scan_codebase, to understand routes, forms, existing tests
  2. get_context("login"), to read the actual login form source code
  3. login, to authenticate in a real browser
  4. explore_page("/dashboard"), clicking everything and observing what breaks
  5. explore_page("/settings"), same
  6. suggest_tests, to find coverage gaps
  7. execute_scenario x N, running targeted test flows
  8. generate_report, HTML report opens automatically
  9. cleanup, closing browsers
Test a specific feature
Test the checkout flow using vibe-test. Get context for checkout,
then run the full purchase flow with card number 4242424242424242.

The AI will:

  1. scan_codebase (if not already done)
  2. get_context("checkout"), reading CheckoutForm.tsx, api/orders/route.ts and so on
  3. login
  4. execute_scenario, filling the real form fields from source code
  5. generate_report
Verify a bug fix
I fixed the login redirect bug. Use vibe-test to confirm it's working.

The AI will:

  1. login, testing the login flow
  2. take_screenshot, visual confirmation of the post-login state
  3. Report back what it sees
Find what's broken
Explore every page and tell me what's broken.

The AI will run explore_page on every route, collecting API errors, broken elements, and failed interactions, then suggest_tests with the broken items marked as high priority.


init command

npx vibe-testing@latest init [options]

What it creates:

File Where Purpose
.mcp.json Project root Claude Code MCP config (project-level)
~/.claude.json Global Claude Code MCP config, user scope (all projects)
~/.codex/config.toml Global Codex MCP config (CLI, IDE extension, desktop app)
.cursor/mcp.json Project root Cursor MCP config
~/.cursor/mcp.json Global Cursor MCP config (all projects)
.cursor/rules/vibe-test.mdc Project Cursor rules, alwaysApply: true
.windsurfrules Project Windsurf instructions
~/.codeium/windsurf/mcp_config.json Global Windsurf MCP config (all projects)
.vscode/mcp.json Project VS Code Copilot MCP config
.github/copilot-instructions.md Project GitHub Copilot instructions
.roo/mcp.json Project Roo Code MCP config
CLAUDE.md Project Claude Code session instructions
AGENTS.md Project Universal agent instructions (Codex, Devin, Zed)
VIBE.md Project Test guidance, edit with your credentials
vibe.config.json Project Config, URL auto-detected from your project

Options:

npx vibe-testing@latest init                     # auto-detect editors, register globally + project
npx vibe-testing@latest init --no-global         # project-level only, skip global registration
npx vibe-testing@latest init --skip-browser-install
npx vibe-testing@latest init --editor cursor     # only configure Cursor
npx vibe-testing@latest init --editor claude-code windsurf
npx vibe-testing@latest init --editor codex      # register Codex even if ~/.codex is not there yet

After init, edit VIBE.md with your login URL and test credentials.


CLI commands

# Set up in current project
npx vibe-testing@latest init

# Install or repair the matching browser build
npx vibe-testing@latest install-browser

# Run tests against a URL
npx vibe-testing@latest run http://localhost:3000
npx vibe-testing@latest run https://staging.myapp.com --mode deep
npx vibe-testing@latest run http://localhost:3000 --codebase /path/to/project --scope /login /dashboard

# After a small change: test what changed thoroughly, everything else lightly
npx vibe-testing@latest run http://localhost:3000 --mode auto
npx vibe-testing@latest run http://localhost:3000 --mode changed --since main

# Iterative testing until coverage thresholds
npx vibe-testing@latest converge http://localhost:3000
npx vibe-testing@latest converge http://localhost:3000 --max-rounds 6 --target-pass-rate 0.95

# Open last report in browser
npx vibe-testing@latest report

# Reset memory and screenshots for a clean run
npx vibe-testing@latest reset
run options
Option Default Description
--mode fast|deep|auto|changed config file, else deep How much to test each page; see Test depth and modes
--since <ref> last run For auto/changed: compare against this branch, tag or commit
--no-headed - Run browser headless (default: visible)
--codebase <path> cwd Path to project root
--scope <routes...> all Test only specific routes
-c <path> vibe.config.json Config file path

run and converge fail with a nonzero exit when no scenarios are discovered or an execution batch is empty. MCP run_full_test and run_converge return isError: true for these cases. Empty runs do not write a successful run snapshot or replace the prior report.

converge options
Option Default Description
--max-rounds <n> 4 Max follow-up rounds after baseline
--target-pass-rate <r> 0.92 Stop when pass rate reaches this (0-1)
--max-gaps <n> 2 Stop when critical plus important gaps fall to this

VIBE.md, project guidance

Create VIBE.md in your project root. vibe-testing reads it automatically on every run.

## Login URL
/login

## Test Credentials
- Email: [email protected]
- Password: TestPass123!

## Never Automate
- delete account
- cancel subscription
- [data-testid="danger-zone"]
- .billing-section

## Known Flaky
- /notifications (WebSocket dependent, skip or expect retry)
- /live-feed

## Notes
- Admin panel at /admin, use [email protected] / adminpass
- Dashboard data loads async, wait for [data-loaded="true"]
- Profile page: click "Edit Profile" before form fields appear

See VIBE.example.md for the full template.


Configuration

vibe.config.json

Created automatically by init with auto-detected URL. Edit as needed:

{
  "url": "http://localhost:3000",
  "mode": "deep",
  "auth": {
    "strategy": "credentials",
    "login_url": "/login",
    "credentials": {
      "email": "[email protected]",
      "password": "TestPass123!"
    }
  },
  "never_interact": [
    "delete account",
    "cancel subscription",
    "[data-testid='danger-zone']"
  ],
  "scope": {
    "include": ["/**"],
    "exclude": ["/admin/**", "/api/**"],
    "max_routes": 30,
    "seed_routes": ["/live/dev-mode-a-now"]
  },
  "browser": {
    "headed": true,
    "slowMo": 40,
    "timeout": 30000
  }
}
Key Description
url App URL, localhost or staging. Auto-detected by init.
mode deep (default), fast, auto or changed; see Test depth and modes
auth.strategy credentials (form login), basic (HTTP Basic Auth), or skip
auth.login_url Explicit login route for non-standard paths keyword matching would miss
auth.credentials Login credentials, used for login and for generated scenarios, persisted across runs
auth.accounts More accounts on the same login form: [{ "name": "Bob", "credentials": { "email": "bob", "password": "…" } }]. With two different accounts, each run logs in as both and checks that the second cannot open the first one's pages (e.g. /orders/42 showing the first user's data).
never_interact Text patterns or CSS selectors to skip during exploration
explore.writes What exploration may change in the app. safe (default): creates new records (add/create forms, "add" buttons, probes on blank forms) but never overwrites a value already in a field, and doesn't probe or create-check forms that edit existing data (settings, profile, branding). all: also overwrites existing values and tests edit forms. none: no data-changing submissions. Every data-changing request exploration made is listed under "Changes made to the app" in the run summary and the report.
scope.include Route patterns to include; default /** includes / and all nested routes. * stays within one segment; a trailing /** includes the subtree root and its descendants. Other characters are literal. Applies to pages from the code and pages found by the live crawl.
scope.exclude Route patterns to exclude from testing (code and crawled pages)
scope.since For mode auto/changed: the branch, tag or commit "changed" is compared against. Default: the commit of the last run (.vibe/baseline.json) plus uncommitted changes.
scope.max_routes Cap how many routes are tested per run
scope.seed_routes Concrete URLs for dynamic-segment routes the parser can't enumerate (e.g. /live/[slug] becomes /live/dev-mode-a-now). Each seeded route inherits requires_auth and the source file from its dynamic parent.
browser.headed true = visible browser. CLI default true, MCP server default false (headless) so editor sessions aren't disrupted by pop-up windows.
browser.slowMo Milliseconds between actions (useful for debugging)
routes Deprecated and ignored; use scope to choose pages.
Test depth and modes

Each page is tested at one of three depths:

Depth What runs
light Load the page; server errors, console errors, broken values and resources, crash text. No clicks or submissions.
standard Light, plus tabs, fills, toggles, buttons that don't change data (with the empty-state check), and links checked by request.
thorough Everything: data-changing buttons, the in-app journey, totals after actions, create-then-verify, boundary probes, and the logout and cross-user session checks.

mode decides the depth per page:

mode Pages
deep (default) Every page thoroughly.
fast Every page lightly.
auto Pages changed since scope.since (default: the last run) thoroughly, pages affected through a shared file at standard, all others lightly. The first run (no baseline yet) behaves like deep.
changed Only changed and affected pages, thoroughly; nothing else.

With source code, "changed" comes from version control: files changed since the baseline (plus uncommitted and untracked files) are followed through the import graph to the pages that use them. A page's own file or a component it imports makes it thorough; a file most pages use (layout, context, API client) makes every page standard; a style sheet asks for a light check; a server handler makes the pages that called its endpoint thorough. Without a repository, auto/changed test every page thoroughly and say why. Without source code (black-box), every page gets a light visit and pages whose structure changed since the last run (controls, links, forms, headings, API calls; data and counts are ignored) are tested thoroughly.

In every mode, pages built from one template (same route pattern such as /tutorial/:page, or the same controls under one parent path) are tested thoroughly once and lightly after that, and any page that shows a problem at light or standard depth, or whose scenario failed, is re-tested thoroughly in the same run. The run summary (summary.plan) and the report's "Test plan" section list every page's depth and the reason; nothing is skipped silently.


Supported frameworks

Framework Routes API endpoints Forms
Next.js App Router yes yes yes
Next.js Pages Router yes yes yes
Next.js (src/ variant) yes yes yes
React SPA (react-router) yes - yes
Vue + Vite (vue-router) yes - yes
Nuxt yes yes yes
SvelteKit yes yes yes
Express / Fastify - yes yes
Monorepos (Turborepo, pnpm, Lerna) yes yes yes

Existing test files are also read to build a coverage map: Jest, Vitest, Playwright, and Cypress suites are all parsed.


Memory and regression detection

vibe-testing learns across runs and stores state in .vibe/:

  • Working selectors: remembers [name='email'] worked on /login, uses it next run
  • Route timings: adjusts timeouts based on measured load times
  • Auth credentials: saved after first login, reused automatically
  • Flaky routes: tracks high fail-rate routes, marks them for retry
  • Skip routes: routes that consistently error (need URL params) are auto-skipped
  • Route manifest (.vibe/route-manifest.json): every scan diffs against the previous one; new and removed routes surface as route_changes on scan_codebase results so the AI can cover them immediately
  • Run snapshot (.vibe/run-snapshot.json): every run captures per-route pass/fail and diffs against the prior run; snapshot_diff flags newly_passing (fixes), newly_failing (regressions), still_failing, plus added and removed routes
{
  "snapshot_diff": {
    "newly_passing": ["/login"],
    "newly_failing": ["/checkout"],
    "still_failing": [],
    "new_routes": ["/admin/users"],
    "removed_routes": []
  }
}

run_converge returns the same shape, so iterative runs in your editor highlight what you just broke.

Reset with npx vibe-testing@latest reset to start fresh.


What a session looks like

When you ask your editor to "test the login flow", here is what it does:

User: "Test the login flow"

AI calls:
  scan_codebase({ codebase_path: ".", url: "http://localhost:3000" })
    -> Finds /login route, LoginForm component, POST /api/auth/login endpoint
    -> Returns 8 generated test scenarios

  get_context({ feature: "login" })
    -> Returns src/app/login/page.tsx (has name="email", name="password" fields)
    -> Returns src/app/api/auth/login/route.ts (POST handler, returns { token })
    -> AI now knows the real selectors: [name='email'], [name='password']

  login({ email: "[email protected]", password: "pass123" })
    -> Opens Chromium, fills the form, clicks submit
    -> Returns: { success: true, final_url: "/dashboard", tokens_found: 2 }
    -> Returns screenshot of post-login dashboard

  execute_scenario({ scenario: { name: "Login with invalid password", ... } })
    -> Returns screenshot showing error state

  generate_report()
    -> Writes .vibe/report.html, opens in browser

AI reports: "Login works. Invalid password shows an error. All 3 login scenarios passed."

FAQ

Does vibe-testing use an LLM internally? No. It uses heuristic verification (URL changes, toast detection, API errors). Your editor's model is the brain: it sees screenshots and decides what to test next. Runs have no API cost.

What's the difference between explore_page and execute_scenario? explore_page is broad: it clicks every button and input it finds and reports the results. execute_scenario is precise: you give it specific steps and it follows them exactly. Use explore_page to find what's on a page, then execute_scenario to test specific flows.

What's get_context for? It returns the actual source code for a feature, so the AI knows [name='email'] instead of guessing #email-input. Always call it before writing test steps for a specific feature.

Does it handle SPAs with client-side routing? Yes. Playwright navigates the real browser, so client-side routing (React Router, Vue Router, and the rest) works naturally.

Does it handle login / authentication? Yes. The login tool fills credentials in a real browser, captures auth tokens from localStorage/cookies, and keeps that session alive for authenticated tests. Credentials are persisted in .vibe/memory/ and reused automatically.

Will it click "Delete Account" or other destructive buttons? No. Set never_interact in vibe.config.json or VIBE.md to blocklist dangerous actions. Any button whose text or selector matches is skipped during exploration.

Can I use it without an AI editor? Yes. vibe-test run https://your-app.com runs standalone. It scans, generates scenarios, executes them, and produces an HTML report without needing an editor.

How do I test a staging environment? Set url in vibe.config.json to your staging URL, or pass it as a CLI argument: npx vibe-testing@latest run https://staging.myapp.com.

Does it work with monorepos? Yes. init detects Turborepo/pnpm/yarn workspaces and finds the frontend app automatically.


Requirements

  • Node.js >= 20 (the test suite uses vitest 4.x which requires Node 20+)
  • Playwright Chromium. init installs the matching build. To install or repair it directly:
    npx vibe-testing@latest install-browser
    

run and converge check for the browser before scanning your project and print the same recovery command when it is missing.

Docker

A Node 20 + Chromium image is included for environments that prefer container-based MCP servers:

docker build -t vibe-test .
# wire into your editor's MCP config:
# { "command": "docker", "args": ["run", "--rm", "-i", "vibe-test"] }

Contributing

git clone https://github.com/AishwaryShrivastav/vibe-testing.git
cd vibe-testing
npm install
npx playwright install chromium
npm run build   # tsc -> dist/
npm run dev     # run CLI without building
npm run mcp     # run MCP server without building
npm test        # unit and isolated integration tests
VIBE_REAL_BROWSER=1 npm test  # also run real Chromium CLI/MCP regressions

See CHANGELOG.md for version history. Bug reports and feature requests: GitHub issues.


License

MIT, Aishwary Shrivastav


1# vibe-testing
2 
3[![npm version](https://img.shields.io/npm/v/vibe-testing.svg)](https://www.npmjs.com/package/vibe-testing)
4[![npm downloads](https://img.shields.io/npm/dt/vibe-testing?label=npm%20downloads)](https://www.npmjs.com/package/vibe-testing)
5[![GitHub stars](https://img.shields.io/github/stars/AishwaryShrivastav/vibe-testing?style=flat)](https://github.com/AishwaryShrivastav/vibe-testing/stargazers)
6[![Node.js](https://img.shields.io/badge/node-%3E%3D20-brightgreen.svg)](https://nodejs.org)
7[![MCP](https://img.shields.io/badge/MCP-compatible-blue.svg)](https://modelcontextprotocol.io)
8[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
9[![CI](https://github.com/AishwaryShrivastav/vibe-testing/actions/workflows/ci.yml/badge.svg)](https://github.com/AishwaryShrivastav/vibe-testing/actions)
10 
11**Code-aware browser testing for AI coding agents.**
12 
13[Product site](https://testing.tfgstudio.com/) · [npm](https://www.npmjs.com/package/vibe-testing) · [MCP Registry](https://registry.modelcontextprotocol.io/?q=io.github.AishwaryShrivastav%2Fvibe-testing) · [Smithery](https://smithery.ai/servers/aish/vibe-testing) · [Privacy](PRIVACY.md) · [Launch status](https://github.com/AishwaryShrivastav/vibe-testing/blob/main/docs/distribution/launch-status.md)
14 
15Listed in [Awesome MCP Servers](https://github.com/punkpeye/awesome-mcp-servers/pull/14575). The download badge shows npm's cumulative package downloads; `npx` package fetches contribute to that total.
16 
17vibe-testing reads your codebase so tests use your real routes and field names, runs them in a real Playwright browser, remembers what broke, and tells you what your last change fixed or regressed. It works as an MCP server that gives your editor (Claude Code, Cursor, Windsurf, VS Code Copilot, Roo Code) 14 testing tools, or as a standalone CLI.
18 
19The repository is also an [Agent Plugin](https://agent-plugins.org/) with a `release-qa` skill. Compatible agents get both the testing tools and a senior-QA workflow for coverage, evidence, regression checks, and a clear release verdict.
20 
21```bash
22cd /path/to/your/project
23npx vibe-testing@latest init
24```
25 
26Then open your editor and say:
27 
28> "Scan this codebase and test it against http://localhost:3000"
29 
30No source code? Point it at a URL from an empty folder and it tests the app black-box:
31 
32```bash
33npx vibe-testing@latest run https://staging.example.com
34```
35 
36---
37 
38## It finds bugs you didn't write a test for
39 
40While it explores, vibe-testing checks for server crashes, console errors, broken values (`NaN`, `[object Object]`, `Invalid Date`), totals that don't match their line items, saved values that never appear, a logout that doesn't end the session, and one user opening another user's pages. No scenarios to write.
41 
42Measured on intentionally buggy apps (0.5.0, [details in #13](https://github.com/AishwaryShrivastav/vibe-testing/pull/13)):
43 
44| App | Mode | Before | 0.5.0 |
45|---|---|---|---|
46| react-simple-project (7 planted functional bugs) | with source code | 1 of 7 | **7 of 7** |
47| react-simple-project | URL only | 0 of 7 | **7 of 7** |
48| OWASP NodeGoat | with source code | 0 issues | `/contributions` crash, `/allocations` 500s, a redirect to `/undefined` |
49| restful-booker-platform (no planted bugs) | both | 3 pages, 4 false errors | 8+ pages, 1 real bug: `/api/room/:id` returns 500 |
50 
51No false findings on these three apps in either mode. Run it against a test environment: exploration creates records and lists every change it made.
52 
53Using it on your project? Add the badge:
54 
55```markdown
56[![tested with vibe-testing](https://img.shields.io/badge/tested%20with-vibe--testing-7c3aed)](https://github.com/AishwaryShrivastav/vibe-testing)
57```
58 
59---
60 
61## What code-aware testing adds
62 
63Playwright MCP gives your agent hands. vibe-testing gives it a testing workflow: code-derived scenarios, memory across runs, and a report. Two things a stateless browser tool cannot do:
64 
65**1. Run it twice and it tells you what you broke.** Every run writes `.vibe/run-snapshot.json` and diffs it against the previous run. Every scan writes `.vibe/route-manifest.json` and diffs your routes. The second run prints regressions and fixes instead of a wall of results:
66 
67```
68Changes since last run
69 Fixed: /login
70 Regression: /checkout
71 New: /admin/users
72```
73 
74The same diff reaches your editor as `snapshot_diff` on `run_full_test` and `run_converge`, and as `route_changes` on `scan_codebase`, so the agent can flag "checkout broke after that commit" without anyone scrolling a report. Flaky routes, working selectors, and measured timeouts are also remembered between runs.
75 
76**2. Zero LLM calls inside the tool.** Pass/fail verification is heuristic: URL changes, toast detection, API errors. Your editor's model decides what to test; vibe-testing does the browsing and checking. No API key, no per-run cost beyond the editor subscription you already pay for.
77 
78---
79 
80## Contents
81 
82- [How it works](#how-it-works)
83- [MCP setup (per editor)](#mcp-setup)
84- [MCP tools reference](#mcp-tools-reference)
85- [Recommended workflow](#recommended-workflow)
86- [init command](#init-command)
87- [CLI commands](#cli-commands)
88- [VIBE.md, project guidance](#vibemd-project-guidance)
89- [Configuration (vibe.config.json)](#configuration)
90- [Supported frameworks](#supported-frameworks)
91- [Memory and regression detection](#memory-and-regression-detection)
92- [FAQ](#faq)
93 
94---
95 
96## How it works
97 
98```
99npx vibe-testing@latest init
100 |
101Registers 14 MCP tools in your editor
102 |
103You ask: "Test the checkout flow"
104 |
105AI calls: scan_codebase -> get_context("checkout") -> login -> explore_page -> execute_scenario -> generate_report
106 |
107HTML report opens in browser with screenshots of every step
108```
109 
110No test cases to write. The AI reads your source code to understand real field names and routes, opens a browser, tests everything, and shows you what's broken.
111 
112`init` also:
113 
114- Detects which AI editors you have installed
115- Registers vibe-test in global editor configs (`~/.claude.json`, `~/.cursor/mcp.json`, `~/.codex/config.toml`, and so on) so the tools are available in every project, every session
116- Creates project-level MCP configs and AI instruction files
117- Auto-detects your app's URL (reads `.env`, `vite.config`, framework defaults)
118- Creates `VIBE.md` (edit with your test credentials) and `vibe.config.json`
119- Installs the matching Playwright Chromium build
120 
121---
122 
123## MCP setup
124 
125### Agent Plugin
126 
127Install this repository as a plugin when your agent supports the Agent Plugins standard. It includes the portable `release-qa` skill and starts the published npm MCP server with no API key.
128 
129- Cursor: submit or install `https://github.com/AishwaryShrivastav/vibe-testing` as an Agent Plugin.
130- Claude Code:
131 
132 ```bash
133 claude plugin marketplace add AishwaryShrivastav/vibe-testing
134 claude plugin install vibe-testing@vibe-testing
135 ```
136- Other compatible agents: load the repository root containing `plugin.json`, `skills/`, and `mcp.json`.
137 
138The direct MCP and CLI setup below remains available for editors without plugin support.
139 
140### MCPB bundle
141 
142Claude Desktop and other MCPB hosts can install one local bundle. Build and validate it from this repository:
143 
144```bash
145npm ci
146npm run build:mcpb
147```
148 
149The artifact is written to `artifacts/vibe-testing-<version>.mcpb`. See the [MCPB distribution guide](docs/distribution/mcpb.md) for the bundle contents, validation steps, Smithery handoff, and the one-time Playwright Chromium prerequisite.
150 
151### Option 1: automatic (recommended)
152 
153```bash
154npx vibe-testing@latest init
155```
156 
157Detects Claude Code, Cursor, Codex, Windsurf, VS Code and Roo Code, registers vibe-test in each, and prints what to do next in each editor. It never overwrites a config file it cannot parse, and running it twice changes nothing.
158 
159### Option 2: one command per editor
160 
161| Editor | Run this | Then |
162|---|---|---|
163| Claude Code | `claude mcp add --scope user vibe-test -- npx -y vibe-testing@latest --mcp` | Start a new `claude` session. `/mcp` shows vibe-test as connected. |
164| Codex (CLI, IDE extension, desktop app) | `codex mcp add vibe-test -- npx -y vibe-testing@latest --mcp` | Start a new `codex` session. `/mcp` lists vibe-test. |
165| VS Code (Copilot) | `code --add-mcp '{"name":"vibe-test","type":"stdio","command":"npx","args":["-y","vibe-testing@latest","--mcp"]}'` | Use Agent mode in Copilot Chat. |
166| Cursor | Add the JSON below to `~/.cursor/mcp.json` | Cursor Settings > MCP: check vibe-test is switched on. |
167| Windsurf | Add the JSON below to `~/.codeium/windsurf/mcp_config.json` | Press Refresh in the Cascade MCP panel. |
168 
169Then say to your agent:
170 
171> "Scan this codebase and test it against http://localhost:3000"
172 
173The first run downloads a Chromium build (one-time, roughly 150 MB). `npx vibe-testing@latest install-browser` does it ahead of time.
174 
175### Option 3: edit the config file yourself
176 
177#### Claude Code
178 
179For every project, the user-scope config is `~/.claude.json` (top-level `mcpServers`). Claude Code does not read MCP servers from `~/.claude/settings.json`. For one project, use `.mcp.json` in the project root, which you can commit for your team:
180 
181```json
182{
183 "mcpServers": {
184 "vibe-test": {
185 "type": "stdio",
186 "command": "npx",
187 "args": ["-y", "vibe-testing@latest", "--mcp"]
188 }
189 }
190}
191```
192 
193Claude Code asks you to approve a project-scoped server the first time it sees it.
194 
195#### Codex
196 
197Add to `~/.codex/config.toml`. The Codex CLI, IDE extension and desktop app share this file:
198 
199```toml
200[mcp_servers.vibe-test]
201command = "npx"
202args = ["-y", "vibe-testing@latest", "--mcp"]
203```
204 
205`init` also writes `AGENTS.md`, which Codex reads for project instructions.
206 
207#### Cursor
208 
209Add to `~/.cursor/mcp.json` (global) or `.cursor/mcp.json` (project):
210 
211```json
212{
213 "mcpServers": {
214 "vibe-test": {
215 "command": "npx",
216 "args": ["-y", "vibe-testing@latest", "--mcp"]
217 }
218 }
219}
220```
221 
222#### Windsurf
223 
224Add to `~/.codeium/windsurf/mcp_config.json`:
225 
226```json
227{
228 "mcpServers": {
229 "vibe-test": {
230 "command": "npx",
231 "args": ["-y", "vibe-testing@latest", "--mcp"]
232 }
233 }
234}
235```
236 
237#### VS Code (GitHub Copilot)
238 
239Add to `.vscode/mcp.json` in your project:
240 
241```json
242{
243 "servers": {
244 "vibe-test": {
245 "type": "stdio",
246 "command": "npx",
247 "args": ["-y", "vibe-testing@latest", "--mcp"]
248 }
249 }
250}
251```
252 
253#### Roo Code / Cline
254 
255Add to `.roo/mcp.json`:
256 
257```json
258{
259 "mcpServers": {
260 "vibe-test": {
261 "command": "npx",
262 "args": ["-y", "vibe-testing@latest", "--mcp"]
263 }
264 }
265}
266```
267 
268#### From local build (development)
269 
270```json
271{
272 "mcpServers": {
273 "vibe-test": {
274 "command": "node",
275 "args": ["/path/to/vibe-testing/dist/mcp-server.js"]
276 }
277 }
278}
279```
280 
281---
282 
283## MCP tools reference
284 
28514 tools available to your AI editor after setup:
286 
287| Tool | When to call | Returns |
288|------|-------------|---------|
289| `configure` | Start here on a new project. Detects framework, server, and authentication | Structured setup result and idempotent project files |
290| `scan_codebase` | Always first. Reads source code, finds routes/forms/tests/gaps | Routes, forms, coverage map, generated scenarios, `route_changes` since last scan |
291| `get_context` | Before writing test steps. Returns source files for a feature | Actual source code with real field names and selectors |
292| `login` | When app requires authentication | Post-login screenshot, token state, API calls observed |
293| `scan_page_elements` | To see all interactive elements on a page | Element list with selectors plus page screenshot |
294| `explore_page` | Broad "does everything work?" testing | Interaction results, API calls, `problems`, `diagnostics`, `warnings`, `changes_made_to_app`, screenshot. `isError` when `problems` is non-empty |
295| `execute_scenario` | Run specific test steps | Step-by-step logs plus screenshots |
296| `get_coverage` | View coverage map and untested routes | Coverage entries, gaps, available scenarios |
297| `suggest_tests` | Find coverage gaps after exploration | Prioritized, ready-to-run scenarios with steps |
298| `take_screenshot` | Quick visual verification | Screenshot of any URL |
299| `generate_report` | Build HTML report (auto-opens) | Report path plus summary |
300| `run_full_test` | One-shot: scan, execute, explore, report | Full results, `summary.failed_scenarios` (name, route, reason) plus `snapshot_diff` vs last run |
301| `run_converge` | Iterative testing until thresholds | Summary across all rounds (incl. `summary.failed_scenarios`) plus `snapshot_diff` vs last run |
302| `cleanup` | Close browsers, free resources | - |
303 
304`explore_page` replaces the old `errors` field with `problems` (real app failures: server errors, console errors, broken values, functional failures) and `diagnostics` (vibe-test's own notes, such as navigation or discovery issues). It also returns `warnings` (possible missing data such as "Category: Unknown"; not failures) and `changes_made_to_app` (data-changing requests it sent, per `explore.writes`), and sets `isError` when there are `problems`.
305 
306Run results (`run_full_test`, `run_converge`, `generate_report`) carry `summary.failed_scenarios`, a list of `{ name, route, status, reason }` for every failed or errored scenario, alongside `explorer_failures`, `explorer_warnings`, `retry_findings` and `app_changes`. The Markdown and HTML reports list the same findings.
307 
308### Tool inputs
309 
310**`scan_codebase`**
311```json
312{
313 "codebase_path": "/path/to/project",
314 "url": "http://localhost:3000",
315 "mode": "deep"
316}
317```
318 
319**`get_context`**
320```json
321{ "feature": "login" }
322{ "feature": "/checkout" }
323{ "feature": "user profile form" }
324```
325 
326**`login`**
327```json
328{
329 "email": "[email protected]",
330 "password": "TestPass123!",
331 "login_url": "/login"
332}
333```
334 
335**`scan_page_elements`** / **`explore_page`**
336```json
337{
338 "route": "/dashboard",
339 "authenticated": true
340}
341```
342 
343**`execute_scenario`**
344```json
345{
346 "scenario": {
347 "id": "create-item",
348 "name": "Create a new item",
349 "route": "/items",
350 "steps": [
351 { "action": "navigate", "url": "/items", "description": "Open items page" },
352 { "action": "click", "selector": "text=Add Item", "description": "Open create form" },
353 { "action": "fill", "selector": "[name='title']", "value": "Test Item", "description": "Fill title" },
354 { "action": "fill", "selector": "[name='description']", "value": "Test description", "description": "Fill description" },
355 { "action": "click", "selector": "button[type='submit']", "description": "Submit form" }
356 ],
357 "expected_outcome": "New item appears in the list",
358 "requires_auth": true
359 }
360}
361```
362 
363Step actions: `navigate`, `fill`, `click`, `select`, `wait`, `assert`, `upload`
364 
365CLI and MCP use the same scenario runner. An `assert` step evaluates every
366supplied condition:
367 
368- `selector`: the target must be visible. CSS, `text=`, `label=`, and
369 `placeholder=` are supported; the named locators match exactly.
370- `value`: visible text must contain this string, on the selected element or on
371 the page body when no selector is supplied.
372- `url`: the current URL must exactly match this absolute URL or path resolved
373 against the configured base URL, including query and fragment.
374 
375For example:
376 
377```json
378{ "action": "assert", "selector": "#confirmation", "value": "Saved", "url": "/settings", "timeout": 5000, "description": "Check saved settings" }
379```
380 
381These checks wait up to the step timeout (default 15000 ms per check). A failed
382assertion stops the scenario, records a failed step and reason, and returns
383`status: "fail"`; MCP also sets `isError: true`. Explicit conditions are used as
384the verdict after the existing authentication and form API checks. The
385`description` and `expected_outcome` prose are not executable assertions.
386Without `selector`, `value`, or `url`, `assert` only checks page health: at least
38710 characters of visible body text and no nonempty visible error indicators.
388This compatibility check does not prove a described business outcome.
389 
390`upload` requires a file-input `selector` and a nonempty file path in `value`.
391Relative paths resolve against the codebase root. Hidden file inputs are
392supported. A missing file, directory, missing target, or target that is not a
393file input returns `status: "error"`. The action selects one file using
394Playwright; add an assertion of the resulting UI to verify application-side
395processing. It does not automate native file-picker dialogs.
396 
397Scenarios must contain at least one step. Unknown actions are errors.
398 
399 
400**`take_screenshot`**
401```json
402{ "url": "/settings", "authenticated": true, "full_page": false }
403```
404 
405**`run_full_test`**
406```json
407{ "url": "http://localhost:3000", "codebase_path": "/path/to/project", "mode": "deep" }
408```
409 
410**`run_converge`**
411```json
412{
413 "url": "http://localhost:3000",
414 "max_followup_rounds": 4,
415 "target_pass_rate": 0.92,
416 "max_high_severity_gaps": 2
417}
418```
419 
420---
421 
422## Recommended workflow
423 
424### Full test session
425 
426Tell your AI editor:
427 
428```
429Scan this codebase and test it against http://localhost:3000.
430Log in with [email protected] / pass123. Explore the dashboard and
431settings pages, run the suggested tests, and generate a report.
432```
433 
434The AI will:
4351. `scan_codebase`, to understand routes, forms, existing tests
4362. `get_context("login")`, to read the actual login form source code
4373. `login`, to authenticate in a real browser
4384. `explore_page("/dashboard")`, clicking everything and observing what breaks
4395. `explore_page("/settings")`, same
4406. `suggest_tests`, to find coverage gaps
4417. `execute_scenario` x N, running targeted test flows
4428. `generate_report`, HTML report opens automatically
4439. `cleanup`, closing browsers
444 
445### Test a specific feature
446 
447```
448Test the checkout flow using vibe-test. Get context for checkout,
449then run the full purchase flow with card number 4242424242424242.
450```
451 
452The AI will:
4531. `scan_codebase` (if not already done)
4542. `get_context("checkout")`, reading `CheckoutForm.tsx`, `api/orders/route.ts` and so on
4553. `login`
4564. `execute_scenario`, filling the real form fields from source code
4575. `generate_report`
458 
459### Verify a bug fix
460 
461```
462I fixed the login redirect bug. Use vibe-test to confirm it's working.
463```
464 
465The AI will:
4661. `login`, testing the login flow
4672. `take_screenshot`, visual confirmation of the post-login state
4683. Report back what it sees
469 
470### Find what's broken
471 
472```
473Explore every page and tell me what's broken.
474```
475 
476The AI will run `explore_page` on every route, collecting API errors, broken elements, and failed interactions, then `suggest_tests` with the broken items marked as high priority.
477 
478---
479 
480## init command
481 
482```bash
483npx vibe-testing@latest init [options]
484```
485 
486What it creates:
487 
488| File | Where | Purpose |
489|------|-------|---------|
490| `.mcp.json` | Project root | Claude Code MCP config (project-level) |
491| `~/.claude.json` | Global | Claude Code MCP config, user scope (all projects) |
492| `~/.codex/config.toml` | Global | Codex MCP config (CLI, IDE extension, desktop app) |
493| `.cursor/mcp.json` | Project root | Cursor MCP config |
494| `~/.cursor/mcp.json` | Global | Cursor MCP config (all projects) |
495| `.cursor/rules/vibe-test.mdc` | Project | Cursor rules, `alwaysApply: true` |
496| `.windsurfrules` | Project | Windsurf instructions |
497| `~/.codeium/windsurf/mcp_config.json` | Global | Windsurf MCP config (all projects) |
498| `.vscode/mcp.json` | Project | VS Code Copilot MCP config |
499| `.github/copilot-instructions.md` | Project | GitHub Copilot instructions |
500| `.roo/mcp.json` | Project | Roo Code MCP config |
501| `CLAUDE.md` | Project | Claude Code session instructions |
502| `AGENTS.md` | Project | Universal agent instructions (Codex, Devin, Zed) |
503| `VIBE.md` | Project | Test guidance, edit with your credentials |
504| `vibe.config.json` | Project | Config, URL auto-detected from your project |
505 
506Options:
507 
508```bash
509npx vibe-testing@latest init # auto-detect editors, register globally + project
510npx vibe-testing@latest init --no-global # project-level only, skip global registration
511npx vibe-testing@latest init --skip-browser-install
512npx vibe-testing@latest init --editor cursor # only configure Cursor
513npx vibe-testing@latest init --editor claude-code windsurf
514npx vibe-testing@latest init --editor codex # register Codex even if ~/.codex is not there yet
515```
516 
517After init, edit `VIBE.md` with your login URL and test credentials.
518 
519---
520 
521## CLI commands
522 
523```bash
524# Set up in current project
525npx vibe-testing@latest init
526 
527# Install or repair the matching browser build
528npx vibe-testing@latest install-browser
529 
530# Run tests against a URL
531npx vibe-testing@latest run http://localhost:3000
532npx vibe-testing@latest run https://staging.myapp.com --mode deep
533npx vibe-testing@latest run http://localhost:3000 --codebase /path/to/project --scope /login /dashboard
534 
535# After a small change: test what changed thoroughly, everything else lightly
536npx vibe-testing@latest run http://localhost:3000 --mode auto
537npx vibe-testing@latest run http://localhost:3000 --mode changed --since main
538 
539# Iterative testing until coverage thresholds
540npx vibe-testing@latest converge http://localhost:3000
541npx vibe-testing@latest converge http://localhost:3000 --max-rounds 6 --target-pass-rate 0.95
542 
543# Open last report in browser
544npx vibe-testing@latest report
545 
546# Reset memory and screenshots for a clean run
547npx vibe-testing@latest reset
548```
549 
550### `run` options
551 
552| Option | Default | Description |
553|--------|---------|-------------|
554| `--mode fast\|deep\|auto\|changed` | config file, else `deep` | How much to test each page; see [Test depth and modes](#test-depth-and-modes) |
555| `--since <ref>` | last run | For `auto`/`changed`: compare against this branch, tag or commit |
556| `--no-headed` | - | Run browser headless (default: visible) |
557| `--codebase <path>` | cwd | Path to project root |
558| `--scope <routes...>` | all | Test only specific routes |
559| `-c <path>` | `vibe.config.json` | Config file path |
560 
561`run` and `converge` fail with a nonzero exit when no scenarios are discovered
562or an execution batch is empty. MCP `run_full_test` and `run_converge` return
563`isError: true` for these cases. Empty runs do not write a successful run
564snapshot or replace the prior report.
565 
566### `converge` options
567 
568| Option | Default | Description |
569|--------|---------|-------------|
570| `--max-rounds <n>` | `4` | Max follow-up rounds after baseline |
571| `--target-pass-rate <r>` | `0.92` | Stop when pass rate reaches this (0-1) |
572| `--max-gaps <n>` | `2` | Stop when critical plus important gaps fall to this |
573 
574---
575 
576## VIBE.md, project guidance
577 
578Create `VIBE.md` in your project root. vibe-testing reads it automatically on every run.
579 
580```markdown
581## Login URL
582/login
583 
584## Test Credentials
585- Email: [email protected]
586- Password: TestPass123!
587 
588## Never Automate
589- delete account
590- cancel subscription
591- [data-testid="danger-zone"]
592- .billing-section
593 
594## Known Flaky
595- /notifications (WebSocket dependent, skip or expect retry)
596- /live-feed
597 
598## Notes
599- Admin panel at /admin, use [email protected] / adminpass
600- Dashboard data loads async, wait for [data-loaded="true"]
601- Profile page: click "Edit Profile" before form fields appear
602```
603 
604See [`VIBE.example.md`](./VIBE.example.md) for the full template.
605 
606---
607 
608## Configuration
609 
610### vibe.config.json
611 
612Created automatically by `init` with auto-detected URL. Edit as needed:
613 
614```json
615{
616 "url": "http://localhost:3000",
617 "mode": "deep",
618 "auth": {
619 "strategy": "credentials",
620 "login_url": "/login",
621 "credentials": {
622 "email": "[email protected]",
623 "password": "TestPass123!"
624 }
625 },
626 "never_interact": [
627 "delete account",
628 "cancel subscription",
629 "[data-testid='danger-zone']"
630 ],
631 "scope": {
632 "include": ["/**"],
633 "exclude": ["/admin/**", "/api/**"],
634 "max_routes": 30,
635 "seed_routes": ["/live/dev-mode-a-now"]
636 },
637 "browser": {
638 "headed": true,
639 "slowMo": 40,
640 "timeout": 30000
641 }
642}
643```
644 
645| Key | Description |
646|-----|-------------|
647| `url` | App URL, localhost or staging. Auto-detected by `init`. |
648| `mode` | `deep` (default), `fast`, `auto` or `changed`; see [Test depth and modes](#test-depth-and-modes) |
649| `auth.strategy` | `credentials` (form login), `basic` (HTTP Basic Auth), or `skip` |
650| `auth.login_url` | Explicit login route for non-standard paths keyword matching would miss |
651| `auth.credentials` | Login credentials, used for login and for generated scenarios, persisted across runs |
652| `auth.accounts` | More accounts on the same login form: `[{ "name": "Bob", "credentials": { "email": "bob", "password": "…" } }]`. With two different accounts, each run logs in as both and checks that the second cannot open the first one's pages (e.g. `/orders/42` showing the first user's data). |
653| `never_interact` | Text patterns or CSS selectors to skip during exploration |
654| `explore.writes` | What exploration may change in the app. `safe` (default): creates new records (add/create forms, "add" buttons, probes on blank forms) but never overwrites a value already in a field, and doesn't probe or create-check forms that edit existing data (settings, profile, branding). `all`: also overwrites existing values and tests edit forms. `none`: no data-changing submissions. Every data-changing request exploration made is listed under "Changes made to the app" in the run summary and the report. |
655| `scope.include` | Route patterns to include; default `/**` includes `/` and all nested routes. `*` stays within one segment; a trailing `/**` includes the subtree root and its descendants. Other characters are literal. Applies to pages from the code and pages found by the live crawl. |
656| `scope.exclude` | Route patterns to exclude from testing (code and crawled pages) |
657| `scope.since` | For mode `auto`/`changed`: the branch, tag or commit "changed" is compared against. Default: the commit of the last run (`.vibe/baseline.json`) plus uncommitted changes. |
658| `scope.max_routes` | Cap how many routes are tested per run |
659| `scope.seed_routes` | Concrete URLs for dynamic-segment routes the parser can't enumerate (e.g. `/live/[slug]` becomes `/live/dev-mode-a-now`). Each seeded route inherits `requires_auth` and the source file from its dynamic parent. |
660| `browser.headed` | `true` = visible browser. CLI default `true`, MCP server default `false` (headless) so editor sessions aren't disrupted by pop-up windows. |
661| `browser.slowMo` | Milliseconds between actions (useful for debugging) |
662| `routes` | Deprecated and ignored; use `scope` to choose pages. |
663 
664### Test depth and modes
665 
666Each page is tested at one of three depths:
667 
668| Depth | What runs |
669|-------|-----------|
670| light | Load the page; server errors, console errors, broken values and resources, crash text. No clicks or submissions. |
671| standard | Light, plus tabs, fills, toggles, buttons that don't change data (with the empty-state check), and links checked by request. |
672| thorough | Everything: data-changing buttons, the in-app journey, totals after actions, create-then-verify, boundary probes, and the logout and cross-user session checks. |
673 
674`mode` decides the depth per page:
675 
676| `mode` | Pages |
677|--------|-------|
678| `deep` (default) | Every page thoroughly. |
679| `fast` | Every page lightly. |
680| `auto` | Pages changed since `scope.since` (default: the last run) thoroughly, pages affected through a shared file at standard, all others lightly. The first run (no baseline yet) behaves like `deep`. |
681| `changed` | Only changed and affected pages, thoroughly; nothing else. |
682 
683With source code, "changed" comes from version control: files changed since the baseline (plus uncommitted and untracked files) are followed through the import graph to the pages that use them. A page's own file or a component it imports makes it thorough; a file most pages use (layout, context, API client) makes every page standard; a style sheet asks for a light check; a server handler makes the pages that called its endpoint thorough. Without a repository, `auto`/`changed` test every page thoroughly and say why. Without source code (black-box), every page gets a light visit and pages whose structure changed since the last run (controls, links, forms, headings, API calls; data and counts are ignored) are tested thoroughly.
684 
685In every mode, pages built from one template (same route pattern such as `/tutorial/:page`, or the same controls under one parent path) are tested thoroughly once and lightly after that, and any page that shows a problem at light or standard depth, or whose scenario failed, is re-tested thoroughly in the same run. The run summary (`summary.plan`) and the report's "Test plan" section list every page's depth and the reason; nothing is skipped silently.
686 
687---
688 
689## Supported frameworks
690 
691| Framework | Routes | API endpoints | Forms |
692|-----------|--------|---------------|-------|
693| Next.js App Router | yes | yes | yes |
694| Next.js Pages Router | yes | yes | yes |
695| Next.js (src/ variant) | yes | yes | yes |
696| React SPA (react-router) | yes | - | yes |
697| Vue + Vite (vue-router) | yes | - | yes |
698| Nuxt | yes | yes | yes |
699| SvelteKit | yes | yes | yes |
700| Express / Fastify | - | yes | yes |
701| Monorepos (Turborepo, pnpm, Lerna) | yes | yes | yes |
702 
703Existing test files are also read to build a coverage map: Jest, Vitest, Playwright, and Cypress suites are all parsed.
704 
705---
706 
707## Memory and regression detection
708 
709vibe-testing learns across runs and stores state in `.vibe/`:
710 
711- **Working selectors**: remembers `[name='email']` worked on `/login`, uses it next run
712- **Route timings**: adjusts timeouts based on measured load times
713- **Auth credentials**: saved after first login, reused automatically
714- **Flaky routes**: tracks high fail-rate routes, marks them for retry
715- **Skip routes**: routes that consistently error (need URL params) are auto-skipped
716- **Route manifest** (`.vibe/route-manifest.json`): every scan diffs against the previous one; new and removed routes surface as `route_changes` on `scan_codebase` results so the AI can cover them immediately
717- **Run snapshot** (`.vibe/run-snapshot.json`): every run captures per-route pass/fail and diffs against the prior run; `snapshot_diff` flags `newly_passing` (fixes), `newly_failing` (regressions), `still_failing`, plus added and removed routes
718 
719```json
720{
721 "snapshot_diff": {
722 "newly_passing": ["/login"],
723 "newly_failing": ["/checkout"],
724 "still_failing": [],
725 "new_routes": ["/admin/users"],
726 "removed_routes": []
727 }
728}
729```
730 
731`run_converge` returns the same shape, so iterative runs in your editor highlight what you just broke.
732 
733Reset with `npx vibe-testing@latest reset` to start fresh.
734 
735---
736 
737## What a session looks like
738 
739When you ask your editor to "test the login flow", here is what it does:
740 
741```
742User: "Test the login flow"
743 
744AI calls:
745 scan_codebase({ codebase_path: ".", url: "http://localhost:3000" })
746 -> Finds /login route, LoginForm component, POST /api/auth/login endpoint
747 -> Returns 8 generated test scenarios
748 
749 get_context({ feature: "login" })
750 -> Returns src/app/login/page.tsx (has name="email", name="password" fields)
751 -> Returns src/app/api/auth/login/route.ts (POST handler, returns { token })
752 -> AI now knows the real selectors: [name='email'], [name='password']
753 
754 login({ email: "[email protected]", password: "pass123" })
755 -> Opens Chromium, fills the form, clicks submit
756 -> Returns: { success: true, final_url: "/dashboard", tokens_found: 2 }
757 -> Returns screenshot of post-login dashboard
758 
759 execute_scenario({ scenario: { name: "Login with invalid password", ... } })
760 -> Returns screenshot showing error state
761 
762 generate_report()
763 -> Writes .vibe/report.html, opens in browser
764 
765AI reports: "Login works. Invalid password shows an error. All 3 login scenarios passed."
766```
767 
768---
769 
770## FAQ
771 
772**Does vibe-testing use an LLM internally?**
773No. It uses heuristic verification (URL changes, toast detection, API errors). Your editor's model is the brain: it sees screenshots and decides what to test next. Runs have no API cost.
774 
775**What's the difference between `explore_page` and `execute_scenario`?**
776`explore_page` is broad: it clicks every button and input it finds and reports the results. `execute_scenario` is precise: you give it specific steps and it follows them exactly. Use `explore_page` to find what's on a page, then `execute_scenario` to test specific flows.
777 
778**What's `get_context` for?**
779It returns the actual source code for a feature, so the AI knows `[name='email']` instead of guessing `#email-input`. Always call it before writing test steps for a specific feature.
780 
781**Does it handle SPAs with client-side routing?**
782Yes. Playwright navigates the real browser, so client-side routing (React Router, Vue Router, and the rest) works naturally.
783 
784**Does it handle login / authentication?**
785Yes. The `login` tool fills credentials in a real browser, captures auth tokens from localStorage/cookies, and keeps that session alive for authenticated tests. Credentials are persisted in `.vibe/memory/` and reused automatically.
786 
787**Will it click "Delete Account" or other destructive buttons?**
788No. Set `never_interact` in `vibe.config.json` or `VIBE.md` to blocklist dangerous actions. Any button whose text or selector matches is skipped during exploration.
789 
790**Can I use it without an AI editor?**
791Yes. `vibe-test run https://your-app.com` runs standalone. It scans, generates scenarios, executes them, and produces an HTML report without needing an editor.
792 
793**How do I test a staging environment?**
794Set `url` in `vibe.config.json` to your staging URL, or pass it as a CLI argument: `npx vibe-testing@latest run https://staging.myapp.com`.
795 
796**Does it work with monorepos?**
797Yes. `init` detects Turborepo/pnpm/yarn workspaces and finds the frontend app automatically.
798 
799---
800 
801## Requirements
802 
803- Node.js >= 20 (the test suite uses vitest 4.x which requires Node 20+)
804- Playwright Chromium. `init` installs the matching build. To install or repair it directly:
805 ```bash
806 npx vibe-testing@latest install-browser
807 ```
808 
809`run` and `converge` check for the browser before scanning your project and print the same recovery command when it is missing.
810 
811### Docker
812 
813A Node 20 + Chromium image is included for environments that prefer container-based MCP servers:
814 
815```bash
816docker build -t vibe-test .
817# wire into your editor's MCP config:
818# { "command": "docker", "args": ["run", "--rm", "-i", "vibe-test"] }
819```
820 
821---
822 
823## Contributing
824 
825```bash
826git clone https://github.com/AishwaryShrivastav/vibe-testing.git
827cd vibe-testing
828npm install
829npx playwright install chromium
830npm run build # tsc -> dist/
831npm run dev # run CLI without building
832npm run mcp # run MCP server without building
833npm test # unit and isolated integration tests
834VIBE_REAL_BROWSER=1 npm test # also run real Chromium CLI/MCP regressions
835```
836 
837See [CHANGELOG.md](./CHANGELOG.md) for version history. Bug reports and feature requests: [GitHub issues](https://github.com/AishwaryShrivastav/vibe-testing/issues).
838 
839---
840 
841## License
842 
843MIT, [Aishwary Shrivastav](https://github.com/AishwaryShrivastav)
844 
845---
846 
847## Links
848 
849- npm: https://www.npmjs.com/package/vibe-testing
850- GitHub: https://github.com/AishwaryShrivastav/vibe-testing
851- Issues: https://github.com/AishwaryShrivastav/vibe-testing/issues
852- Official MCP registry: listed as `io.github.AishwaryShrivastav/vibe-testing` at https://registry.modelcontextprotocol.io
853- [![mcpindex](https://mcpindex.ai/api/v1/badge/io-github-aishwaryshrivastav-vibe-testing)](https://mcpindex.ai/server/io-github-aishwaryshrivastav-vibe-testing)
854- [Model Context Protocol](https://modelcontextprotocol.io)
855- [Playwright](https://playwright.dev)
856 
View all files on GitHub →

Details

Updated
Nov 13, 2026
License
MIT
Stars on the repo
★ 18
Checked
Source
AishwaryShrivastav/vibe-testing ↗
Creator
AishwaryShrivastav · 1 listing
View creator

Similar MCP servers

See all →
Skill29 production-ready scripts for iOS app testing, buildingIos simulator skillconorluddy/ios-simulator-skill · by conorluddy29 production-ready scripts for iOS app testing, building, and automation. Provides semantic UI navigation, build automation, accessibility testing, and simulator lifecycle management. Optimized for AI agents with minimal token output.★ 1.3k GitHub starsSkillMoAI unified orchestrator for autonomous developmentmodu-ai/moai-adk · by modu-aiMoAI unified orchestrator for autonomous development. Routes natural language or subcommands (plan, run, sync, project, fix, loop, mx, feedback, review, clean, codemaps, gate, e2e, harness, goal, gtd, todo) to specialized agents.★ 1.2k GitHub starsSkillWrite Android unit, Compose UI, and Hilt-integrated testsAndroid Testing StandardsHoangNguyen0403/agent-skills-standard · by HoangNguyen0403Write Android unit, Compose UI, and Hilt-integrated tests. Use when designing test behavior with MockK or coroutine test utilities; defer database/WorkManager-specific recipes to the owning feature skill.★ 569 GitHub starsSkillImplementing any feature or bugfixTest-Driven Development (TDD)obra/superpowers · by obraUse when implementing any feature or bugfix, before writing implementation code★ 290k GitHub starsSkillToolkit for interacting with and testing local webWebapp testinganthropics/skills · by anthropicsToolkit for interacting with and testing local web applications using Playwright. Supports verifying frontend functionality, debugging UI behavior, capturing browser screenshots, and viewing browser logs.★ 178k GitHub starsPromptGuide to fixing bugs using a test-first approachTest first bug fixing approachf/prompts.chat · by Ilker UlusoyGuide to fixing bugs using a test-first approach, ensuring code reliability through systematic testing and implementation.New listing