{"_id":"@autotelic/openapi-test-coverage","name":"@autotelic/openapi-test-coverage","dist-tags":{"latest":"0.1.0"},"versions":{"0.1.0":{"name":"@autotelic/openapi-test-coverage","publishConfig":{"access":"public"},"version":"0.1.0","description":"OpenAPI test coverage analysis based on the A-TEST '19 coverage criteria (TCL 0-7). Records HTTP traffic, computes coverage against an OpenAPI spec, and reports results.","license":"MIT","repository":{"type":"git","url":"git+https://github.com/autotelic/openapi-test-coverage.git"},"bugs":{"url":"https://github.com/autotelic/openapi-test-coverage/issues"},"homepage":"https://github.com/autotelic/openapi-test-coverage#readme","type":"module","exports":{".":{"import":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"require":{"types":"./dist/index.d.cts","default":"./dist/index.cjs"}},"./adapters/fastify":{"import":{"types":"./dist/adapters/fastify.d.ts","default":"./dist/adapters/fastify.js"},"require":{"types":"./dist/adapters/fastify.d.cts","default":"./dist/adapters/fastify.cjs"}},"./adapters/mocha":{"import":{"types":"./dist/adapters/mocha.d.ts","default":"./dist/adapters/mocha.js"},"require":{"types":"./dist/adapters/mocha.d.cts","default":"./dist/adapters/mocha.cjs"}}},"main":"./dist/index.cjs","module":"./dist/index.js","types":"./dist/index.d.cts","dependencies":{"colorette":"^2.0.20"},"devDependencies":{"@types/node":"^20.11.27","fastify":"^4.26.0","tsup":"^8.0.0","typescript":"^5.4.0","vitest":"^3.0.0"},"peerDependencies":{"fastify":">=4.0.0"},"peerDependenciesMeta":{"fastify":{"optional":true}},"keywords":["openapi","swagger","test-coverage","api-testing","coverage","rest-api","mocha","integration-testing"],"scripts":{"build":"tsup","dev":"tsup --watch","test":"vitest run","test:watch":"vitest","typecheck":"tsc --noEmit"},"_id":"@autotelic/openapi-test-coverage@0.1.0","_integrity":"sha512-51BDeS+gAYvIU4FeG6v7Gpd4VfBnVcXbM3eHA0gpvdHqbNg5BxpyjQ/LwFN/3SrTDKxpKZekK2uhCfvgtvgl4Q==","_resolved":"/tmp/71b38d22e902efa71c0233cb00aaff4c/autotelic-openapi-test-coverage-0.1.0.tgz","_from":"file:autotelic-openapi-test-coverage-0.1.0.tgz","_nodeVersion":"20.20.1","_npmVersion":"10.8.2","dist":{"integrity":"sha512-51BDeS+gAYvIU4FeG6v7Gpd4VfBnVcXbM3eHA0gpvdHqbNg5BxpyjQ/LwFN/3SrTDKxpKZekK2uhCfvgtvgl4Q==","shasum":"852d6557523dd235facfd20d0590215568b9185c","tarball":"https://registry.npmjs.org/@autotelic/openapi-test-coverage/-/openapi-test-coverage-0.1.0.tgz","fileCount":22,"unpackedSize":355382,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIDXgECrrOOAavb8MOwRl0tAdgvadA8xZQQaQX3JMKKU1AiEAhIhGujxWAKzvGLUHBj6h4VLY04px0SD53h1av2eVwpk="}]},"_npmUser":{"name":"autotelic","email":"info+npm@autotelic.com"},"directories":{},"maintainers":[{"name":"autotelic","email":"info+npm@autotelic.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/openapi-test-coverage_0.1.0_1774374580449_0.154571798600889"},"_hasShrinkwrap":false}},"time":{"created":"2026-03-24T17:49:40.365Z","0.1.0":"2026-03-24T17:49:40.593Z","modified":"2026-03-24T17:49:40.759Z"},"maintainers":[{"name":"autotelic","email":"info+npm@autotelic.com"}],"description":"OpenAPI test coverage analysis based on the A-TEST '19 coverage criteria (TCL 0-7). Records HTTP traffic, computes coverage against an OpenAPI spec, and reports results.","homepage":"https://github.com/autotelic/openapi-test-coverage#readme","keywords":["openapi","swagger","test-coverage","api-testing","coverage","rest-api","mocha","integration-testing"],"repository":{"type":"git","url":"git+https://github.com/autotelic/openapi-test-coverage.git"},"bugs":{"url":"https://github.com/autotelic/openapi-test-coverage/issues"},"license":"MIT","readme":"# @autotelic/openapi-test-coverage\n\nOpenAPI test coverage analysis based on the [A-TEST '19 paper](./Test_Coverage_Criteria_for_RESTful_Web_APIs.pdf) \"Test Coverage Criteria for RESTful Web APIs\" (Martin-Lopez, Segura, Ruiz-Cortes).\n\nRecords HTTP traffic during integration tests, computes coverage against an OpenAPI 3.x spec, and reports results across 10 criteria organised into Test Coverage Levels (TCL 0--7).\n\n## Coverage Criteria\n\n| TCL | Criteria added |\n|-----|----------------|\n| 0 | (none) |\n| 1 | Path coverage |\n| 2 | + Operation coverage |\n| 3 | + Input and output content-type coverage |\n| 4 | + Parameter coverage, status code class coverage |\n| 5 | + Parameter value coverage, status code coverage |\n| 6 | + Response body properties coverage |\n| 7 | + Operation flow coverage (not yet implemented) |\n\n## Install\n\n```bash\nnpm install @autotelic/openapi-test-coverage\n```\n\nOr from git:\n\n```bash\nnpm install https://github.com/autotelic/openapi-test-coverage.git\n```\n\n## Quick Start\n\n### 1. Record HTTP calls\n\nUse the Fastify adapter to automatically record all requests and responses:\n\n```js\nconst { registerCoverageHooks } = require('@autotelic/openapi-test-coverage/adapters/fastify')\n\n// After creating your Fastify app and registering routes:\nconst recorder = registerCoverageHooks(app, { autoAssertOnInject: true })\n\nawait app.ready()\n```\n\nOr record manually with the core `Recorder`:\n\n```js\nconst { Recorder } = require('@autotelic/openapi-test-coverage')\n\nconst recorder = new Recorder()\n\nrecorder.record({\n  method: 'GET',\n  pathname: '/v1/items',\n  queryParams: { limit: '10' },\n  responseStatusCode: 200,\n  responseContentType: 'application/json',\n  responseBody: [{ id: '1', name: 'Item' }],\n})\n```\n\n### 2. Compute coverage\n\n```js\nconst { computeCoverage } = require('@autotelic/openapi-test-coverage')\n\nconst coverage = computeCoverage(recorder.getCalls(), openapiSpec, {\n  excludedPaths: ['/internal/health'],\n  excludedStatusCodes: ['/legacy\\tGET\\t404'],\n})\n\nconsole.log(`TCL: ${coverage.tcl}`)\nconsole.log(`Paths: ${coverage.path.covered}/${coverage.path.total}`)\nconsole.log(`Operations: ${coverage.operation.covered}/${coverage.operation.total}`)\n```\n\n### 3. Report\n\n```js\nconst { printReport, writeJsonReport, writeHtmlReport } = require('@autotelic/openapi-test-coverage')\n\nprintReport(coverage, { verbose: true })\n\nwriteJsonReport(coverage, 'test/output/openapi-coverage.json')\nwriteHtmlReport(coverage, 'test/output/openapi-coverage.html')\n```\n\n## Adapters\n\n### Fastify\n\n`registerCoverageHooks(app, options?)` registers `onSend` and `onResponse` hooks on a Fastify instance. Returns a `Recorder`.\n\n```js\nconst { registerCoverageHooks } = require('@autotelic/openapi-test-coverage/adapters/fastify')\n\nconst recorder = registerCoverageHooks(app, {\n  // Pass an existing recorder (optional, creates one if omitted)\n  recorder: myRecorder,\n  // Wrap app.inject() to auto-mark responses as asserted (default: true)\n  autoAssertOnInject: true,\n})\n```\n\n### Mocha\n\n`createCoverageAfterAll(options)` returns a function suitable for use in Mocha's `afterAll` hook. It computes coverage, prints reports, and optionally enforces a minimum TCL.\n\n```js\nconst { createCoverageAfterAll } = require('@autotelic/openapi-test-coverage/adapters/mocha')\n\nmodule.exports.mochaHooks = {\n  async beforeAll() {\n    // ... set up app, spec, recorder ...\n  },\n  async afterAll() {\n    const reportCoverage = createCoverageAfterAll({\n      getRecorder: () => app.coverageRecorder,\n      getSpec: () => app.openapiSpec,\n      config: {\n        excludedPaths: [],\n        excludedStatusCodes: [],\n        excludedResponseBodyProperties: [],\n      },\n      console: { verbose: true },\n      jsonReportPath: process.env.OPENAPI_COVERAGE_JSON,\n      htmlReportPath: process.env.OPENAPI_COVERAGE_HTML,\n      minTcl: 6,\n    })\n    reportCoverage()\n\n    await app.close()\n  },\n}\n```\n\n## API\n\n### Core\n\n| Export | Description |\n|--------|-------------|\n| `Recorder` | Class that stores recorded HTTP calls. Methods: `record(opts)`, `markLastResponseAsserted()`, `getCalls()`, `clear()`. |\n| `computeCoverage(calls, spec, config?)` | Compute all coverage metrics and TCL from recorded calls against an OpenAPI spec. Returns a `CoverageResult`. |\n| `computeTcl(inputs)` | Compute the TCL (0--6) from individual metric totals/covered counts. |\n| `walkSpec(spec, excludedPaths?)` | Extract all coverage targets (paths, operations, parameters, etc.) from a resolved OpenAPI spec. |\n| `matchRequestToSpec(call, specPaths, basePath)` | Match a recorded request to a spec path template. |\n| `getBasePath(spec)` | Derive the base path from the spec's `servers[0].url`. |\n| `collectSchemaPaths(spec, schema)` | Collect all property paths from an OpenAPI schema (for response body coverage). |\n| `collectPathsFromValue(value)` | Collect property paths from an actual JSON response body. |\n\n### Reporters\n\n| Export | Description |\n|--------|-------------|\n| `printReport(coverage, opts?)` | Print a coloured console report. Options: `{ verbose: boolean, maxMissingItems: number }`. |\n| `writeJsonReport(coverage, filepath)` | Write coverage as JSON. Creates parent directories if needed. |\n| `writeHtmlReport(coverage, filepath)` | Write a standalone HTML report. |\n\n### Configuration\n\n`CoverageConfig` supports three exclusion lists:\n\n- **`excludedPaths`** -- Path keys to omit entirely (e.g. `['/admin/reports']`).\n- **`excludedStatusCodes`** -- Tab-separated `path\\tmethod\\tstatusCode` keys to exclude from status code and response body coverage.\n- **`excludedResponseBodyProperties`** -- Tab-separated `path\\tmethod\\tstatusCode\\tcontentType\\tpropertyPath` keys to exclude from response body property coverage.\n\n### Environment Variables\n\nThese are conventions used by the Mocha adapter; the core library is env-agnostic.\n\n| Variable | Description |\n|----------|-------------|\n| `OPENAPI_COVERAGE_JSON` | Path to write a JSON coverage report. |\n| `OPENAPI_COVERAGE_HTML` | Path to write an HTML coverage report. |\n| `OPENAPI_COVERAGE_MIN_TCL` | Minimum TCL required; test run fails if below this. |\n\n## Coverage Result Shape\n\n```ts\ninterface CoverageResult {\n  path:                   { total: number; covered: number; missing: string[] }\n  operation:              { total: number; covered: number; missing: string[] }\n  statusCode:             { total: number; covered: number; missing: string[] }\n  parameter:              { total: number; covered: number; missing: string[] }\n  parameterValue:         { total: number; covered: number; missing: string[] }\n  inputContentType:       { total: number; covered: number; missing: string[] }\n  outputContentType:      { total: number; covered: number; missing: string[] }\n  statusCodeClass:        { total: number; covered: number; missing: string[] }\n  responseBodyProperties: { total: number; covered: number; missing: string[] }\n  responseAsserted:       { total: number; covered: number; missing: string[] }\n  tcl: number\n}\n```\n\n## Development\n\n```bash\npnpm install\npnpm build        # Build CJS + ESM + .d.ts\npnpm test         # Run vitest\npnpm typecheck    # tsc --noEmit\n```\n\n## License\n\nMIT\n","readmeFilename":"README.md","_rev":"1-6a787846078d2ef0c6c789264517773f"}