@elench/testkit 0.1.83 → 0.1.84

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.
Files changed (83) hide show
  1. package/lib/cli/agents/providers/codex.mjs +1 -1
  2. package/lib/cli/tui/run-session-app.mjs +1 -1
  3. package/node_modules/@elench/next-analysis/package.json +1 -1
  4. package/node_modules/@elench/testkit-bridge/package.json +2 -2
  5. package/node_modules/@elench/testkit-protocol/package.json +1 -1
  6. package/node_modules/@elench/ts-analysis/package.json +1 -1
  7. package/package.json +7 -6
  8. package/lib/app/configs.test.mjs +0 -34
  9. package/lib/app/typecheck.test.mjs +0 -24
  10. package/lib/bundler/index.test.mjs +0 -164
  11. package/lib/cli/agents/investigation-context.test.mjs +0 -144
  12. package/lib/cli/agents/providers/claude.test.mjs +0 -95
  13. package/lib/cli/agents/providers/codex.test.mjs +0 -93
  14. package/lib/cli/args.test.mjs +0 -110
  15. package/lib/cli/command-helpers.test.mjs +0 -122
  16. package/lib/cli/commands/investigate.test.mjs +0 -83
  17. package/lib/cli/presentation/code-frames.test.mjs +0 -71
  18. package/lib/cli/presentation/events-reporter.test.mjs +0 -73
  19. package/lib/cli/presentation/run-reporter.test.mjs +0 -192
  20. package/lib/cli/presentation/summary-box.test.mjs +0 -60
  21. package/lib/cli/presentation/terminal-layout.test.mjs +0 -23
  22. package/lib/cli/presentation/tree-reporter.test.mjs +0 -166
  23. package/lib/cli/tui/run-session-app.test.mjs +0 -50
  24. package/lib/cli/tui/run-tree-state.test.mjs +0 -324
  25. package/lib/config/database.test.mjs +0 -29
  26. package/lib/config/discovery.test.mjs +0 -276
  27. package/lib/config/env.test.mjs +0 -40
  28. package/lib/config/index.test.mjs +0 -44
  29. package/lib/config/paths.test.mjs +0 -27
  30. package/lib/config/runtime.test.mjs +0 -82
  31. package/lib/config/skip-config.test.mjs +0 -63
  32. package/lib/config-api/index.test.mjs +0 -398
  33. package/lib/config-api/next-runtime-tsconfig.test.mjs +0 -58
  34. package/lib/coverage/backend-discovery.test.mjs +0 -61
  35. package/lib/coverage/evidence.test.mjs +0 -87
  36. package/lib/coverage/index.test.mjs +0 -715
  37. package/lib/coverage/routing.test.mjs +0 -36
  38. package/lib/coverage/shared.test.mjs +0 -72
  39. package/lib/database/fingerprint.test.mjs +0 -99
  40. package/lib/database/index.test.mjs +0 -95
  41. package/lib/database/naming.test.mjs +0 -39
  42. package/lib/database/state.test.mjs +0 -66
  43. package/lib/database/template-steps.test.mjs +0 -43
  44. package/lib/discovery/file-metadata.test.mjs +0 -51
  45. package/lib/discovery/index.test.mjs +0 -182
  46. package/lib/discovery/path-policy.test.mjs +0 -65
  47. package/lib/drizzle/index.test.mjs +0 -33
  48. package/lib/env/index.test.mjs +0 -82
  49. package/lib/history/index.test.mjs +0 -115
  50. package/lib/package.test.mjs +0 -59
  51. package/lib/playwright/index.test.mjs +0 -43
  52. package/lib/regressions/github.test.mjs +0 -324
  53. package/lib/regressions/index.test.mjs +0 -187
  54. package/lib/reporters/playwright.test.mjs +0 -167
  55. package/lib/runner/default-runtime-errors.test.mjs +0 -49
  56. package/lib/runner/execution-config.test.mjs +0 -67
  57. package/lib/runner/failure-details.test.mjs +0 -114
  58. package/lib/runner/formatting.test.mjs +0 -205
  59. package/lib/runner/metadata.test.mjs +0 -52
  60. package/lib/runner/planning.test.mjs +0 -371
  61. package/lib/runner/playwright-config.test.mjs +0 -78
  62. package/lib/runner/processes.test.mjs +0 -21
  63. package/lib/runner/regressions.test.mjs +0 -168
  64. package/lib/runner/reporting.test.mjs +0 -310
  65. package/lib/runner/results.test.mjs +0 -376
  66. package/lib/runner/runtime-manager.test.mjs +0 -252
  67. package/lib/runner/runtime-preparation.test.mjs +0 -141
  68. package/lib/runner/selection.test.mjs +0 -24
  69. package/lib/runner/setup-operations.test.mjs +0 -94
  70. package/lib/runner/state.test.mjs +0 -62
  71. package/lib/runner/suite-selection.test.mjs +0 -49
  72. package/lib/runner/template.test.mjs +0 -272
  73. package/lib/runtime-src/k6/http-checks.test.mjs +0 -120
  74. package/lib/runtime-src/k6/http.test.mjs +0 -205
  75. package/lib/runtime-src/shared/http-parsing.test.mjs +0 -69
  76. package/lib/shared/build-config.test.mjs +0 -132
  77. package/lib/shared/configured-steps.test.mjs +0 -102
  78. package/lib/shared/execution-schema.test.mjs +0 -26
  79. package/lib/shared/file-timeout.test.mjs +0 -64
  80. package/lib/shared/test-context.test.mjs +0 -43
  81. package/lib/timing/index.test.mjs +0 -64
  82. package/lib/toolchains/index.test.mjs +0 -168
  83. package/lib/vitest/index.test.mjs +0 -20
@@ -1,110 +0,0 @@
1
- import { describe, expect, it } from "vitest";
2
- import {
3
- parseFileTimeoutOption,
4
- parseShardOption,
5
- parseSuiteOption,
6
- parseTypeOption,
7
- parseWorkersOption,
8
- resolveRequestedFiles,
9
- resolveCliSelection,
10
- } from "./args.mjs";
11
-
12
- describe("cli-args", () => {
13
- it("resolves a positional suite type", () => {
14
- expect(
15
- resolveCliSelection({
16
- first: "int",
17
- second: null,
18
- third: null,
19
- })
20
- ).toEqual({
21
- dbAction: null,
22
- lifecycle: null,
23
- positionalType: "int",
24
- });
25
- });
26
-
27
- it("resolves lifecycle commands", () => {
28
- expect(
29
- resolveCliSelection({
30
- first: "status",
31
- second: null,
32
- third: null,
33
- })
34
- ).toEqual({
35
- dbAction: null,
36
- lifecycle: "status",
37
- positionalType: null,
38
- });
39
- });
40
-
41
- it("resolves db subcommands", () => {
42
- expect(
43
- resolveCliSelection({
44
- first: "db",
45
- second: "snapshot",
46
- third: "capture",
47
- })
48
- ).toEqual({
49
- dbAction: "snapshot-capture",
50
- lifecycle: null,
51
- positionalType: null,
52
- });
53
- });
54
-
55
- it("rejects unknown positional arguments", () => {
56
- expect(() =>
57
- resolveCliSelection({
58
- first: "mystery",
59
- second: null,
60
- third: null,
61
- })
62
- ).toThrow('Unknown argument "mystery"');
63
- });
64
-
65
- it("parses types and suite selectors", () => {
66
- expect(parseTypeOption(["e2e,scenario,dal"], "int")).toEqual([
67
- "int",
68
- "e2e",
69
- "scenario",
70
- "dal",
71
- ]);
72
- expect(() => parseTypeOption(["all", "int"])).toThrow("cannot be combined");
73
-
74
- expect(parseSuiteOption(["auth,scenario:journeys,dal:queries"])).toEqual([
75
- { kind: "plain", name: "auth", raw: "auth" },
76
- { kind: "typed", type: "scenario", name: "journeys", raw: "scenario:journeys" },
77
- { kind: "typed", type: "dal", name: "queries", raw: "dal:queries" },
78
- ]);
79
- });
80
-
81
- it("parses and validates execution options", () => {
82
- expect(parseWorkersOption("3")).toBe(3);
83
- expect(parseFileTimeoutOption("45")).toBe(45);
84
- expect(() => parseWorkersOption("0")).toThrow("Invalid --workers value");
85
- expect(() => parseFileTimeoutOption("0")).toThrow(
86
- "Invalid --file-timeout-seconds value"
87
- );
88
- });
89
-
90
- it("parses and validates shards", () => {
91
- expect(parseShardOption("2/5")).toEqual({ index: 2, total: 5 });
92
- expect(parseShardOption(null)).toBeNull();
93
- expect(() => parseShardOption("2-of-5")).toThrow("Invalid --shard value");
94
- expect(() => parseShardOption("3/2")).toThrow("Expected 1 <= i <= n");
95
- });
96
-
97
- it("normalizes requested file paths against the product directory", () => {
98
- expect(
99
- resolveRequestedFiles(
100
- [
101
- "/tmp/product/tests/api/integration/health.int.testkit.ts",
102
- "./tests/api/integration/health.int.testkit.ts",
103
- "product/tests/api/integration/health.int.testkit.ts",
104
- ],
105
- "/tmp/product",
106
- "/tmp"
107
- )
108
- ).toEqual(["tests/api/integration/health.int.testkit.ts"]);
109
- });
110
- });
@@ -1,122 +0,0 @@
1
- import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
2
-
3
- const loadManagedConfigsMock = vi.fn();
4
- const runAllMock = vi.fn();
5
- const createRunReporterMock = vi.fn();
6
- const createTreeReporterMock = vi.fn();
7
- const createRunEventsReporterMock = vi.fn();
8
-
9
- vi.mock("../app/configs.mjs", () => ({
10
- loadManagedConfigs: loadManagedConfigsMock,
11
- }));
12
-
13
- vi.mock("../runner/index.mjs", () => ({
14
- runAll: runAllMock,
15
- }));
16
-
17
- vi.mock("./presentation/run-reporter.mjs", () => ({
18
- createRunReporter: createRunReporterMock,
19
- }));
20
-
21
- vi.mock("./presentation/tree-reporter.mjs", () => ({
22
- createTreeReporter: createTreeReporterMock,
23
- }));
24
-
25
- vi.mock("./presentation/events-reporter.mjs", () => ({
26
- createRunEventsReporter: createRunEventsReporterMock,
27
- }));
28
-
29
- const originalIsTTY = process.stdout.isTTY;
30
- const originalStdoutGetWindowSize = process.stdout.getWindowSize;
31
- const originalStderrGetWindowSize = process.stderr.getWindowSize;
32
-
33
- beforeEach(() => {
34
- loadManagedConfigsMock.mockResolvedValue({
35
- allConfigs: [{ name: "api", productDir: "/tmp/product" }],
36
- configs: [{ name: "api", productDir: "/tmp/product" }],
37
- });
38
- runAllMock.mockResolvedValue({ ok: true });
39
- createRunReporterMock.mockReturnValue({ outputMode: "compact" });
40
- createRunEventsReporterMock.mockReturnValue({ outputMode: "events" });
41
- createTreeReporterMock.mockReturnValue({
42
- reporter: { outputMode: "compact" },
43
- finalize: Promise.resolve(),
44
- close: vi.fn(),
45
- });
46
- Object.defineProperty(process.stdout, "isTTY", {
47
- configurable: true,
48
- value: true,
49
- });
50
- process.stdout.getWindowSize = vi.fn(() => [100, 40]);
51
- process.stderr.getWindowSize = vi.fn(() => [100, 40]);
52
- });
53
-
54
- afterEach(() => {
55
- loadManagedConfigsMock.mockReset();
56
- runAllMock.mockReset();
57
- createRunReporterMock.mockReset();
58
- createTreeReporterMock.mockReset();
59
- createRunEventsReporterMock.mockReset();
60
- Object.defineProperty(process.stdout, "isTTY", {
61
- configurable: true,
62
- value: originalIsTTY,
63
- });
64
- process.stdout.getWindowSize = originalStdoutGetWindowSize;
65
- process.stderr.getWindowSize = originalStderrGetWindowSize;
66
- });
67
-
68
- describe("executeRunCommand", () => {
69
- it("uses the tree reporter for compact TTY runs and awaits finalization", async () => {
70
- let finalizeResolved = false;
71
- createTreeReporterMock.mockReturnValueOnce({
72
- reporter: { outputMode: "compact" },
73
- finalize: Promise.resolve().then(() => {
74
- finalizeResolved = true;
75
- }),
76
- close: vi.fn(),
77
- });
78
-
79
- const { executeRunCommand } = await import("./command-helpers.mjs");
80
- const result = await executeRunCommand({ jsonEnabled: () => false }, {}, null);
81
-
82
- expect(createTreeReporterMock).toHaveBeenCalledWith(
83
- expect.objectContaining({ productDir: "/tmp/product" })
84
- );
85
- expect(runAllMock).toHaveBeenCalledWith(
86
- expect.any(Array),
87
- expect.any(Array),
88
- expect.any(Array),
89
- expect.objectContaining({ reporter: { outputMode: "compact" } }),
90
- expect.any(Array)
91
- );
92
- expect(finalizeResolved).toBe(true);
93
- expect(result.outputMode).toBe("compact");
94
- });
95
-
96
- it("uses the events reporter when requested", async () => {
97
- const { executeRunCommand } = await import("./command-helpers.mjs");
98
- await executeRunCommand(
99
- { jsonEnabled: () => false },
100
- { "output-mode": "events" },
101
- null
102
- );
103
-
104
- expect(createRunEventsReporterMock).toHaveBeenCalled();
105
- expect(createRunReporterMock).not.toHaveBeenCalled();
106
- });
107
-
108
- it("closes the tree reporter when runner.runAll throws", async () => {
109
- const close = vi.fn();
110
- createTreeReporterMock.mockReturnValueOnce({
111
- reporter: { outputMode: "compact" },
112
- finalize: Promise.resolve(),
113
- close,
114
- });
115
- runAllMock.mockRejectedValueOnce(new Error("boom"));
116
-
117
- const { executeRunCommand } = await import("./command-helpers.mjs");
118
-
119
- await expect(executeRunCommand({ jsonEnabled: () => false }, {}, null)).rejects.toThrow("boom");
120
- expect(close).toHaveBeenCalled();
121
- });
122
- });
@@ -1,83 +0,0 @@
1
- import { afterEach, describe, expect, it, vi } from "vitest";
2
-
3
- const loadCurrentRunArtifactMock = vi.fn();
4
- const resolveFileSubjectMock = vi.fn();
5
- const startHostedInvestigationMock = vi.fn();
6
- const runInteractiveInvestigationMock = vi.fn();
7
-
8
- vi.mock("../viewer.mjs", () => ({
9
- loadCurrentRunArtifact: loadCurrentRunArtifactMock,
10
- resolveFileSubject: resolveFileSubjectMock,
11
- }));
12
-
13
- vi.mock("../agents/investigate.mjs", () => ({
14
- startHostedInvestigation: startHostedInvestigationMock,
15
- runInteractiveInvestigation: runInteractiveInvestigationMock,
16
- }));
17
-
18
- afterEach(() => {
19
- loadCurrentRunArtifactMock.mockReset();
20
- resolveFileSubjectMock.mockReset();
21
- startHostedInvestigationMock.mockReset();
22
- runInteractiveInvestigationMock.mockReset();
23
- });
24
-
25
- function seedSubject() {
26
- loadCurrentRunArtifactMock.mockReturnValue({});
27
- resolveFileSubjectMock.mockReturnValue({
28
- service: { name: "api" },
29
- suite: { name: "users", type: "integration" },
30
- file: { path: "tests/api/users.int.testkit.ts" },
31
- });
32
- }
33
-
34
- describe("InvestigateCommand", () => {
35
- it("runs hosted investigation and returns the final text", async () => {
36
- seedSubject();
37
- startHostedInvestigationMock.mockReturnValue({
38
- completion: Promise.resolve({
39
- provider: "codex",
40
- exitCode: 0,
41
- finalText: "Likely root cause.",
42
- }),
43
- });
44
-
45
- const { default: InvestigateCommand } = await import("./investigate.mjs");
46
- const result = await InvestigateCommand.run(["--json"]);
47
-
48
- expect(startHostedInvestigationMock).toHaveBeenCalledWith(
49
- expect.objectContaining({
50
- productDir: process.cwd(),
51
- serviceName: "api",
52
- filePath: "tests/api/users.int.testkit.ts",
53
- })
54
- );
55
- expect(result).toMatchObject({
56
- provider: "codex",
57
- finalText: "Likely root cause.",
58
- file: "tests/api/users.int.testkit.ts",
59
- service: "api",
60
- });
61
- });
62
-
63
- it("runs handoff investigation when requested", async () => {
64
- seedSubject();
65
- runInteractiveInvestigationMock.mockResolvedValue({
66
- provider: "claude",
67
- exitCode: 0,
68
- });
69
-
70
- const { default: InvestigateCommand } = await import("./investigate.mjs");
71
- const result = await InvestigateCommand.run(["--json", "--handoff", "--provider", "claude"]);
72
-
73
- expect(runInteractiveInvestigationMock).toHaveBeenCalledWith(
74
- expect.objectContaining({
75
- productDir: process.cwd(),
76
- serviceName: "api",
77
- filePath: "tests/api/users.int.testkit.ts",
78
- provider: "claude",
79
- })
80
- );
81
- expect(result).toMatchObject({ provider: "claude", exitCode: 0 });
82
- });
83
- });
@@ -1,71 +0,0 @@
1
- import fs from "fs";
2
- import os from "os";
3
- import path from "path";
4
- import { afterEach, describe, expect, it } from "vitest";
5
- import { findFailureLocation, formatLocation, renderCodeFrame } from "./code-frames.mjs";
6
-
7
- const cleanups = [];
8
-
9
- afterEach(() => {
10
- while (cleanups.length > 0) {
11
- cleanups.pop()();
12
- }
13
- });
14
-
15
- describe("code frame presentation", () => {
16
- it("finds a location from structured failure metadata", () => {
17
- expect(
18
- findFailureLocation({
19
- location: {
20
- path: "/tmp/example.ts",
21
- line: 10,
22
- column: 2,
23
- },
24
- })
25
- ).toEqual({
26
- path: "/tmp/example.ts",
27
- line: 10,
28
- column: 2,
29
- });
30
- });
31
-
32
- it("renders a code frame for a local file", () => {
33
- const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), "testkit-code-frame-"));
34
- cleanups.push(() => fs.rmSync(tempDir, { recursive: true, force: true }));
35
- const filePath = path.join(tempDir, "example.ts");
36
- fs.writeFileSync(
37
- filePath,
38
- [
39
- "export function run() {",
40
- " const value = 1;",
41
- " return value + missing;",
42
- "}",
43
- ].join("\n")
44
- );
45
-
46
- const lines = renderCodeFrame(
47
- {
48
- path: filePath,
49
- line: 3,
50
- column: 18,
51
- },
52
- { cwd: tempDir }
53
- );
54
-
55
- expect(lines.join("\n")).toContain("example.ts:3:18");
56
- expect(lines.join("\n")).toContain("return value + missing;");
57
- });
58
-
59
- it("formats locations relative to the cwd", () => {
60
- expect(
61
- formatLocation(
62
- {
63
- path: "/tmp/example.ts",
64
- line: 7,
65
- column: 3,
66
- },
67
- "/tmp"
68
- )
69
- ).toBe("example.ts:7:3");
70
- });
71
- });
@@ -1,73 +0,0 @@
1
- import { Writable } from "stream";
2
- import { describe, expect, it } from "vitest";
3
- import { createRunEventsReporter } from "./events-reporter.mjs";
4
-
5
- function createCapture() {
6
- let output = "";
7
- const stream = new Writable({
8
- write(chunk, _encoding, callback) {
9
- output += chunk.toString();
10
- callback();
11
- },
12
- });
13
- return {
14
- stream,
15
- lines() {
16
- return output.trim().split("\n").filter(Boolean).map((line) => JSON.parse(line));
17
- },
18
- };
19
- }
20
-
21
- describe("events reporter", () => {
22
- it("emits structured run lifecycle events", () => {
23
- const capture = createCapture();
24
- const reporter = createRunEventsReporter({ stdout: capture.stream });
25
-
26
- reporter.setTotalFileCount(2);
27
- reporter.taskStarted({
28
- serviceName: "api",
29
- file: "tests/api/users.int.testkit.ts",
30
- suiteName: "users",
31
- type: "integration",
32
- framework: "k6",
33
- });
34
- reporter.taskFinished(
35
- {
36
- serviceName: "api",
37
- file: "tests/api/users.int.testkit.ts",
38
- suiteName: "users",
39
- type: "integration",
40
- framework: "k6",
41
- },
42
- { failed: true, error: "status 500" }
43
- );
44
- reporter.runSummary([{ name: "api", failed: true }], 1200, null);
45
-
46
- expect(capture.lines()).toEqual([
47
- { type: "run.total_files", total: 2 },
48
- {
49
- type: "run.task_started",
50
- service: "api",
51
- file: "tests/api/users.int.testkit.ts",
52
- suite: "users",
53
- type: "integration",
54
- framework: "k6",
55
- },
56
- {
57
- type: "run.task_finished",
58
- service: "api",
59
- file: "tests/api/users.int.testkit.ts",
60
- suite: "users",
61
- type: "integration",
62
- framework: "k6",
63
- outcome: { failed: true, error: "status 500" },
64
- },
65
- {
66
- type: "run.summary",
67
- results: [{ name: "api", failed: true }],
68
- durationMs: 1200,
69
- regressionReport: null,
70
- },
71
- ]);
72
- });
73
- });
@@ -1,192 +0,0 @@
1
- import { Writable } from "stream";
2
- import figures from "figures";
3
- import { describe, expect, it } from "vitest";
4
- import { createRunReporter } from "./run-reporter.mjs";
5
-
6
- function createCapture(columns = 100) {
7
- let stdout = "";
8
- const stream = new Writable({
9
- write(chunk, _encoding, callback) {
10
- stdout += chunk.toString();
11
- callback();
12
- },
13
- });
14
- stream.columns = columns;
15
- return {
16
- stream,
17
- read() {
18
- return stdout;
19
- },
20
- };
21
- }
22
-
23
- describe("run reporter setup output", () => {
24
- it("prints concise high-level setup summaries in compact mode", () => {
25
- const capture = createCapture();
26
- const reporter = createRunReporter({
27
- outputMode: "compact",
28
- stdout: capture.stream,
29
- });
30
-
31
- reporter.setupOperationFinished({
32
- serviceName: "api",
33
- stage: "template",
34
- kind: "database-template",
35
- summary: "template rebuild",
36
- status: "passed",
37
- durationMs: 8_000,
38
- });
39
-
40
- expect(capture.read()).toContain(`${figures.play} RUN SETUP api template rebuild`);
41
- expect(capture.read()).toContain("8s");
42
- });
43
-
44
- it("does not print low-level setup steps in compact mode", () => {
45
- const capture = createCapture();
46
- const reporter = createRunReporter({
47
- outputMode: "compact",
48
- stdout: capture.stream,
49
- });
50
-
51
- reporter.setupOperationFinished({
52
- serviceName: "api",
53
- stage: "template:migrate:api:1",
54
- kind: "setup-step",
55
- summary: "sql-file: db/schema.sql",
56
- status: "passed",
57
- durationMs: 8_000,
58
- });
59
-
60
- expect(capture.read()).toBe("");
61
- });
62
-
63
- it("prints concise setup failures", () => {
64
- const capture = createCapture();
65
- const reporter = createRunReporter({
66
- outputMode: "compact",
67
- stdout: capture.stream,
68
- });
69
-
70
- reporter.setupOperationFinished({
71
- serviceName: "api",
72
- stage: "runtime:prepare",
73
- kind: "runtime-prepare",
74
- summary: "runtime prepare",
75
- status: "failed",
76
- durationMs: 1_200,
77
- error: "Command failed with exit code 1: node scripts/fail-prepare.mjs",
78
- });
79
-
80
- expect(capture.read()).toContain(`${figures.cross} FAIL SETUP api runtime:prepare`);
81
- expect(capture.read()).toContain("Command failed with exit code 1");
82
- });
83
- });
84
-
85
- describe("run reporter task output", () => {
86
- it("prints failure details on lines beneath the failed file result", () => {
87
- const capture = createCapture(88);
88
- const reporter = createRunReporter({
89
- outputMode: "compact",
90
- stdout: capture.stream,
91
- });
92
-
93
- reporter.setTotalFileCount(3);
94
- reporter.taskFinished(
95
- {
96
- serviceName: "api",
97
- type: "integration",
98
- framework: "k6",
99
- file: "__testkit__/health/health.int.testkit.ts",
100
- },
101
- {
102
- status: "failed",
103
- failed: true,
104
- durationMs: 4_000,
105
- error: "Default runtime thresholds failed: checks(rate==1.0)",
106
- failureDetails: [
107
- {
108
- kind: "http-assertion",
109
- title: "status is 200",
110
- message: "GET /health expected 200, got 404",
111
- request: {
112
- method: "GET",
113
- path: "/health",
114
- requestId: "req-1",
115
- },
116
- response: {
117
- status: 404,
118
- bodyPreview: '{"error":"route not found"}',
119
- },
120
- },
121
- ],
122
- }
123
- );
124
-
125
- const lines = capture.read().trimEnd().split("\n");
126
- expect(lines[0]).toContain("[1/3]");
127
- expect(lines[0]).toContain(`${figures.cross} FAIL api int __testkit__/health/health.int.testkit.ts 4s`);
128
- expect(lines[1]).toBe(" GET /health expected 200, got 404");
129
- expect(lines[2]).toContain(' response: {"error":"route not found"}');
130
- expect(lines[3]).toBe(" regression: new");
131
- expect(lines[4]).toBe(" logs: requestId=req-1");
132
- });
133
-
134
- it("renders a compact aggregate summary box", () => {
135
- const capture = createCapture(72);
136
- const reporter = createRunReporter({
137
- outputMode: "compact",
138
- stdout: capture.stream,
139
- });
140
-
141
- reporter.runSummary(
142
- [
143
- {
144
- name: "api",
145
- skipped: false,
146
- failed: true,
147
- suiteCount: 1,
148
- completedSuiteCount: 1,
149
- skippedSuiteCount: 0,
150
- failedSuiteCount: 1,
151
- totalFileCount: 3,
152
- passedFileCount: 2,
153
- failedFileCount: 1,
154
- skippedFileCount: 0,
155
- notRunFileCount: 0,
156
- durationMs: 10_000,
157
- suites: [],
158
- errors: [],
159
- },
160
- ],
161
- 20_000,
162
- {
163
- summary: {
164
- newRegressions: 1,
165
- knownRegressions: 2,
166
- fixedKnownRegressions: 3,
167
- catalogStale: 4,
168
- catalogSyncUnavailable: false,
169
- usedStaleCache: true,
170
- },
171
- }
172
- );
173
-
174
- const output = capture.read();
175
- expect(output).toContain("┌");
176
- expect(output).toContain("│ Result");
177
- expect(output).toContain("FAILED");
178
- expect(output).toContain("│ Passed");
179
- expect(output).toContain("│ Failed");
180
- expect(output).toContain("│ Skipped");
181
- expect(output).toContain("│ Not run");
182
- expect(output).toContain("│ Files");
183
- expect(output).toContain("│ Duration");
184
- expect(output).toContain("│ New regressions");
185
- expect(output).toContain("│ Known regressions");
186
- expect(output).toContain("│ Fixed known");
187
- expect(output).toContain("│ Catalog stale");
188
- expect(output).toContain("│ Catalog sync");
189
- expect(output).not.toContain("Failures:");
190
- expect(output).not.toContain("Runtime Errors:");
191
- });
192
- });