Skip to content

Commit 9fe0515

Browse files
committed
feat: ✨ implement the coverage reporter with the LLM friend
1 parent 94a21ca commit 9fe0515

File tree

4 files changed

+412
-2
lines changed

4 files changed

+412
-2
lines changed

package.json

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,7 @@
44
"description": "A plugin for vitest that generates a coverage summary in json format",
55
"main": "index.js",
66
"scripts": {
7-
"test": "echo \"Error: no test specified\" && exit 1",
8-
"coverage": "vitest run --coverage"
7+
"test": "vitest run --coverage"
98
},
109
"author": "Typeguard Inc.",
1110
"license": "MIT",

src/v8.json.summary.reporter.test.ts

Lines changed: 231 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,231 @@
1+
import { describe, it, expect } from "vitest";
2+
import { generateV8CoverageSummary } from "./v8.json.summary.reporter";
3+
4+
describe("generateV8CoverageSummary", () => {
5+
it("should generate correct summary for 100% coverage", () => {
6+
const mockCoverage = {
7+
data: {
8+
"test.js": {
9+
path: "/test.js",
10+
s: { "0": 1, "1": 1, "2": 1 },
11+
f: { "0": 1 },
12+
b: { "0": [1, 1] },
13+
statementMap: {
14+
"0": { start: { line: 1 } },
15+
"1": { start: { line: 2 } },
16+
"2": { start: { line: 3 } },
17+
},
18+
},
19+
},
20+
};
21+
22+
const summary = generateV8CoverageSummary(mockCoverage);
23+
24+
expect(summary.summary.statements).toBe(100);
25+
expect(summary.summary.branches).toBe(100);
26+
expect(summary.summary.functions).toBe(100);
27+
expect(summary.summary.lines).toBe(100);
28+
expect(summary.files).toHaveLength(1);
29+
expect(summary.files[0].statements).toBe(100);
30+
expect(summary.files[0].branches).toBe(100);
31+
expect(summary.files[0].functions).toBe(100);
32+
expect(summary.files[0].lines).toBe(100);
33+
expect(summary.files[0].uncoveredLines).toBeUndefined();
34+
});
35+
36+
it("should generate correct summary for partial coverage", () => {
37+
const mockCoverage = {
38+
data: {
39+
"test.js": {
40+
path: "/test.js",
41+
s: { "0": 1, "1": 0, "2": 1, "3": 0 },
42+
f: { "0": 1, "1": 0 },
43+
b: { "0": [1, 0], "1": [0, 0] },
44+
statementMap: {
45+
"0": { start: { line: 1 } },
46+
"1": { start: { line: 2 } },
47+
"2": { start: { line: 3 } },
48+
"3": { start: { line: 4 } },
49+
},
50+
},
51+
},
52+
};
53+
54+
const summary = generateV8CoverageSummary(mockCoverage);
55+
56+
expect(summary.summary.statements).toBe(50);
57+
expect(summary.summary.branches).toBe(25);
58+
expect(summary.summary.functions).toBe(50);
59+
expect(summary.summary.lines).toBe(50);
60+
expect(summary.files[0].statements).toBe(50);
61+
expect(summary.files[0].branches).toBe(25);
62+
expect(summary.files[0].functions).toBe(50);
63+
expect(summary.files[0].lines).toBe(50);
64+
expect(summary.files[0].uncoveredLines).toEqual([2, 4]);
65+
});
66+
67+
it("should generate correct summary for 0% coverage", () => {
68+
const mockCoverage = {
69+
data: {
70+
"test.js": {
71+
path: "/test.js",
72+
s: { "0": 0, "1": 0 },
73+
f: { "0": 0 },
74+
b: { "0": [0, 0] },
75+
statementMap: {
76+
"0": { start: { line: 1 } },
77+
"1": { start: { line: 2 } },
78+
},
79+
},
80+
},
81+
};
82+
83+
const summary = generateV8CoverageSummary(mockCoverage);
84+
85+
expect(summary.summary.statements).toBe(0);
86+
expect(summary.summary.branches).toBe(0);
87+
expect(summary.summary.functions).toBe(0);
88+
expect(summary.summary.lines).toBe(0);
89+
expect(summary.files[0].statements).toBe(0);
90+
expect(summary.files[0].branches).toBe(0);
91+
expect(summary.files[0].functions).toBe(0);
92+
expect(summary.files[0].lines).toBe(0);
93+
expect(summary.files[0].uncoveredLines).toEqual([1, 2]);
94+
});
95+
96+
it("should handle multiple files correctly", () => {
97+
const mockCoverage = {
98+
data: {
99+
"file1.js": {
100+
path: "/file1.js",
101+
s: { "0": 1, "1": 1 },
102+
f: { "0": 1 },
103+
b: { "0": [1, 1] },
104+
statementMap: {
105+
"0": { start: { line: 1 } },
106+
"1": { start: { line: 2 } },
107+
},
108+
},
109+
"file2.js": {
110+
path: "/file2.js",
111+
s: { "0": 0, "1": 1 },
112+
f: { "0": 0, "1": 1 },
113+
b: { "0": [0, 0] },
114+
statementMap: {
115+
"0": { start: { line: 1 } },
116+
"1": { start: { line: 2 } },
117+
},
118+
},
119+
},
120+
};
121+
122+
const summary = generateV8CoverageSummary(mockCoverage);
123+
124+
expect(summary.files).toHaveLength(2);
125+
expect(summary.summary.statements).toBe(75); // (2+1)/(2+2) = 75
126+
expect(summary.summary.branches).toBe(50); // (2/4) = 50
127+
expect(summary.summary.functions).toBe(66.67); // (1+1)/(1+2) = 66.67
128+
expect(summary.summary.lines).toBe(75); // Same as statements
129+
});
130+
131+
it("should handle empty coverage data", () => {
132+
const mockCoverage = { data: {} };
133+
const summary = generateV8CoverageSummary(mockCoverage);
134+
135+
expect(summary.summary.statements).toBe(100);
136+
expect(summary.summary.branches).toBe(100);
137+
expect(summary.summary.functions).toBe(100);
138+
expect(summary.summary.lines).toBe(100);
139+
expect(summary.files).toHaveLength(0);
140+
});
141+
142+
it("should handle files with missing coverage data", () => {
143+
const mockCoverage = {
144+
data: {
145+
"valid.js": {
146+
path: "/valid.js",
147+
s: { "0": 1 },
148+
f: { "0": 1 },
149+
b: { "0": [1] },
150+
statementMap: { "0": { start: { line: 1 } } },
151+
},
152+
"invalid.js": {
153+
path: "/invalid.js",
154+
// Missing s, f, b properties
155+
},
156+
},
157+
};
158+
159+
const summary = generateV8CoverageSummary(mockCoverage);
160+
161+
expect(summary.files).toHaveLength(1);
162+
expect(summary.files[0].file).toContain("valid.js");
163+
expect(summary.summary.statements).toBe(100);
164+
});
165+
166+
it("should handle coverage data without .data property", () => {
167+
const mockCoverage = {
168+
"test.js": {
169+
path: "/test.js",
170+
s: { "0": 1 },
171+
f: { "0": 1 },
172+
b: { "0": [1] },
173+
statementMap: { "0": { start: { line: 1 } } },
174+
},
175+
};
176+
177+
const summary = generateV8CoverageSummary(mockCoverage);
178+
179+
expect(summary.files).toHaveLength(1);
180+
expect(summary.summary.statements).toBe(100);
181+
});
182+
183+
it("should calculate percentages with proper rounding", () => {
184+
const mockCoverage = {
185+
data: {
186+
"test.js": {
187+
path: "/test.js",
188+
s: { "0": 1, "1": 1, "2": 0 }, // 2/3 = 66.666...%
189+
f: { "0": 1, "1": 0 }, // 1/2 = 50%
190+
b: { "0": [1, 0], "1": [0, 0] }, // 1/4 = 25%
191+
statementMap: {
192+
"0": { start: { line: 1 } },
193+
"1": { start: { line: 2 } },
194+
"2": { start: { line: 3 } },
195+
},
196+
},
197+
},
198+
};
199+
200+
const summary = generateV8CoverageSummary(mockCoverage);
201+
202+
expect(summary.files[0].statements).toBe(66.67); // Rounded to 2 decimal places
203+
expect(summary.files[0].functions).toBe(50);
204+
expect(summary.files[0].branches).toBe(25);
205+
expect(summary.files[0].lines).toBe(66.67);
206+
});
207+
208+
it("should handle files with no branches or functions", () => {
209+
const mockCoverage = {
210+
data: {
211+
"simple.js": {
212+
path: "/simple.js",
213+
s: { "0": 1, "1": 0 },
214+
f: {}, // No functions
215+
b: {}, // No branches
216+
statementMap: {
217+
"0": { start: { line: 1 } },
218+
"1": { start: { line: 2 } },
219+
},
220+
},
221+
},
222+
};
223+
224+
const summary = generateV8CoverageSummary(mockCoverage);
225+
226+
expect(summary.files[0].statements).toBe(50);
227+
expect(summary.files[0].branches).toBe(100); // No branches = 100% coverage
228+
expect(summary.files[0].functions).toBe(100); // No functions = 100% coverage
229+
expect(summary.files[0].lines).toBe(50);
230+
});
231+
});

0 commit comments

Comments
 (0)