@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,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
- });