@vitest-agent/ui 2.1.2 → 2.1.3

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.
@@ -8,9 +8,10 @@ const DEFAULT_WIDTH = 80;
8
8
  const renderAgent = (inputs) => {
9
9
  const modulePath = soleModulePath(inputs.state);
10
10
  if (modulePath === void 0) return "";
11
- const { passCount, failCount, skipCount, durationMs } = inputs.state.totals;
12
- const parts = [`${passCount}/${passCount + failCount + skipCount} passed`];
11
+ const { passCount, failCount, skipCount, timeoutCount, durationMs } = inputs.state.totals;
12
+ const parts = [`${passCount}/${passCount + failCount + skipCount + timeoutCount} passed`];
13
13
  if (failCount > 0) parts.push(`${failCount} failed`);
14
+ if (timeoutCount > 0) parts.push(`${timeoutCount} timed out`);
14
15
  if (skipCount > 0) parts.push(`${skipCount} skipped`);
15
16
  const sections = [`${modulePath}: ${parts.join(", ")} (${formatDisplayDuration(durationMs)})`];
16
17
  if (inputs.state.failures.length > 0) {
@@ -29,10 +29,14 @@ const classifyRunShape = (state, projects) => {
29
29
  /**
30
30
  * Compute the outcome class from the reduced state.
31
31
  *
32
- * Precedence: failures win over threshold violations. A run with one
33
- * failing test and a coverage gap classifies as `some-fail`; the
34
- * threshold-violation cell is reserved for runs where the test suite
35
- * itself is clean but coverage policy is not.
32
+ * Precedence: failures win over timeouts, and both win over threshold
33
+ * violations. A run with one failing test and a coverage gap classifies
34
+ * as `some-fail`; the threshold-violation cell is reserved for runs
35
+ * where the test suite itself is clean but coverage policy is not. A
36
+ * run whose only non-passing signal is one or more timed-out tests
37
+ * (`totals.timeoutCount > 0`, `totals.failCount === 0`) also
38
+ * classifies as `some-fail` — timeouts are not passes, and must not
39
+ * route to a passing cell (issue #224).
36
40
  *
37
41
  * @param state - the fully-reduced render state
38
42
  * @returns the outcome classification
@@ -40,6 +44,7 @@ const classifyRunShape = (state, projects) => {
40
44
  */
41
45
  const classifyOutcome = (state) => {
42
46
  if (state.totals.failCount > 0) return "some-fail";
47
+ if (state.totals.timeoutCount > 0) return "some-fail";
43
48
  if (state.coverage !== null && state.coverage.violations.length > 0) return "threshold-violation";
44
49
  return "all-pass";
45
50
  };
@@ -11,12 +11,16 @@ const truncate = (line, max) => {
11
11
  return `${line.slice(0, slice)}…`;
12
12
  };
13
13
  /**
14
- * Format the `Tests:` header line — `<pass>/<total> passed[, <fail> failed][, <skip> skipped] (Xms)`.
14
+ * Format the `Tests:` header line —
15
+ * `<pass>/<total> passed[, <fail> failed][, <timeout> timed out][, <skip> skipped] (Xms)`.
16
+ * `total` folds in `timeoutCount` — a timed-out test is a real collected
17
+ * test, not a pass (issue #224).
15
18
  */
16
19
  const formatTotals = (state) => {
17
- const { passCount, failCount, skipCount, durationMs } = state.totals;
18
- const parts = [`${passCount}/${passCount + failCount + skipCount} passed`];
20
+ const { passCount, failCount, skipCount, timeoutCount, durationMs } = state.totals;
21
+ const parts = [`${passCount}/${passCount + failCount + skipCount + timeoutCount} passed`];
19
22
  if (failCount > 0) parts.push(`${failCount} failed`);
23
+ if (timeoutCount > 0) parts.push(`${timeoutCount} timed out`);
20
24
  if (skipCount > 0) parts.push(`${skipCount} skipped`);
21
25
  const suffix = state.collectedModules !== void 0 && state.collectedModules > 0 ? ` across ${state.collectedModules} files` : "";
22
26
  return `Tests: ${parts.join(", ")} (${formatDisplayDuration(durationMs)})${suffix}`;
package/index.d.ts CHANGED
@@ -1007,10 +1007,14 @@ declare const classifyRunShape: (state: RenderState, projects: ReadonlyArray<Pro
1007
1007
  /**
1008
1008
  * Compute the outcome class from the reduced state.
1009
1009
  *
1010
- * Precedence: failures win over threshold violations. A run with one
1011
- * failing test and a coverage gap classifies as `some-fail`; the
1012
- * threshold-violation cell is reserved for runs where the test suite
1013
- * itself is clean but coverage policy is not.
1010
+ * Precedence: failures win over timeouts, and both win over threshold
1011
+ * violations. A run with one failing test and a coverage gap classifies
1012
+ * as `some-fail`; the threshold-violation cell is reserved for runs
1013
+ * where the test suite itself is clean but coverage policy is not. A
1014
+ * run whose only non-passing signal is one or more timed-out tests
1015
+ * (`totals.timeoutCount > 0`, `totals.failCount === 0`) also
1016
+ * classifies as `some-fail` — timeouts are not passes, and must not
1017
+ * route to a passing cell (issue #224).
1014
1018
  *
1015
1019
  * @param state - the fully-reduced render state
1016
1020
  * @returns the outcome classification
package/index.js CHANGED
@@ -33,7 +33,7 @@ import { ActionSeverity, CoverageFile, CoverageGap, CoverageMetric, CoverageRend
33
33
  *
34
34
  * @public
35
35
  */
36
- const CURRENT_UI_VERSION = "2.1.2";
36
+ const CURRENT_UI_VERSION = "2.1.3";
37
37
 
38
38
  //#endregion
39
39
  export { ActionSeverity, CURRENT_UI_VERSION, CountColumns, CoverageBlock, CoverageFile, CoverageGap, CoverageMetric, CoverageRenderState, DURATION_CELL_WIDTH, FailureRecord, FailureSection, FailuresSection, ModuleHeader, ModuleRecord, ProjectRow, RenderState, RenderTotals, RunEvent, RunEventChannel, RunEventChannelLive, SPINNER_FRAMES, SPINNER_FRAME_MS, SUITE_LOAD_FAILURE_LABEL, StatusIcon, StreamApp, SuggestedActionRecord, SuggestedActions, TagColumns, TestRecord, TestRow, TrendLine, accumulateUntilFinished, buildFooter, classifyOutcome, classifyRunShape, dispatch, dispatchInk, dispatcherTable, dominantClassification, forEachRenderState, formatDisplayDuration, initialRenderState, publish, publishAll, reduceRenderState, reduceRenderStateAll, renderAgent, renderStateStream, spinnerFrame, spinnerFrameForTime, subscribeRaw, synthesizeFromAgentReport, synthesizeRunEvents, tagUnion };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vitest-agent/ui",
3
- "version": "2.1.2",
3
+ "version": "2.1.3",
4
4
  "private": false,
5
5
  "description": "Shared event-sourced renderer for vitest-agent. React Ink view for humans, plain-string view for agents, both fed by the same reducer over a RunEvent stream.",
6
6
  "keywords": [
@@ -39,7 +39,7 @@
39
39
  "./package.json": "./package.json"
40
40
  },
41
41
  "dependencies": {
42
- "@vitest-agent/sdk": "2.2.1",
42
+ "@vitest-agent/sdk": "2.3.0",
43
43
  "effect": "4.0.0-beta.107"
44
44
  },
45
45
  "peerDependencies": {
package/render-agent.js CHANGED
@@ -9,9 +9,10 @@ const severityLabel = {
9
9
  blocker: "blocker"
10
10
  };
11
11
  const formatHeader = (state) => {
12
- const { passCount, failCount, skipCount, durationMs } = state.totals;
13
- const parts = [`${passCount}/${passCount + failCount + skipCount} passed`];
12
+ const { passCount, failCount, skipCount, timeoutCount, durationMs } = state.totals;
13
+ const parts = [`${passCount}/${passCount + failCount + skipCount + timeoutCount} passed`];
14
14
  if (failCount > 0) parts.push(`${failCount} failed`);
15
+ if (timeoutCount > 0) parts.push(`${timeoutCount} timed out`);
15
16
  if (skipCount > 0) parts.push(`${skipCount} skipped`);
16
17
  return `Tests: ${parts.join(", ")} (${formatDisplayDuration(durationMs)})`;
17
18
  };