Add support for mocha-json

This commit is contained in:
Michal Dorner 2021-02-23 22:39:35 +01:00
parent f285c4c6d7
commit 9b675bd55f
No known key found for this signature in database
GPG key ID: 9EEE04B48DA36786
21 changed files with 1588 additions and 59 deletions

View file

@ -49,6 +49,7 @@ export class DotnetTrxParser implements TestParser {
const trx = await this.getTrxReport(path, content)
const tc = this.getTestClasses(trx)
const tr = this.getTestRunResult(path, trx, tc)
tr.sort(true)
return tr
}
@ -88,11 +89,6 @@ export class DotnetTrxParser implements TestParser {
}
const result = Object.values(testClasses)
result.sort((a, b) => a.name.localeCompare(b.name))
for (const tc of result) {
tc.tests.sort((a, b) => a.name.localeCompare(b.name))
}
return result
}

View file

@ -2,6 +2,7 @@ import {ParseOptions, TestParser} from '../../test-parser'
import {parseStringPromise} from 'xml2js'
import {JunitReport, TestCase, TestSuite} from './jest-junit-types'
import {getExceptionSource} from '../../utils/node-utils'
import {getBasePath, normalizeFilePath} from '../../utils/path-utils'
import {
@ -81,7 +82,7 @@ export class JestJunitParser implements TestParser {
let path
let line
const src = this.exceptionThrowSource(details)
const src = getExceptionSource(details, this.options.trackedFiles, file => this.getRelativePath(file))
if (src) {
path = src.path
line = src.line
@ -94,31 +95,13 @@ export class JestJunitParser implements TestParser {
}
}
private exceptionThrowSource(stackTrace: string): {path: string; line: number} | undefined {
const lines = stackTrace.split(/\r?\n/)
const re = /\((.*):(\d+):\d+\)$/
const {trackedFiles} = this.options
for (const str of lines) {
const match = str.match(re)
if (match !== null) {
const [_, fileStr, lineStr] = match
const filePath = normalizeFilePath(fileStr)
if (filePath.startsWith('internal/') || filePath.includes('/node_modules/')) {
continue
}
const workDir = this.getWorkDir(filePath)
if (!workDir) {
continue
}
const path = filePath.substr(workDir.length)
if (trackedFiles.includes(path)) {
const line = parseInt(lineStr)
return {path, line}
}
}
private getRelativePath(path: string): string {
path = normalizeFilePath(path)
const workDir = this.getWorkDir(path)
if (workDir !== undefined && path.startsWith(workDir)) {
path = path.substr(workDir.length)
}
return path
}
private getWorkDir(path: string): string | undefined {

View file

@ -0,0 +1,118 @@
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: ParseOptions) {}
async parse(path: string, content: string): Promise<TestRunResult> {
const mocha = this.getMochaJson(path, content)
const result = this.getTestRunResult(path, mocha)
result.sort(true)
return Promise.resolve(result)
}
private getMochaJson(path: string, content: string): MochaJson {
try {
return JSON.parse(content)
} catch (e) {
throw new Error(`Invalid JSON at ${path}\n\n${e}`)
}
}
private getTestRunResult(resultsPath: string, mocha: MochaJson): TestRunResult {
const suitesMap: {[path: string]: TestSuiteResult} = {}
const getSuite = (test: MochaJsonTest): 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: TestSuiteResult, test: MochaJsonTest, result: TestExecutionResult): void {
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, error)
group.tests.push(testCase)
}
private getTestCaseError(test: MochaJsonTest): TestCaseError | undefined {
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: string): string {
path = normalizeFilePath(path)
const workDir = this.getWorkDir(path)
if (workDir !== undefined && path.startsWith(workDir)) {
path = path.substr(workDir.length)
}
return path
}
private getWorkDir(path: string): string | undefined {
return (
this.options.workDir ??
this.assumedWorkDir ??
(this.assumedWorkDir = getBasePath(path, this.options.trackedFiles))
)
}
}

View file

@ -0,0 +1,23 @@
export interface MochaJson {
stats: MochaJsonStats
passes: MochaJsonTest[]
pending: MochaJsonTest[]
failures: MochaJsonTest[]
}
export interface MochaJsonStats {
duration: number
}
export interface MochaJsonTest {
title: string
fullTitle: string
file: string
duration: number
err: MochaJsonTestError
}
export interface MochaJsonTestError {
stack?: string
message?: string
}