Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Add file coverage compare logic #427

Merged
merged 6 commits into from
Nov 2, 2024
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
4 changes: 2 additions & 2 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,14 @@ 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";
import { generateSummaryTableHtml } from "./report/generateSummaryTableHtml.js";
import type { JsonSummary } from "./types/JsonSummary.js";
import { writeSummaryToCommit } from "./writeSummaryToComment.js";
import { writeSummaryToPR } from "./writeSummaryToPR.js";
import { aw } from "vitest/dist/chunks/reporters.C_zwCd4j.js";

type GitHubSummary = typeof core.summary;

Expand Down Expand Up @@ -61,6 +60,7 @@ const run = async () => {
const jsonFinal = await parseVitestJsonFinal(options.jsonFinalPath);
const fileTable = generateFileCoverageHtml({
jsonSummary,
jsonSummaryCompare,
jsonFinal,
fileCoverageMode: options.fileCoverageMode,
pullChanges,
Expand Down
4 changes: 2 additions & 2 deletions src/inputs/getCommentOn.test.ts
Original file line number Diff line number Diff line change
@@ -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");

Expand Down
71 changes: 40 additions & 31 deletions src/inputs/getPullChanges.test.ts
Original file line number Diff line number Diff line change
@@ -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";

Expand Down Expand Up @@ -68,48 +68,57 @@ 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* () {
it("handles RequestError with status 404 gracefully", async () => {
mockOctokit.paginate.iterator = vi
.fn()
// biome-ignore lint/correctness/useYield: Mock implementation for testing purposes
.mockImplementation(async function* () {
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([]);

const result = await getPullChanges({
fileCoverageMode: FileCoverageMode.Changes,
prNumber: 123,
octokit: mockOctokit,
});

it("handles RequestError with status 403 gracefully", async () => {
mockOctokit.paginate.iterator = vi.fn().mockImplementation(async function* () {
expect(result).toEqual([]);
});

it("handles RequestError with status 403 gracefully", async () => {
mockOctokit.paginate.iterator = vi
.fn()
// biome-ignore lint/correctness/useYield: Mock implementation for testing purposes
.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* () {
expect(result).toEqual([]);
});

it("throws an error for other exceptions", async () => {
mockOctokit.paginate.iterator = vi
.fn()
// biome-ignore lint/correctness/useYield: Mock implementation for testing error handling
.mockImplementation(async function* () {
throw new Error("Unexpected error");
});
await expect(
getPullChanges({
fileCoverageMode: FileCoverageMode.Changes,
prNumber: 123,
octokit: mockOctokit,
}),
).rejects.toThrow("Unexpected error");
});
await expect(
getPullChanges({
fileCoverageMode: FileCoverageMode.Changes,
prNumber: 123,
octokit: mockOctokit,
}),
).rejects.toThrow("Unexpected error");
});
});
3 changes: 1 addition & 2 deletions src/inputs/options.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +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";
import { report } from "node:process";

type Options = {
fileCoverageMode: FileCoverageMode;
Expand Down
115 changes: 115 additions & 0 deletions src/report/generateFileCoverageHtml.test.ts
Original file line number Diff line number Diff line change
@@ -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";
Expand Down Expand Up @@ -30,9 +31,11 @@ describe("generateFileCoverageHtml()", () => {

const html = generateFileCoverageHtml({
jsonSummary,
jsonSummaryCompare: undefined,
jsonFinal: {},
fileCoverageMode: FileCoverageMode.All,
pullChanges: [],
commitSHA: "test-sha",
});

const firstTableLine = getTableLine(1, html);
Expand All @@ -50,9 +53,11 @@ describe("generateFileCoverageHtml()", () => {

const html = generateFileCoverageHtml({
jsonSummary,
jsonSummaryCompare: undefined,
jsonFinal: {},
fileCoverageMode: FileCoverageMode.All,
pullChanges: [relativeChangedFilePath],
commitSHA: "test-sha",
});

expect(getTableLine(1, html)).toContain("Changed Files");
Expand All @@ -69,9 +74,11 @@ describe("generateFileCoverageHtml()", () => {

const html = generateFileCoverageHtml({
jsonSummary,
jsonSummaryCompare: undefined,
jsonFinal: {},
fileCoverageMode: FileCoverageMode.All,
pullChanges: [changedFileName],
commitSHA: "test-sha",
});

expect(html).not.toContain("Unchanged Files");
Expand All @@ -84,9 +91,11 @@ describe("generateFileCoverageHtml()", () => {

const html = generateFileCoverageHtml({
jsonSummary,
jsonSummaryCompare: undefined,
jsonFinal: {},
fileCoverageMode: FileCoverageMode.Changes,
pullChanges: [],
commitSHA: "test-sha",
});

expect(html).toContain("No changed files found.");
Expand All @@ -104,9 +113,11 @@ describe("generateFileCoverageHtml()", () => {

const html = generateFileCoverageHtml({
jsonSummary,
jsonSummaryCompare: undefined,
jsonFinal: {},
fileCoverageMode: FileCoverageMode.All,
pullChanges: [],
commitSHA: "test-sha",
});

const tableLine = getTableLine(2, html);
Expand All @@ -132,9 +143,11 @@ describe("generateFileCoverageHtml()", () => {

const html = generateFileCoverageHtml({
jsonSummary,
jsonSummaryCompare: undefined,
jsonFinal,
fileCoverageMode: FileCoverageMode.All,
pullChanges: [],
commitSHA: "test-sha",
});

const tableLine = getTableLine(2, html);
Expand All @@ -159,8 +172,10 @@ describe("generateFileCoverageHtml()", () => {
const html = generateFileCoverageHtml({
jsonSummary,
jsonFinal,
jsonSummaryCompare: undefined,
fileCoverageMode: FileCoverageMode.All,
pullChanges: [],
commitSHA: "test-sha",
});

const tableLine = getTableLine(2, html);
Expand All @@ -187,14 +202,114 @@ describe("generateFileCoverageHtml()", () => {

const html = generateFileCoverageHtml({
jsonSummary,
jsonSummaryCompare: undefined,
jsonFinal,
fileCoverageMode: FileCoverageMode.All,
pullChanges: [],
commitSHA: "test-sha",
});

const tableLine = getTableLine(2, html);

expect(tableLine).toContain("#L2");
expect(tableLine).toContain("#L5-L6");
});

it("renders an equal sign for files without changes to covergage", () => {
const jsonSummary: JsonSummary = createMockJsonSummary({
"file1.ts": createMockCoverageReport(),
});

const jsonSummaryCompare: JsonSummary = createMockJsonSummary({
"file1.ts": createMockCoverageReport(),
});
const jsonFinal: JsonFinal = {
...createJsonFinalEntry("src/exampleFile.ts", [
{ line: 1, covered: true },
]),
};

const html = generateFileCoverageHtml({
jsonSummary,
jsonSummaryCompare,
jsonFinal,
fileCoverageMode: FileCoverageMode.All,
pullChanges: ["file1.ts"],
commitSHA: "test-sha",
});

expect(html).toContain("file1.ts");
expect(html).toContain(icons.equal);
const equalSignCount = (html.match(new RegExp(icons.equal, "g")) || [])
.length;
expect(equalSignCount).toBe(4);
});

it("renders a plus sign and the increased percentage for files with increased coverage", () => {
const jsonSummary: JsonSummary = createMockJsonSummary({
"file1.ts": createMockCoverageReport({
branches: createMockReportNumbers({ pct: 70 }),
}),
});

const jsonSummaryCompare: JsonSummary = createMockJsonSummary({
"file1.ts": createMockCoverageReport({
branches: createMockReportNumbers({ pct: 60 }),
}),
});
const jsonFinal: JsonFinal = {
...createJsonFinalEntry("src/exampleFile.ts", [
{ line: 1, covered: true },
]),
};

const html = generateFileCoverageHtml({
jsonSummary,
jsonSummaryCompare,
jsonFinal,
fileCoverageMode: FileCoverageMode.All,
pullChanges: ["file1.ts"],
commitSHA: "test-sha",
});

expect(html).toContain("file1.ts");
expect(html).toContain(`${icons.increase} <em>+10.00%</em>`);
const equalSignCount = (html.match(new RegExp(icons.increase, "g")) || [])
.length;
expect(equalSignCount).toBe(1);
});

it("renders a minus sign and the decreased percentage for files with decreased coverage", () => {
const jsonSummary: JsonSummary = createMockJsonSummary({
"file1.ts": createMockCoverageReport({
branches: createMockReportNumbers({ pct: 70 }),
}),
});

const jsonSummaryCompare: JsonSummary = createMockJsonSummary({
"file1.ts": createMockCoverageReport({
branches: createMockReportNumbers({ pct: 80 }),
}),
});
const jsonFinal: JsonFinal = {
...createJsonFinalEntry("src/exampleFile.ts", [
{ line: 1, covered: true },
]),
};

const html = generateFileCoverageHtml({
jsonSummary,
jsonSummaryCompare,
jsonFinal,
fileCoverageMode: FileCoverageMode.All,
pullChanges: ["file1.ts"],
commitSHA: "test-sha",
});

expect(html).toContain("file1.ts");
expect(html).toContain(`${icons.decrease} <em>-10.00%</em>`);
const equalSignCount = (html.match(new RegExp(icons.decrease, "g")) || [])
.length;
expect(equalSignCount).toBe(1);
});
});
Loading
Loading