Skip to content

Commit

Permalink
Extend dart-json report with suites summary and test case results
Browse files Browse the repository at this point in the history
  • Loading branch information
Michal Dorner committed Jan 6, 2021
1 parent e169ffb commit cc11ace
Show file tree
Hide file tree
Showing 3 changed files with 116 additions and 27 deletions.
36 changes: 35 additions & 1 deletion __tests__/__snapshots__/dart-json.test.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,41 @@
exports[`dart-json tests matches report snapshot 1`] = `
Object {
"annotations": Array [],
"summary": "**6** tests were completed in **3.760s** with **1** passed, **1** skipped and **4** failed.",
"summary": "**6** tests were completed in **3.760s** with **1** passed, **1** skipped and **4** failed.
| Result | Suite | Tests | Time | Passed ✔️ | Failed| Skipped ✖️ |
| :---: | :--- | ---: | ---: | ---: | ---: | ---: |
|| [test\\\\main_test.dart](#ts-0-test-maintest-dart) | 4 | 74ms | 1 | 3 | 0 |
|| [test\\\\second_test.dart](#ts-1-test-secondtest-dart) | 2 | 51ms | 0 | 1 | 1 |
# Test Suites
## <a id=\\"user-content-ts-0-test-maintest-dart\\" href=\\"#ts-0-test-maintest-dart\\">test\\\\main_test.dart</a>
### Test 1
| Result | Test | Time |
| :---: | :--- | ---: |
| ✔️ | Test 1 Passing test | 36ms |
### Test 1 Test 1.1
| Result | Test | Time |
| :---: | :--- | ---: |
|| Test 1 Test 1.1 Failing test | 20ms |
|| Test 1 Test 1.1 Exception in target unit | 6ms |
### Test 2
| Result | Test | Time |
| :---: | :--- | ---: |
|| Test 2 Exception in test | 12ms |
## <a id=\\"user-content-ts-1-test-secondtest-dart\\" href=\\"#ts-1-test-secondtest-dart\\">test\\\\second_test.dart</a>
| Result | Test | Time |
| :---: | :--- | ---: |
|| Timeout test | 37ms |
| ✖️ | Skipped test | 14ms |
",
"title": "Dart tests ❌",
}
`;
6 changes: 3 additions & 3 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

101 changes: 78 additions & 23 deletions src/parsers/dart-json/dart-json-parser.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import {ParseOptions, TestResult} from '../test-parser'

import {Icon} from '../../utils/markdown-utils'
import {Align, Icon, link, table} from '../../utils/markdown-utils'
import {slug} from '../../utils/slugger'

import {
ReportEvent,
Expand Down Expand Up @@ -35,28 +35,27 @@ class TestRun {

class TestSuite {
constructor(readonly suite: Suite) {}
tests = new TestGroup()
groups: {[id: number]: TestGroup} = {}
get count(): number {
return this.tests.count + Object.values(this.groups).reduce((sum, g) => sum + g.count, 0)
return Object.values(this.groups).reduce((sum, g) => sum + g.count, 0)
}
get passed(): number {
return this.tests.passed + Object.values(this.groups).reduce((sum, g) => sum + g.passed, 0)
return Object.values(this.groups).reduce((sum, g) => sum + g.passed, 0)
}
get failed(): number {
return this.tests.failed + Object.values(this.groups).reduce((sum, g) => sum + g.failed, 0)
return Object.values(this.groups).reduce((sum, g) => sum + g.failed, 0)
}
get skipped(): number {
return this.tests.skipped + Object.values(this.groups).reduce((sum, g) => sum + g.skipped, 0)
return Object.values(this.groups).reduce((sum, g) => sum + g.skipped, 0)
}
get time(): number {
return this.tests.time + Object.values(this.groups).reduce((sum, g) => sum + g.time, 0)
return Object.values(this.groups).reduce((sum, g) => sum + g.time, 0)
}
}

class TestGroup {
constructor(readonly group?: Group) {}
tests: TestSuiteTest[] = []
constructor(readonly group: Group) {}
tests: TestCase[] = []
get count(): number {
return this.tests.length
}
Expand All @@ -74,7 +73,7 @@ class TestGroup {
}
}

class TestSuiteTest {
class TestCase {
constructor(readonly testStart: TestStartEvent) {
this.groupId = testStart.test.groupIDs[testStart.test.groupIDs.length - 1]
}
Expand Down Expand Up @@ -116,18 +115,17 @@ function getTestRun(content: string): TestRun {
let success = false
let totalTime = 0
const suites: {[id: number]: TestSuite} = {}
const tests: {[id: number]: TestSuiteTest} = {}
const tests: {[id: number]: TestCase} = {}

for (const evt of events) {
if (isSuiteEvent(evt)) {
suites[evt.suite.id] = new TestSuite(evt.suite)
} else if (isGroupEvent(evt)) {
suites[evt.group.suiteID].groups[evt.group.id] = new TestGroup(evt.group)
} else if (isTestStartEvent(evt) && evt.test.url !== null) {
const test: TestSuiteTest = new TestSuiteTest(evt)
const test: TestCase = new TestCase(evt)
const suite = suites[evt.test.suiteID]
const group =
evt.test.groupIDs.length === 0 ? suite.tests : suite.groups[evt.test.groupIDs[evt.test.groupIDs.length - 1]]
const group = suite.groups[evt.test.groupIDs[evt.test.groupIDs.length - 1]]
group.tests.push(test)
tests[evt.test.id] = test
} else if (isTestDoneEvent(evt) && !evt.hidden) {
Expand All @@ -143,13 +141,70 @@ function getTestRun(content: string): TestRun {
return new TestRun(Object.values(suites), success, totalTime)
}

function getSummary(testRun: TestRun): string {
const tests = testRun.count
const time = `${(testRun.time / 1000).toFixed(3)}s`
const passed = testRun.passed
const skipped = testRun.skipped
const failed = testRun.failed
function getSummary(tr: TestRun): string {
const time = `${(tr.time / 1000).toFixed(3)}s`
const headingLine = `**${tr.count}** tests were completed in **${time}** with **${tr.passed}** passed, **${tr.skipped}** skipped and **${tr.failed}** failed.`

const suitesSummary = tr.suites.map((s, i) => {
const icon = s.failed === 0 ? Icon.success : Icon.fail
const tsTime = `${s.time}ms`
const tsName = s.suite.path
const tsAddr = makeSuiteSlug(i, tsName).link
const tsNameLink = link(tsName, tsAddr)
return [icon, tsNameLink, s.count, tsTime, s.passed, s.failed, s.skipped]
})

const summary = table(
['Result', 'Suite', 'Tests', 'Time', `Passed ${Icon.success}`, `Failed ${Icon.fail}`, `Skipped ${Icon.skip}`],
[Align.Center, Align.Left, Align.Right, Align.Right, Align.Right, Align.Right, Align.Right],
...suitesSummary
)

const suites = tr.suites.map((ts, i) => getSuiteSummary(ts, i)).join('\n')
const suitesSection = `# Test Suites\n\n${suites}`

return `${headingLine}\n${summary}\n${suitesSection}`
}

function getSuiteSummary(ts: TestSuite, index: number): string {
const icon = ts.failed === 0 ? Icon.success : Icon.fail

const groups = Object.values(ts.groups)
groups.sort((a, b) => (a.group.line ?? 0) - (b.group.line ?? 0))

const content = groups
.filter(grp => grp.count > 0)
.map(grp => {
const header = grp.group.name !== null ? `### ${grp.group.name}\n\n` : ''
grp.tests.sort((a, b) => (a.testStart.test.line ?? 0) - (b.testStart.test.line ?? 0))
const tests = table(
['Result', 'Test', 'Time'],
[Align.Center, Align.Left, Align.Right],
...grp.tests.map(tc => {
const name = tc.testStart.test.name
const time = `${tc.time}ms`
const result = getTestCaseIcon(tc)
return [result, name, time]
})
)

return `${header}${tests}\n`
})
.join('\n')

const tsName = ts.suite.path
const tsSlug = makeSuiteSlug(index, tsName)
const tsNameLink = `<a id="${tsSlug.id}" href="${tsSlug.link}">${tsName}</a>`
return `## ${tsNameLink} ${icon}\n\n${content}`
}

function makeSuiteSlug(index: number, name: string): {id: string; link: string} {
// use "ts-$index-" as prefix to avoid slug conflicts after escaping the paths
return slug(`ts-${index}-${name}`)
}

const headingLine = `**${tests}** tests were completed in **${time}** with **${passed}** passed, **${skipped}** skipped and **${failed}** failed.`
return `${headingLine}`
function getTestCaseIcon(test: TestCase): string {
if (test.isFailed) return Icon.fail
if (test.isSkipped) return Icon.skip
return Icon.success
}

0 comments on commit cc11ace

Please sign in to comment.