import { ParseOptions , TestParser } from '../../test-parser' ; import { TestCaseError , TestCaseResult , TestExecutionResult , TestGroupResult , TestRunResult , TestSuiteResult } from '../../test-results' ; import { getExceptionSource } from '../../utils/node-utils' ; import { getBasePath , normalizeFilePath } from '../../utils/path-utils' ; import { MochaJson , MochaJsonTest } from './mocha-json-types' ; export class MochaJsonParser implements TestParser { assumedWorkDir : string | undefined ; constructor ( readonly options ) { } async parse ( path , content ) { const mocha = this . getMochaJson ( path , content ) ; const result = this . getTestRunResult ( path , mocha ) ; result . sort ( true ) ; return Promise . resolve ( result ) ; } private getMochaJson ( path , content ) { try { return JSON . parse ( content ) ; } catch ( e ) { throw new Error ( `Invalid JSON at ${ path }\n\n${ e }` ) ; } } private getTestRunResult ( resultsPath , mocha ) { const suitesMap = { } ; const getSuite = ( test ) : TestSuiteResult => { const path = this . getRelativePath ( test . file ) ; return suitesMap [ path ] ?? ( suitesMap [ path ] = new TestSuiteResult ( path , [ ] ) ) ; } ; for ( const test of mocha . passes ) { const suite = getSuite ( test ) ; this . processTest ( suite , test , 'success' ) ; } for ( const test of mocha . failures ) { const suite = getSuite ( test ) ; this . processTest ( suite , test , 'failed' ) ; } for ( const test of mocha . pending ) { const suite = getSuite ( test ) ; this . processTest ( suite , test , 'skipped' ) ; } const suites = Object . values ( suitesMap ) ; return new TestRunResult ( resultsPath , suites , mocha . stats . duration ) ; } private processTest ( suite , test , result ) { const groupName = test . fullTitle !== test . title ? test . fullTitle . substr ( 0 , test . fullTitle . length - test . title . length ) . trimEnd ( ) : null ; let group = suite . groups . find ( grp => grp . name === groupName ) ; if ( group === undefined ) { group = new TestGroupResult ( groupName , [ ] ) ; suite . groups . push ( group ) ; } const error = this . getTestCaseError ( test ) ; const testCase = new TestCaseResult ( test . title , result , test . duration ?? 0 , error ) ; group . tests . push ( testCase ) ; } private getTestCaseError ( test ) { const details = test . err . stack ; const message = test . err . message ; if ( details === undefined ) { return undefined ; } let path ; let line ; const src = getExceptionSource ( details , this . options . trackedFiles , file => this . getRelativePath ( file ) ) ; if ( src ) { path = src . path ; line = src . line ; } return { path , line , message , details } ; } private getRelativePath ( path ) { path = normalizeFilePath ( path ) ; const workDir = this . getWorkDir ( path ) ; if ( workDir !== undefined && path . startsWith ( workDir ) ) { path = path . substr ( workDir . length ) ; } return path ; } private getWorkDir ( path ) { return ( this . options . workDir ?? this . assumedWorkDir ?? ( this . assumedWorkDir = getBasePath ( path , this . options . trackedFiles ) ) ) ; } }