Skip to content

Commit

Permalink
Minor improvements and fixes (#45)
Browse files Browse the repository at this point in the history
* Minor code style improvements
* Set correct default value for show-failed-tests-only input
* Fixed html test summary in case there are no tests to display due to show-failed-tests-only flag
  • Loading branch information
bibipkins authored Feb 7, 2024
1 parent 3886e4e commit bd040a7
Show file tree
Hide file tree
Showing 11 changed files with 90 additions and 128 deletions.
46 changes: 17 additions & 29 deletions .github/workflows/test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -15,74 +15,62 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- run: |
npm ci
- run: |
npm run build
- run: npm ci
- run: npm run build
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Test Results All
- name: Test - Results All
uses: ./
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
comment-title: Test Results All
comment-title: Test - Results All
results-path: ./files/**/*.trx
allow-failed-tests: true
- name: Test Results Success
- name: Test - Results Success
uses: ./
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
comment-title: Test Results Success
comment-title: Test - Results Success
results-path: ./files/success/*
- name: Test Results Fail
- name: Test - Results Fail
uses: ./
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
comment-title: Test Results Fail
comment-title: Test - Results Fail
results-path: ./files/fail/*
allow-failed-tests: true
- name: Test Coverage OpenCover
- name: Test - Coverage OpenCover
uses: ./
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
comment-title: Test Coverage OpenCover
comment-title: Test - Coverage OpenCover
results-path: ./files/success/*
coverage-path: ./files/success/test_coverage_opencover.xml
coverage-threshold: 44
- name: Test Coverage Cobertura
- name: Test - Coverage Cobertura
uses: ./
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
comment-title: Test Coverage Cobertura
comment-title: Test - Coverage Cobertura
results-path: ./files/success/*
coverage-path: ./files/success/test_coverage_cobertura.xml
coverage-type: cobertura
coverage-threshold: 44
- name: Test Hide Success
- name: Test - Show Failed Tests Only
uses: ./
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
comment-title: Test Hide Success
comment-title: Test - Hide Success
results-path: ./files/**/*.trx
allow-failed-tests: true
show-failed-tests-only : true
- name: Test Hide Output
show-failed-tests-only: true
- name: Test - Hide Test Output
uses: ./
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
comment-title: Test Hide Output
comment-title: Test - Hide Output
results-path: ./files/**/test_result.trx
allow-failed-tests: true
show-failed-tests-only: false
show-test-output: false
- name: Test Show Output
uses: ./
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
comment-title: Test Show Output
results-path: ./files/**/test_result.trx
allow-failed-tests: true
show-test-output: true
show-failed-tests-only: false
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ Set to `false` or leave blank to fail the job if there are any failed tests (rec

#### `show-failed-tests-only`
**Optional** - Boolean flag.
Set to `true` to show only the failed tests. This is useful if you you have many tests and the results exceed the markdown comment limit in github
Set to `true` to show only the failed tests. This is useful if you have many tests and the results exceed the markdown comment limit in github
Set to `false` or leave blank to show all the test results (recommended).
<br/>Default: `false`

Expand Down
10 changes: 7 additions & 3 deletions action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -34,11 +34,15 @@ inputs:
required: false
default: false
show-failed-tests-only:
description: 'Boolean flag. Show only failed tests in summary. Useful for when test count is large and the details are truncated'
description:
'Boolean flag. Show only failed tests in summary. Useful for when test count is large and the details are
truncated'
required: false
default: true
default: false
show-test-output:
description: 'Boolean flag. Show the output of the tests. Useful if there is too much output leading to truncation on the summary'
description:
'Boolean flag. Show the output of the tests. Useful if there is too much output leading to truncation on the
summary'
required: false
default: true
outputs:
Expand Down
75 changes: 32 additions & 43 deletions dist/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -96,21 +96,14 @@ const outcomeIcons = {
};
const formatTitleHtml = (title) => wrap(title, { tag: 'h1', attributes: { id: (0, common_1.getSectionLink)(title) } });
exports.formatTitleHtml = formatTitleHtml;
const formatResultHtml = (result, onlyShowFailedTests, showTestOutput) => {
const formatResultHtml = (result, showFailedTestsOnly, showTestOutput) => {
let html = wrap('Tests', 'h3');
html += formatTable([{ name: '✔️ Passed' }, { name: '❌ Failed' }, { name: '⚠️ Skipped' }, { name: '⏱️ Time' }], [[`${result.passed}`, `${result.failed}`, `${result.skipped}`, (0, common_1.formatElapsedTime)(result.elapsed)]]);
let filteredSuits = (0, fast_sort_1.sort)(result.suits).asc([s => s.tests.filter(t => t.outcome === 'Failed').length > 0 ? 0 : 1, s => s.name]);
filteredSuits.forEach(suit => {
let filteredTests = (0, fast_sort_1.sort)(suit.tests).asc([u => u.outcome])
.filter(test => (onlyShowFailedTests && test.outcome === 'Failed') || !onlyShowFailedTests);
if (!showTestOutput) {
filteredTests.forEach(t => {
t.output = "";
});
}
suit.tests = filteredTests;
});
html += filteredSuits.map(formatTestSuit).join('');
const sortedSuits = (0, fast_sort_1.sort)(result.suits).asc([
s => (s.tests.filter(t => t.outcome === 'Failed').length > 0 ? 0 : 1),
s => s.name
]);
html += sortedSuits.map(suit => formatTestSuit(suit, showFailedTestsOnly, showTestOutput)).join('');
return html;
};
exports.formatResultHtml = formatResultHtml;
Expand Down Expand Up @@ -156,15 +149,21 @@ const formatLinesToCover = (linesToCover) => {
.map(group => (group.length < 3 ? group.join(', ') : `${group[0]}-${group[group.length - 1]}`))
.join(', ');
};
const formatTestSuit = (suit) => {
const formatTestSuit = (suit, showFailedTestsOnly, showTestOutput) => {
const icon = (0, common_1.getStatusIcon)(suit.success);
const summary = `${icon} ${suit.name} - ${suit.passed}/${suit.tests.length}`;
const hasOutput = suit.tests.some(test => (test.output && test.output !== '') || test.error);
const table = formatTable([{ name: 'Result', align: 'center' }, { name: 'Test' }, ...(hasOutput ? [{ name: 'Output' }] : [])], suit.tests.map(test => [outcomeIcons[test.outcome], test.name, ...(hasOutput ? [formatTestOutput(test)] : [])]));
return formatDetails(summary, table);
const sortedTests = (0, fast_sort_1.sort)(suit.tests).asc([test => test.outcome]);
const filteredTests = sortedTests.filter(test => !showFailedTestsOnly || test.outcome === 'Failed');
const showOutput = filteredTests.some(test => (test.output && showTestOutput) || test.error);
const table = formatTable([{ name: 'Result', align: 'center' }, { name: 'Test' }, ...(showOutput ? [{ name: 'Output' }] : [])], filteredTests.map(test => [
outcomeIcons[test.outcome],
test.name,
...(showOutput ? [formatTestOutput(test, showTestOutput)] : [])
]));
return formatDetails(summary, filteredTests.length ? table : '');
};
const formatTestOutput = (test) => {
let output = test.output;
const formatTestOutput = (test, showTestOutput) => {
let output = showTestOutput ? test.output : '';
if (test.error) {
output += `${output ? '<br/><br/>' : ''}<b>Error Message</b><br/>${test.error}`;
}
Expand Down Expand Up @@ -194,17 +193,12 @@ const formatDetails = (summary, details) => wrap(`${wrap(summary, 'summary')}<br
const formatColumn = (column, header) => wrap(column, { tag: 'td', attributes: header.align ? { align: header.align } : undefined });
const formatTable = (headers, rows) => {
const headerNames = headers.map(h => h.name);
if (rows.length > 0) {
const headersData = wrapMany(headerNames, 'th');
const headersHtml = wrap(headersData, 'tr');
const rowsData = rows.map(row => row.map((column, i) => formatColumn(column, headers[i])).join(''));
const rowsHtml = wrapMany(rowsData, 'tr');
const bodyHtml = wrap(`${headersHtml}${rowsHtml}`, 'tbody');
return wrap(bodyHtml, { tag: 'table', attributes: { role: 'table' } });
}
else {
return "";
}
const headersData = wrapMany(headerNames, 'th');
const headersHtml = wrap(headersData, 'tr');
const rowsData = rows.map(row => row.map((column, i) => formatColumn(column, headers[i])).join(''));
const rowsHtml = wrapMany(rowsData, 'tr');
const bodyHtml = wrap(`${headersHtml}${rowsHtml}`, 'tbody');
return wrap(bodyHtml, { tag: 'table', attributes: { role: 'table' } });
};


Expand Down Expand Up @@ -273,12 +267,12 @@ const markdown_1 = __nccwpck_require__(2519);
const html_1 = __nccwpck_require__(9339);
const run = () => __awaiter(void 0, void 0, void 0, function* () {
try {
const { token, title, resultsPath, coveragePath, coverageType, coverageThreshold, postNewComment, allowFailedTests, onlyShowFailedTests, showTestOutput } = (0, utils_1.getInputs)();
const { token, title, resultsPath, coveragePath, coverageType, coverageThreshold, postNewComment, allowFailedTests, showFailedTestsOnly, showTestOutput } = (0, utils_1.getInputs)();
let comment = '';
let summary = (0, html_1.formatTitleHtml)(title);
const testResult = yield (0, results_1.processTestResults)(resultsPath, allowFailedTests);
comment += (0, markdown_1.formatResultMarkdown)(testResult);
summary += (0, html_1.formatResultHtml)(testResult, onlyShowFailedTests, showTestOutput);
summary += (0, html_1.formatResultHtml)(testResult, showFailedTestsOnly, showTestOutput);
if (coveragePath) {
const testCoverage = yield (0, coverage_1.processTestCoverage)(coveragePath, coverageType, coverageThreshold);
comment += testCoverage ? (0, markdown_1.formatCoverageMarkdown)(testCoverage, coverageThreshold) : '';
Expand Down Expand Up @@ -557,10 +551,8 @@ const parseSummary = (file) => {
};
};
const parseResults = (file) => {
if (!file.TestRun.Results || !file.TestRun.Results[0].UnitTestResult) {
return [];
}
const results = file.TestRun.Results[0].UnitTestResult;
var _a, _b, _c, _d;
const results = ((_d = (_c = (_b = (_a = file.TestRun) === null || _a === void 0 ? void 0 : _a.Results) === null || _b === void 0 ? void 0 : _b[0]) === null || _c === void 0 ? void 0 : _c.UnitTestResult) !== null && _d !== void 0 ? _d : []);
return results.map((result) => {
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r;
return ({
Expand All @@ -582,10 +574,8 @@ const parseResults = (file) => {
});
};
const parseDefinitions = (file) => {
if (!file.TestRun.TestDefinitions || !file.TestRun.TestDefinitions[0].UnitTest) {
return [];
}
const definitions = file.TestRun.TestDefinitions[0].UnitTest;
var _a, _b, _c, _d;
const definitions = ((_d = (_c = (_b = (_a = file.TestRun) === null || _a === void 0 ? void 0 : _a.TestDefinitions) === null || _b === void 0 ? void 0 : _b[0]) === null || _c === void 0 ? void 0 : _c.UnitTest) !== null && _d !== void 0 ? _d : []);
return definitions.map(definition => {
var _a;
return ({
Expand Down Expand Up @@ -758,7 +748,7 @@ const inputs = {
coveragePath: 'coverage-path',
coverageType: 'coverage-type',
coverageThreshold: 'coverage-threshold',
onlyShowFailedTests: 'show-failed-tests-only',
showFailedTestsOnly: 'show-failed-tests-only',
showTestOutput: 'show-test-output'
};
const outputs = {
Expand All @@ -784,7 +774,7 @@ const getInputs = () => {
coveragePath: core.getInput(inputs.coveragePath),
coverageType: core.getInput(inputs.coverageType),
coverageThreshold: Number(core.getInput(inputs.coverageThreshold)),
onlyShowFailedTests: core.getBooleanInput(inputs.onlyShowFailedTests),
showFailedTestsOnly: core.getBooleanInput(inputs.showFailedTestsOnly),
showTestOutput: core.getBooleanInput(inputs.showTestOutput)
};
};
Expand Down Expand Up @@ -876,7 +866,6 @@ const tryGetUserLogin = (octokit) => __awaiter(void 0, void 0, void 0, function*
}
catch (_b) {
(0, action_1.log)('⚠️ Failed to get username without user scope, will check comment with user type instead');
// when token doesn't have user scope
return undefined;
}
});
Expand Down
2 changes: 1 addition & 1 deletion dist/index.js.map

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion src/data/IActionInputs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,6 @@ export default interface IActionInputs {
coverageThreshold: number;
postNewComment: boolean;
allowFailedTests: boolean;
onlyShowFailedTests: boolean;
showFailedTestsOnly: boolean;
showTestOutput: boolean;
}
61 changes: 25 additions & 36 deletions src/formatting/html.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,31 +21,20 @@ const outcomeIcons: { [key in TestOutcome]: string } = {
export const formatTitleHtml = (title: string): string =>
wrap(title, { tag: 'h1', attributes: { id: getSectionLink(title) } });

export const formatResultHtml = (result: IResult, onlyShowFailedTests:boolean, showTestOutput:boolean): string => {
export const formatResultHtml = (result: IResult, showFailedTestsOnly: boolean, showTestOutput: boolean): string => {
let html = wrap('Tests', 'h3');

html += formatTable(
[{ name: '✔️ Passed' }, { name: '❌ Failed' }, { name: '⚠️ Skipped' }, { name: '⏱️ Time' }],
[[`${result.passed}`, `${result.failed}`, `${result.skipped}`, formatElapsedTime(result.elapsed)]]
);

let filteredSuits = sort(result.suits).asc([s=> s.tests.filter(t=> t.outcome === 'Failed').length > 0 ? 0 : 1, s => s.name]);

filteredSuits.forEach(suit => {
let filteredTests =
sort(suit.tests).asc([u => u.outcome])
.filter(test => (onlyShowFailedTests && test.outcome === 'Failed') || !onlyShowFailedTests);
const sortedSuits = sort(result.suits).asc([
s => (s.tests.filter(t => t.outcome === 'Failed').length > 0 ? 0 : 1),
s => s.name
]);

if(!showTestOutput) {
filteredTests.forEach(t => {
t.output = "";
})
}

suit.tests = filteredTests;
})

html += filteredSuits.map(formatTestSuit).join('');
html += sortedSuits.map(suit => formatTestSuit(suit, showFailedTestsOnly, showTestOutput)).join('');

return html;
};
Expand Down Expand Up @@ -101,21 +90,27 @@ const formatLinesToCover = (linesToCover: number[]): string => {
.join(', ');
};

const formatTestSuit = (suit: ITestSuit): string => {
const formatTestSuit = (suit: ITestSuit, showFailedTestsOnly: boolean, showTestOutput: boolean): string => {
const icon = getStatusIcon(suit.success);
const summary = `${icon} ${suit.name} - ${suit.passed}/${suit.tests.length}`;
const hasOutput = suit.tests.some(test => (test.output && test.output !== '') || test.error);
const sortedTests = sort(suit.tests).asc([test => test.outcome]);
const filteredTests = sortedTests.filter(test => !showFailedTestsOnly || test.outcome === 'Failed');
const showOutput = filteredTests.some(test => (test.output && showTestOutput) || test.error);

const table = formatTable(
[{ name: 'Result', align: 'center' }, { name: 'Test' }, ...(hasOutput ? [{ name: 'Output' }] : [])],
suit.tests.map(test => [outcomeIcons[test.outcome], test.name, ...(hasOutput ? [formatTestOutput(test)] : [])])
[{ name: 'Result', align: 'center' }, { name: 'Test' }, ...(showOutput ? [{ name: 'Output' }] : [])],
filteredTests.map(test => [
outcomeIcons[test.outcome],
test.name,
...(showOutput ? [formatTestOutput(test, showTestOutput)] : [])
])
);

return formatDetails(summary, table);
return formatDetails(summary, filteredTests.length ? table : '');
};

const formatTestOutput = (test: ITest): string => {
let output = test.output;
const formatTestOutput = (test: ITest, showTestOutput: boolean): string => {
let output = showTestOutput ? test.output : '';

if (test.error) {
output += `${output ? '<br/><br/>' : ''}<b>Error Message</b><br/>${test.error}`;
Expand Down Expand Up @@ -157,18 +152,12 @@ const formatColumn = (column: string, header: Header): string =>

const formatTable = (headers: Header[], rows: string[][]): string => {
const headerNames = headers.map(h => h.name);
const headersData = wrapMany(headerNames, 'th');
const headersHtml = wrap(headersData, 'tr');

if(rows.length > 0) {
const headersData = wrapMany(headerNames, 'th');
const headersHtml = wrap(headersData, 'tr');
const rowsData = rows.map(row => row.map((column, i) => formatColumn(column, headers[i])).join(''));
const rowsHtml = wrapMany(rowsData, 'tr');
const bodyHtml = wrap(`${headersHtml}${rowsHtml}`, 'tbody');

const rowsData = rows.map(row => row.map((column, i) => formatColumn(column, headers[i])).join(''));
const rowsHtml = wrapMany(rowsData, 'tr');
const bodyHtml = wrap(`${headersHtml}${rowsHtml}`, 'tbody');

return wrap(bodyHtml, { tag: 'table', attributes: { role: 'table' } });
}
else {
return ""
}
return wrap(bodyHtml, { tag: 'table', attributes: { role: 'table' } });
};
4 changes: 2 additions & 2 deletions src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ const run = async (): Promise<void> => {
coverageThreshold,
postNewComment,
allowFailedTests,
onlyShowFailedTests,
showFailedTestsOnly,
showTestOutput
} = getInputs();

Expand All @@ -24,7 +24,7 @@ const run = async (): Promise<void> => {

const testResult = await processTestResults(resultsPath, allowFailedTests);
comment += formatResultMarkdown(testResult);
summary += formatResultHtml(testResult, onlyShowFailedTests, showTestOutput);
summary += formatResultHtml(testResult, showFailedTestsOnly, showTestOutput);

if (coveragePath) {
const testCoverage = await processTestCoverage(coveragePath, coverageType, coverageThreshold);
Expand Down
Loading

0 comments on commit bd040a7

Please sign in to comment.