@elench/testkit 0.1.83 → 0.1.85

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 (87) hide show
  1. package/lib/cli/agents/investigation-interpreter.mjs +320 -0
  2. package/lib/cli/agents/investigation-log.mjs +37 -0
  3. package/lib/cli/agents/providers/codex.mjs +1 -1
  4. package/lib/cli/presentation/tree-reporter.mjs +33 -1
  5. package/lib/cli/tui/run-session-app.mjs +73 -11
  6. package/lib/cli/tui/run-session-state.mjs +29 -5
  7. package/node_modules/@elench/next-analysis/package.json +1 -1
  8. package/node_modules/@elench/testkit-bridge/package.json +2 -2
  9. package/node_modules/@elench/testkit-protocol/package.json +1 -1
  10. package/node_modules/@elench/ts-analysis/package.json +1 -1
  11. package/package.json +7 -6
  12. package/lib/app/configs.test.mjs +0 -34
  13. package/lib/app/typecheck.test.mjs +0 -24
  14. package/lib/bundler/index.test.mjs +0 -164
  15. package/lib/cli/agents/investigation-context.test.mjs +0 -144
  16. package/lib/cli/agents/providers/claude.test.mjs +0 -95
  17. package/lib/cli/agents/providers/codex.test.mjs +0 -93
  18. package/lib/cli/args.test.mjs +0 -110
  19. package/lib/cli/command-helpers.test.mjs +0 -122
  20. package/lib/cli/commands/investigate.test.mjs +0 -83
  21. package/lib/cli/presentation/code-frames.test.mjs +0 -71
  22. package/lib/cli/presentation/events-reporter.test.mjs +0 -73
  23. package/lib/cli/presentation/run-reporter.test.mjs +0 -192
  24. package/lib/cli/presentation/summary-box.test.mjs +0 -60
  25. package/lib/cli/presentation/terminal-layout.test.mjs +0 -23
  26. package/lib/cli/presentation/tree-reporter.test.mjs +0 -166
  27. package/lib/cli/tui/run-session-app.test.mjs +0 -50
  28. package/lib/cli/tui/run-tree-state.test.mjs +0 -324
  29. package/lib/config/database.test.mjs +0 -29
  30. package/lib/config/discovery.test.mjs +0 -276
  31. package/lib/config/env.test.mjs +0 -40
  32. package/lib/config/index.test.mjs +0 -44
  33. package/lib/config/paths.test.mjs +0 -27
  34. package/lib/config/runtime.test.mjs +0 -82
  35. package/lib/config/skip-config.test.mjs +0 -63
  36. package/lib/config-api/index.test.mjs +0 -398
  37. package/lib/config-api/next-runtime-tsconfig.test.mjs +0 -58
  38. package/lib/coverage/backend-discovery.test.mjs +0 -61
  39. package/lib/coverage/evidence.test.mjs +0 -87
  40. package/lib/coverage/index.test.mjs +0 -715
  41. package/lib/coverage/routing.test.mjs +0 -36
  42. package/lib/coverage/shared.test.mjs +0 -72
  43. package/lib/database/fingerprint.test.mjs +0 -99
  44. package/lib/database/index.test.mjs +0 -95
  45. package/lib/database/naming.test.mjs +0 -39
  46. package/lib/database/state.test.mjs +0 -66
  47. package/lib/database/template-steps.test.mjs +0 -43
  48. package/lib/discovery/file-metadata.test.mjs +0 -51
  49. package/lib/discovery/index.test.mjs +0 -182
  50. package/lib/discovery/path-policy.test.mjs +0 -65
  51. package/lib/drizzle/index.test.mjs +0 -33
  52. package/lib/env/index.test.mjs +0 -82
  53. package/lib/history/index.test.mjs +0 -115
  54. package/lib/package.test.mjs +0 -59
  55. package/lib/playwright/index.test.mjs +0 -43
  56. package/lib/regressions/github.test.mjs +0 -324
  57. package/lib/regressions/index.test.mjs +0 -187
  58. package/lib/reporters/playwright.test.mjs +0 -167
  59. package/lib/runner/default-runtime-errors.test.mjs +0 -49
  60. package/lib/runner/execution-config.test.mjs +0 -67
  61. package/lib/runner/failure-details.test.mjs +0 -114
  62. package/lib/runner/formatting.test.mjs +0 -205
  63. package/lib/runner/metadata.test.mjs +0 -52
  64. package/lib/runner/planning.test.mjs +0 -371
  65. package/lib/runner/playwright-config.test.mjs +0 -78
  66. package/lib/runner/processes.test.mjs +0 -21
  67. package/lib/runner/regressions.test.mjs +0 -168
  68. package/lib/runner/reporting.test.mjs +0 -310
  69. package/lib/runner/results.test.mjs +0 -376
  70. package/lib/runner/runtime-manager.test.mjs +0 -252
  71. package/lib/runner/runtime-preparation.test.mjs +0 -141
  72. package/lib/runner/selection.test.mjs +0 -24
  73. package/lib/runner/setup-operations.test.mjs +0 -94
  74. package/lib/runner/state.test.mjs +0 -62
  75. package/lib/runner/suite-selection.test.mjs +0 -49
  76. package/lib/runner/template.test.mjs +0 -272
  77. package/lib/runtime-src/k6/http-checks.test.mjs +0 -120
  78. package/lib/runtime-src/k6/http.test.mjs +0 -205
  79. package/lib/runtime-src/shared/http-parsing.test.mjs +0 -69
  80. package/lib/shared/build-config.test.mjs +0 -132
  81. package/lib/shared/configured-steps.test.mjs +0 -102
  82. package/lib/shared/execution-schema.test.mjs +0 -26
  83. package/lib/shared/file-timeout.test.mjs +0 -64
  84. package/lib/shared/test-context.test.mjs +0 -43
  85. package/lib/timing/index.test.mjs +0 -64
  86. package/lib/toolchains/index.test.mjs +0 -168
  87. package/lib/vitest/index.test.mjs +0 -20
@@ -1,324 +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 { normalizeRegressionCatalogDocument } from "./index.mjs";
6
- import {
7
- parseGitHubRepoSlug,
8
- shouldFailRegressionSync,
9
- validateRegressionIssues,
10
- } from "./github.mjs";
11
-
12
- const tempDirs = [];
13
-
14
- afterEach(() => {
15
- for (const tempDir of tempDirs.splice(0)) {
16
- fs.rmSync(tempDir, { recursive: true, force: true });
17
- }
18
- });
19
-
20
- describe("regression GitHub sync", () => {
21
- it("parses GitHub repo slugs from common origin URLs", () => {
22
- expect(parseGitHubRepoSlug("https://github.com/acme/repo.git")).toBe("acme/repo");
23
- expect(parseGitHubRepoSlug("git@github.com:acme/repo.git")).toBe("acme/repo");
24
- expect(parseGitHubRepoSlug("ssh://git@github.com/acme/repo.git")).toBe("acme/repo");
25
- expect(parseGitHubRepoSlug("https://gitlab.com/acme/repo.git")).toBe(null);
26
- });
27
-
28
- it("fails sync when a linked issue is closed but the regression still reproduces", async () => {
29
- const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), "testkit-regressions-gh-"));
30
- tempDirs.push(tempDir);
31
- const document = normalizeRegressionCatalogDocument({
32
- schemaVersion: 1,
33
- issueRepo: "acme/repo",
34
- entries: [
35
- {
36
- id: "bad-message",
37
- classification: "product_bug",
38
- issue: {
39
- repo: "acme/repo",
40
- number: 12,
41
- },
42
- summary: "API returns the wrong message",
43
- cause: "The payload is wrong.",
44
- lastReviewedAt: "2026-05-04",
45
- fingerprints: [
46
- {
47
- service: "api",
48
- type: "int",
49
- path: "src/api/routes/__testkit__/failing.int.testkit.ts",
50
- },
51
- ],
52
- },
53
- ],
54
- });
55
-
56
- const result = await validateRegressionIssues({
57
- productDir: tempDir,
58
- document,
59
- statusArtifact: {
60
- tests: [
61
- {
62
- service: "api",
63
- type: "int",
64
- path: "src/api/routes/__testkit__/failing.int.testkit.ts",
65
- status: "failed",
66
- },
67
- ],
68
- },
69
- config: {
70
- provider: "github",
71
- mode: "error",
72
- cacheTtlSeconds: 60,
73
- },
74
- gitMetadata: {
75
- repoSlug: "acme/repo",
76
- remoteUrl: "https://github.com/acme/repo.git",
77
- },
78
- transport: {
79
- async fetchRepoIssues(repo, numbers) {
80
- const map = new Map();
81
- map.set(numbers[0], {
82
- repo,
83
- number: numbers[0],
84
- exists: true,
85
- title: "API returns the wrong message",
86
- state: "CLOSED",
87
- url: `https://github.com/${repo}/issues/${numbers[0]}`,
88
- checkedAt: "2026-05-04T00:00:00.000Z",
89
- source: "github",
90
- });
91
- return map;
92
- },
93
- },
94
- });
95
-
96
- expect(result.summary.byCode.closed_but_failing).toBe(1);
97
- expect(result.summary.errors).toBeGreaterThan(0);
98
- expect(result.entries[0].status).toBe("closed_but_failing");
99
- expect(shouldFailRegressionSync(result)).toBe(true);
100
- });
101
-
102
- it("allows multiple local entries to share one GitHub issue", async () => {
103
- const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), "testkit-regressions-gh-shared-"));
104
- tempDirs.push(tempDir);
105
- const document = normalizeRegressionCatalogDocument({
106
- schemaVersion: 1,
107
- issueRepo: "acme/repo",
108
- entries: [
109
- {
110
- id: "route-a-invalid-uuid",
111
- classification: "product_bug",
112
- issue: {
113
- repo: "acme/repo",
114
- number: 77,
115
- },
116
- summary: "Route A leaks UUID parse errors",
117
- cause: "Route A is missing UUID validation.",
118
- lastReviewedAt: "2026-05-04",
119
- fingerprints: [
120
- {
121
- service: "api",
122
- type: "int",
123
- path: "src/api/routes/__testkit__/route-a.int.testkit.ts",
124
- },
125
- ],
126
- },
127
- {
128
- id: "route-b-invalid-uuid",
129
- classification: "product_bug",
130
- issue: {
131
- repo: "acme/repo",
132
- number: 77,
133
- },
134
- summary: "Route B leaks UUID parse errors",
135
- cause: "Route B is missing UUID validation.",
136
- lastReviewedAt: "2026-05-04",
137
- fingerprints: [
138
- {
139
- service: "api",
140
- type: "int",
141
- path: "src/api/routes/__testkit__/route-b.int.testkit.ts",
142
- },
143
- ],
144
- },
145
- ],
146
- });
147
-
148
- const result = await validateRegressionIssues({
149
- productDir: tempDir,
150
- document,
151
- statusArtifact: {
152
- tests: [
153
- {
154
- service: "api",
155
- type: "int",
156
- path: "src/api/routes/__testkit__/route-a.int.testkit.ts",
157
- status: "failed",
158
- },
159
- {
160
- service: "api",
161
- type: "int",
162
- path: "src/api/routes/__testkit__/route-b.int.testkit.ts",
163
- status: "failed",
164
- },
165
- ],
166
- },
167
- config: {
168
- provider: "github",
169
- mode: "error",
170
- },
171
- transport: {
172
- async fetchRepoIssues(repo, numbers) {
173
- const map = new Map();
174
- map.set(numbers[0], {
175
- repo,
176
- number: numbers[0],
177
- exists: true,
178
- title: "UUID path params reach Postgres and return 500 instead of 400",
179
- state: "OPEN",
180
- url: `https://github.com/${repo}/issues/${numbers[0]}`,
181
- checkedAt: "2026-05-04T00:00:00.000Z",
182
- source: "github",
183
- });
184
- return map;
185
- },
186
- },
187
- });
188
-
189
- expect(result.summary.errors).toBe(0);
190
- expect(result.entries).toHaveLength(2);
191
- expect(result.entries[0].findings).toEqual([]);
192
- expect(result.entries[1].findings).toEqual([]);
193
- expect(result.entries[0].status).toBe("open_and_failing");
194
- expect(result.entries[1].status).toBe("open_and_failing");
195
- });
196
-
197
- it("warns when an open issue is not reproduced", async () => {
198
- const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), "testkit-regressions-gh-open-"));
199
- tempDirs.push(tempDir);
200
- const document = normalizeRegressionCatalogDocument({
201
- schemaVersion: 1,
202
- issueRepo: "acme/repo",
203
- entries: [
204
- {
205
- id: "bad-message",
206
- classification: "product_bug",
207
- issue: {
208
- repo: "acme/repo",
209
- number: 12,
210
- },
211
- summary: "API returns the wrong message",
212
- cause: "The payload is wrong.",
213
- lastReviewedAt: "2026-05-04",
214
- fingerprints: [
215
- {
216
- service: "api",
217
- type: "int",
218
- path: "src/api/routes/__testkit__/failing.int.testkit.ts",
219
- },
220
- ],
221
- },
222
- ],
223
- });
224
-
225
- const result = await validateRegressionIssues({
226
- productDir: tempDir,
227
- document,
228
- statusArtifact: {
229
- tests: [
230
- {
231
- service: "api",
232
- type: "int",
233
- path: "src/api/routes/__testkit__/failing.int.testkit.ts",
234
- status: "passed",
235
- },
236
- ],
237
- },
238
- config: {
239
- provider: "github",
240
- mode: "warn",
241
- },
242
- gitMetadata: {
243
- repoSlug: "acme/repo",
244
- },
245
- transport: {
246
- async fetchRepoIssues(repo, numbers) {
247
- const map = new Map();
248
- map.set(numbers[0], {
249
- repo,
250
- number: numbers[0],
251
- exists: true,
252
- title: "API returns the wrong message",
253
- state: "OPEN",
254
- url: `https://github.com/${repo}/issues/${numbers[0]}`,
255
- checkedAt: "2026-05-04T00:00:00.000Z",
256
- source: "github",
257
- });
258
- return map;
259
- },
260
- },
261
- });
262
-
263
- expect(result.summary.byCode.open_not_reproduced).toBe(1);
264
- expect(result.summary.errors).toBe(0);
265
- expect(result.summary.warnings).toBe(1);
266
- expect(result.entries[0].status).toBe("open_not_reproduced");
267
- });
268
-
269
- it("falls back to warning when sync is unavailable", async () => {
270
- const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), "testkit-regressions-gh-unavailable-"));
271
- tempDirs.push(tempDir);
272
- const document = normalizeRegressionCatalogDocument({
273
- schemaVersion: 1,
274
- entries: [
275
- {
276
- id: "bad-message",
277
- classification: "product_bug",
278
- issue: {
279
- repo: "acme/repo",
280
- number: 12,
281
- },
282
- summary: "API returns the wrong message",
283
- cause: "The payload is wrong.",
284
- lastReviewedAt: "2026-05-04",
285
- fingerprints: [
286
- {
287
- service: "api",
288
- type: "int",
289
- path: "src/api/routes/__testkit__/failing.int.testkit.ts",
290
- },
291
- ],
292
- },
293
- ],
294
- });
295
-
296
- const result = await validateRegressionIssues({
297
- productDir: tempDir,
298
- document,
299
- statusArtifact: {
300
- tests: [
301
- {
302
- service: "api",
303
- type: "int",
304
- path: "src/api/routes/__testkit__/failing.int.testkit.ts",
305
- status: "failed",
306
- },
307
- ],
308
- },
309
- config: {
310
- provider: "github",
311
- mode: "warn",
312
- },
313
- transport: {
314
- async fetchRepoIssues() {
315
- throw new Error("boom");
316
- },
317
- },
318
- });
319
-
320
- expect(result.summary.byCode.validation_unavailable).toBe(1);
321
- expect(result.summary.errors).toBe(0);
322
- expect(result.summary.warnings).toBe(1);
323
- });
324
- });
@@ -1,187 +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 {
6
- findMatchingRegressionEntries,
7
- normalizeRegressionCatalogDocument,
8
- renderRegressionCatalogMarkdown,
9
- validateRegressionCatalogDocument,
10
- } from "./index.mjs";
11
-
12
- const tempDirs = [];
13
-
14
- afterEach(() => {
15
- for (const tempDir of tempDirs.splice(0)) {
16
- fs.rmSync(tempDir, { recursive: true, force: true });
17
- }
18
- });
19
-
20
- describe("regression catalog", () => {
21
- it("matches entries by service, type, path, and failure key", () => {
22
- const document = normalizeRegressionCatalogDocument({
23
- schemaVersion: 1,
24
- entries: [
25
- {
26
- id: "bad-message",
27
- classification: "product_bug",
28
- issue: {
29
- repo: "acme/repo",
30
- number: 12,
31
- },
32
- summary: "API returns the wrong message",
33
- cause: "The payload is wrong.",
34
- lastReviewedAt: "2026-05-04",
35
- fingerprints: [
36
- {
37
- service: "api",
38
- type: "int",
39
- path: "src/api/routes/__testkit__/failing.int.testkit.ts",
40
- failureKey: "returns the wrong message",
41
- },
42
- ],
43
- },
44
- ],
45
- });
46
-
47
- const matches = findMatchingRegressionEntries(document, {
48
- service: "api",
49
- type: "int",
50
- path: "src/api/routes/__testkit__/failing.int.testkit.ts",
51
- error: "boom",
52
- failureDetails: [{ key: "returns the wrong message" }],
53
- });
54
-
55
- expect(matches).toHaveLength(1);
56
- expect(matches[0].id).toBe("bad-message");
57
- });
58
-
59
- it("matches fingerprint failureKey against detail title", () => {
60
- const document = normalizeRegressionCatalogDocument({
61
- schemaVersion: 1,
62
- entries: [
63
- {
64
- id: "missing-route",
65
- classification: "product_bug",
66
- issue: {
67
- repo: "acme/repo",
68
- number: 13,
69
- },
70
- summary: "Missing route returns the wrong status",
71
- cause: "The route returns 404.",
72
- lastReviewedAt: "2026-05-04",
73
- fingerprints: [
74
- {
75
- service: "api",
76
- type: "int",
77
- path: "__testkit__/health/http-failure.int.testkit.ts",
78
- failureKey: "GET /missing returns 200",
79
- },
80
- ],
81
- },
82
- ],
83
- });
84
-
85
- const matches = findMatchingRegressionEntries(document, {
86
- service: "api",
87
- type: "int",
88
- path: "__testkit__/health/http-failure.int.testkit.ts",
89
- error: "Default runtime thresholds failed: checks(rate==1.0)",
90
- failureDetails: [
91
- {
92
- key: "GET /missing > GET /missing returns 200",
93
- title: "GET /missing returns 200",
94
- },
95
- ],
96
- });
97
-
98
- expect(matches).toHaveLength(1);
99
- expect(matches[0].id).toBe("missing-route");
100
- });
101
-
102
- it("validates status coverage and filesystem fingerprints", () => {
103
- const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), "testkit-regressions-"));
104
- tempDirs.push(tempDir);
105
- const testPath = path.join(tempDir, "src/api/routes/__testkit__/failing.int.testkit.ts");
106
- fs.mkdirSync(path.dirname(testPath), { recursive: true });
107
- fs.writeFileSync(testPath, "export default {};\n");
108
-
109
- const document = normalizeRegressionCatalogDocument({
110
- schemaVersion: 1,
111
- issueRepo: "acme/repo",
112
- entries: [
113
- {
114
- id: "bad-message",
115
- classification: "product_bug",
116
- issue: {
117
- repo: "acme/repo",
118
- number: 12,
119
- },
120
- summary: "API returns the wrong message",
121
- cause: "The payload is wrong.",
122
- lastReviewedAt: "2026-05-04",
123
- fingerprints: [
124
- {
125
- service: "api",
126
- type: "int",
127
- path: "src/api/routes/__testkit__/failing.int.testkit.ts",
128
- },
129
- ],
130
- },
131
- ],
132
- });
133
-
134
- const result = validateRegressionCatalogDocument(document, {
135
- productDir: tempDir,
136
- statusArtifact: {
137
- tests: [
138
- {
139
- service: "api",
140
- type: "int",
141
- path: "src/api/routes/__testkit__/failing.int.testkit.ts",
142
- status: "failed",
143
- },
144
- {
145
- service: "api",
146
- type: "int",
147
- path: "src/api/routes/__testkit__/other.int.testkit.ts",
148
- status: "failed",
149
- },
150
- ],
151
- },
152
- });
153
-
154
- expect(result.errors).toEqual([]);
155
- expect(result.stats.failedTests).toBe(2);
156
- expect(result.stats.diagnosedFailedTests).toBe(1);
157
- expect(result.warnings).toContain(
158
- "New failing test not yet in regression catalog: src/api/routes/__testkit__/other.int.testkit.ts"
159
- );
160
- });
161
-
162
- it("renders markdown from the canonical document", () => {
163
- const markdown = renderRegressionCatalogMarkdown(
164
- normalizeRegressionCatalogDocument({
165
- schemaVersion: 1,
166
- entries: [
167
- {
168
- id: "bad-message",
169
- classification: "product_bug",
170
- issue: {
171
- repo: "acme/repo",
172
- number: 12,
173
- },
174
- summary: "API returns the wrong message",
175
- cause: "The payload is wrong.",
176
- lastReviewedAt: "2026-05-04",
177
- fingerprints: [{ path: "src/api/routes/__testkit__/failing.int.testkit.ts" }],
178
- },
179
- ],
180
- })
181
- );
182
-
183
- expect(markdown).toContain("# Regression Catalog");
184
- expect(markdown).toContain("API returns the wrong message");
185
- expect(markdown).toContain("#12");
186
- });
187
- });
@@ -1,167 +0,0 @@
1
- import { describe, expect, it } from "vitest";
2
- import {
3
- choosePlaywrightFinalResult,
4
- extractPlaywrightFailure,
5
- parsePlaywrightJsonResults,
6
- } from "./playwright.mjs";
7
-
8
- describe("playwright-report", () => {
9
- it("handles empty and invalid output", () => {
10
- expect(parsePlaywrightJsonResults("", "/tmp")).toEqual({
11
- fileResults: new Map(),
12
- errors: [],
13
- });
14
-
15
- const invalid = parsePlaywrightJsonResults("{", "/tmp");
16
- expect(invalid.errors[0]).toContain("Could not parse Playwright JSON output");
17
- });
18
-
19
- it("collects nested suite results", () => {
20
- const stdout = JSON.stringify({
21
- errors: [{ message: "reporter failure" }],
22
- suites: [
23
- {
24
- file: "/tmp/tests/auth.spec.js",
25
- specs: [
26
- {
27
- title: "auth works",
28
- tests: [
29
- {
30
- outcome: "unexpected",
31
- results: [
32
- {
33
- status: "failed",
34
- duration: 15,
35
- error: {
36
- message: "boom\nstack",
37
- },
38
- },
39
- ],
40
- },
41
- ],
42
- },
43
- ],
44
- },
45
- ],
46
- });
47
-
48
- const parsed = parsePlaywrightJsonResults(stdout, "/tmp");
49
- expect(parsed.errors).toEqual(["reporter failure"]);
50
- expect(parsed.fileResults.get("tests/auth.spec.js")).toEqual({
51
- failed: true,
52
- status: "failed",
53
- error: "boom",
54
- durationMs: 15,
55
- failureDetails: [
56
- {
57
- kind: "playwright-spec",
58
- key: "auth works",
59
- title: "auth works",
60
- count: 1,
61
- message: "boom",
62
- },
63
- ],
64
- });
65
- });
66
-
67
- it("marks files as skipped when every Playwright test is skipped", () => {
68
- const stdout = JSON.stringify({
69
- suites: [
70
- {
71
- file: "/tmp/tests/billing.spec.js",
72
- specs: [
73
- {
74
- title: "billing is stubbed",
75
- tests: [
76
- {
77
- outcome: "skipped",
78
- results: [
79
- {
80
- status: "skipped",
81
- duration: 7,
82
- },
83
- ],
84
- },
85
- ],
86
- },
87
- ],
88
- },
89
- ],
90
- });
91
-
92
- const parsed = parsePlaywrightJsonResults(stdout, "/tmp");
93
- expect(parsed.fileResults.get("tests/billing.spec.js")).toEqual({
94
- failed: false,
95
- status: "skipped",
96
- error: null,
97
- durationMs: 7,
98
- failureDetails: [],
99
- });
100
- });
101
-
102
- it("keeps file status passed when one spec passes and another is skipped", () => {
103
- const stdout = JSON.stringify({
104
- suites: [
105
- {
106
- file: "/tmp/tests/mixed.spec.js",
107
- specs: [
108
- {
109
- title: "passes",
110
- tests: [
111
- {
112
- outcome: "expected",
113
- results: [
114
- {
115
- status: "passed",
116
- duration: 5,
117
- },
118
- ],
119
- },
120
- ],
121
- },
122
- {
123
- title: "skips",
124
- tests: [
125
- {
126
- outcome: "skipped",
127
- results: [
128
- {
129
- status: "skipped",
130
- duration: 3,
131
- },
132
- ],
133
- },
134
- ],
135
- },
136
- ],
137
- },
138
- ],
139
- });
140
-
141
- const parsed = parsePlaywrightJsonResults(stdout, "/tmp");
142
- expect(parsed.fileResults.get("tests/mixed.spec.js")).toEqual({
143
- failed: false,
144
- status: "passed",
145
- error: null,
146
- durationMs: 8,
147
- failureDetails: [],
148
- });
149
- });
150
-
151
- it("chooses the final result and extracts failures", () => {
152
- expect(
153
- choosePlaywrightFinalResult([
154
- { status: "failed" },
155
- { status: "passed" },
156
- ])
157
- ).toEqual({ status: "passed" });
158
-
159
- expect(
160
- extractPlaywrightFailure(
161
- { error: { message: "first line\nsecond line" } },
162
- { title: "spec title" },
163
- { errors: [] }
164
- )
165
- ).toBe("first line");
166
- });
167
- });