mirror of
https://github.com/dorny/test-reporter.git
synced 2026-02-04 13:37:56 +01:00
Merge pull request #463 from ritchxu/ritchxu/support-actions-summary
This commit is contained in:
commit
9557e57e83
22 changed files with 2430 additions and 901 deletions
11
README.md
11
README.md
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
This [Github Action](https://github.com/features/actions) displays test results from popular testing frameworks directly in GitHub.
|
This [Github Action](https://github.com/features/actions) displays test results from popular testing frameworks directly in GitHub.
|
||||||
|
|
||||||
✔️ Parses test results in XML or JSON format and creates nice report as Github Check Run
|
✔️ Parses test results in XML or JSON format and creates nice report as GitHub Check Run or GitHub Actions job summaries
|
||||||
|
|
||||||
✔️ Annotates code where it failed based on message and stack trace captured during test execution
|
✔️ Annotates code where it failed based on message and stack trace captured during test execution
|
||||||
|
|
||||||
|
|
@ -151,9 +151,18 @@ jobs:
|
||||||
# Detailed listing of test suites and test cases will be skipped.
|
# Detailed listing of test suites and test cases will be skipped.
|
||||||
only-summary: 'false'
|
only-summary: 'false'
|
||||||
|
|
||||||
|
# Allows you to generate reports for Actions Summary
|
||||||
|
# https://github.blog/2022-05-09-supercharging-github-actions-with-job-summaries/
|
||||||
|
use-actions-summary: 'true'
|
||||||
|
|
||||||
|
# Customize the title of badges shown for each Actions Summary.
|
||||||
|
# Useful when distinguish summaries for tests ran in multiple Actions steps.
|
||||||
|
badge-title: 'tests'
|
||||||
|
|
||||||
# Limits which test suites are listed:
|
# Limits which test suites are listed:
|
||||||
# all
|
# all
|
||||||
# failed
|
# failed
|
||||||
|
# none
|
||||||
list-suites: 'all'
|
list-suites: 'all'
|
||||||
|
|
||||||
# Limits which test cases are listed:
|
# Limits which test cases are listed:
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,7 @@
|
||||||

|

|
||||||
|
|Report|Passed|Failed|Skipped|Time|
|
||||||
|
|:---|---:|---:|---:|---:|
|
||||||
|
|fixtures/dart-json.json|1 ✅|4 ❌|1 ⚪|4s|
|
||||||
## ❌ <a id="user-content-r0" href="#r0">fixtures/dart-json.json</a>
|
## ❌ <a id="user-content-r0" href="#r0">fixtures/dart-json.json</a>
|
||||||
**6** tests were completed in **4s** with **1** passed, **4** failed and **1** skipped.
|
**6** tests were completed in **4s** with **1** passed, **4** failed and **1** skipped.
|
||||||
|Test suite|Passed|Failed|Skipped|Time|
|
|Test suite|Passed|Failed|Skipped|Time|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,7 @@
|
||||||

|

|
||||||
|
|Report|Passed|Failed|Skipped|Time|
|
||||||
|
|:---|---:|---:|---:|---:|
|
||||||
|
|fixtures/dotnet-nunit.xml|3 ✅|5 ❌|1 ⚪|230ms|
|
||||||
## ❌ <a id="user-content-r0" href="#r0">fixtures/dotnet-nunit.xml</a>
|
## ❌ <a id="user-content-r0" href="#r0">fixtures/dotnet-nunit.xml</a>
|
||||||
**9** tests were completed in **230ms** with **3** passed, **5** failed and **1** skipped.
|
**9** tests were completed in **230ms** with **3** passed, **5** failed and **1** skipped.
|
||||||
|Test suite|Passed|Failed|Skipped|Time|
|
|Test suite|Passed|Failed|Skipped|Time|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,7 @@
|
||||||

|

|
||||||
|
|Report|Passed|Failed|Skipped|Time|
|
||||||
|
|:---|---:|---:|---:|---:|
|
||||||
|
|fixtures/dotnet-trx.trx|5 ✅|5 ❌|1 ⚪|1s|
|
||||||
## ❌ <a id="user-content-r0" href="#r0">fixtures/dotnet-trx.trx</a>
|
## ❌ <a id="user-content-r0" href="#r0">fixtures/dotnet-trx.trx</a>
|
||||||
**11** tests were completed in **1s** with **5** passed, **5** failed and **1** skipped.
|
**11** tests were completed in **1s** with **5** passed, **5** failed and **1** skipped.
|
||||||
|Test suite|Passed|Failed|Skipped|Time|
|
|Test suite|Passed|Failed|Skipped|Time|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,9 @@
|
||||||

|

|
||||||
|
<details><summary>Expand for details</summary>
|
||||||
|
|
||||||
|
|Report|Passed|Failed|Skipped|Time|
|
||||||
|
|:---|---:|---:|---:|---:|
|
||||||
|
|fixtures/external/FluentValidation.Tests.trx|803 ✅||1 ⚪|4s|
|
||||||
## ✅ <a id="user-content-r0" href="#r0">fixtures/external/FluentValidation.Tests.trx</a>
|
## ✅ <a id="user-content-r0" href="#r0">fixtures/external/FluentValidation.Tests.trx</a>
|
||||||
**804** tests were completed in **4s** with **803** passed, **0** failed and **1** skipped.
|
**804** tests were completed in **4s** with **803** passed, **0** failed and **1** skipped.
|
||||||
|Test suite|Passed|Failed|Skipped|Time|
|
|Test suite|Passed|Failed|Skipped|Time|
|
||||||
|
|
@ -1055,3 +1060,4 @@
|
||||||
✅ Unexpected_severity_check
|
✅ Unexpected_severity_check
|
||||||
✅ Unexpected_state_check
|
✅ Unexpected_state_check
|
||||||
```
|
```
|
||||||
|
</details>
|
||||||
|
|
@ -1,4 +1,7 @@
|
||||||

|

|
||||||
|
|Report|Passed|Failed|Skipped|Time|
|
||||||
|
|:---|---:|---:|---:|---:|
|
||||||
|
|fixtures/jest-junit.xml|1 ✅|4 ❌|1 ⚪|1s|
|
||||||
## ❌ <a id="user-content-r0" href="#r0">fixtures/jest-junit.xml</a>
|
## ❌ <a id="user-content-r0" href="#r0">fixtures/jest-junit.xml</a>
|
||||||
**6** tests were completed in **1s** with **1** passed, **4** failed and **1** skipped.
|
**6** tests were completed in **1s** with **1** passed, **4** failed and **1** skipped.
|
||||||
|Test suite|Passed|Failed|Skipped|Time|
|
|Test suite|Passed|Failed|Skipped|Time|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,9 @@
|
||||||

|

|
||||||
|
<details><summary>Expand for details</summary>
|
||||||
|
|
||||||
|
|Report|Passed|Failed|Skipped|Time|
|
||||||
|
|:---|---:|---:|---:|---:|
|
||||||
|
|fixtures/external/jest/jest-react-component-test-results.xml|1 ✅|||1000ms|
|
||||||
## ✅ <a id="user-content-r0" href="#r0">fixtures/external/jest/jest-react-component-test-results.xml</a>
|
## ✅ <a id="user-content-r0" href="#r0">fixtures/external/jest/jest-react-component-test-results.xml</a>
|
||||||
**1** tests were completed in **1000ms** with **1** passed, **0** failed and **0** skipped.
|
**1** tests were completed in **1000ms** with **1** passed, **0** failed and **0** skipped.
|
||||||
|Test suite|Passed|Failed|Skipped|Time|
|
|Test suite|Passed|Failed|Skipped|Time|
|
||||||
|
|
@ -8,3 +13,4 @@
|
||||||
```
|
```
|
||||||
✅ <Component /> should render properly
|
✅ <Component /> should render properly
|
||||||
```
|
```
|
||||||
|
</details>
|
||||||
|
|
@ -1,4 +1,7 @@
|
||||||

|

|
||||||
|
|Report|Passed|Failed|Skipped|Time|
|
||||||
|
|:---|---:|---:|---:|---:|
|
||||||
|
|fixtures/external/jest/jest-test-results.xml|4207 ✅|2 ❌|30 ⚪|166s|
|
||||||
## ❌ <a id="user-content-r0" href="#r0">fixtures/external/jest/jest-test-results.xml</a>
|
## ❌ <a id="user-content-r0" href="#r0">fixtures/external/jest/jest-test-results.xml</a>
|
||||||
**4239** tests were completed in **166s** with **4207** passed, **2** failed and **30** skipped.
|
**4239** tests were completed in **166s** with **4207** passed, **2** failed and **30** skipped.
|
||||||
|Test suite|Passed|Failed|Skipped|Time|
|
|Test suite|Passed|Failed|Skipped|Time|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,7 @@
|
||||||

|

|
||||||
|
|Report|Passed|Failed|Skipped|Time|
|
||||||
|
|:---|---:|---:|---:|---:|
|
||||||
|
|fixtures/mocha-json.json|1 ✅|4 ❌|1 ⚪|12ms|
|
||||||
## ❌ <a id="user-content-r0" href="#r0">fixtures/mocha-json.json</a>
|
## ❌ <a id="user-content-r0" href="#r0">fixtures/mocha-json.json</a>
|
||||||
**6** tests were completed in **12ms** with **1** passed, **4** failed and **1** skipped.
|
**6** tests were completed in **12ms** with **1** passed, **4** failed and **1** skipped.
|
||||||
|Test suite|Passed|Failed|Skipped|Time|
|
|Test suite|Passed|Failed|Skipped|Time|
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -1,4 +1,7 @@
|
||||||

|

|
||||||
|
|Report|Passed|Failed|Skipped|Time|
|
||||||
|
|:---|---:|---:|---:|---:|
|
||||||
|
|fixtures/external/flutter/provider-test-results.json|268 ✅|1 ❌||0ms|
|
||||||
## ❌ <a id="user-content-r0" href="#r0">fixtures/external/flutter/provider-test-results.json</a>
|
## ❌ <a id="user-content-r0" href="#r0">fixtures/external/flutter/provider-test-results.json</a>
|
||||||
**269** tests were completed in **0ms** with **268** passed, **1** failed and **0** skipped.
|
**269** tests were completed in **0ms** with **268** passed, **1** failed and **0** skipped.
|
||||||
|Test suite|Passed|Failed|Skipped|Time|
|
|Test suite|Passed|Failed|Skipped|Time|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,7 @@
|
||||||

|

|
||||||
|
|Report|Passed|Failed|Skipped|Time|
|
||||||
|
|:---|---:|---:|---:|---:|
|
||||||
|
|fixtures/external/java/TEST-org.apache.pulsar.AddMissingPatchVersionTest.xml||1 ❌|1 ⚪|116ms|
|
||||||
## ❌ <a id="user-content-r0" href="#r0">fixtures/external/java/TEST-org.apache.pulsar.AddMissingPatchVersionTest.xml</a>
|
## ❌ <a id="user-content-r0" href="#r0">fixtures/external/java/TEST-org.apache.pulsar.AddMissingPatchVersionTest.xml</a>
|
||||||
**2** tests were completed in **116ms** with **0** passed, **1** failed and **1** skipped.
|
**2** tests were completed in **116ms** with **0** passed, **1** failed and **1** skipped.
|
||||||
|Test suite|Passed|Failed|Skipped|Time|
|
|Test suite|Passed|Failed|Skipped|Time|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,7 @@
|
||||||

|

|
||||||
|
|Report|Passed|Failed|Skipped|Time|
|
||||||
|
|:---|---:|---:|---:|---:|
|
||||||
|
|fixtures/external/java/pulsar-test-report.xml|793 ✅|1 ❌|14 ⚪|2127s|
|
||||||
## ❌ <a id="user-content-r0" href="#r0">fixtures/external/java/pulsar-test-report.xml</a>
|
## ❌ <a id="user-content-r0" href="#r0">fixtures/external/java/pulsar-test-report.xml</a>
|
||||||
**808** tests were completed in **2127s** with **793** passed, **1** failed and **14** skipped.
|
**808** tests were completed in **2127s** with **793** passed, **1** failed and **14** skipped.
|
||||||
|Test suite|Passed|Failed|Skipped|Time|
|
|Test suite|Passed|Failed|Skipped|Time|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,7 @@
|
||||||

|

|
||||||
|
|Report|Passed|Failed|Skipped|Time|
|
||||||
|
|:---|---:|---:|---:|---:|
|
||||||
|
|fixtures/rspec-json.json|1 ✅|1 ❌|1 ⚪|0ms|
|
||||||
## ❌ <a id="user-content-r0" href="#r0">fixtures/rspec-json.json</a>
|
## ❌ <a id="user-content-r0" href="#r0">fixtures/rspec-json.json</a>
|
||||||
**3** tests were completed in **0ms** with **1** passed, **1** failed and **1** skipped.
|
**3** tests were completed in **0ms** with **1** passed, **1** failed and **1** skipped.
|
||||||
|Test suite|Passed|Failed|Skipped|Time|
|
|Test suite|Passed|Failed|Skipped|Time|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,9 @@
|
||||||

|

|
||||||
|
<details><summary>Expand for details</summary>
|
||||||
|
|
||||||
|
|Report|Passed|Failed|Skipped|Time|
|
||||||
|
|:---|---:|---:|---:|---:|
|
||||||
|
|fixtures/external/SilentNotes.trx|67 ✅||12 ⚪|1s|
|
||||||
## ✅ <a id="user-content-r0" href="#r0">fixtures/external/SilentNotes.trx</a>
|
## ✅ <a id="user-content-r0" href="#r0">fixtures/external/SilentNotes.trx</a>
|
||||||
**79** tests were completed in **1s** with **67** passed, **0** failed and **12** skipped.
|
**79** tests were completed in **1s** with **67** passed, **0** failed and **12** skipped.
|
||||||
|Test suite|Passed|Failed|Skipped|Time|
|
|Test suite|Passed|Failed|Skipped|Time|
|
||||||
|
|
@ -134,3 +139,4 @@
|
||||||
✅ SerializedXmlDoesNotContainNullProperties
|
✅ SerializedXmlDoesNotContainNullProperties
|
||||||
✅ SerializedXmlDoesNotContainPlaintextData
|
✅ SerializedXmlDoesNotContainPlaintextData
|
||||||
```
|
```
|
||||||
|
</details>
|
||||||
|
|
@ -1,4 +1,7 @@
|
||||||

|

|
||||||
|
|Report|Passed|Failed|Skipped|Time|
|
||||||
|
|:---|---:|---:|---:|---:|
|
||||||
|
|fixtures/swift-xunit.xml|2 ✅|1 ❌||220ms|
|
||||||
## ❌ <a id="user-content-r0" href="#r0">fixtures/swift-xunit.xml</a>
|
## ❌ <a id="user-content-r0" href="#r0">fixtures/swift-xunit.xml</a>
|
||||||
**3** tests were completed in **220ms** with **2** passed, **1** failed and **0** skipped.
|
**3** tests were completed in **220ms** with **2** passed, **1** failed and **0** skipped.
|
||||||
|Test suite|Passed|Failed|Skipped|Time|
|
|Test suite|Passed|Failed|Skipped|Time|
|
||||||
|
|
|
||||||
11
action.yml
11
action.yml
|
|
@ -40,6 +40,7 @@ inputs:
|
||||||
Limits which test suites are listed. Supported options:
|
Limits which test suites are listed. Supported options:
|
||||||
- all
|
- all
|
||||||
- only-failed
|
- only-failed
|
||||||
|
- none
|
||||||
required: false
|
required: false
|
||||||
default: 'all'
|
default: 'all'
|
||||||
list-tests:
|
list-tests:
|
||||||
|
|
@ -74,6 +75,16 @@ inputs:
|
||||||
Detailed listing of test suites and test cases will be skipped.
|
Detailed listing of test suites and test cases will be skipped.
|
||||||
default: 'false'
|
default: 'false'
|
||||||
required: false
|
required: false
|
||||||
|
use-actions-summary:
|
||||||
|
description: |
|
||||||
|
Allows you to generate reports for Actions Summary
|
||||||
|
https://github.com/orgs/github/teams/engineering/discussions/871
|
||||||
|
default: 'true'
|
||||||
|
required: false
|
||||||
|
badge-title:
|
||||||
|
description: Customize badge title
|
||||||
|
required: false
|
||||||
|
default: 'tests'
|
||||||
token:
|
token:
|
||||||
description: GitHub Access Token
|
description: GitHub Access Token
|
||||||
required: false
|
required: false
|
||||||
|
|
|
||||||
73
dist/index.js
generated
vendored
73
dist/index.js
generated
vendored
|
|
@ -275,12 +275,14 @@ class TestReporter {
|
||||||
failOnEmpty = core.getInput('fail-on-empty', { required: true }) === 'true';
|
failOnEmpty = core.getInput('fail-on-empty', { required: true }) === 'true';
|
||||||
workDirInput = core.getInput('working-directory', { required: false });
|
workDirInput = core.getInput('working-directory', { required: false });
|
||||||
onlySummary = core.getInput('only-summary', { required: false }) === 'true';
|
onlySummary = core.getInput('only-summary', { required: false }) === 'true';
|
||||||
|
useActionsSummary = core.getInput('use-actions-summary', { required: false }) === 'true';
|
||||||
|
badgeTitle = core.getInput('badge-title', { required: false });
|
||||||
token = core.getInput('token', { required: true });
|
token = core.getInput('token', { required: true });
|
||||||
octokit;
|
octokit;
|
||||||
context = (0, github_utils_1.getCheckRunContext)();
|
context = (0, github_utils_1.getCheckRunContext)();
|
||||||
constructor() {
|
constructor() {
|
||||||
this.octokit = github.getOctokit(this.token);
|
this.octokit = github.getOctokit(this.token);
|
||||||
if (this.listSuites !== 'all' && this.listSuites !== 'failed') {
|
if (this.listSuites !== 'all' && this.listSuites !== 'failed' && this.listSuites !== 'none') {
|
||||||
core.setFailed(`Input parameter 'list-suites' has invalid value`);
|
core.setFailed(`Input parameter 'list-suites' has invalid value`);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -367,6 +369,15 @@ class TestReporter {
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
const { listSuites, listTests, onlySummary, useActionsSummary, badgeTitle } = this;
|
||||||
|
let baseUrl = '';
|
||||||
|
if (this.useActionsSummary) {
|
||||||
|
const summary = (0, get_report_1.getReport)(results, { listSuites, listTests, baseUrl, onlySummary, useActionsSummary, badgeTitle });
|
||||||
|
core.info('Summary content:');
|
||||||
|
core.info(summary);
|
||||||
|
await core.summary.addRaw(summary).write();
|
||||||
|
}
|
||||||
|
else {
|
||||||
core.info(`Creating check run ${name}`);
|
core.info(`Creating check run ${name}`);
|
||||||
const createResp = await this.octokit.rest.checks.create({
|
const createResp = await this.octokit.rest.checks.create({
|
||||||
head_sha: this.context.sha,
|
head_sha: this.context.sha,
|
||||||
|
|
@ -379,9 +390,8 @@ class TestReporter {
|
||||||
...github.context.repo
|
...github.context.repo
|
||||||
});
|
});
|
||||||
core.info('Creating report summary');
|
core.info('Creating report summary');
|
||||||
const { listSuites, listTests, onlySummary } = this;
|
baseUrl = createResp.data.html_url;
|
||||||
const baseUrl = createResp.data.html_url;
|
const summary = (0, get_report_1.getReport)(results, { listSuites, listTests, baseUrl, onlySummary, useActionsSummary, badgeTitle });
|
||||||
const summary = (0, get_report_1.getReport)(results, { listSuites, listTests, baseUrl, onlySummary });
|
|
||||||
core.info('Creating annotations');
|
core.info('Creating annotations');
|
||||||
const annotations = (0, get_annotations_1.getAnnotations)(results, this.maxAnnotations);
|
const annotations = (0, get_annotations_1.getAnnotations)(results, this.maxAnnotations);
|
||||||
const isFailed = this.failOnError && results.some(tr => tr.result === 'failed');
|
const isFailed = this.failOnError && results.some(tr => tr.result === 'failed');
|
||||||
|
|
@ -407,6 +417,7 @@ class TestReporter {
|
||||||
core.info(`Check run HTML: ${resp.data.html_url}`);
|
core.info(`Check run HTML: ${resp.data.html_url}`);
|
||||||
core.setOutput('url', resp.data.url);
|
core.setOutput('url', resp.data.url);
|
||||||
core.setOutput('url_html', resp.data.html_url);
|
core.setOutput('url_html', resp.data.html_url);
|
||||||
|
}
|
||||||
return results;
|
return results;
|
||||||
}
|
}
|
||||||
getParser(reporter, options) {
|
getParser(reporter, options) {
|
||||||
|
|
@ -1731,11 +1742,14 @@ const node_utils_1 = __nccwpck_require__(5824);
|
||||||
const parse_utils_1 = __nccwpck_require__(7811);
|
const parse_utils_1 = __nccwpck_require__(7811);
|
||||||
const slugger_1 = __nccwpck_require__(3328);
|
const slugger_1 = __nccwpck_require__(3328);
|
||||||
const MAX_REPORT_LENGTH = 65535;
|
const MAX_REPORT_LENGTH = 65535;
|
||||||
|
const MAX_ACTIONS_SUMMARY_LENGTH = 131072; // 1048576 soon
|
||||||
const defaultOptions = {
|
const defaultOptions = {
|
||||||
listSuites: 'all',
|
listSuites: 'all',
|
||||||
listTests: 'all',
|
listTests: 'all',
|
||||||
baseUrl: '',
|
baseUrl: '',
|
||||||
onlySummary: false
|
onlySummary: false,
|
||||||
|
useActionsSummary: true,
|
||||||
|
badgeTitle: 'tests'
|
||||||
};
|
};
|
||||||
function getReport(results, options = defaultOptions) {
|
function getReport(results, options = defaultOptions) {
|
||||||
core.info('Generating check run summary');
|
core.info('Generating check run summary');
|
||||||
|
|
@ -1743,7 +1757,7 @@ function getReport(results, options = defaultOptions) {
|
||||||
const opts = { ...options };
|
const opts = { ...options };
|
||||||
let lines = renderReport(results, opts);
|
let lines = renderReport(results, opts);
|
||||||
let report = lines.join('\n');
|
let report = lines.join('\n');
|
||||||
if (getByteLength(report) <= MAX_REPORT_LENGTH) {
|
if (getByteLength(report) <= getMaxReportLength(options)) {
|
||||||
return report;
|
return report;
|
||||||
}
|
}
|
||||||
if (opts.listTests === 'all') {
|
if (opts.listTests === 'all') {
|
||||||
|
|
@ -1751,18 +1765,21 @@ function getReport(results, options = defaultOptions) {
|
||||||
opts.listTests = 'failed';
|
opts.listTests = 'failed';
|
||||||
lines = renderReport(results, opts);
|
lines = renderReport(results, opts);
|
||||||
report = lines.join('\n');
|
report = lines.join('\n');
|
||||||
if (getByteLength(report) <= MAX_REPORT_LENGTH) {
|
if (getByteLength(report) <= getMaxReportLength(options)) {
|
||||||
return report;
|
return report;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
core.warning(`Test report summary exceeded limit of ${MAX_REPORT_LENGTH} bytes and will be trimmed`);
|
core.warning(`Test report summary exceeded limit of ${getMaxReportLength(options)} bytes and will be trimmed`);
|
||||||
return trimReport(lines);
|
return trimReport(lines, options);
|
||||||
}
|
}
|
||||||
function trimReport(lines) {
|
function getMaxReportLength(options = defaultOptions) {
|
||||||
|
return options.useActionsSummary ? MAX_ACTIONS_SUMMARY_LENGTH : MAX_REPORT_LENGTH;
|
||||||
|
}
|
||||||
|
function trimReport(lines, options) {
|
||||||
const closingBlock = '```';
|
const closingBlock = '```';
|
||||||
const errorMsg = `**Report exceeded GitHub limit of ${MAX_REPORT_LENGTH} bytes and has been trimmed**`;
|
const errorMsg = `**Report exceeded GitHub limit of ${getMaxReportLength(options)} bytes and has been trimmed**`;
|
||||||
const maxErrorMsgLength = closingBlock.length + errorMsg.length + 2;
|
const maxErrorMsgLength = closingBlock.length + errorMsg.length + 2;
|
||||||
const maxReportLength = MAX_REPORT_LENGTH - maxErrorMsgLength;
|
const maxReportLength = getMaxReportLength(options) - maxErrorMsgLength;
|
||||||
let reportLength = 0;
|
let reportLength = 0;
|
||||||
let codeBlock = false;
|
let codeBlock = false;
|
||||||
let endLineIndex = 0;
|
let endLineIndex = 0;
|
||||||
|
|
@ -1795,19 +1812,19 @@ function getByteLength(text) {
|
||||||
}
|
}
|
||||||
function renderReport(results, options) {
|
function renderReport(results, options) {
|
||||||
const sections = [];
|
const sections = [];
|
||||||
const badge = getReportBadge(results);
|
const badge = getReportBadge(results, options);
|
||||||
sections.push(badge);
|
sections.push(badge);
|
||||||
const runs = getTestRunsReport(results, options);
|
const runs = getTestRunsReport(results, options);
|
||||||
sections.push(...runs);
|
sections.push(...runs);
|
||||||
return sections;
|
return sections;
|
||||||
}
|
}
|
||||||
function getReportBadge(results) {
|
function getReportBadge(results, options) {
|
||||||
const passed = results.reduce((sum, tr) => sum + tr.passed, 0);
|
const passed = results.reduce((sum, tr) => sum + tr.passed, 0);
|
||||||
const skipped = results.reduce((sum, tr) => sum + tr.skipped, 0);
|
const skipped = results.reduce((sum, tr) => sum + tr.skipped, 0);
|
||||||
const failed = results.reduce((sum, tr) => sum + tr.failed, 0);
|
const failed = results.reduce((sum, tr) => sum + tr.failed, 0);
|
||||||
return getBadge(passed, failed, skipped);
|
return getBadge(passed, failed, skipped, options);
|
||||||
}
|
}
|
||||||
function getBadge(passed, failed, skipped) {
|
function getBadge(passed, failed, skipped, options) {
|
||||||
const text = [];
|
const text = [];
|
||||||
if (passed > 0) {
|
if (passed > 0) {
|
||||||
text.push(`${passed} passed`);
|
text.push(`${passed} passed`);
|
||||||
|
|
@ -1827,21 +1844,26 @@ function getBadge(passed, failed, skipped) {
|
||||||
color = 'yellow';
|
color = 'yellow';
|
||||||
}
|
}
|
||||||
const hint = failed > 0 ? 'Tests failed' : 'Tests passed successfully';
|
const hint = failed > 0 ? 'Tests failed' : 'Tests passed successfully';
|
||||||
const uri = encodeURIComponent(`tests-${message}-${color}`);
|
const uri = encodeURIComponent(`${options.badgeTitle}-${message}-${color}`);
|
||||||
return ``;
|
return ``;
|
||||||
}
|
}
|
||||||
function getTestRunsReport(testRuns, options) {
|
function getTestRunsReport(testRuns, options) {
|
||||||
const sections = [];
|
const sections = [];
|
||||||
if (testRuns.length > 1 || options.onlySummary) {
|
const totalFailed = testRuns.reduce((sum, tr) => sum + tr.failed, 0);
|
||||||
const tableData = testRuns.map((tr, runIndex) => {
|
if (totalFailed === 0) {
|
||||||
|
sections.push(`<details><summary>Expand for details</summary>`);
|
||||||
|
sections.push(` `);
|
||||||
|
}
|
||||||
|
if (testRuns.length > 0 || options.onlySummary) {
|
||||||
|
const tableData = testRuns
|
||||||
|
.filter(tr => tr.passed > 0 || tr.failed > 0 || tr.skipped > 0)
|
||||||
|
.map(tr => {
|
||||||
const time = (0, markdown_utils_1.formatTime)(tr.time);
|
const time = (0, markdown_utils_1.formatTime)(tr.time);
|
||||||
const name = tr.path;
|
const name = tr.path;
|
||||||
const addr = options.baseUrl + makeRunSlug(runIndex).link;
|
|
||||||
const nameLink = (0, markdown_utils_1.link)(name, addr);
|
|
||||||
const passed = tr.passed > 0 ? `${tr.passed} ${markdown_utils_1.Icon.success}` : '';
|
const passed = tr.passed > 0 ? `${tr.passed} ${markdown_utils_1.Icon.success}` : '';
|
||||||
const failed = tr.failed > 0 ? `${tr.failed} ${markdown_utils_1.Icon.fail}` : '';
|
const failed = tr.failed > 0 ? `${tr.failed} ${markdown_utils_1.Icon.fail}` : '';
|
||||||
const skipped = tr.skipped > 0 ? `${tr.skipped} ${markdown_utils_1.Icon.skip}` : '';
|
const skipped = tr.skipped > 0 ? `${tr.skipped} ${markdown_utils_1.Icon.skip}` : '';
|
||||||
return [nameLink, passed, failed, skipped, time];
|
return [name, passed, failed, skipped, time];
|
||||||
});
|
});
|
||||||
const resultsTable = (0, markdown_utils_1.table)(['Report', 'Passed', 'Failed', 'Skipped', 'Time'], [markdown_utils_1.Align.Left, markdown_utils_1.Align.Right, markdown_utils_1.Align.Right, markdown_utils_1.Align.Right, markdown_utils_1.Align.Right], ...tableData);
|
const resultsTable = (0, markdown_utils_1.table)(['Report', 'Passed', 'Failed', 'Skipped', 'Time'], [markdown_utils_1.Align.Left, markdown_utils_1.Align.Right, markdown_utils_1.Align.Right, markdown_utils_1.Align.Right, markdown_utils_1.Align.Right], ...tableData);
|
||||||
sections.push(resultsTable);
|
sections.push(resultsTable);
|
||||||
|
|
@ -1850,10 +1872,15 @@ function getTestRunsReport(testRuns, options) {
|
||||||
const suitesReports = testRuns.map((tr, i) => getSuitesReport(tr, i, options)).flat();
|
const suitesReports = testRuns.map((tr, i) => getSuitesReport(tr, i, options)).flat();
|
||||||
sections.push(...suitesReports);
|
sections.push(...suitesReports);
|
||||||
}
|
}
|
||||||
|
if (totalFailed === 0) {
|
||||||
|
sections.push(`</details>`);
|
||||||
|
}
|
||||||
return sections;
|
return sections;
|
||||||
}
|
}
|
||||||
function getSuitesReport(tr, runIndex, options) {
|
function getSuitesReport(tr, runIndex, options) {
|
||||||
const sections = [];
|
const sections = [];
|
||||||
|
const suites = options.listSuites === 'failed' ? tr.failedSuites : tr.suites;
|
||||||
|
if (options.listSuites !== 'none') {
|
||||||
const trSlug = makeRunSlug(runIndex);
|
const trSlug = makeRunSlug(runIndex);
|
||||||
const nameLink = `<a id="${trSlug.id}" href="${options.baseUrl + trSlug.link}">${tr.path}</a>`;
|
const nameLink = `<a id="${trSlug.id}" href="${options.baseUrl + trSlug.link}">${tr.path}</a>`;
|
||||||
const icon = getResultIcon(tr.result);
|
const icon = getResultIcon(tr.result);
|
||||||
|
|
@ -1863,7 +1890,6 @@ function getSuitesReport(tr, runIndex, options) {
|
||||||
? `**${tr.tests}** tests were completed in **${time}** with **${tr.passed}** passed, **${tr.failed}** failed and **${tr.skipped}** skipped.`
|
? `**${tr.tests}** tests were completed in **${time}** with **${tr.passed}** passed, **${tr.failed}** failed and **${tr.skipped}** skipped.`
|
||||||
: 'No tests found';
|
: 'No tests found';
|
||||||
sections.push(headingLine2);
|
sections.push(headingLine2);
|
||||||
const suites = options.listSuites === 'failed' ? tr.failedSuites : tr.suites;
|
|
||||||
if (suites.length > 0) {
|
if (suites.length > 0) {
|
||||||
const suitesTable = (0, markdown_utils_1.table)(['Test suite', 'Passed', 'Failed', 'Skipped', 'Time'], [markdown_utils_1.Align.Left, markdown_utils_1.Align.Right, markdown_utils_1.Align.Right, markdown_utils_1.Align.Right, markdown_utils_1.Align.Right], ...suites.map((s, suiteIndex) => {
|
const suitesTable = (0, markdown_utils_1.table)(['Test suite', 'Passed', 'Failed', 'Skipped', 'Time'], [markdown_utils_1.Align.Left, markdown_utils_1.Align.Right, markdown_utils_1.Align.Right, markdown_utils_1.Align.Right, markdown_utils_1.Align.Right], ...suites.map((s, suiteIndex) => {
|
||||||
const tsTime = (0, markdown_utils_1.formatTime)(s.time);
|
const tsTime = (0, markdown_utils_1.formatTime)(s.time);
|
||||||
|
|
@ -1878,6 +1904,7 @@ function getSuitesReport(tr, runIndex, options) {
|
||||||
}));
|
}));
|
||||||
sections.push(suitesTable);
|
sections.push(suitesTable);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
if (options.listTests !== 'none') {
|
if (options.listTests !== 'none') {
|
||||||
const tests = suites.map((ts, suiteIndex) => getTestsReport(ts, runIndex, suiteIndex, options)).flat();
|
const tests = suites.map((ts, suiteIndex) => getTestsReport(ts, runIndex, suiteIndex, options)).flat();
|
||||||
if (tests.length > 1) {
|
if (tests.length > 1) {
|
||||||
|
|
|
||||||
2
dist/index.js.map
generated
vendored
2
dist/index.js.map
generated
vendored
File diff suppressed because one or more lines are too long
3
package-lock.json
generated
3
package-lock.json
generated
|
|
@ -43,6 +43,9 @@
|
||||||
"prettier": "^3.3.2",
|
"prettier": "^3.3.2",
|
||||||
"ts-jest": "^29.1.5",
|
"ts-jest": "^29.1.5",
|
||||||
"typescript": "^5.5.2"
|
"typescript": "^5.5.2"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=20"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@aashutoshrathi/word-wrap": {
|
"node_modules/@aashutoshrathi/word-wrap": {
|
||||||
|
|
|
||||||
22
src/main.ts
22
src/main.ts
|
|
@ -38,13 +38,15 @@ class TestReporter {
|
||||||
readonly path = core.getInput('path', {required: true})
|
readonly path = core.getInput('path', {required: true})
|
||||||
readonly pathReplaceBackslashes = core.getInput('path-replace-backslashes', {required: false}) === 'true'
|
readonly pathReplaceBackslashes = core.getInput('path-replace-backslashes', {required: false}) === 'true'
|
||||||
readonly reporter = core.getInput('reporter', {required: true})
|
readonly reporter = core.getInput('reporter', {required: true})
|
||||||
readonly listSuites = core.getInput('list-suites', {required: true}) as 'all' | 'failed'
|
readonly listSuites = core.getInput('list-suites', {required: true}) as 'all' | 'failed' | 'none'
|
||||||
readonly listTests = core.getInput('list-tests', {required: true}) as 'all' | 'failed' | 'none'
|
readonly listTests = core.getInput('list-tests', {required: true}) as 'all' | 'failed' | 'none'
|
||||||
readonly maxAnnotations = parseInt(core.getInput('max-annotations', {required: true}))
|
readonly maxAnnotations = parseInt(core.getInput('max-annotations', {required: true}))
|
||||||
readonly failOnError = core.getInput('fail-on-error', {required: true}) === 'true'
|
readonly failOnError = core.getInput('fail-on-error', {required: true}) === 'true'
|
||||||
readonly failOnEmpty = core.getInput('fail-on-empty', {required: true}) === 'true'
|
readonly failOnEmpty = core.getInput('fail-on-empty', {required: true}) === 'true'
|
||||||
readonly workDirInput = core.getInput('working-directory', {required: false})
|
readonly workDirInput = core.getInput('working-directory', {required: false})
|
||||||
readonly onlySummary = core.getInput('only-summary', {required: false}) === 'true'
|
readonly onlySummary = core.getInput('only-summary', {required: false}) === 'true'
|
||||||
|
readonly useActionsSummary = core.getInput('use-actions-summary', {required: false}) === 'true'
|
||||||
|
readonly badgeTitle = core.getInput('badge-title', {required: false})
|
||||||
readonly token = core.getInput('token', {required: true})
|
readonly token = core.getInput('token', {required: true})
|
||||||
readonly octokit: InstanceType<typeof GitHub>
|
readonly octokit: InstanceType<typeof GitHub>
|
||||||
readonly context = getCheckRunContext()
|
readonly context = getCheckRunContext()
|
||||||
|
|
@ -52,7 +54,7 @@ class TestReporter {
|
||||||
constructor() {
|
constructor() {
|
||||||
this.octokit = github.getOctokit(this.token)
|
this.octokit = github.getOctokit(this.token)
|
||||||
|
|
||||||
if (this.listSuites !== 'all' && this.listSuites !== 'failed') {
|
if (this.listSuites !== 'all' && this.listSuites !== 'failed' && this.listSuites !== 'none') {
|
||||||
core.setFailed(`Input parameter 'list-suites' has invalid value`)
|
core.setFailed(`Input parameter 'list-suites' has invalid value`)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
@ -162,6 +164,16 @@ class TestReporter {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const {listSuites, listTests, onlySummary, useActionsSummary, badgeTitle} = this
|
||||||
|
|
||||||
|
let baseUrl = ''
|
||||||
|
if (this.useActionsSummary) {
|
||||||
|
const summary = getReport(results, {listSuites, listTests, baseUrl, onlySummary, useActionsSummary, badgeTitle})
|
||||||
|
|
||||||
|
core.info('Summary content:')
|
||||||
|
core.info(summary)
|
||||||
|
await core.summary.addRaw(summary).write()
|
||||||
|
} else {
|
||||||
core.info(`Creating check run ${name}`)
|
core.info(`Creating check run ${name}`)
|
||||||
const createResp = await this.octokit.rest.checks.create({
|
const createResp = await this.octokit.rest.checks.create({
|
||||||
head_sha: this.context.sha,
|
head_sha: this.context.sha,
|
||||||
|
|
@ -175,9 +187,8 @@ class TestReporter {
|
||||||
})
|
})
|
||||||
|
|
||||||
core.info('Creating report summary')
|
core.info('Creating report summary')
|
||||||
const {listSuites, listTests, onlySummary} = this
|
baseUrl = createResp.data.html_url as string
|
||||||
const baseUrl = createResp.data.html_url as string
|
const summary = getReport(results, {listSuites, listTests, baseUrl, onlySummary, useActionsSummary, badgeTitle})
|
||||||
const summary = getReport(results, {listSuites, listTests, baseUrl, onlySummary})
|
|
||||||
|
|
||||||
core.info('Creating annotations')
|
core.info('Creating annotations')
|
||||||
const annotations = getAnnotations(results, this.maxAnnotations)
|
const annotations = getAnnotations(results, this.maxAnnotations)
|
||||||
|
|
@ -207,6 +218,7 @@ class TestReporter {
|
||||||
core.info(`Check run HTML: ${resp.data.html_url}`)
|
core.info(`Check run HTML: ${resp.data.html_url}`)
|
||||||
core.setOutput('url', resp.data.url)
|
core.setOutput('url', resp.data.url)
|
||||||
core.setOutput('url_html', resp.data.html_url)
|
core.setOutput('url_html', resp.data.html_url)
|
||||||
|
}
|
||||||
|
|
||||||
return results
|
return results
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,19 +6,24 @@ import {getFirstNonEmptyLine} from '../utils/parse-utils'
|
||||||
import {slug} from '../utils/slugger'
|
import {slug} from '../utils/slugger'
|
||||||
|
|
||||||
const MAX_REPORT_LENGTH = 65535
|
const MAX_REPORT_LENGTH = 65535
|
||||||
|
const MAX_ACTIONS_SUMMARY_LENGTH = 131072 // 1048576 soon
|
||||||
|
|
||||||
export interface ReportOptions {
|
export interface ReportOptions {
|
||||||
listSuites: 'all' | 'failed'
|
listSuites: 'all' | 'failed' | 'none'
|
||||||
listTests: 'all' | 'failed' | 'none'
|
listTests: 'all' | 'failed' | 'none'
|
||||||
baseUrl: string
|
baseUrl: string
|
||||||
onlySummary: boolean
|
onlySummary: boolean
|
||||||
|
useActionsSummary: boolean
|
||||||
|
badgeTitle: string
|
||||||
}
|
}
|
||||||
|
|
||||||
const defaultOptions: ReportOptions = {
|
const defaultOptions: ReportOptions = {
|
||||||
listSuites: 'all',
|
listSuites: 'all',
|
||||||
listTests: 'all',
|
listTests: 'all',
|
||||||
baseUrl: '',
|
baseUrl: '',
|
||||||
onlySummary: false
|
onlySummary: false,
|
||||||
|
useActionsSummary: true,
|
||||||
|
badgeTitle: 'tests'
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getReport(results: TestRunResult[], options: ReportOptions = defaultOptions): string {
|
export function getReport(results: TestRunResult[], options: ReportOptions = defaultOptions): string {
|
||||||
|
|
@ -30,7 +35,7 @@ export function getReport(results: TestRunResult[], options: ReportOptions = def
|
||||||
let lines = renderReport(results, opts)
|
let lines = renderReport(results, opts)
|
||||||
let report = lines.join('\n')
|
let report = lines.join('\n')
|
||||||
|
|
||||||
if (getByteLength(report) <= MAX_REPORT_LENGTH) {
|
if (getByteLength(report) <= getMaxReportLength(options)) {
|
||||||
return report
|
return report
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -39,20 +44,24 @@ export function getReport(results: TestRunResult[], options: ReportOptions = def
|
||||||
opts.listTests = 'failed'
|
opts.listTests = 'failed'
|
||||||
lines = renderReport(results, opts)
|
lines = renderReport(results, opts)
|
||||||
report = lines.join('\n')
|
report = lines.join('\n')
|
||||||
if (getByteLength(report) <= MAX_REPORT_LENGTH) {
|
if (getByteLength(report) <= getMaxReportLength(options)) {
|
||||||
return report
|
return report
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
core.warning(`Test report summary exceeded limit of ${MAX_REPORT_LENGTH} bytes and will be trimmed`)
|
core.warning(`Test report summary exceeded limit of ${getMaxReportLength(options)} bytes and will be trimmed`)
|
||||||
return trimReport(lines)
|
return trimReport(lines, options)
|
||||||
}
|
}
|
||||||
|
|
||||||
function trimReport(lines: string[]): string {
|
function getMaxReportLength(options: ReportOptions = defaultOptions): number {
|
||||||
|
return options.useActionsSummary ? MAX_ACTIONS_SUMMARY_LENGTH : MAX_REPORT_LENGTH
|
||||||
|
}
|
||||||
|
|
||||||
|
function trimReport(lines: string[], options: ReportOptions): string {
|
||||||
const closingBlock = '```'
|
const closingBlock = '```'
|
||||||
const errorMsg = `**Report exceeded GitHub limit of ${MAX_REPORT_LENGTH} bytes and has been trimmed**`
|
const errorMsg = `**Report exceeded GitHub limit of ${getMaxReportLength(options)} bytes and has been trimmed**`
|
||||||
const maxErrorMsgLength = closingBlock.length + errorMsg.length + 2
|
const maxErrorMsgLength = closingBlock.length + errorMsg.length + 2
|
||||||
const maxReportLength = MAX_REPORT_LENGTH - maxErrorMsgLength
|
const maxReportLength = getMaxReportLength(options) - maxErrorMsgLength
|
||||||
|
|
||||||
let reportLength = 0
|
let reportLength = 0
|
||||||
let codeBlock = false
|
let codeBlock = false
|
||||||
|
|
@ -92,7 +101,7 @@ function getByteLength(text: string): number {
|
||||||
|
|
||||||
function renderReport(results: TestRunResult[], options: ReportOptions): string[] {
|
function renderReport(results: TestRunResult[], options: ReportOptions): string[] {
|
||||||
const sections: string[] = []
|
const sections: string[] = []
|
||||||
const badge = getReportBadge(results)
|
const badge = getReportBadge(results, options)
|
||||||
sections.push(badge)
|
sections.push(badge)
|
||||||
|
|
||||||
const runs = getTestRunsReport(results, options)
|
const runs = getTestRunsReport(results, options)
|
||||||
|
|
@ -101,14 +110,14 @@ function renderReport(results: TestRunResult[], options: ReportOptions): string[
|
||||||
return sections
|
return sections
|
||||||
}
|
}
|
||||||
|
|
||||||
function getReportBadge(results: TestRunResult[]): string {
|
function getReportBadge(results: TestRunResult[], options: ReportOptions): string {
|
||||||
const passed = results.reduce((sum, tr) => sum + tr.passed, 0)
|
const passed = results.reduce((sum, tr) => sum + tr.passed, 0)
|
||||||
const skipped = results.reduce((sum, tr) => sum + tr.skipped, 0)
|
const skipped = results.reduce((sum, tr) => sum + tr.skipped, 0)
|
||||||
const failed = results.reduce((sum, tr) => sum + tr.failed, 0)
|
const failed = results.reduce((sum, tr) => sum + tr.failed, 0)
|
||||||
return getBadge(passed, failed, skipped)
|
return getBadge(passed, failed, skipped, options)
|
||||||
}
|
}
|
||||||
|
|
||||||
function getBadge(passed: number, failed: number, skipped: number): string {
|
function getBadge(passed: number, failed: number, skipped: number, options: ReportOptions): string {
|
||||||
const text = []
|
const text = []
|
||||||
if (passed > 0) {
|
if (passed > 0) {
|
||||||
text.push(`${passed} passed`)
|
text.push(`${passed} passed`)
|
||||||
|
|
@ -128,23 +137,28 @@ function getBadge(passed: number, failed: number, skipped: number): string {
|
||||||
color = 'yellow'
|
color = 'yellow'
|
||||||
}
|
}
|
||||||
const hint = failed > 0 ? 'Tests failed' : 'Tests passed successfully'
|
const hint = failed > 0 ? 'Tests failed' : 'Tests passed successfully'
|
||||||
const uri = encodeURIComponent(`tests-${message}-${color}`)
|
const uri = encodeURIComponent(`${options.badgeTitle}-${message}-${color}`)
|
||||||
return ``
|
return ``
|
||||||
}
|
}
|
||||||
|
|
||||||
function getTestRunsReport(testRuns: TestRunResult[], options: ReportOptions): string[] {
|
function getTestRunsReport(testRuns: TestRunResult[], options: ReportOptions): string[] {
|
||||||
const sections: string[] = []
|
const sections: string[] = []
|
||||||
|
const totalFailed = testRuns.reduce((sum, tr) => sum + tr.failed, 0)
|
||||||
|
if (totalFailed === 0) {
|
||||||
|
sections.push(`<details><summary>Expand for details</summary>`)
|
||||||
|
sections.push(` `)
|
||||||
|
}
|
||||||
|
|
||||||
if (testRuns.length > 1 || options.onlySummary) {
|
if (testRuns.length > 0 || options.onlySummary) {
|
||||||
const tableData = testRuns.map((tr, runIndex) => {
|
const tableData = testRuns
|
||||||
|
.filter(tr => tr.passed > 0 || tr.failed > 0 || tr.skipped > 0)
|
||||||
|
.map(tr => {
|
||||||
const time = formatTime(tr.time)
|
const time = formatTime(tr.time)
|
||||||
const name = tr.path
|
const name = tr.path
|
||||||
const addr = options.baseUrl + makeRunSlug(runIndex).link
|
|
||||||
const nameLink = link(name, addr)
|
|
||||||
const passed = tr.passed > 0 ? `${tr.passed} ${Icon.success}` : ''
|
const passed = tr.passed > 0 ? `${tr.passed} ${Icon.success}` : ''
|
||||||
const failed = tr.failed > 0 ? `${tr.failed} ${Icon.fail}` : ''
|
const failed = tr.failed > 0 ? `${tr.failed} ${Icon.fail}` : ''
|
||||||
const skipped = tr.skipped > 0 ? `${tr.skipped} ${Icon.skip}` : ''
|
const skipped = tr.skipped > 0 ? `${tr.skipped} ${Icon.skip}` : ''
|
||||||
return [nameLink, passed, failed, skipped, time]
|
return [name, passed, failed, skipped, time]
|
||||||
})
|
})
|
||||||
|
|
||||||
const resultsTable = table(
|
const resultsTable = table(
|
||||||
|
|
@ -159,12 +173,18 @@ function getTestRunsReport(testRuns: TestRunResult[], options: ReportOptions): s
|
||||||
const suitesReports = testRuns.map((tr, i) => getSuitesReport(tr, i, options)).flat()
|
const suitesReports = testRuns.map((tr, i) => getSuitesReport(tr, i, options)).flat()
|
||||||
sections.push(...suitesReports)
|
sections.push(...suitesReports)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (totalFailed === 0) {
|
||||||
|
sections.push(`</details>`)
|
||||||
|
}
|
||||||
return sections
|
return sections
|
||||||
}
|
}
|
||||||
|
|
||||||
function getSuitesReport(tr: TestRunResult, runIndex: number, options: ReportOptions): string[] {
|
function getSuitesReport(tr: TestRunResult, runIndex: number, options: ReportOptions): string[] {
|
||||||
const sections: string[] = []
|
const sections: string[] = []
|
||||||
|
const suites = options.listSuites === 'failed' ? tr.failedSuites : tr.suites
|
||||||
|
|
||||||
|
if (options.listSuites !== 'none') {
|
||||||
const trSlug = makeRunSlug(runIndex)
|
const trSlug = makeRunSlug(runIndex)
|
||||||
const nameLink = `<a id="${trSlug.id}" href="${options.baseUrl + trSlug.link}">${tr.path}</a>`
|
const nameLink = `<a id="${trSlug.id}" href="${options.baseUrl + trSlug.link}">${tr.path}</a>`
|
||||||
const icon = getResultIcon(tr.result)
|
const icon = getResultIcon(tr.result)
|
||||||
|
|
@ -177,7 +197,6 @@ function getSuitesReport(tr: TestRunResult, runIndex: number, options: ReportOpt
|
||||||
: 'No tests found'
|
: 'No tests found'
|
||||||
sections.push(headingLine2)
|
sections.push(headingLine2)
|
||||||
|
|
||||||
const suites = options.listSuites === 'failed' ? tr.failedSuites : tr.suites
|
|
||||||
if (suites.length > 0) {
|
if (suites.length > 0) {
|
||||||
const suitesTable = table(
|
const suitesTable = table(
|
||||||
['Test suite', 'Passed', 'Failed', 'Skipped', 'Time'],
|
['Test suite', 'Passed', 'Failed', 'Skipped', 'Time'],
|
||||||
|
|
@ -196,6 +215,7 @@ function getSuitesReport(tr: TestRunResult, runIndex: number, options: ReportOpt
|
||||||
)
|
)
|
||||||
sections.push(suitesTable)
|
sections.push(suitesTable)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (options.listTests !== 'none') {
|
if (options.listTests !== 'none') {
|
||||||
const tests = suites.map((ts, suiteIndex) => getTestsReport(ts, runIndex, suiteIndex, options)).flat()
|
const tests = suites.map((ts, suiteIndex) => getTestsReport(ts, runIndex, suiteIndex, options)).flat()
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue