Skip to content

Commit b0cb71b

Browse files
committed
Merge branch 'yarn-workspaces' of github.com:source-academy/modules into yarn-workspaces
2 parents 10c2591 + dd49bec commit b0cb71b

File tree

5 files changed

+138
-11
lines changed

5 files changed

+138
-11
lines changed

lib/vitest-reporter/build/coverage-reporter.cjs

Lines changed: 0 additions & 1 deletion
This file was deleted.
Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
// src/coverage-reporter.ts
2+
import fs from "fs";
3+
import { ReportBase } from "istanbul-lib-report";
4+
function isFull(metrics) {
5+
return metrics.statements.pct === 100 && metrics.branches.pct === 100 && metrics.functions.pct === 100 && metrics.lines.pct === 100;
6+
}
7+
function getUncoveredLines(node) {
8+
if (node.isSummary()) {
9+
return [];
10+
}
11+
const metrics = node.getCoverageSummary(false);
12+
const isEmpty = metrics.isEmpty();
13+
const lines = isEmpty ? 0 : metrics.lines.pct;
14+
let coveredLines;
15+
const fileCoverage = node.getFileCoverage();
16+
if (lines === 100) {
17+
const branches = fileCoverage.getBranchCoverageByLine();
18+
coveredLines = Object.entries(branches).map(([key, { coverage }]) => [key, coverage === 100]);
19+
} else {
20+
coveredLines = Object.entries(fileCoverage.getLineCoverage());
21+
}
22+
let newRange = true;
23+
const ranges = coveredLines.reduce((acum, [line, hit]) => {
24+
if (hit) {
25+
newRange = true;
26+
} else {
27+
const linenum = parseInt(line);
28+
if (newRange) {
29+
acum.push([linenum]);
30+
newRange = false;
31+
} else {
32+
acum[acum.length - 1][1] = linenum;
33+
}
34+
}
35+
return acum;
36+
}, []);
37+
return ranges;
38+
}
39+
var headers = ["Statements", "Branches", "Functions", "Lines"];
40+
var GithubActionsCoverageReporter = class extends ReportBase {
41+
skipEmpty;
42+
skipFull;
43+
results = {};
44+
cw = null;
45+
watermarks = null;
46+
constructor(opts) {
47+
super(opts);
48+
this.skipEmpty = Boolean(opts.skipEmpty);
49+
this.skipFull = Boolean(opts.skipFull);
50+
}
51+
onStart(_node, context) {
52+
if (!process.env.GITHUB_STEP_SUMMARY) {
53+
console.log("Reporter not being executed in Github Actions environment");
54+
return;
55+
}
56+
this.cw = fs.createWriteStream(process.env.GITHUB_STEP_SUMMARY, { encoding: "utf-8", flags: "a" });
57+
this.watermarks = context.watermarks;
58+
this.cw.write("<h2>Test Coverage</h2>");
59+
this.cw.write("<table><thead><tr>");
60+
for (const heading of ["File", ...headers, "Uncovered Lines"]) {
61+
this.cw.write(`<th>${heading}</th>`);
62+
}
63+
this.cw.write("</tr></thead><tbody>");
64+
}
65+
onSummary(node) {
66+
const nodeName = node.getRelativeName() || "All Files";
67+
const rawMetrics = node.getCoverageSummary(false);
68+
const isEmpty = rawMetrics.isEmpty();
69+
if (this.skipEmpty && isEmpty) {
70+
return;
71+
}
72+
if (this.skipFull && isFull(rawMetrics)) {
73+
return;
74+
}
75+
this.results[nodeName] = {
76+
statements: isEmpty ? 0 : rawMetrics.statements.pct,
77+
branches: isEmpty ? 0 : rawMetrics.branches.pct,
78+
functions: isEmpty ? 0 : rawMetrics.functions.pct,
79+
lines: isEmpty ? 0 : rawMetrics.lines.pct,
80+
uncoveredLines: getUncoveredLines(node)
81+
};
82+
}
83+
onDetail(node) {
84+
return this.onSummary(node);
85+
}
86+
formatter(pct, watermark) {
87+
if (!this.watermarks || this.watermarks[watermark] === void 0) return `<td>${pct}%</td>`;
88+
const [low, high] = this.watermarks[watermark];
89+
if (pct < low) {
90+
return `<td><p style="color:red">${pct}%</p></td>`;
91+
}
92+
if (pct > high) {
93+
return `<td><p style="color:green">${pct}%</p></td>`;
94+
}
95+
return `<td><p style="color:yellow">${pct}%</p></td>`;
96+
}
97+
onEnd() {
98+
if (!this.cw) return;
99+
const fileNames = Object.keys(this.results).sort();
100+
for (const fileName of fileNames) {
101+
const metrics = this.results[fileName];
102+
this.cw.write(`<tr><td><code>${fileName}</code></td>`);
103+
this.cw.write(this.formatter(metrics.statements, "statements"));
104+
this.cw.write(this.formatter(metrics.branches, "branches"));
105+
this.cw.write(this.formatter(metrics.functions, "functions"));
106+
this.cw.write(this.formatter(metrics.lines, "lines"));
107+
if (metrics.uncoveredLines.length > 0) {
108+
this.cw.write("<td><details><summary>Expand</summary><ul>");
109+
for (const range of metrics.uncoveredLines) {
110+
if (range.length === 1) {
111+
this.cw.write(`<li>${range[0]}</li>`);
112+
} else {
113+
this.cw.write(`<li>${range[0]}-${range[1]}</li>`);
114+
}
115+
}
116+
this.cw.write("</ul></details></td>");
117+
} else {
118+
this.cw.write("<td></td>");
119+
}
120+
this.cw.write("</tr>");
121+
}
122+
this.cw.write("</tbody></table>");
123+
this.cw.close();
124+
}
125+
};
126+
export {
127+
GithubActionsCoverageReporter as default
128+
};

lib/vitest-reporter/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
},
2020
"scripts": {
2121
"build": "yarn build:coverage-reporter && yarn build:test-reporter",
22-
"build:coverage-reporter": "esbuild --outfile=./build/coverage-reporter.cjs --format=cjs --bundle=true --minify --external:\"istanbul-lib-report\" --platform=node src/coverage-reporter.ts",
22+
"build:coverage-reporter": "esbuild --outfile=./build/coverage-reporter.js --format=esm --bundle=true --minify=false --external:\"istanbul-lib-report\" --platform=node src/coverage-reporter.ts",
2323
"build:test-reporter": "esbuild --outfile=./build/test-reporter.js --format=esm --bundle=true --minify --external:\"vitest*\" --platform=node src/test-reporter.ts",
2424
"test": "vitest"
2525
}

lib/vitest-reporter/src/coverage-reporter.ts

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
*/
77
import fs from 'fs';
88
import type { CoverageSummary } from 'istanbul-lib-coverage';
9-
import * as report from 'istanbul-lib-report';
9+
import { ReportBase, type ContextOptions, type ReportNode, type Watermarks } from 'istanbul-lib-report';
1010

1111
/**
1212
* Determines if the coverage summary has full coverage
@@ -23,7 +23,7 @@ function isFull(metrics: CoverageSummary) {
2323
/**
2424
* Determines the uncovered lines
2525
*/
26-
function getUncoveredLines(node: report.ReportNode) {
26+
function getUncoveredLines(node: ReportNode) {
2727
if (node.isSummary()) {
2828
return [];
2929
}
@@ -77,12 +77,12 @@ interface ResultObject {
7777
/**
7878
* A Vitest coverage reporter that writes to the Github Actions summary
7979
*/
80-
export default class GithubActionsCoverageReporter extends report.ReportBase {
80+
export default class GithubActionsCoverageReporter extends ReportBase {
8181
private readonly skipEmpty: boolean;
8282
private readonly skipFull: boolean;
8383
private readonly results: Record<string, ResultObject> = {};
8484
private cw: fs.WriteStream | null = null;
85-
private watermarks: Partial<report.Watermarks> | null = null;
85+
private watermarks: Partial<Watermarks> | null = null;
8686

8787
constructor(opts: any) {
8888
super(opts);
@@ -91,7 +91,7 @@ export default class GithubActionsCoverageReporter extends report.ReportBase {
9191
this.skipFull = Boolean(opts.skipFull);
9292
}
9393

94-
onStart(_node: any, context: report.ContextOptions) {
94+
onStart(_node: any, context: ContextOptions) {
9595
if (!process.env.GITHUB_STEP_SUMMARY) {
9696
console.log('Reporter not being executed in Github Actions environment');
9797
return;
@@ -108,7 +108,7 @@ export default class GithubActionsCoverageReporter extends report.ReportBase {
108108
this.cw.write('</tr></thead><tbody>');
109109
}
110110

111-
onSummary(node: report.ReportNode) {
111+
onSummary(node: ReportNode) {
112112
const nodeName = node.getRelativeName() || 'All Files';
113113
const rawMetrics = node.getCoverageSummary(false);
114114
const isEmpty = rawMetrics.isEmpty();
@@ -129,11 +129,11 @@ export default class GithubActionsCoverageReporter extends report.ReportBase {
129129
};
130130
}
131131

132-
onDetail(node: report.ReportNode) {
132+
onDetail(node: ReportNode) {
133133
return this.onSummary(node);
134134
}
135135

136-
private formatter(pct: number, watermark: keyof report.Watermarks) {
136+
private formatter(pct: number, watermark: keyof Watermarks) {
137137
if (!this.watermarks || this.watermarks[watermark] === undefined) return `<td>${pct}%</td>`;
138138
const [low, high] = this.watermarks[watermark];
139139

vitest.config.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ const coverageReporters = ['text'];
1212
const testReporters = ['default'];
1313

1414
if (process.env.GITHUB_ACTIONS) {
15-
const reporter = pathlib.resolve(import.meta.dirname, './lib/vitest-reporter/build/coverage-reporter.cjs');
15+
const reporter = pathlib.resolve(import.meta.dirname, './lib/vitest-reporter/build/coverage-reporter.js');
1616
coverageReporters.push(reporter);
1717
testReporters.push(new GithubActionsSummaryReporter());
1818
} else {

0 commit comments

Comments
 (0)