The reference implementation in TypeScript for the Common Test Report Format (CTRF) specification.
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.
- CTRF Specification: https://github.com/ctrf-io/ctrf
The official specification defining the format and semantics - Discussions: https://github.com/orgs/ctrf-io/discussions
Community forum for questions, ideas, and support
Note
⭐ Starring the CTRF specification repository (https://github.com/ctrf-io/ctrf) helps support the standard.
npm install ctrfimport{ReportBuilder,TestBuilder,validateStrict}from'ctrf'// Build a report using the fluent APIconstreport=newReportBuilder().tool({name: 'jest',version: '29.0.0'}).addTest(newTestBuilder().name('should add numbers').status('passed').duration(150).build()).addTest(newTestBuilder().name('should handle errors').status('failed').duration(200).message('Expected 5 but got 4').build()).build()// Validate the reportvalidateStrict(report)📚 Full API Documentation:API Reference
Full TypeScript types are provided for all CTRF entities.
importtype{CTRFReport,Test}from'ctrf'constreport: CTRFReport={/* ... */}consttest: Test={/* ... */}import{isValid,validate,validateStrict,isCTRFReport,ValidationError}from'ctrf'// Quick validation (returns boolean)if(isValid(report)){console.log('Report is valid')}// Detailed validation (returns ValidationResult)constresult=validate(report)if(!result.valid){result.errors?.forEach(err=>console.error(err.message))}// Strict validation (throws on invalid)try{validateStrict(report)}catch(error){if(errorinstanceofValidationError){console.error('Invalid report:',error.errors)}}// Type guardsif(isCTRFReport(data)){// data is typed as CTRFReport}import{ReportBuilder,TestBuilder}from'ctrf'// ReportBuilder - fluent API for constructing reportsconstreport=newReportBuilder().runId('run-2026-08-13').tool({name: 'vitest',version: '1.0.0'}).environment({osPlatform: 'linux',shardId: 'shard-1-of-4'}).addTest(/* ... */).build()// TestBuilder - fluent API for constructing testsconsttest=newTestBuilder().testId('authentication/login').executionId('execution-123').name('User login test').status('passed').duration(1500).suite(['Authentication','Login']).tags(['smoke','critical']).filePath('tests/auth/login.test.ts').browser('chrome').build()import{parse,stringify}from'ctrf'// Parse from stringconstparsed=parse(jsonString)// Stringify with formattingconstjson=stringify(report,{pretty: true,indent: 2})import{filterTests,findTest}from'ctrf'// Filter by criteriaconstfiltered=filterTests(report,{status: 'failed',suite: 'Authentication',tags: ['smoke'],})// Find specific testconsttest=findTest(report,{name: 'login test'})consttestById=findTest(report,{id: 'test-uuid'})import{merge}from'ctrf'// Merge multiple reports into oneconstmerged=merge([report1,report2,report3],{deduplicateTests: true,// Remove duplicate tests by ID})import{generateTestId,generateReportId}from'ctrf'// Generate deterministic test ID from propertiesconsttestId=generateTestId({name: 'should add numbers',suite: ['Math','Addition'],filePath: 'tests/math.test.ts',})// Generate random report IDconstreportId=generateReportId()import{addInsights,isTestFlaky}from'ctrf'// Enrich a report with insights from historical dataconstenriched=addInsights(currentReport,historicalReports,{baseline: baselineReport})// Access insightsconsole.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 flakyconstisFlaky=isTestFlaky(test)import{calculateSummary}from'ctrf'// Calculate summary from testsconstsummary=calculateSummary(tests)// { tests: 10, passed: 8, failed: 1, skipped: 1, pending: 0, other: 0, ... }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 IDsimport{validateStrict,ValidationError,ParseError}from'ctrf'try{validateStrict(report)}catch(error){if(errorinstanceofValidationError){console.error('Schema validation failed:',error.errors)}}try{constparsed=parse(jsonString)}catch(error){if(errorinstanceofParseError){console.error('Invalid JSON:',error.message)}}import{schema,getSchema,getCurrentSpecVersion,getSupportedSpecVersions}from'ctrf'// Get the current JSON Schemaconsole.log(schema)// Get schema for specific versionconstv0_0Schema=getSchema('0.0.0')// Get version infoconstversion=getCurrentSpecVersion()// '0.0.0'constsupported=getSupportedSpecVersions()// ['0.0.0']