Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,8 @@ For more advanced usage, there are several inputs available.
# Advanced Options
artifact-name: 'ctrf-report' # Name of the artifact containing test reports. Default is ctrf-report
previous-results-max: 10 # Maximum number of previous test results to display in the report. Default is 10
flaky-rate-report-max: -1 # Maximum number of flaky tests to display in the flaky rate report. Default is -1 (all results)
fail-rate-report-max: -1 # Maximum number of failed tests to display in the fail rate report. Default is -1 (all results)
fetch-previous-results: false # Always fetch previous workflow runs when using custom templates. Default is false
max-workflow-runs-to-check: 400 # Maximum number of workflow runs to check for previous results. Default is 400
max-previous-runs-to-fetch: 100 # Maximum number of previous runs to fetch and process for metrics and reports. Default is 100
Expand Down
109 changes: 108 additions & 1 deletion __tests__/ctrf/helpers.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,11 @@
import { getEmoji, normalizeSuite, stripAnsi } from "../../src/ctrf/helpers.js";
import {
getEmoji,
limitFailRateReport,
limitFlakyRateReport,
normalizeSuite,
stripAnsi,
} from "../../src/ctrf/helpers.js";
import type { CTRFReport } from "ctrf";

describe("getEmoji", () => {
it('returns the correct emoji for "passed"', () => {
Expand Down Expand Up @@ -82,6 +89,106 @@ describe("normalizeSuite", () => {
});
});

describe("limitFlakyRateReport", () => {
function makeReport(): CTRFReport {
return {
results: {
tests: [
{ name: "low", insights: { flakyRate: { current: 0.1 } } },
{ name: "high", insights: { flakyRate: { current: 0.5 } } },
{ name: "stable", insights: { flakyRate: { current: 0 } } },
{ name: "missing" },
],
},
} as unknown as CTRFReport;
}

it("limits flaky tests by descending flaky rate without changing the source report", () => {
const report = makeReport();

const limitedReport = limitFlakyRateReport(report, 1);

expect(limitedReport.results.tests.map((test) => test.name)).toEqual([
"high",
]);
expect(report.results.tests).toHaveLength(4);
});

it("returns the original report when the limit is zero or negative", () => {
const report = makeReport();

expect(limitFlakyRateReport(report, 0)).toBe(report);
expect(limitFlakyRateReport(report, -1)).toBe(report);
});

it("returns all positive flaky-rate tests when the limit exceeds the matches", () => {
const report = makeReport();

const limitedReport = limitFlakyRateReport(report, 10);

expect(limitedReport.results.tests.map((test) => test.name)).toEqual([
"high",
"low",
]);
});

it("returns the original report when tests are unavailable", () => {
const report = { results: {} } as unknown as CTRFReport;

expect(limitFlakyRateReport(report, 1)).toBe(report);
});
});

describe("limitFailRateReport", () => {
function makeReport(): CTRFReport {
return {
results: {
tests: [
{ name: "low", insights: { failRate: { current: 0.1 } } },
{ name: "high", insights: { failRate: { current: 0.5 } } },
{ name: "stable", insights: { failRate: { current: 0 } } },
{ name: "missing" },
],
},
} as unknown as CTRFReport;
}

it("limits failed tests by descending fail rate without changing the source report", () => {
const report = makeReport();

const limitedReport = limitFailRateReport(report, 1);

expect(limitedReport.results.tests.map((test) => test.name)).toEqual([
"high",
]);
expect(report.results.tests).toHaveLength(4);
});

it("returns the original report when the limit is zero or negative", () => {
const report = makeReport();

expect(limitFailRateReport(report, 0)).toBe(report);
expect(limitFailRateReport(report, -1)).toBe(report);
});

it("returns all positive fail-rate tests when the limit exceeds the matches", () => {
const report = makeReport();

const limitedReport = limitFailRateReport(report, 10);

expect(limitedReport.results.tests.map((test) => test.name)).toEqual([
"high",
"low",
]);
});

it("returns the original report when tests are unavailable", () => {
const report = { results: {} } as unknown as CTRFReport;

expect(limitFailRateReport(report, 1)).toBe(report);
});
});

describe("stripAnsi", () => {
it("removes ANSI escape codes from a string", () => {
const ansiString = "\u001b[31mHello\u001b[39m";
Expand Down
8 changes: 8 additions & 0 deletions action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,14 @@ inputs:
Includes test results from current run'
required: false
default: 10
flaky-rate-report-max:
description: 'Maximum number of flaky tests to display in the flaky rate report.'
required: false
default: -1
fail-rate-report-max:
description: 'Maximum number of failed tests to display in the fail rate report.'
required: false
default: -1
fetch-previous-results:
description:
'Always fetch previous workflow runs when using custom templates.'
Expand Down
48 changes: 45 additions & 3 deletions dist/index.js

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

2 changes: 1 addition & 1 deletion dist/index.js.map

Large diffs are not rendered by default.

8 changes: 8 additions & 0 deletions src/core/inputs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,14 @@ export function getInputs(): Inputs {
core.getInput("previous-results-max") || "10",
10,
),
flakyRateReportMax: parseInt(
core.getInput("flaky-rate-report-max") || "-1",
10,
),
failRateReportMax: parseInt(
core.getInput("fail-rate-report-max") || "-1",
10,
),
metricsReportsMax: parseInt(
core.getInput("metrics-reports-max") || "100",
10,
Expand Down
66 changes: 66 additions & 0 deletions src/ctrf/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,72 @@ export function limitPreviousReports(
return report;
}

/**
* Limits the tests included in the flaky rate report to a specified maximum.
*
* @param report - The CTRF report to modify.
* @param maxFlakyTests - The maximum number of flaky tests to include.
* @returns The updated CTRF report with the limited flaky tests.
*/
export function limitFlakyRateReport(
report: CTRFReport,
maxFlakyTests: number,
): CTRFReport {
if (!report.results?.tests || maxFlakyTests <= 0) {
return report;
}

const flakyTests = report.results.tests
.filter((test) => test.insights?.flakyRate?.current > 0)
.sort(
(a, b) =>
(b.insights?.flakyRate?.current ?? 0) -
(a.insights?.flakyRate?.current ?? 0),
)
.slice(0, maxFlakyTests);

return {
...report,
results: {
...report.results,
tests: flakyTests,
},
};
}

/**
* Limits the tests included in the fail rate report to a specified maximum.
*
* @param report - The CTRF report to modify.
* @param maxFailedTests - The maximum number of failed tests to include.
* @returns The updated CTRF report with the limited failed tests.
*/
export function limitFailRateReport(
report: CTRFReport,
maxFailedTests: number,
): CTRFReport {
if (!report.results?.tests || maxFailedTests <= 0) {
return report;
}

const failedTests = report.results.tests
.filter((test) => test.insights?.failRate?.current > 0)
.sort(
(a, b) =>
(b.insights?.failRate?.current ?? 0) -
(a.insights?.failRate?.current ?? 0),
)
.slice(0, maxFailedTests);

return {
...report,
results: {
...report.results,
tests: failedTests,
},
};
}

/**
* Retrieves an emoji representation for a given test state or category.
*
Expand Down
22 changes: 18 additions & 4 deletions src/github/core.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
import * as core from "@actions/core";
import { limitPreviousReports, stripAnsi, getEmoji } from "../ctrf/index.js";
import {
limitFailRateReport,
limitFlakyRateReport,
limitPreviousReports,
stripAnsi,
getEmoji,
} from "../ctrf/index.js";
import { generateMarkdown } from "../handlebars/core.js";
import type {
Inputs,
Expand Down Expand Up @@ -278,7 +284,13 @@ function generateReportByType(
case "fail-rate-report":
if (reportConditionals?.showFailedReports) {
core.info("Adding fail rate report to summary");
addViewToSummary("### Fail Rate", BuiltInReports.FailRateTable, report);
addViewToSummary(
inputs.failRateReportMax > 0
? `### Fail Rate - Top ${inputs.failRateReportMax} `
: "### Fail Rate",
BuiltInReports.FailRateTable,
limitFailRateReport(report, inputs.failRateReportMax),
);
} else {
core.info("No failed tests to display, skipping fail-rate-report");
}
Expand Down Expand Up @@ -307,9 +319,11 @@ function generateReportByType(
if (reportConditionals?.showFlakyReports) {
core.info("Adding flaky rate report to summary");
addViewToSummary(
"### Flaky Rate",
inputs.flakyRateReportMax > 0
? `### Flaky Rate - Top ${inputs.flakyRateReportMax} `
: "### Flaky Rate",
BuiltInReports.FlakyRateTable,
report,
limitFlakyRateReport(report, inputs.flakyRateReportMax),
);
} else {
core.info("No flaky tests to display, skipping flaky-rate-report");
Expand Down
2 changes: 2 additions & 0 deletions src/types/reporter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@ export interface Inputs {
exitOnFail: boolean;
useSuiteName: boolean;
previousResultsMax: number;
flakyRateReportMax: number;
failRateReportMax: number;
metricsReportsMax: number;
maxWorkflowRunsToCheck: number;
maxPreviousRunsToFetch: number;
Expand Down
Loading