mirror of
https://github.com/dorny/test-reporter.git
synced 2025-12-18 07:07:08 +01:00
feat: implement apex test parser and add coverage percentage
This commit is contained in:
parent
c4f7701aa1
commit
0f142e1e2a
15 changed files with 6278 additions and 18 deletions
|
|
@ -1,10 +1,61 @@
|
|||
import {ParseOptions, TestParser} from '../../test-parser'
|
||||
import {TestRunResult} from '../../test-results'
|
||||
import {TestCaseError, TestCaseResult, TestExecutionResult, TestGroupResult, TestRunResult, TestSuiteResult} from '../../test-results'
|
||||
import {ApexTestReport} from './apex-json-types'
|
||||
|
||||
export class ApexJsonParser implements TestParser {
|
||||
constructor(readonly options: ParseOptions) {}
|
||||
|
||||
async parse(path: string, content: string): Promise<TestRunResult> {
|
||||
throw new Error('Method not implemented.')
|
||||
const report = await this.getReport(path, content)
|
||||
|
||||
return this.getTestRunResult(path, report)
|
||||
}
|
||||
|
||||
private async getReport(path: string, content: string): Promise<ApexTestReport> {
|
||||
try {
|
||||
return JSON.parse(content) as ApexTestReport
|
||||
} catch (e) {
|
||||
throw new Error(`Invalid JSON at ${path}\n\n${e}`)
|
||||
}
|
||||
}
|
||||
|
||||
private getTestRunResult(path: string, report: ApexTestReport): TestRunResult {
|
||||
const time = report.result.summary.testTotalTime
|
||||
const timeAsNumber = Number.parseInt(time, 10)
|
||||
|
||||
// group tests by test.ApexClass.Name
|
||||
const groupsMap: Map<string, TestCaseResult[]> = report.result.tests.reduce((map, test) => {
|
||||
const key = test.ApexClass.Name
|
||||
const testResults = map.get(key) || []
|
||||
|
||||
let result: TestExecutionResult = 'skipped'
|
||||
if (test.Outcome === 'Pass') {
|
||||
result = 'success'
|
||||
} else if (test.Outcome === 'Fail') {
|
||||
result = 'failed'
|
||||
}
|
||||
|
||||
const testCaseError: TestCaseError | undefined = test.Message ? {details: test.Message} : undefined
|
||||
|
||||
const testResult = new TestCaseResult(test.MethodName, result, test.RunTime, testCaseError)
|
||||
|
||||
testResults.push(testResult)
|
||||
map.set(key, testResults)
|
||||
return map
|
||||
}, new Map<string, TestCaseResult[]>())
|
||||
|
||||
const groups: TestGroupResult[] = []
|
||||
|
||||
for (const [name, tests] of groupsMap) {
|
||||
const suite = new TestGroupResult(name, tests)
|
||||
groups.push(suite)
|
||||
}
|
||||
|
||||
const coverageString = report.result.summary.testRunCoverage
|
||||
const coverage = coverageString ? Number.parseInt(coverageString.replace('%', ''), 10) : undefined
|
||||
|
||||
const suite = new TestSuiteResult('Apex Tests', groups, timeAsNumber, coverage)
|
||||
|
||||
return new TestRunResult(path, [suite], timeAsNumber, coverage)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
export interface RootObject {
|
||||
export interface ApexTestReport {
|
||||
result: Result
|
||||
}
|
||||
|
||||
|
|
@ -55,7 +55,7 @@ export interface Test {
|
|||
Id: string
|
||||
QueueItemId: string
|
||||
StackTrace: null
|
||||
Message: null
|
||||
Message: string | null
|
||||
AsyncApexJobId: string
|
||||
MethodName: string
|
||||
Outcome: string
|
||||
|
|
|
|||
|
|
@ -149,6 +149,16 @@ function getTestRunsReport(testRuns: TestRunResult[], options: ReportOptions): s
|
|||
sections.push(` `)
|
||||
}
|
||||
|
||||
const shouldShowCoverage = testRuns.some(tr => tr.coverage !== undefined)
|
||||
|
||||
const columnNames = ['Report', 'Passed', 'Failed', 'Skipped', 'Time']
|
||||
const columnAligns = [Align.Left, Align.Right, Align.Right, Align.Right, Align.Right]
|
||||
|
||||
if (shouldShowCoverage) {
|
||||
columnNames.push('Coverage')
|
||||
columnAligns.push(Align.Right)
|
||||
}
|
||||
|
||||
if (testRuns.length > 0 || options.onlySummary) {
|
||||
const tableData = testRuns
|
||||
.filter(tr => tr.passed > 0 || tr.failed > 0 || tr.skipped > 0)
|
||||
|
|
@ -158,14 +168,16 @@ function getTestRunsReport(testRuns: TestRunResult[], options: ReportOptions): s
|
|||
const passed = tr.passed > 0 ? `${tr.passed} ${Icon.success}` : ''
|
||||
const failed = tr.failed > 0 ? `${tr.failed} ${Icon.fail}` : ''
|
||||
const skipped = tr.skipped > 0 ? `${tr.skipped} ${Icon.skip}` : ''
|
||||
|
||||
if (shouldShowCoverage) {
|
||||
const coverage = tr.coverage !== undefined ? tr.coverage + '%' : ''
|
||||
return [name, passed, failed, skipped, time, coverage]
|
||||
}
|
||||
|
||||
return [name, passed, failed, skipped, time]
|
||||
})
|
||||
|
||||
const resultsTable = table(
|
||||
['Report', 'Passed', 'Failed', 'Skipped', 'Time'],
|
||||
[Align.Left, Align.Right, Align.Right, Align.Right, Align.Right],
|
||||
...tableData
|
||||
)
|
||||
const resultsTable = table(columnNames, columnAligns, ...tableData)
|
||||
sections.push(resultsTable)
|
||||
}
|
||||
|
||||
|
|
@ -198,9 +210,19 @@ function getSuitesReport(tr: TestRunResult, runIndex: number, options: ReportOpt
|
|||
sections.push(headingLine2)
|
||||
|
||||
if (suites.length > 0) {
|
||||
const shouldShowCoverage = suites.some(s => s.coverage !== undefined)
|
||||
|
||||
const columnNames = ['Test suite', 'Passed', 'Failed', 'Skipped', 'Time']
|
||||
const columnAligns = [Align.Left, Align.Right, Align.Right, Align.Right, Align.Right]
|
||||
|
||||
if (shouldShowCoverage) {
|
||||
columnNames.push('Coverage')
|
||||
columnAligns.push(Align.Right)
|
||||
}
|
||||
|
||||
const suitesTable = table(
|
||||
['Test suite', 'Passed', 'Failed', 'Skipped', 'Time'],
|
||||
[Align.Left, Align.Right, Align.Right, Align.Right, Align.Right],
|
||||
columnNames,
|
||||
columnAligns,
|
||||
...suites.map((s, suiteIndex) => {
|
||||
const tsTime = formatTime(s.time)
|
||||
const tsName = s.name
|
||||
|
|
@ -210,6 +232,13 @@ function getSuitesReport(tr: TestRunResult, runIndex: number, options: ReportOpt
|
|||
const passed = s.passed > 0 ? `${s.passed} ${Icon.success}` : ''
|
||||
const failed = s.failed > 0 ? `${s.failed} ${Icon.fail}` : ''
|
||||
const skipped = s.skipped > 0 ? `${s.skipped} ${Icon.skip}` : ''
|
||||
|
||||
const coverage = s.coverage !== undefined ? s.coverage + '%' : ''
|
||||
|
||||
if (shouldShowCoverage) {
|
||||
return [tsNameLink, passed, failed, skipped, tsTime, coverage]
|
||||
}
|
||||
|
||||
return [tsNameLink, passed, failed, skipped, tsTime]
|
||||
})
|
||||
)
|
||||
|
|
|
|||
|
|
@ -4,7 +4,8 @@ export class TestRunResult {
|
|||
constructor(
|
||||
readonly path: string,
|
||||
readonly suites: TestSuiteResult[],
|
||||
private totalTime?: number
|
||||
private totalTime?: number,
|
||||
private coveragePercentage?: number
|
||||
) {}
|
||||
|
||||
get tests(): number {
|
||||
|
|
@ -25,6 +26,10 @@ export class TestRunResult {
|
|||
return this.totalTime ?? this.suites.reduce((sum, g) => sum + g.time, 0)
|
||||
}
|
||||
|
||||
get coverage(): number | undefined {
|
||||
return this.coveragePercentage
|
||||
}
|
||||
|
||||
get result(): TestExecutionResult {
|
||||
return this.suites.some(t => t.result === 'failed') ? 'failed' : 'success'
|
||||
}
|
||||
|
|
@ -47,7 +52,8 @@ export class TestSuiteResult {
|
|||
constructor(
|
||||
readonly name: string,
|
||||
readonly groups: TestGroupResult[],
|
||||
private totalTime?: number
|
||||
private totalTime?: number,
|
||||
private coveragePercentage?: number
|
||||
) {}
|
||||
|
||||
get tests(): number {
|
||||
|
|
@ -66,6 +72,9 @@ export class TestSuiteResult {
|
|||
get time(): number {
|
||||
return this.totalTime ?? this.groups.reduce((sum, g) => sum + g.time, 0)
|
||||
}
|
||||
get coverage(): number | undefined {
|
||||
return this.coveragePercentage
|
||||
}
|
||||
|
||||
get result(): TestExecutionResult {
|
||||
return this.groups.some(t => t.result === 'failed') ? 'failed' : 'success'
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue