1
0
Fork 0
mirror of https://github.com/dorny/test-reporter.git synced 2026-03-22 07:52:14 +01:00
This commit is contained in:
Alexandru Turda 2026-03-02 12:55:06 +01:00 committed by GitHub
commit e39aa79e92
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 48 additions and 11 deletions

View file

@ -1,5 +1,8 @@
# Changelog # Changelog
## 2.6.0
* Feature: Add `sort-suites` input to order test suites by execution time (descending)
## 2.5.0 ## 2.5.0
* Feature: Add Nette Tester support with `tester-junit` reporter https://github.com/dorny/test-reporter/pull/707 * Feature: Add Nette Tester support with `tester-junit` reporter https://github.com/dorny/test-reporter/pull/707
* Maintenance: Bump actions/upload-artifact from 5 to 6 https://github.com/dorny/test-reporter/pull/695 * Maintenance: Bump actions/upload-artifact from 5 to 6 https://github.com/dorny/test-reporter/pull/695

View file

@ -46,6 +46,13 @@ inputs:
- none - none
required: false required: false
default: 'all' default: 'all'
sort-suites:
description: |
Sort order for test suites. Supported options:
- name: Sort alphabetically by name (default)
- time-desc: Sort by execution time, slowest first
required: false
default: 'name'
list-tests: list-tests:
description: | description: |
Limits which test cases are listed. Supported options: Limits which test cases are listed. Supported options:

21
dist/index.js generated vendored
View file

@ -303,6 +303,7 @@ class TestReporter {
pathReplaceBackslashes = core.getInput('path-replace-backslashes', { required: false }) === 'true'; pathReplaceBackslashes = core.getInput('path-replace-backslashes', { required: false }) === 'true';
reporter = core.getInput('reporter', { required: true }); reporter = core.getInput('reporter', { required: true });
listSuites = core.getInput('list-suites', { required: true }); listSuites = core.getInput('list-suites', { required: true });
sortSuites = core.getInput('sort-suites', { required: false });
listTests = core.getInput('list-tests', { required: true }); listTests = core.getInput('list-tests', { required: true });
maxAnnotations = parseInt(core.getInput('max-annotations', { required: true })); maxAnnotations = parseInt(core.getInput('max-annotations', { required: true }));
failOnError = core.getInput('fail-on-error', { required: true }) === 'true'; failOnError = core.getInput('fail-on-error', { required: true }) === 'true';
@ -322,6 +323,10 @@ class TestReporter {
core.setFailed(`Input parameter 'list-suites' has invalid value`); core.setFailed(`Input parameter 'list-suites' has invalid value`);
return; return;
} }
if (this.sortSuites !== 'name' && this.sortSuites !== 'time-desc') {
core.setFailed(`Input parameter 'sort-suites' has invalid value`);
return;
}
if (this.listTests !== 'all' && this.listTests !== 'failed' && this.listTests !== 'none') { if (this.listTests !== 'all' && this.listTests !== 'failed' && this.listTests !== 'none') {
core.setFailed(`Input parameter 'list-tests' has invalid value`); core.setFailed(`Input parameter 'list-tests' has invalid value`);
return; return;
@ -409,7 +414,7 @@ class TestReporter {
throw error; throw error;
} }
} }
const { listSuites, listTests, onlySummary, useActionsSummary, badgeTitle, reportTitle, collapsed } = this; const { listSuites, sortSuites, listTests, onlySummary, useActionsSummary, badgeTitle, reportTitle, collapsed } = this;
const passed = results.reduce((sum, tr) => sum + tr.passed, 0); const passed = results.reduce((sum, tr) => sum + tr.passed, 0);
const failed = results.reduce((sum, tr) => sum + tr.failed, 0); const failed = results.reduce((sum, tr) => sum + tr.failed, 0);
const skipped = results.reduce((sum, tr) => sum + tr.skipped, 0); const skipped = results.reduce((sum, tr) => sum + tr.skipped, 0);
@ -418,6 +423,7 @@ class TestReporter {
if (this.useActionsSummary) { if (this.useActionsSummary) {
const summary = (0, get_report_1.getReport)(results, { const summary = (0, get_report_1.getReport)(results, {
listSuites, listSuites,
sortSuites,
listTests, listTests,
baseUrl, baseUrl,
onlySummary, onlySummary,
@ -446,6 +452,7 @@ class TestReporter {
baseUrl = createResp.data.html_url; baseUrl = createResp.data.html_url;
const summary = (0, get_report_1.getReport)(results, { const summary = (0, get_report_1.getReport)(results, {
listSuites, listSuites,
sortSuites,
listTests, listTests,
baseUrl, baseUrl,
onlySummary, onlySummary,
@ -2446,6 +2453,7 @@ const MAX_ACTIONS_SUMMARY_LENGTH = 1048576;
exports.DEFAULT_OPTIONS = { exports.DEFAULT_OPTIONS = {
listSuites: 'all', listSuites: 'all',
listTests: 'all', listTests: 'all',
sortSuites: 'name',
baseUrl: '', baseUrl: '',
onlySummary: false, onlySummary: false,
useActionsSummary: true, useActionsSummary: true,
@ -2454,7 +2462,7 @@ exports.DEFAULT_OPTIONS = {
collapsed: 'auto' collapsed: 'auto'
}; };
function getReport(results, options = exports.DEFAULT_OPTIONS, shortSummary = '') { function getReport(results, options = exports.DEFAULT_OPTIONS, shortSummary = '') {
applySort(results); applySort(results, options);
const opts = { ...options }; const opts = { ...options };
let lines = renderReport(results, opts, shortSummary); let lines = renderReport(results, opts, shortSummary);
let report = lines.join('\n'); let report = lines.join('\n');
@ -2502,10 +2510,15 @@ function trimReport(lines, options) {
reportLines.push(errorMsg); reportLines.push(errorMsg);
return reportLines.join('\n'); return reportLines.join('\n');
} }
function applySort(results) { function applySort(results, options) {
results.sort((a, b) => a.path.localeCompare(b.path, node_utils_1.DEFAULT_LOCALE)); results.sort((a, b) => a.path.localeCompare(b.path, node_utils_1.DEFAULT_LOCALE));
for (const res of results) { for (const res of results) {
res.suites.sort((a, b) => a.name.localeCompare(b.name, node_utils_1.DEFAULT_LOCALE)); if (options.sortSuites === 'time-desc') {
res.suites.sort((a, b) => b.time - a.time);
}
else {
res.suites.sort((a, b) => a.name.localeCompare(b.name, node_utils_1.DEFAULT_LOCALE));
}
} }
} }
function getByteLength(text) { function getByteLength(text) {

4
package-lock.json generated
View file

@ -1,12 +1,12 @@
{ {
"name": "test-reporter", "name": "test-reporter",
"version": "2.5.0", "version": "2.6.0",
"lockfileVersion": 3, "lockfileVersion": 3,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "test-reporter", "name": "test-reporter",
"version": "2.5.0", "version": "2.6.0",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@actions/core": "^1.11.1", "@actions/core": "^1.11.1",

View file

@ -1,6 +1,6 @@
{ {
"name": "test-reporter", "name": "test-reporter",
"version": "2.5.0", "version": "2.6.0",
"private": true, "private": true,
"description": "Presents test results from popular testing frameworks as Github check run", "description": "Presents test results from popular testing frameworks as Github check run",
"main": "lib/main.js", "main": "lib/main.js",

View file

@ -42,6 +42,7 @@ class TestReporter {
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' | 'none' readonly listSuites = core.getInput('list-suites', {required: true}) as 'all' | 'failed' | 'none'
readonly sortSuites = core.getInput('sort-suites', {required: false}) as 'name' | 'time-desc'
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'
@ -64,6 +65,11 @@ class TestReporter {
return return
} }
if (this.sortSuites !== 'name' && this.sortSuites !== 'time-desc') {
core.setFailed(`Input parameter 'sort-suites' has invalid value`)
return
}
if (this.listTests !== 'all' && this.listTests !== 'failed' && this.listTests !== 'none') { if (this.listTests !== 'all' && this.listTests !== 'failed' && this.listTests !== 'none') {
core.setFailed(`Input parameter 'list-tests' has invalid value`) core.setFailed(`Input parameter 'list-tests' has invalid value`)
return return
@ -174,7 +180,7 @@ class TestReporter {
} }
} }
const {listSuites, listTests, onlySummary, useActionsSummary, badgeTitle, reportTitle, collapsed} = this const {listSuites, sortSuites, listTests, onlySummary, useActionsSummary, badgeTitle, reportTitle, collapsed} = this
const passed = results.reduce((sum, tr) => sum + tr.passed, 0) const passed = results.reduce((sum, tr) => sum + tr.passed, 0)
const failed = results.reduce((sum, tr) => sum + tr.failed, 0) const failed = results.reduce((sum, tr) => sum + tr.failed, 0)
@ -187,6 +193,7 @@ class TestReporter {
results, results,
{ {
listSuites, listSuites,
sortSuites,
listTests, listTests,
baseUrl, baseUrl,
onlySummary, onlySummary,
@ -218,6 +225,7 @@ class TestReporter {
baseUrl = createResp.data.html_url as string baseUrl = createResp.data.html_url as string
const summary = getReport(results, { const summary = getReport(results, {
listSuites, listSuites,
sortSuites,
listTests, listTests,
baseUrl, baseUrl,
onlySummary, onlySummary,

View file

@ -11,6 +11,7 @@ const MAX_ACTIONS_SUMMARY_LENGTH = 1048576
export interface ReportOptions { export interface ReportOptions {
listSuites: 'all' | 'failed' | 'none' listSuites: 'all' | 'failed' | 'none'
listTests: 'all' | 'failed' | 'none' listTests: 'all' | 'failed' | 'none'
sortSuites: 'name' | 'time-desc'
baseUrl: string baseUrl: string
onlySummary: boolean onlySummary: boolean
useActionsSummary: boolean useActionsSummary: boolean
@ -22,6 +23,7 @@ export interface ReportOptions {
export const DEFAULT_OPTIONS: ReportOptions = { export const DEFAULT_OPTIONS: ReportOptions = {
listSuites: 'all', listSuites: 'all',
listTests: 'all', listTests: 'all',
sortSuites: 'name',
baseUrl: '', baseUrl: '',
onlySummary: false, onlySummary: false,
useActionsSummary: true, useActionsSummary: true,
@ -35,7 +37,7 @@ export function getReport(
options: ReportOptions = DEFAULT_OPTIONS, options: ReportOptions = DEFAULT_OPTIONS,
shortSummary = '' shortSummary = ''
): string { ): string {
applySort(results) applySort(results, options)
const opts = {...options} const opts = {...options}
let lines = renderReport(results, opts, shortSummary) let lines = renderReport(results, opts, shortSummary)
@ -94,10 +96,14 @@ function trimReport(lines: string[], options: ReportOptions): string {
return reportLines.join('\n') return reportLines.join('\n')
} }
function applySort(results: TestRunResult[]): void { function applySort(results: TestRunResult[], options: ReportOptions): void {
results.sort((a, b) => a.path.localeCompare(b.path, DEFAULT_LOCALE)) results.sort((a, b) => a.path.localeCompare(b.path, DEFAULT_LOCALE))
for (const res of results) { for (const res of results) {
res.suites.sort((a, b) => a.name.localeCompare(b.name, DEFAULT_LOCALE)) if (options.sortSuites === 'time-desc') {
res.suites.sort((a, b) => b.time - a.time)
} else {
res.suites.sort((a, b) => a.name.localeCompare(b.name, DEFAULT_LOCALE))
}
} }
} }