Skip to content

JavaScript Integration

@tracecov/core is a coverage engine for Node.js: give it your OpenAPI specification and the HTTP interactions your tests make, and it reports which operations, parameters, and JSON Schema keywords you exercised. Feed it interactions with record() from your HTTP client's interceptor or middleware.

Installation

npm install @tracecov/core
# or
yarn add @tracecov/core
# or
pnpm add @tracecov/core

Requirements:

  • Node.js ≥ 18
  • ESM project ("type": "module" in package.json) or TypeScript with "moduleResolution": "nodenext" or "bundler" in tsconfig.json
  • CommonJS projects: load it with a dynamic import() inside an async function:
async function main() {
  const { CoverageMap } = await import('@tracecov/core');
  const coverage = CoverageMap.fromPath('openapi.json');
  // ...
}

main();

@tracecov/core is a native Node.js addon and does not run in browser bundles.

Recording interactions

Load your spec, then record each request/response pair:

import { CoverageMap } from '@tracecov/core';

const coverage = CoverageMap.fromPath('openapi.json');

const url = 'https://api.example.com/users?limit=10';
const start = Date.now();
const res = await fetch(url);
coverage.record(
  { method: 'GET', url, headers: {} },
  {
    statusCode: res.status,
    elapsed: (Date.now() - start) / 1000,
    headers: Object.fromEntries(res.headers),
    body: Buffer.from(await res.arrayBuffer()),
  },
);

fromPath reads JSON or YAML; fromDict takes a parsed object; fromUrl fetches over HTTP (await it).

Call record() wherever you make requests — most clients let you do it once in an interceptor or middleware. Pass the request body as a Buffer in body (Buffer.from(JSON.stringify(payload))); a string throws. Pass the response body and headers to measure response coverage. Annotate a network failure with recordError(method, url, message). For Axios, @tracecov/axios wires this up for you.

Check that requests matched the spec:

console.log(coverage.statistic().operations);
console.log(coverage.unmatchedRequests());
{ seen: 1, total: 12 }
[]

If seen is 0 and unmatchedRequests() lists your requests with reason: 'no_matching_path', the API is served under a prefix the spec does not declare. Pass it as basePath:

const coverage = CoverageMap.fromPath('openapi.json', { basePath: '/api/v1' });

Automatic capture with Axios

@tracecov/axios attaches interceptors that record every request an Axios client makes — success, 4xx/5xx, and network failures — including request bodies, so you never call record() by hand:

npm install @tracecov/axios
import { CoverageMap } from '@tracecov/core';
import { instrumentAxios } from '@tracecov/axios';
import axios from 'axios';

const coverage = CoverageMap.fromPath('openapi.json');
const client = axios.create({ baseURL: 'https://api.example.com' });
instrumentAxios(client, coverage);

// Every call through `client` is recorded.
await client.get('/users', { params: { limit: 10 } });

coverage.saveHtmlReport({ outputFile: 'coverage.html' });

instrumentAxios records the URL Axios actually sends plus the request body and its media type. If recording ever throws it warns and continues; pass { onError } to handle it yourself.

Automatic capture with fetch

@tracecov/fetch wraps fetch so every call is recorded — no record() by hand. Patch the global fetch (returns a restore function), or wrap a specific one:

npm install @tracecov/fetch
import { CoverageMap } from '@tracecov/core';
import { instrumentFetch } from '@tracecov/fetch';

const coverage = CoverageMap.fromPath('openapi.json');
const restore = instrumentFetch(coverage); // patches globalThis.fetch

await fetch('https://api.example.com/users', {
  method: 'POST',
  headers: { 'content-type': 'application/json' },
  body: JSON.stringify({ name: 'a' }),
});

restore(); // undo the patch in afterAll
coverage.saveHtmlReport({ outputFile: 'coverage.html' });

Don't want to touch the global? wrapFetch(fetch, coverage) returns an instrumented fetch you call directly. Both accept the same { onError } option.

Express

@tracecov/express records coverage from the server side: one call captures every request the app handles — supertest, a real HTTP client, or a browser — so it works with the in-process test style that never touches a client you can instrument. Works on Express 4 and 5.

npm install @tracecov/express
import express from 'express';
import request from 'supertest';
import { CoverageMap } from '@tracecov/core';
import { instrumentExpress } from '@tracecov/express';

const app = express();
app.use(express.json());
app.get('/items', (req, res) => res.json([]));

const coverage = CoverageMap.fromPath('openapi.json');
instrumentExpress(app, coverage);

await request(app).get('/items?limit=10'); // recorded

coverage.saveHtmlReport({ outputFile: 'coverage.html' });

It hooks the app's request dispatch, so it captures whatever drives the app — supertest, fetch against a running server, or a browser — including request bodies. Pass { onError } to handle recording failures yourself.

Vitest

@tracecov/vitest merges the requests from every test file into one report. Feed it with @tracecov/fetch, @tracecov/axios, or record() by hand. Requires Vitest 3 or later.

npm install -D @tracecov/vitest @tracecov/fetch

Add the plugin to vitest.config.ts:

import { tracecov } from '@tracecov/vitest';
import { defineConfig } from 'vitest/config';

export default defineConfig({
  plugins: [
    tracecov({
      schema: 'openapi.json',
      setup: './tracecov.setup.ts',
      report: { html: 'coverage.html' },
      thresholds: { operations: 80 },
    }),
  ],
});

Then create the setup file it points at — grab a coverage map and wire it to your client:

// tracecov.setup.ts
import { instrumentFetch } from '@tracecov/fetch';
import { collectCoverage } from '@tracecov/vitest/setup';

instrumentFetch(collectCoverage()); // or: instrumentAxios(client, collectCoverage())

Run your suite as usual. The configured reports are written when the run ends. A thresholds breach prints one line per metric and sets a non-zero exit code:

tracecov: Operations       50.0% / 80% required

report accepts html, json, and markdown output paths (plus title for HTML); thresholds takes any of operations, parameters, keywords, examples, responses, responseKeywords. schema and setup are resolved from the working directory, or from root if you set it in your Vitest config. collectCoverage() throws a clear error if the plugin isn't configured.

Jest

@tracecov/jest captures fetch calls in every Jest worker and merges them into one report. It needs no --experimental-vm-modules. Requires Jest 29 or later.

npm install -D @tracecov/jest
// jest.config.js
module.exports = {
  setupFilesAfterEnv: ['./tracecov.setup.js'],
  reporters: [
    'default',
    ['@tracecov/jest/reporter', { schema: 'openapi.json', report: { html: 'coverage.html' } }],
  ],
};
// tracecov.setup.js
const { collectCoverage, instrumentFetch } = require('@tracecov/jest');

instrumentFetch(collectCoverage());

Same report/thresholds options and threshold output as the Vitest plugin.

Playwright

@tracecov/playwright instruments the request fixture and merges worker results into one report.

npm install -D @tracecov/playwright

See Playwright Integration for setup, worker merging and limitations.

Writing a report

coverage.saveHtmlReport({ outputFile: 'coverage.html' });

generateHtmlReport / generateJsonReport / generateMarkdownReport / generateTextReport return a string; saveHtmlReport / saveJsonReport / saveMarkdownReport write a file. See JSON Report Format for the machine-readable schema.

Enforcing thresholds

const violations = coverage.checkThresholds({ operations: 80, keywords: 70 });
for (const v of violations) {
  console.error(`${v.dimension}: ${v.actual.toFixed(1)}% < ${v.minimum}%`);
}

Each violation reports the dimension, its actual percentage, and the minimum required. Exit non-zero when violations is non-empty to fail your CI.

Importing recorded traffic

@tracecov/core is the Community edition: recordFromHar, recordFromPostman, and recordFromVcr always throw, for example HAR import requires TraceCov Professional. See https://docs.tracecov.sh/editions/. Import HAR files, Postman collections, and VCR cassettes with the Professional CLI:

tracecov report openapi.json traffic.har

Full method-by-method documentation is in the API reference.