Skip to content

ctrf-io/ctrf-js

CTRF Reference Implementation TypeScript

The reference implementation in TypeScript for the Common Test Report Format (CTRF) specification.

CTRF Open Standard

CTRF is a community-driven open standard for test reporting.

By standardizing test results, reports can be validated, merged, compared, and analyzed consistently across languages and frameworks.

Note

⭐ Starring the CTRF specification repository (https://github.com/ctrf-io/ctrf) helps support the standard.

Installation

npm install ctrf

Quick Start

import { ReportBuilder, TestBuilder, validateStrict } from 'ctrf'

// Build a report using the fluent API
const report = new ReportBuilder()
  .tool({ name: 'jest', version: '29.0.0' })
  .addTest(
    new TestBuilder()
      .name('should add numbers')
      .status('passed')
      .duration(150)
      .build()
  )
  .addTest(
    new TestBuilder()
      .name('should handle errors')
      .status('failed')
      .duration(200)
      .message('Expected 5 but got 4')
      .build()
  )
  .build()

// Validate the report
validateStrict(report)

API Reference

📚 Full API Documentation: API Reference

Types

Full TypeScript types are provided for all CTRF entities.

import type { CTRFReport, Test } from 'ctrf'

const report: CTRFReport = { /* ... */ }
const test: Test = { /* ... */ }

Validation

import { isValid, validate, validateStrict, isCTRFReport, ValidationError } from 'ctrf'

// Quick validation (returns boolean)
if (isValid(report)) {
  console.log('Report is valid')
}

// Detailed validation (returns ValidationResult)
const result = validate(report)
if (!result.valid) {
  result.errors?.forEach(err => console.error(err.message))
}

// Strict validation (throws on invalid)
try {
  validateStrict(report)
} catch (error) {
  if (error instanceof ValidationError) {
    console.error('Invalid report:', error.errors)
  }
}

// Type guards
if (isCTRFReport(data)) {
  // data is typed as CTRFReport
}

Building Reports

import { ReportBuilder, TestBuilder } from 'ctrf'

// ReportBuilder - fluent API for constructing reports
const report = new ReportBuilder()
  .tool({ name: 'vitest', version: '1.0.0' })
  .environment({ os: 'linux', arch: 'x64' })
  .addTest(/* ... */)
  .build()

// TestBuilder - fluent API for constructing tests
const test = new TestBuilder()
  .name('User login test')
  .status('passed')
  .duration(1500)
  .suite(['Authentication', 'Login'])
  .tags(['smoke', 'critical'])
  .filePath('tests/auth/login.test.ts')
  .browser('chrome')
  .build()

Parsing Reports

import { parse, stringify } from 'ctrf'

// Parse from string
const parsed = parse(jsonString)

// Stringify with formatting
const json = stringify(report, { pretty: true, indent: 2 })

Filtering & Querying

import { filterTests, findTest } from 'ctrf'

// Filter by criteria
const filtered = filterTests(report, {
  status: 'failed',
  suite: 'Authentication',
  tags: ['smoke'],
})

// Find specific test
const test = findTest(report, { name: 'login test' })
const testById = findTest(report, { id: 'test-uuid' })

Merging Reports

import { merge } from 'ctrf'

// Merge multiple reports into one
const merged = merge([report1, report2, report3], {
  deduplicateTests: true,  // Remove duplicate tests by ID
})

ID Generation

import { generateTestId, generateReportId } from 'ctrf'

// Generate deterministic test ID from properties
const testId = generateTestId({
  name: 'should add numbers',
  suite: ['Math', 'Addition'],
  filePath: 'tests/math.test.ts',
})

// Generate random report ID
const reportId = generateReportId()

Insights & Analytics

import { addInsights, isTestFlaky } from 'ctrf'

// Enrich a report with insights from historical data
const enriched = addInsights(
  currentReport,
  historicalReports,
  { baseline: baselineReport }
)

// Access insights
console.log(enriched.insights?.passRate)    // { current: 0.95, baseline: 0.90, change: 0.05 }
console.log(enriched.insights?.flakyRate)   // { current: 0.02, baseline: 0.05, change: -0.03 }

// Check if a test is flaky
const isFlaky = isTestFlaky(test)

Summary Calculation

import { calculateSummary } from 'ctrf'

// Calculate summary from tests
const summary = calculateSummary(tests)
// { tests: 10, passed: 8, failed: 1, skipped: 1, pending: 0, other: 0, ... }

Constants

import {
  REPORT_FORMAT,
  CURRENT_SPEC_VERSION,
  SUPPORTED_SPEC_VERSIONS,
  TEST_STATUSES,
  CTRF_NAMESPACE,
} from 'ctrf'

REPORT_FORMAT           // 'CTRF'
CURRENT_SPEC_VERSION    // '0.0.0'
SUPPORTED_SPEC_VERSIONS // ['0.0.0']
TEST_STATUSES           // ['passed', 'failed', 'skipped', 'pending', 'other']
CTRF_NAMESPACE          // UUID namespace for deterministic IDs

Error Handling

import { validateStrict, ValidationError, ParseError } from 'ctrf'

try {
  validateStrict(report)
} catch (error) {
  if (error instanceof ValidationError) {
    console.error('Schema validation failed:', error.errors)
  }
}

try {
  const parsed = parse(jsonString)
} catch (error) {
  if (error instanceof ParseError) {
    console.error('Invalid JSON:', error.message)
  }
}

Schema Access

import { schema, getSchema, getCurrentSpecVersion, getSupportedSpecVersions } from 'ctrf'

// Get the current JSON Schema
console.log(schema)

// Get schema for specific version
const v0_0Schema = getSchema('0.0.0')

// Get version info
const version = getCurrentSpecVersion()      // '0.0.0'
const supported = getSupportedSpecVersions() // ['0.0.0']

⚠️ Upgrading from v0.0.17?

Version 0.1.0 contains breaking changes. See the Migration Guide for detailed upgrade instructions.

About

CTRF reference implementation in TypeScript

Resources

License

Code of conduct

Contributing

Security policy

Stars

Watchers

Forks

Contributors 2

  •  
  •