Back to Discover

testivai-oss

connector

mcbuddy

Local-first visual regression for AI agents: verdicts, diff images, explain_snapshot. No API key.

View on GitHub
0 starsSynced Aug 2, 2026

Install to Claude Code

/plugin marketplace add mcbuddy/testivai-oss

README

TestivAI Open Source

@testivai/common @testivai/witness @testivai/witness-playwright @testivai/witness-webdriverio License: MIT

Local-first visual regression testing SDKs for modern web applications.

This is the home of TestivAI. It contains everything you need to capture, diff, and report visual regressions fully locally โ€” MIT-licensed, no account, no server.

๐Ÿ‘€ See a live report โ†’ โ€” a real TestivAI OSS report rendered in your browser, straight from CI. No install, no signup.

Real TestivAI report โ€” style-only-change verdict, selector-attributed regions, heatmap diff

Why TestivAI?

Pixel-only visual testing drowns you in false positives โ€” a font re-hint or an anti-aliasing shift across machines lights up as a "change," and you spend your time re-approving noise.

TestivAI pairs every screenshot with a snapshot of the page DOM. When pixels differ but the DOM is structurally identical, the report flags the diff as likely render noise instead of crying wolf. When the DOM actually changed, you see exactly what (2 added, 1 removed). That single signal is the difference between a flaky test wall and a report you trust.

  • ๐Ÿ†“ Fully local, no account โ€” captures, diffs, and a self-contained HTML report all stay on your machine.
  • ๐Ÿง  DOM + style-aware noise hint โ€” separates real changes from render jitter, and catches the stylesheet-only case: identical DOM with changed computed styles reads as "Styles changed on button.cta", never as noise.
  • ๐ŸŽญ Auditable masks & region-level diffs โ€” exclude dynamic areas (selectors or coordinates) with the masked region hatched in the diff, and get "3 changed regions" with bounding boxes instead of a raw pixel percentage.
  • ๐Ÿ“ Element attribution & exact shift detection โ€” the report names which element changed ("div.card:nth-of-type(2) shifted +8px vertically โ€” content unchanged") and spots the injected-banner case ("everything below y=80 moved +24px"), derived from layout, not pixel guesswork. No local-first tool does this.
  • ๐Ÿ”Œ First-class adapters โ€” Playwright (TS/JS and Python, Java experimental) and WebdriverIO, using each framework's native APIs; every language shares one set of baselines and one report.
  • ๐Ÿค– PR-native workflow โ€” a GitHub Action posts the diff and approves baselines from a /testivai approve comment.
  • ๐Ÿ”“ No lock-in โ€” MIT license, baselines live in your git, and results.json is a semver-governed public contract.

Evaluating this for a team? Maintenance & roadmap covers who builds it, the release cadence, and what happens to your setup if maintenance ever stops.

Already using Playwright's toHaveScreenshot()? It's good, and if a pixel diff answers your question you should keep using it. Here's an honest look at what TestivAI adds and when it isn't worth the dependency.

Eyes for your coding agent

If an AI agent (Claude Code, Cursor, Copilot, โ€ฆ) writes your UI code, someone still has to check what the UI looks like โ€” and it shouldn't be you, one screenshot at a time. TestivAI is built to be that check:

  • No account, no API key, no network โ€” an agent can run it inside any sandbox without you provisioning secrets.
  • Machine-readable output โ€” every run writes visual-report/results.json (a semver-governed schema) with per-snapshot diff percentages and DOM change summaries, so an agent can read the result and self-correct.
  • Noise-aware verdicts โ€” the DOM hint tells the agent whether a pixel diff is likely render noise or a real structural change (2 added, 1 removed), so it doesn't chase anti-aliasing ghosts.
  • Explanations, bring-your-own-model โ€” the MCP explain_snapshot tool hands your agent layered evidence (which selectors shifted vs changed, whole-page shift detection, style-only changes) and your model writes the narrative: "card #2 shifted +24px โ€” likely the banner injected above it." No hosted AI service in the loop.
  • Human approval stays in the PR โ€” the agent iterates locally; you approve baselines with one /testivai approve comment.

Paste this into your project's AGENTS.md / CLAUDE.md to wire it up (full guide with MCP setup, a real agent transcript, and the approval rule: docs/guides/ai-agents.md):

## Visual verification
After changing any UI code, run `npx playwright test` (TestivAI captures
screenshots automatically), then read `visual-report/results.json`.
- `status: "changed"` with `dom.changed: true` โ†’ describe the DOM summary and
  ask whether the change is intended before approving.
- `status: "changed"` with `dom.noiseHint: true` โ†’ likely render noise; mention
  it but don't block.
- Never run `testivai approve` yourself โ€” baseline approval is a human decision.

Packages

Live versions are shown by the badges at the top of this README.

PackageDescription
@testivai/commonShared utilities (config loading, API client, auth, compression)
@testivai/witnessCore SDK: CLI, local diffing, baselines, HTML report generator
@testivai/witness-playwrightPlaywright reporter/adapter built on top of @testivai/witness
@testivai/witness-webdriverioWebdriverIO service + capture function (local mode)
@testivai/witness-seleniumSelenium WebDriver capture adapter (Python/Java Selenium live in python/ and java/)
@testivai/mcpMCP server โ€” visual results + diff images for AI coding agents
testivai (PyPI)Python adapter for playwright-python + pytest plugin โ€” same baselines & report
ai.testiv:testivaiJava adapter for playwright-java + JUnit 5 extension (experimental)
testivai (RubyGems)Ruby adapter for Capybara / RSpec / Cucumber โ€” same baselines & report

Plus:

  • action/ โ€” GitHub Action for PR-based visual approvals
  • examples/ โ€” minimal real-world example projects
  • docs/ โ€” public documentation
  • e2e/ โ€” OSS smoke E2E test suite

No test suite? One command.

AI-built and vibe-coded apps (Lovable, Bolt, v0, ...) usually ship with zero tests. You still get the full safety net:

npx testivai witness http://localhost:3000

TestivAI launches a headless Chrome, discovers your pages (or takes --pages "/,/pricing"), and captures each one โ€” baselines, diffs, noise hints, HTML report, and PR approvals all work exactly as below, no test framework required. See the vibe-coded apps guide.

Quick Start (Playwright, Local Mode)

# 1. Install
npm install -D @testivai/witness-playwright @playwright/test
npx playwright install chromium
// 2. (OPTIONAL) Customize tolerances and report settings.
// Everything runs locally โ€” no config needed.
// Only create this file if you want to tune threshold, reportDir, etc.
// File: .testivai/config.json
{
  "mode": "local",
  "threshold": 0.1,            // per-pixel color sensitivity (0-1)
  "maxDiffPercent": 0,         // pass diffs at or below this % (your tolerance dial)
  "noiseAutoPass": false,      // true: DOM-identical diffs within noiseMaxDiffPercent pass
  "stabilize": true,           // freeze animations, hide caret, wait for fonts
  "ignoreSelectors": [],       // e.g. [".live-chat", "[data-testid=clock]"]
  "reportDir": "visual-report",
  "autoOpen": false
}
// 3. Wire the reporter โ€” playwright.config.ts
import { defineConfig } from '@playwright/test';

export default defineConfig({
  reporter: [
    ['list'],
    ['@testivai/witness-playwright/reporter'],
  ],
});
// 4. Add a capture call โ€” tests/example.spec.ts
import { test } from '@playwright/test';
import { testivai } from '@testivai/witness-playwright';

test('homepage looks correct', async ({ page }, testInfo) => {
  await page.goto('http://localhost:3000');
  await testivai.witness(page, testInfo, 'homepage');
});
# 5. Run
npx playwright test

First run: baselines are written to .testivai/baselines/. Later runs: screenshots are diffed and a self-contained HTML report is written to ./visual-report/.

What you get out of the box (free, no account)

  • โœ… Full-page screenshot capture via Playwright
  • โœ… Stabilized captures by default โ€” animations/transitions frozen, caret hidden, web fonts awaited (the top causes of flaky visual tests, neutralized before every screenshot)
  • โœ… Local pixel diff with configurable threshold
  • โœ… Tunable pass criteria โ€” maxDiffPercent / maxDiffPixels tolerances, plus opt-in noiseAutoPass so DOM-identical render noise stops demanding review
  • โœ… ignoreSelectors for dynamic content (both adapters, global or per-snapshot)
  • โœ… Self-contained HTML report (visual-report/index.html)
  • โœ… Machine-readable results (visual-report/results.json)
  • โœ… Committed baselines under .testivai/baselines/ (just git add them)

CI Integration (GitHub Actions)

Copy this single workflow file into your repository. It handles both running the visual regression tests and processing /testivai approve commands from PR comments โ€” no extra secrets, no external services required.

# .github/workflows/testivai-oss.yml
name: TestivAI OSS

on:
  pull_request:
    branches: [main]
  issue_comment:
    types: [created]        # listens for /testivai approve commands

permissions:
  contents: write           # approve action commits updated baselines to the branch
  pull-requests: write      # post PR diff comment
  statuses: write           # set pass/fail indicator on the PR

jobs:

  # Runs on every PR โ€” captures screenshots, diffs against baselines, posts report
  visual-regression:
    name: Visual Regression (OSS)
    if: github.event_name == 'pull_request'
    runs-on: ubuntu-latest
    timeout-minutes: 15
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with: { node-version: '20', cache: 'npm' }
      - run: npm ci
      - run: npx playwright install chromium --with-deps
      - run: npm run build
      - run: npm run test:oss          # runs playwright.oss.config.ts

      - name: Post results + upload report
        uses: mcbuddy/testivai-oss@v1
        if: always()
        with:
          github-token: ${{ secrets.GITHUB_TOKEN }}
          report-dir: visual-report   # where @testivai/witness writes results.json

  # Runs when a collaborator comments /testivai approve on the PR
  approve-baselines:
    name: Approve Baselines
    if: |
      github.event_name == 'issue_comment' &&
      github.event.issue.pull_request != null &&
      startsWith(github.event.comment.body, '/testivai')
    runs-on: ubuntu-latest
    timeout-minutes: 10
    steps:
      - uses: mcbuddy/testivai-oss/approve@v1
        with:
          github-token: ${{ secrets.GITHUB_TOKEN }}
          workflow: testivai-oss.yml   # this file's name โ€” used to find the report artifact

Approve changed baselines

After CI posts the diff report on your PR, review the testivai-visual-report artifact, then comment:

CommentEffect
/testivai approve homepageApproves one named snapshot
/testivai approve --allApproves every changed snapshot at once

What happens:

  1. Action verifies you have write access to the repository (others get a polite rejection)
  2. Downloads the testivai-visual-report artifact from the latest CI run on your branch
  3. Copies approved screenshots into .testivai/baselines/ and commits them to your PR branch
  4. Posts a confirmation comment listing what was approved
  5. CI re-runs automatically โ€” approved snapshots now pass โœ…

What the PR comment looks like

๐Ÿ” TestivAI Visual Report

โš ๏ธ 2 changed ยท ๐Ÿ†• 1 new ยท โœ… 4 passed   Total snapshots: 7

Changed Snapshots

โ–ผ homepage โ€” 12.34% different
  ๐Ÿ’ก DOM unchanged โ€” pixel diff is likely render noise (font hinting, anti-aliasing).

โ–ผ dashboard โ€” 8.91% different
  ๐Ÿงฑ DOM changed โ€” 2 added, 1 removed.

Real-World Example

A complete, minimal consumer project lives at testivai-example: a static page, three witness() calls, the PR /testivai approve flow, and a live report on Pages โ€” all against the published packages.

Repository Layout

packages/
  common/      @testivai/common
  witness/     @testivai/witness              โ€” CLI, diff engine, baselines, report
  playwright/  @testivai/witness-playwright   โ€” Playwright reporter + capture
  webdriverio/ @testivai/witness-webdriverio  โ€” WebdriverIO service + capture
  selenium/    @testivai/witness-selenium     โ€” Selenium adapter
  mcp/         @testivai/mcp                  โ€” MCP server for AI agents
action/        GitHub Action for PR comments
approve/       GitHub Action for /testivai approve
examples/      framework-specific minimal examples
docs/          public documentation (Markdown)
e2e/           OSS smoke E2E

Development

# Prereqs: Node 20+, pnpm 10+
pnpm install
pnpm build       # tsc all 6 packages
pnpm test        # 476 unit tests
pnpm e2e         # smoke E2E
pnpm pack:dry    # validate publish artifacts

Contributing

Bug reports, feature requests, and PRs welcome. Please see:

Releases

Releases are published to npm under the latest dist-tag. See CUTOVER.md for the release runbook and .github/workflows/release.yml for the release workflow.

Attribution

This repository was extracted from the private TestivAI monorepo with a clean initial git history. Original development history is preserved internally; this public repository is the new source of truth for the SDKs going forward.

License

MIT โ€” see LICENSE.

Rendered live from mcbuddy/testivai-oss's GitHub README โ€” not stored, always reflects the source repo.

1 Install Method

NameDescriptionCategorySource
npm packageInstall via npm (stdio transport)mcp-server@testivai/mcp

0 Comments

Login required
Log in to post a comment or update on this repo.

No comments yet โ€” be the first to share an update.