supercov 0.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/vitest.ts ADDED
@@ -0,0 +1,101 @@
1
+ import { mkdirSync, writeFileSync } from "node:fs";
2
+ import { relative, resolve, sep } from "node:path";
3
+ import { afterEach, beforeEach } from "vitest";
4
+ import { coverageSnapshot, resetCoverage } from "./runtime.ts";
5
+ import { inferTestProvenance } from "./provenance.ts";
6
+ import type { McdcRawTestResult } from "./types.ts";
7
+
8
+ const evidenceDirectory = process.env["SUPERCOV_EVIDENCE_DIR"];
9
+ const emittedSetupFiles = new Set<string>();
10
+
11
+ function attemptStatus(
12
+ state: string | undefined,
13
+ ): McdcRawTestResult["status"] {
14
+ if (state === "pass") return "passed";
15
+ if (state === "fail") return "failed";
16
+ if (state === "skip" || state === "todo") return "skipped";
17
+ return "unknown";
18
+ }
19
+
20
+ function titlePath(
21
+ task: Readonly<{ name: string; suite?: unknown }>,
22
+ ): string[] {
23
+ const names: string[] = [task.name];
24
+ let suite = task.suite as { name?: string; suite?: unknown } | undefined;
25
+ while (suite?.name) {
26
+ names.unshift(suite.name);
27
+ suite = suite.suite as typeof suite;
28
+ }
29
+ return names;
30
+ }
31
+
32
+ function writeEvidence(payload: McdcRawTestResult, suffix: string): void {
33
+ if (!evidenceDirectory) return;
34
+ const directory = resolve(process.cwd(), evidenceDirectory, suffix);
35
+ mkdirSync(directory, { recursive: true });
36
+ writeFileSync(
37
+ resolve(directory, "mcdc.json"),
38
+ `${JSON.stringify(payload)}\n`,
39
+ );
40
+ }
41
+
42
+ beforeEach((context) => {
43
+ const task = context.task;
44
+ const testFile = relative(process.cwd(), task.file.filepath)
45
+ .split(sep)
46
+ .join("/");
47
+ if (!emittedSetupFiles.has(testFile)) {
48
+ emittedSetupFiles.add(testFile);
49
+ const setupSnapshot = coverageSnapshot();
50
+ if (setupSnapshot.hits.length || setupSnapshot.decisions.length) {
51
+ writeEvidence(
52
+ {
53
+ testId: `vitest:${task.file.id}:setup`,
54
+ test: `${testFile} > module setup`,
55
+ testFile,
56
+ title: "module setup",
57
+ retry: 0,
58
+ status: "passed",
59
+ provenance: inferTestProvenance({
60
+ runner: "vitest",
61
+ file: testFile,
62
+ project: task.file.projectName,
63
+ explicitKind: process.env["SUPERCOV_TEST_KIND"],
64
+ }),
65
+ role: "setup",
66
+ runtime: [setupSnapshot],
67
+ browser: [],
68
+ server: [],
69
+ },
70
+ `vitest-${task.file.id}-setup`,
71
+ );
72
+ }
73
+ }
74
+ resetCoverage(`vitest:${task.id}`);
75
+ });
76
+
77
+ afterEach((context) => {
78
+ const task = context.task;
79
+ const testFile = relative(process.cwd(), task.file.filepath)
80
+ .split(sep)
81
+ .join("/");
82
+ const retry = task.result?.retryCount ?? 0;
83
+ const payload: McdcRawTestResult = {
84
+ testId: `vitest:${task.id}`,
85
+ test: [...titlePath(task)].join(" > "),
86
+ testFile,
87
+ title: task.name,
88
+ retry,
89
+ status: attemptStatus(task.result?.state),
90
+ provenance: inferTestProvenance({
91
+ runner: "vitest",
92
+ file: testFile,
93
+ project: task.file.projectName,
94
+ explicitKind: process.env["SUPERCOV_TEST_KIND"],
95
+ }),
96
+ runtime: [coverageSnapshot()],
97
+ browser: [],
98
+ server: [],
99
+ };
100
+ writeEvidence(payload, `vitest-${task.id}-${retry}`);
101
+ });
@@ -0,0 +1,72 @@
1
+ import { mkdirSync, writeFileSync } from "node:fs";
2
+ import { relative, resolve, sep } from "node:path";
3
+ import { fileURLToPath } from "node:url";
4
+ import type { Reporter } from "vitest/reporters";
5
+ import { inferTestProvenance } from "./provenance.ts";
6
+ import type { McdcRawTestResult } from "./types.ts";
7
+
8
+ interface ReportedTestCase {
9
+ id: string;
10
+ name: string;
11
+ fullName: string;
12
+ module: { moduleId: string };
13
+ project: { name?: string };
14
+ options: { fails?: boolean };
15
+ result(): {
16
+ state: "passed" | "failed" | "skipped" | "pending";
17
+ };
18
+ diagnostic():
19
+ | { retryCount: number; flaky: boolean }
20
+ | undefined;
21
+ }
22
+
23
+ function sourcePath(moduleId: string): string {
24
+ const absolute = moduleId.startsWith("file:")
25
+ ? fileURLToPath(moduleId)
26
+ : moduleId;
27
+ return relative(process.cwd(), absolute).split(sep).join("/");
28
+ }
29
+
30
+ /** Records final runner outcomes, including tests that never execute hooks. */
31
+ export default class SupercovVitestReporter implements Reporter {
32
+ onTestCaseResult(testCase: ReportedTestCase): void {
33
+ const evidenceDirectory =
34
+ process.env["SUPERCOV_EVIDENCE_DIR"];
35
+ if (!evidenceDirectory) return;
36
+ const result = testCase.result();
37
+ if (result.state === "pending") return;
38
+ const diagnostic = testCase.diagnostic();
39
+ const testFile = sourcePath(testCase.module.moduleId);
40
+ const retry = diagnostic?.retryCount ?? 0;
41
+ const payload: McdcRawTestResult = {
42
+ testId: `vitest:${testCase.id}`,
43
+ test: testCase.fullName,
44
+ testFile,
45
+ title: testCase.name,
46
+ retry,
47
+ status: result.state,
48
+ expectedStatus: testCase.options.fails ? "failed" : "passed",
49
+ flaky: diagnostic?.flaky ?? false,
50
+ provenance: inferTestProvenance({
51
+ runner: "vitest",
52
+ file: testFile,
53
+ project: testCase.project.name,
54
+ explicitKind: process.env["SUPERCOV_TEST_KIND"],
55
+ }),
56
+ runtime: [],
57
+ browser: [],
58
+ server: [],
59
+ };
60
+ const safeId = testCase.id.replace(/[^a-zA-Z0-9_-]/g, "_");
61
+ const directory = resolve(
62
+ process.cwd(),
63
+ evidenceDirectory,
64
+ `vitest-${safeId}-${retry}-status`,
65
+ );
66
+ mkdirSync(directory, { recursive: true });
67
+ writeFileSync(
68
+ resolve(directory, "mcdc.json"),
69
+ `${JSON.stringify(payload)}\n`,
70
+ );
71
+ }
72
+ }