@vitest-agent/reporter 2.1.10 → 2.2.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/defaultReporter.js +80 -11
- package/githubLog.js +61 -0
- package/index.js +1 -1
- package/package.json +3 -3
package/defaultReporter.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { renderGithubLog, toDisplayPath } from "./githubLog.js";
|
|
1
2
|
import { createLiveInk } from "./LiveInkRenderer.js";
|
|
2
3
|
import { countSuiteFailures } from "@vitest-agent/sdk";
|
|
3
4
|
import { classifyOutcome, classifyRunShape, dispatch, dispatcherTable, reduceRenderStateAll, synthesizeFromAgentReport } from "@vitest-agent/ui";
|
|
@@ -136,17 +137,82 @@ const renderHumanStringForReport = async (report, options = {}) => {
|
|
|
136
137
|
if (cell.ink === void 0) return dispatch(inputs, opts);
|
|
137
138
|
return renderToString(cell.ink(inputs, opts), { columns: options.width ?? 80 });
|
|
138
139
|
};
|
|
139
|
-
const
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
140
|
+
const NON_STABLE_SUMMARY_CLASSIFICATIONS = [
|
|
141
|
+
"new-failure",
|
|
142
|
+
"persistent",
|
|
143
|
+
"flaky",
|
|
144
|
+
"recovered"
|
|
145
|
+
];
|
|
146
|
+
const MAX_SUMMARY_COVERAGE_ROWS = 10;
|
|
147
|
+
const renderClassificationsSection = (classifications) => {
|
|
148
|
+
const counts = /* @__PURE__ */ new Map();
|
|
149
|
+
for (const classification of classifications.values()) counts.set(classification, (counts.get(classification) ?? 0) + 1);
|
|
150
|
+
const rows = NON_STABLE_SUMMARY_CLASSIFICATIONS.filter((kind) => (counts.get(kind) ?? 0) > 0).map((kind) => `| ${kind} | ${counts.get(kind)} |`);
|
|
151
|
+
if (rows.length === 0) return null;
|
|
152
|
+
return [
|
|
153
|
+
"### Classifications",
|
|
154
|
+
"",
|
|
155
|
+
"| Classification | Count |",
|
|
156
|
+
"| --- | --- |",
|
|
157
|
+
...rows
|
|
158
|
+
].join("\n");
|
|
159
|
+
};
|
|
160
|
+
const formatCoveragePercent = (totals) => `stmts ${totals.statements}%, branches ${totals.branches}%, funcs ${totals.functions}%, lines ${totals.lines}%`;
|
|
161
|
+
const renderCoverageSection = (reports) => {
|
|
162
|
+
const belowTarget = reports.flatMap((r) => r.coverage?.belowTarget ?? []);
|
|
163
|
+
if (belowTarget.length === 0) return null;
|
|
164
|
+
const rows = belowTarget.slice(0, MAX_SUMMARY_COVERAGE_ROWS).map((f) => `| ${toDisplayPath(f.file)} | ${formatCoveragePercent(f.summary)} |`);
|
|
165
|
+
const lines = [
|
|
166
|
+
"### Coverage",
|
|
167
|
+
"",
|
|
168
|
+
`${belowTarget.length} file(s) below target.`,
|
|
169
|
+
"",
|
|
170
|
+
"| File | Coverage |",
|
|
171
|
+
"| --- | --- |",
|
|
172
|
+
...rows
|
|
173
|
+
];
|
|
174
|
+
if (belowTarget.length > MAX_SUMMARY_COVERAGE_ROWS) lines.push("", `(+${belowTarget.length - MAX_SUMMARY_COVERAGE_ROWS} more not shown)`);
|
|
175
|
+
return lines.join("\n");
|
|
176
|
+
};
|
|
177
|
+
const renderTrendSection = (trendSummary) => {
|
|
178
|
+
if (trendSummary === void 0) return null;
|
|
179
|
+
const lines = [
|
|
180
|
+
"### Trend",
|
|
181
|
+
"",
|
|
182
|
+
`Direction: ${trendSummary.direction}`,
|
|
183
|
+
`Run count: ${trendSummary.runCount}`
|
|
184
|
+
];
|
|
185
|
+
const firstMetric = trendSummary.firstMetric;
|
|
186
|
+
if (firstMetric !== void 0) {
|
|
187
|
+
const targetSuffix = firstMetric.target !== void 0 ? ` (target: ${firstMetric.target})` : "";
|
|
188
|
+
lines.push(`${firstMetric.name}: ${firstMetric.from} → ${firstMetric.to}${targetSuffix}`);
|
|
148
189
|
}
|
|
149
|
-
return
|
|
190
|
+
return lines.join("\n");
|
|
191
|
+
};
|
|
192
|
+
/**
|
|
193
|
+
* Builds the vitest-agent GitHub step-summary payload — ONE `RenderedOutput`
|
|
194
|
+
* for the whole run, carrying only data Vitest's own built-in
|
|
195
|
+
* `github-actions` reporter cannot know: test classifications (new-failure /
|
|
196
|
+
* persistent / flaky / recovered), coverage-target shortfalls, and the
|
|
197
|
+
* coverage trend. Vitest's reporter already writes pass/fail/skip counts
|
|
198
|
+
* and a flaky-tests section to the same `$GITHUB_STEP_SUMMARY` file, so
|
|
199
|
+
* duplicating that per-project breakdown here would be redundant noise
|
|
200
|
+
* multiplied across every project in a workspace. Returns an empty array
|
|
201
|
+
* when all three sections would be empty — a clean run should not leave a
|
|
202
|
+
* bare heading in the job summary.
|
|
203
|
+
*/
|
|
204
|
+
const renderGithubSummary = (input) => {
|
|
205
|
+
const sections = [
|
|
206
|
+
renderClassificationsSection(input.classifications),
|
|
207
|
+
renderCoverageSection(input.reports),
|
|
208
|
+
renderTrendSection(input.trendSummary)
|
|
209
|
+
].filter((section) => section !== null);
|
|
210
|
+
if (sections.length === 0) return [];
|
|
211
|
+
return [{
|
|
212
|
+
target: "github-summary",
|
|
213
|
+
content: `\n${["## vitest-agent", ...sections].join("\n\n")}\n`,
|
|
214
|
+
contentType: "text/markdown"
|
|
215
|
+
}];
|
|
150
216
|
};
|
|
151
217
|
/**
|
|
152
218
|
* Subscribe a live Ink mount to the kit's run-event channel.
|
|
@@ -207,7 +273,10 @@ const DefaultVitestAgentReporter = (kit) => {
|
|
|
207
273
|
contentType: "text/plain"
|
|
208
274
|
});
|
|
209
275
|
}
|
|
210
|
-
if (renderKit.config.githubActions === true)
|
|
276
|
+
if (renderKit.config.githubActions === true) {
|
|
277
|
+
out.push(...renderGithubSummary(input));
|
|
278
|
+
out.push(renderGithubLog(input, renderKit));
|
|
279
|
+
}
|
|
211
280
|
return out;
|
|
212
281
|
} };
|
|
213
282
|
};
|
package/githubLog.js
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { relative } from "node:path";
|
|
2
|
+
|
|
3
|
+
//#region src/githubLog.ts
|
|
4
|
+
/**
|
|
5
|
+
* Light end-of-run log block for GitHub Actions.
|
|
6
|
+
*
|
|
7
|
+
* @privateRemarks
|
|
8
|
+
* Wraps a summary of the run in GitHub's collapsed-group log markers so it
|
|
9
|
+
* is collapsed by default in the Actions log viewer and never competes
|
|
10
|
+
* with Vitest's own console output. Pushed alongside `renderGithubSummary`
|
|
11
|
+
* whenever `kit.config.githubActions` is true. All data is derived from
|
|
12
|
+
* fields already on `ReporterRenderInput` / `ReporterKit` — no new
|
|
13
|
+
* plumbing. No ANSI escapes: GitHub renders raw log text.
|
|
14
|
+
*
|
|
15
|
+
* @internal
|
|
16
|
+
*/
|
|
17
|
+
const MAX_NAMED_FILES = 3;
|
|
18
|
+
/**
|
|
19
|
+
* Renders a coverage-target file path relative to `process.cwd()` for
|
|
20
|
+
* display. Falls back to the original string unchanged when the relative
|
|
21
|
+
* path is empty or escapes the root (starts with `..`) rather than
|
|
22
|
+
* printing a `../../..` chain.
|
|
23
|
+
*/
|
|
24
|
+
function toDisplayPath(file) {
|
|
25
|
+
const rel = relative(process.cwd(), file);
|
|
26
|
+
if (rel === "" || rel.startsWith("..")) return file;
|
|
27
|
+
return rel;
|
|
28
|
+
}
|
|
29
|
+
const NON_STABLE_CLASSIFICATIONS = [
|
|
30
|
+
"new-failure",
|
|
31
|
+
"persistent",
|
|
32
|
+
"flaky",
|
|
33
|
+
"recovered"
|
|
34
|
+
];
|
|
35
|
+
function renderGithubLog(input, kit) {
|
|
36
|
+
const lines = ["::group::vitest-agent"];
|
|
37
|
+
for (const report of input.reports) {
|
|
38
|
+
const name = report.project ?? "default";
|
|
39
|
+
lines.push(`${name}: ${report.summary.passed}/${report.summary.total} passed, ${report.summary.failed} failed, ${report.summary.skipped} skipped`);
|
|
40
|
+
}
|
|
41
|
+
const belowTarget = input.reports.flatMap((r) => r.coverage?.belowTarget ?? []);
|
|
42
|
+
if (belowTarget.length > 0) {
|
|
43
|
+
const names = belowTarget.slice(0, MAX_NAMED_FILES).map((f) => toDisplayPath(f.file));
|
|
44
|
+
const suffix = belowTarget.length > MAX_NAMED_FILES ? `, +${belowTarget.length - MAX_NAMED_FILES} more` : "";
|
|
45
|
+
lines.push(`coverage: ${belowTarget.length} file(s) below target (${names.join(", ")}${suffix})`);
|
|
46
|
+
}
|
|
47
|
+
const classificationCounts = /* @__PURE__ */ new Map();
|
|
48
|
+
for (const classification of input.classifications.values()) classificationCounts.set(classification, (classificationCounts.get(classification) ?? 0) + 1);
|
|
49
|
+
const classificationParts = NON_STABLE_CLASSIFICATIONS.filter((kind) => (classificationCounts.get(kind) ?? 0) > 0).map((kind) => `${kind}: ${classificationCounts.get(kind)}`);
|
|
50
|
+
if (classificationParts.length > 0) lines.push(`classifications: ${classificationParts.join(", ")}`);
|
|
51
|
+
if (kit.config.dbPath !== void 0) lines.push(`db: ${kit.config.dbPath}`);
|
|
52
|
+
lines.push("::endgroup::");
|
|
53
|
+
return {
|
|
54
|
+
target: "stdout",
|
|
55
|
+
content: lines.join("\n"),
|
|
56
|
+
contentType: "text/plain"
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
//#endregion
|
|
61
|
+
export { renderGithubLog, toDisplayPath };
|
package/index.js
CHANGED
|
@@ -9,7 +9,7 @@ import { DefaultVitestAgentReporter, buildDispatchInputs, renderAgentStringForRe
|
|
|
9
9
|
*
|
|
10
10
|
* @public
|
|
11
11
|
*/
|
|
12
|
-
const CURRENT_REPORTER_VERSION = "2.
|
|
12
|
+
const CURRENT_REPORTER_VERSION = "2.2.0";
|
|
13
13
|
|
|
14
14
|
//#endregion
|
|
15
15
|
export { CURRENT_REPORTER_VERSION, DefaultVitestAgentReporter, createLiveInk as _createLiveInk, buildDispatchInputs, renderAgentStringForReport, renderHumanStringForReport, resolveCellOptions };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vitest-agent/reporter",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.2.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "Named VitestAgentReporterFactory implementations for the vitest-agent ecosystem.",
|
|
6
6
|
"keywords": [
|
|
@@ -41,8 +41,8 @@
|
|
|
41
41
|
"dependencies": {
|
|
42
42
|
"@effect/platform-node": "4.0.0-rc.109",
|
|
43
43
|
"@effect/sql-sqlite-node": "4.0.0-rc.109",
|
|
44
|
-
"@vitest-agent/sdk": "2.4.
|
|
45
|
-
"@vitest-agent/ui": "2.2.
|
|
44
|
+
"@vitest-agent/sdk": "2.4.11",
|
|
45
|
+
"@vitest-agent/ui": "2.2.11",
|
|
46
46
|
"effect": "4.0.0-rc.109",
|
|
47
47
|
"ink": "^7.1.1",
|
|
48
48
|
"react": "^19.2.8"
|