npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@bernardo75/ai-test-analyzer

v0.3.0

Published

AI-powered analysis of automated test reports (Allure, Playwright, JUnit XML): classifies failures as product bugs, broken tests, flaky or environment issues, and proposes diagnosis and fixes for broken tests.

Downloads

74

Readme

ai-test-analyzer

AI-powered analysis of automated test reports. Feed it an Allure results directory, a Playwright JSON report or a JUnit XML file and it classifies every failure as:

| Verdict | Meaning | |---|---| | product_bug | The product misbehaves; the test is right | | broken_test | The test is stale or badly built — includes a diagnosis and a recommended fix | | flaky | Non-deterministic failure (timeouts, races, ordering) — includes a stabilization fix | | environment_issue | Infra problem (network, DNS, 5xx dependencies, disk) |

For Allure it can also enrich the report itself: every failed test gets an "🤖 AI Analysis" section, a filterable ai-verdict label, and the Categories tab groups failures by verdict.

Powered by Anthropic Claude behind a minimal provider interface. Disabled by default — with the feature flag off, every call is a strict no-op (zero network, zero tokens, zero file writes).

Install

npm install @bernardo75/ai-test-analyzer

Requires Node.js ≥ 20.

Quickstart

import { analyze } from "@bernardo75/ai-test-analyzer";

// Enable via env: AI_ANALYZER_ENABLED=true, ANTHROPIC_API_KEY=sk-ant-...
const result = await analyze({
  reportPath: "./allure-results",
  format: "allure", // "allure" | "playwright" | "junit"
});

if (result.status === "completed") {
  for (const [testId, entry] of Object.entries(result.verdictsByTest)) {
    if ("verdict" in entry) {
      console.log(testId, entry.verdict, entry.confidence);
      if (entry.verdict === "broken_test") {
        console.log("  diagnosis:", entry.diagnosis);
        console.log("  fix:", entry.recommendedFix);
      }
    } else {
      console.log(testId, "analysis failed:", entry.reason);
    }
  }
  console.log(result.summary);
}

Analyze failures already in memory (no report file)

When you already have the failures — from a CI REST API (Jenkins, GitHub Actions), a database, or pasted output — feed them directly, no file on disk required:

import { analyzeFailures } from "@bernardo75/ai-test-analyzer";

const result = await analyzeFailures({
  failures: [
    {
      name: "should log in",
      fullName: "auth.LoginSuite › should log in",
      errorMessage: "TimeoutError: locator not enabled",
      stackTrace: "at login.spec.ts:42",
      file: "login.spec.ts",
      line: 42,
    },
  ],
  totalTests: 20,               // optional — defaults to failures.length
  config: { enabled: true },    // same feature flag + config as analyze()
});

Only name plus an error is required per failure; everything else defaults. Same feature flag, config, providers and result shape as analyze() — the input just comes from memory instead of a report path.

Enrich the Allure report

import { analyzeAndEnrich } from "@bernardo75/ai-test-analyzer";

// Run BEFORE `allure generate`:
const { analysis, enrichment } = await analyzeAndEnrich({
  reportPath: "./allure-results",
  format: "allure",
});
// then: npx allure generate ./allure-results -o ./allure-report

Enrichment is strictly additive and idempotent: it only appends content (attachments, labels, description blocks, a [ai-verdict:*] message suffix, categories.json entries and an ai.analyzer.* block in environment.properties), never deletes or replaces existing results, and re-running it is a no-op.

Feature flag

The analyzer is off by default. Precedence:

  1. config.enabled (programmatic — wins in both directions)
  2. AI_ANALYZER_ENABLED env var ("true" / "1" to enable)
  3. Default: disabled

With the flag off, analyze() / enrichAllureResults() / analyzeAndEnrich() return {status: "disabled"} without reading files, calling the network or consuming tokens — safe to leave installed in CI.

Configuration

await analyze({
  reportPath: "./allure-results",
  format: "allure",
  config: {
    enabled: true,                 // overrides AI_ANALYZER_ENABLED
    apiKey: process.env.MY_KEY,    // overrides ANTHROPIC_API_KEY
    model: "claude-sonnet-5",       // default
    maxConcurrency: 4,             // parallel analyses (default 4)
    maxGroups: 25,                 // hard cost cap per run (default: unlimited)
    pricing: { inputPerMTok: 5, outputPerMTok: 25 }, // cost-estimate override
    failureContext: {              // extra failure evidence sent to the LLM
      pageSnapshot: true,          //   Playwright error-context (text, ~8k cap)
      screenshot: true,            //   failure screenshot (vision providers only)
    },
    provider: myCustomProvider,    // inject your own AnalysisProvider
  },
});

Cost controls

  • Only failures are analyzed — a green run costs nothing.
  • Deduplication: failures sharing a normalized signature (masked error + own stack frames) are analyzed once; the verdict fans out to every test. 40 failures with 5 root causes = 5 LLM calls.
  • Prompt caching: the system prompt is cached across groups of a run.
  • maxGroups: hard ceiling of analyses per run.
  • Usage report: every run returns totals — failures, groups, duplicates avoided, token usage and an estimated cost in USD.
  • Failure evidence: when the report carries a Playwright error-context page snapshot and/or a failure screenshot, they are included in the analysis (size-capped, gated by config.failureContext) — decisive for telling a renamed selector (broken_test) apart from a missing feature (product_bug). The screenshot is used by AnthropicProvider (vision); ClaudeCodeProvider uses the text snapshot only.
result.summary;
// {
//   totalFailures: 40, groupsAnalyzed: 5, groupsFailed: 0,
//   duplicatesAvoided: 35,
//   usage: { inputTokens, outputTokens, cacheCreationInputTokens, cacheReadInputTokens },
//   estimatedCostUsd: 0.19, model: "claude-sonnet-5", durationMs: 41200
// }

API

| Export | Description | |---|---| | analyze(options) | Parse + classify. Returns AnalysisResult (disabled | nothing_to_analyze | completed). Never rejects on provider failures — failed groups are reported per-test as analysis_failed. | | enrichAllureResults(dir, analysis, options?) | Additive, idempotent enrichment of an allure-results directory. | | analyzeAndEnrich(options) | Both steps in one call (Allure only). | | AnthropicProvider | Production provider (official @anthropic-ai/sdk, structured outputs, prompt caching). | | MockProvider | Deterministic provider for your own tests — zero network. | | Errors | ReportNotFoundError, ReportParseError, ConfigurationError, ProviderError. |

Credentials are never logged, persisted or written into enriched reports. The only data sent to the LLM is the failure context: error message, stack trace, steps and a ±20-line snippet of the failing test file.

What the analysis looks like in Allure

Each failed test gets:

  • An attachment 🤖 AI Analysis with verdict, confidence, reasoning and — for broken tests — diagnosis and recommended fix.
  • A label ai-verdict=<verdict> you can filter/search by.
  • A summary block appended to the test description.
  • Grouping under Categories: "Product Bugs (AI)", "Broken Tests (AI)", "Flaky (AI)", "Environment Issues (AI)".

And the report home shows the run summary in the Environment widget (ai.analyzer.* keys in environment.properties): model, groups analyzed, duplicates avoided, token usage and estimated cost. User-authored properties are preserved.

Experimental: ClaudeCodeProvider (no API key)

If the machine has Claude Code installed and authenticated — including via a Claude Pro/Max subscription — you can route the analysis through it instead of the API:

import { analyze, ClaudeCodeProvider } from "@bernardo75/ai-test-analyzer";

const result = await analyze({
  reportPath: "./allure-results",
  format: "allure",
  config: {
    enabled: true,
    provider: new ClaudeCodeProvider(), // uses the local `claude` CLI headless
  },
});

For CI, generate a long-lived credential with claude setup-token and expose it to the runner. Read this before using it in a pipeline:

  • ⚠️ Subscriptions are personal. Sharing one account across a team pipeline violates Anthropic's usage terms — use an API key (workspace-owned) for team CI. This provider is meant for personal projects and evaluation.
  • Subscription rate-limit windows are shared with your interactive usage; CI runs may fail unpredictably when the window is exhausted.
  • No structured outputs: the verdict is parsed from text and re-validated against the same schema — invalid responses become per-group analysis failures, never crashes.
  • Usage/cost reporting depends on what the CLI returns (may be zeros).

Options: cliPath (default "claude"), model (passed as --model, default "sonnet"), timeoutMs (default 120000).

Examples

Runnable scripts in examples/: mock analysis (no cost), real analysis, enrichment end-to-end, multi-format, and an accuracy-evaluation harness against a human-labeled dataset.

License

MIT