diff --git a/src/index.ts b/src/index.ts
index 26aedf6..a92ee6d 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -8,7 +8,7 @@ import {
parseVitestJsonFinal,
parseVitestJsonSummary,
} from "./inputs/parseJsonReports.js";
-import { createOctokit, type Octokit } from "./octokit.js";
+import { type Octokit, createOctokit } from "./octokit.js";
import { generateCommitSHAUrl } from "./report/generateCommitSHAUrl.js";
import { generateFileCoverageHtml } from "./report/generateFileCoverageHtml.js";
import { generateHeadline } from "./report/generateHeadline.js";
diff --git a/src/inputs/getCommentOn.test.ts b/src/inputs/getCommentOn.test.ts
index 936ed9c..e687592 100644
--- a/src/inputs/getCommentOn.test.ts
+++ b/src/inputs/getCommentOn.test.ts
@@ -1,6 +1,6 @@
-import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
import * as core from "@actions/core";
-import { getCommentOn, type CommentOn } from "./getCommentOn";
+import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
+import { type CommentOn, getCommentOn } from "./getCommentOn";
vi.mock("@actions/core");
diff --git a/src/inputs/getPullChanges.test.ts b/src/inputs/getPullChanges.test.ts
index 5e873a3..a378e68 100644
--- a/src/inputs/getPullChanges.test.ts
+++ b/src/inputs/getPullChanges.test.ts
@@ -1,6 +1,6 @@
+import { RequestError } from "@octokit/request-error";
import { Mock, beforeEach, describe, expect, it, vi } from "vitest";
import type { Octokit } from "../octokit";
-import { RequestError } from "@octokit/request-error";
import { FileCoverageMode } from "./FileCoverageMode";
import { getPullChanges } from "./getPullChanges";
@@ -68,48 +68,48 @@ describe("getPullChanges()", () => {
expect(result).toEqual(["file1.ts", "file2.ts"]);
});
- it("handles RequestError with status 404 gracefully", async () => {
- mockOctokit.paginate.iterator = vi.fn().mockImplementation(async function* () {
- throw new RequestError("Not Found", 404, {
- request: { headers: {}, method: "GET", url: "" },
- });
+ it("handles RequestError with status 404 gracefully", async () => {
+ mockOctokit.paginate.iterator = vi.fn().mockImplementation(async () => {
+ throw new RequestError("Not Found", 404, {
+ request: { headers: {}, method: "GET", url: "" },
});
-
- const result = await getPullChanges({
- fileCoverageMode: FileCoverageMode.Changes,
- prNumber: 123,
- octokit: mockOctokit,
- });
-
- expect(result).toEqual([]);
});
- it("handles RequestError with status 403 gracefully", async () => {
- mockOctokit.paginate.iterator = vi.fn().mockImplementation(async function* () {
- throw new RequestError("Forbidden", 403, {
- request: { headers: {}, method: "GET", url: "" },
- });
- });
-
- const result = await getPullChanges({
- fileCoverageMode: FileCoverageMode.Changes,
- prNumber: 123,
- octokit: mockOctokit,
- });
-
- expect(result).toEqual([]);
+ const result = await getPullChanges({
+ fileCoverageMode: FileCoverageMode.Changes,
+ prNumber: 123,
+ octokit: mockOctokit,
});
- it("throws an error for other exceptions", async () => {
- mockOctokit.paginate.iterator = vi.fn().mockImplementation(async function* () {
- throw new Error("Unexpected error");
+ expect(result).toEqual([]);
+ });
+
+ it("handles RequestError with status 403 gracefully", async () => {
+ mockOctokit.paginate.iterator = vi.fn().mockImplementation(async () => {
+ throw new RequestError("Forbidden", 403, {
+ request: { headers: {}, method: "GET", url: "" },
});
- await expect(
- getPullChanges({
- fileCoverageMode: FileCoverageMode.Changes,
- prNumber: 123,
- octokit: mockOctokit,
- }),
- ).rejects.toThrow("Unexpected error");
});
+
+ const result = await getPullChanges({
+ fileCoverageMode: FileCoverageMode.Changes,
+ prNumber: 123,
+ octokit: mockOctokit,
+ });
+
+ expect(result).toEqual([]);
+ });
+
+ it("throws an error for other exceptions", async () => {
+ mockOctokit.paginate.iterator = vi.fn().mockImplementation(async () => {
+ throw new Error("Unexpected error");
+ });
+ await expect(
+ getPullChanges({
+ fileCoverageMode: FileCoverageMode.Changes,
+ prNumber: 123,
+ octokit: mockOctokit,
+ }),
+ ).rejects.toThrow("Unexpected error");
+ });
});
diff --git a/src/inputs/options.ts b/src/inputs/options.ts
index 12948f2..e1aa355 100644
--- a/src/inputs/options.ts
+++ b/src/inputs/options.ts
@@ -3,11 +3,11 @@ import * as core from "@actions/core";
import type { Octokit } from "../octokit";
import type { Thresholds } from "../types/Threshold";
import { type FileCoverageMode, getCoverageModeFrom } from "./FileCoverageMode";
+import { type CommentOn, getCommentOn } from "./getCommentOn";
import { getCommitSHA } from "./getCommitSHA";
import { getPullRequestNumber } from "./getPullRequestNumber";
import { getViteConfigPath } from "./getViteConfigPath";
import { parseCoverageThresholds } from "./parseCoverageThresholds";
-import { getCommentOn, type CommentOn } from "./getCommentOn";
type Options = {
fileCoverageMode: FileCoverageMode;
diff --git a/src/report/generateFileCoverageHtml.test.ts b/src/report/generateFileCoverageHtml.test.ts
index fce7ef4..a92e437 100644
--- a/src/report/generateFileCoverageHtml.test.ts
+++ b/src/report/generateFileCoverageHtml.test.ts
@@ -1,6 +1,7 @@
import * as path from "node:path";
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
import { getTableLine } from "../../test/queryHelper";
+import { icons } from "../icons";
import { FileCoverageMode } from "../inputs/FileCoverageMode";
import type { JsonFinal } from "../types/JsonFinal";
import { createJsonFinalEntry } from "../types/JsonFinalMockFactory";
@@ -11,7 +12,6 @@ import {
createMockReportNumbers,
} from "../types/JsonSummaryMockFactory";
import { generateFileCoverageHtml } from "./generateFileCoverageHtml";
-import { icons } from "../icons";
const workspacePath = process.cwd();
describe("generateFileCoverageHtml()", () => {
diff --git a/src/report/generateFileCoverageHtml.ts b/src/report/generateFileCoverageHtml.ts
index a45e5a8..3025726 100644
--- a/src/report/generateFileCoverageHtml.ts
+++ b/src/report/generateFileCoverageHtml.ts
@@ -4,12 +4,11 @@ import { FileCoverageMode } from "../inputs/FileCoverageMode";
import type { JsonFinal } from "../types/JsonFinal";
import type { CoverageReport, JsonSummary } from "../types/JsonSummary";
import { generateBlobFileUrl } from "./generateFileUrl";
+import { getCompareString } from "./getCompareString";
import {
type LineRange,
getUncoveredLinesFromStatements,
} from "./getUncoveredLinesFromStatements";
-import { icons } from "../icons";
-import { getCompareString } from "./getCompareString";
type FileCoverageInputs = {
jsonSummary: JsonSummary;
@@ -21,6 +20,7 @@ type FileCoverageInputs = {
};
const workspacePath = process.cwd();
+
const generateFileCoverageHtml = ({
jsonSummary,
jsonSummaryCompare,
@@ -31,31 +31,6 @@ const generateFileCoverageHtml = ({
}: FileCoverageInputs) => {
const filePaths = Object.keys(jsonSummary).filter((key) => key !== "total");
- const formatFileLine = (filePath: string) => {
- const coverageSummary = jsonSummary[filePath];
- const coverageSummaryCompare = jsonSummaryCompare
- ? jsonSummaryCompare[filePath]
- : undefined;
- const lineCoverage = jsonFinal[filePath];
-
- // LineCoverage might be empty if coverage-final.json was not provided.
- const uncoveredLines = lineCoverage
- ? getUncoveredLinesFromStatements(jsonFinal[filePath])
- : [];
- const relativeFilePath = path.relative(workspacePath, filePath);
- const url = generateBlobFileUrl(relativeFilePath, commitSHA);
-
- return `
-
- ${relativeFilePath} |
- ${generateCoverageCell(coverageSummary, coverageSummaryCompare, "statements")}
- ${generateCoverageCell(coverageSummary, coverageSummaryCompare, "branches")}
- ${generateCoverageCell(coverageSummary, coverageSummaryCompare, "functions")}
- ${generateCoverageCell(coverageSummary, coverageSummaryCompare, "lines")}
- ${createRangeURLs(uncoveredLines, url)} |
-
`;
- };
-
let reportData = "";
const [changedFiles, unchangedFiles] = splitFilesByChangeStatus(
@@ -72,37 +47,88 @@ const generateFileCoverageHtml = ({
if (changedFiles.length > 0) {
reportData += `
- ${formatGroupLine("Changed Files")}
- ${changedFiles.map(formatFileLine).join("")}
- `;
+ ${formatGroupLine("Changed Files")}
+ ${changedFiles
+ .map((filePath) =>
+ generateRow(
+ filePath,
+ jsonSummary,
+ jsonSummaryCompare,
+ jsonFinal,
+ commitSHA,
+ ),
+ )
+ .join("")}
+ `;
}
if (fileCoverageMode === FileCoverageMode.All && unchangedFiles.length > 0) {
reportData += `
- ${formatGroupLine("Unchanged Files")}
- ${unchangedFiles.map(formatFileLine).join("")}
- `;
+ ${formatGroupLine("Unchanged Files")}
+ ${unchangedFiles
+ .map((filePath) =>
+ generateRow(
+ filePath,
+ jsonSummary,
+ undefined,
+ jsonFinal,
+ commitSHA,
+ ),
+ )
+ .join("")}
+ `;
}
return oneLine`
-
-
-
- File |
- Stmts |
- % Branch |
- % Funcs |
- % Lines |
- Uncovered Lines |
-
-
-
- ${reportData}
-
-
- `;
+
+
+
+ File |
+ Stmts |
+ % Branch |
+ % Funcs |
+ % Lines |
+ Uncovered Lines |
+
+
+
+ ${reportData}
+
+
+ `;
};
+function generateRow(
+ filePath: string,
+ jsonSummary: JsonSummary,
+ jsonSummaryCompare: JsonSummary | undefined,
+ jsonFinal: JsonFinal,
+ commitSHA: string,
+): string {
+ const coverageSummary = jsonSummary[filePath];
+ const coverageSummaryCompare = jsonSummaryCompare
+ ? jsonSummaryCompare[filePath]
+ : undefined;
+ const lineCoverage = jsonFinal[filePath];
+
+ // LineCoverage might be empty if coverage-final.json was not provided.
+ const uncoveredLines = lineCoverage
+ ? getUncoveredLinesFromStatements(jsonFinal[filePath])
+ : [];
+ const relativeFilePath = path.relative(workspacePath, filePath);
+ const url = generateBlobFileUrl(relativeFilePath, commitSHA);
+
+ return `
+
+ ${relativeFilePath} |
+ ${generateCoverageCell(coverageSummary, coverageSummaryCompare, "statements")}
+ ${generateCoverageCell(coverageSummary, coverageSummaryCompare, "branches")}
+ ${generateCoverageCell(coverageSummary, coverageSummaryCompare, "functions")}
+ ${generateCoverageCell(coverageSummary, coverageSummaryCompare, "lines")}
+ ${createRangeURLs(uncoveredLines, url)} |
+
`;
+}
+
function generateCoverageCell(
summary: CoverageReport,
summaryCompare: CoverageReport | undefined,
@@ -118,9 +144,9 @@ function generateCoverageCell(
function formatGroupLine(caption: string): string {
return `
-
- ${caption} |
-
+
+ ${caption} |
+
`;
}