@rpcbase/test 0.357.0 → 0.359.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.
Files changed (41) hide show
  1. package/dist/clearDatabase.js +12 -10
  2. package/dist/clearDatabase.js.map +1 -1
  3. package/dist/cli.js +556 -439
  4. package/dist/cli.js.map +1 -1
  5. package/dist/coverage/collect.js +101 -63
  6. package/dist/coverage/collect.js.map +1 -1
  7. package/dist/coverage/config-loader.js +230 -180
  8. package/dist/coverage/config-loader.js.map +1 -1
  9. package/dist/coverage/config.js +100 -76
  10. package/dist/coverage/config.js.map +1 -1
  11. package/dist/coverage/console-text-report.js +220 -175
  12. package/dist/coverage/console-text-report.js.map +1 -1
  13. package/dist/coverage/files.js +58 -45
  14. package/dist/coverage/files.js.map +1 -1
  15. package/dist/coverage/fixtures.js +38 -27
  16. package/dist/coverage/fixtures.js.map +1 -1
  17. package/dist/coverage/global-setup.js +18 -15
  18. package/dist/coverage/global-setup.js.map +1 -1
  19. package/dist/coverage/index.js +55 -38
  20. package/dist/coverage/index.js.map +1 -1
  21. package/dist/coverage/report.js +466 -341
  22. package/dist/coverage/report.js.map +1 -1
  23. package/dist/coverage/reporter.js +60 -47
  24. package/dist/coverage/reporter.js.map +1 -1
  25. package/dist/coverage/v8-tracker.js +147 -115
  26. package/dist/coverage/v8-tracker.js.map +1 -1
  27. package/dist/index.js +75 -46
  28. package/dist/index.js.map +1 -1
  29. package/dist/runners/playwright.js +563 -438
  30. package/dist/runners/playwright.js.map +1 -1
  31. package/dist/runners/process.d.ts.map +1 -1
  32. package/dist/runners/process.js +183 -125
  33. package/dist/runners/process.js.map +1 -1
  34. package/dist/runners/vitest.js +171 -124
  35. package/dist/runners/vitest.js.map +1 -1
  36. package/dist/serverCoverage.js +42 -28
  37. package/dist/serverCoverage.js.map +1 -1
  38. package/dist/vitest.config.d.ts +1 -1
  39. package/dist/vitest.config.js +74 -62
  40. package/dist/vitest.config.js.map +1 -1
  41. package/package.json +4 -4
@@ -1,490 +1,615 @@
1
- import { spawnAndCaptureStdout, spawnWithLogs, withRegisterShim } from "./process.js";
2
- import fsPromises from "node:fs/promises";
3
1
  import fs from "node:fs";
2
+ import fs$1 from "node:fs/promises";
4
3
  import path from "node:path";
5
4
  import { createRequire } from "node:module";
6
5
  import { fileURLToPath } from "node:url";
7
- //#region src/runners/playwright.ts
8
- var require = createRequire(import.meta.url);
9
- var moduleDir = path.dirname(fileURLToPath(import.meta.url));
10
- var COMBINED_COVERAGE_ENV_VAR = "RB_TEST_COMBINED_COVERAGE";
11
- var PLAYWRIGHT_RESULTS_FILE = path.join(process.cwd(), "build", "playwright", "results.json");
12
- var PLAYWRIGHT_OPTIONS_WITH_REQUIRED_VALUE = new Set([
13
- "--browser",
14
- "--config",
15
- "-c",
16
- "--grep",
17
- "-g",
18
- "--grep-invert",
19
- "--global-timeout",
20
- "--max-failures",
21
- "--output",
22
- "--project",
23
- "--repeat-each",
24
- "--reporter",
25
- "--retries",
26
- "--shard",
27
- "--timeout",
28
- "--trace",
29
- "--tsconfig",
30
- "--workers",
31
- "-j"
32
- ]);
33
- var PLAYWRIGHT_OPTIONS_WITH_OPTIONAL_VALUE = new Set([
34
- "--only-changed",
35
- "--update-snapshots",
36
- "-u"
37
- ]);
38
- var PLAYWRIGHT_OPTIONS_TO_REMOVE_FOR_WORKER_RETRY = new Set([
39
- "--last-failed",
40
- "--only-changed",
41
- "--output",
42
- "--retries",
43
- "--pass-with-no-tests",
44
- "--reporter",
45
- "--workers",
46
- "-j"
47
- ]);
48
- var PLAYWRIGHT_OPTIONS_TO_REMOVE_FOR_INITIAL_FRESH_RUN = new Set(["--retries"]);
49
- var PLAYWRIGHT_RETRY_LOG_LABEL_MAX_LENGTH = 20;
50
- async function runPlaywright(userArgs, { disableCoverage = false } = {}) {
51
- const configPath = fs.existsSync(path.join(process.cwd(), "playwright.config.ts")) ? path.join(process.cwd(), "playwright.config.ts") : path.join(moduleDir, "..", "playwright.config.ts");
52
- const hasCustomConfig = userArgs.some((arg) => {
53
- if (arg === "--config" || arg === "-c") return true;
54
- return arg.startsWith("--config=");
55
- });
56
- ensureJsxRuntimeShim(process.cwd());
57
- const launcher = resolvePlaywrightLauncher();
58
- const env = withRegisterShim(process.env);
59
- env[COMBINED_COVERAGE_ENV_VAR] = "1";
60
- if (disableCoverage) env.RB_DISABLE_COVERAGE = "1";
61
- const runtimeSettings = await resolveFreshWorkerRetrySettings({
62
- launcher,
63
- configPath,
64
- hasCustomConfig,
65
- userArgs,
66
- env
67
- });
68
- const configuredRetries = runtimeSettings.retries;
69
- const retryConcurrency = Math.max(1, runtimeSettings.workers ?? 1);
70
- const resultsMtimeBeforeRun = getFileMtimeMs(PLAYWRIGHT_RESULTS_FILE);
71
- const initialRunArgs = buildPlaywrightInitialFreshWorkerArgs(userArgs);
72
- const initialPlaywrightArgs = ["test"];
73
- if (!hasCustomConfig) initialPlaywrightArgs.push("--config", configPath);
74
- initialPlaywrightArgs.push(...initialRunArgs);
75
- try {
76
- await runPlaywrightOnce({
77
- launcher,
78
- args: initialPlaywrightArgs,
79
- env
80
- });
81
- return;
82
- } catch (error) {
83
- const summary = await readPlaywrightReportSummary(PLAYWRIGHT_RESULTS_FILE, resultsMtimeBeforeRun);
84
- if (!summary || configuredRetries <= 0 || summary.failedFiles.length === 0) throw error;
85
- let lastError = error;
86
- let failedFiles = summary.failedFiles;
87
- const maxAttempts = configuredRetries;
88
- for (let attempt = 1; attempt <= maxAttempts && failedFiles.length > 0; attempt += 1) {
89
- const activeRetryWorkers = Math.max(1, Math.min(retryConcurrency, failedFiles.length));
90
- console.warn(`[rb-test] Retrying ${failedFiles.length} failed Playwright file(s) with fresh workers (${attempt}/${maxAttempts}, up to ${activeRetryWorkers} in parallel)`);
91
- const retryResults = await runPlaywrightRetryAttempt({
92
- launcher,
93
- userArgs,
94
- failedFiles,
95
- retryConcurrency: activeRetryWorkers,
96
- configPath,
97
- hasCustomConfig,
98
- env,
99
- attempt
100
- });
101
- if (retryResults.lastError) lastError = retryResults.lastError;
102
- failedFiles = retryResults.failedFiles;
103
- }
104
- if (failedFiles.length === 0) return;
105
- throw lastError;
106
- }
107
- }
108
- function runPlaywrightOnce({ launcher, args, env, outputMode = "chunk", bufferOutput = false, successMessage, failureMessage, stdoutLinePrefix, stderrLinePrefix }) {
109
- return spawnWithLogs({
110
- name: "Playwright",
111
- launcher,
112
- args,
113
- env,
114
- outputMode,
115
- bufferOutput,
116
- successMessage: successMessage === void 0 ? "Playwright suite passed!" : successMessage ?? void 0,
117
- failureMessage: failureMessage === void 0 ? "Playwright failed" : failureMessage ?? void 0,
118
- stdoutLinePrefix,
119
- stderrLinePrefix
120
- });
6
+ import { withRegisterShim, spawnWithLogs, spawnAndCaptureStdout } from "./process.js";
7
+ const require$1 = createRequire(import.meta.url);
8
+ const moduleDir = path.dirname(fileURLToPath(import.meta.url));
9
+ const COMBINED_COVERAGE_ENV_VAR = "RB_TEST_COMBINED_COVERAGE";
10
+ const PLAYWRIGHT_RESULTS_FILE = path.join(process.cwd(), "build", "playwright", "results.json");
11
+ const PLAYWRIGHT_OPTIONS_WITH_REQUIRED_VALUE = /* @__PURE__ */ new Set(["--browser", "--config", "-c", "--grep", "-g", "--grep-invert", "--global-timeout", "--max-failures", "--output", "--project", "--repeat-each", "--reporter", "--retries", "--shard", "--timeout", "--trace", "--tsconfig", "--workers", "-j"]);
12
+ const PLAYWRIGHT_OPTIONS_WITH_OPTIONAL_VALUE = /* @__PURE__ */ new Set(["--only-changed", "--update-snapshots", "-u"]);
13
+ const PLAYWRIGHT_OPTIONS_TO_REMOVE_FOR_WORKER_RETRY = /* @__PURE__ */ new Set(["--last-failed", "--only-changed", "--output", "--retries", "--pass-with-no-tests", "--reporter", "--workers", "-j"]);
14
+ const PLAYWRIGHT_OPTIONS_TO_REMOVE_FOR_INITIAL_FRESH_RUN = /* @__PURE__ */ new Set(["--retries"]);
15
+ const PLAYWRIGHT_RETRY_LOG_LABEL_MAX_LENGTH = 20;
16
+ async function runPlaywright(userArgs, {
17
+ disableCoverage = false
18
+ } = {}) {
19
+ const configPath = fs.existsSync(path.join(process.cwd(), "playwright.config.ts")) ? path.join(process.cwd(), "playwright.config.ts") : path.join(moduleDir, "..", "playwright.config.ts");
20
+ const hasCustomConfig = userArgs.some((arg) => {
21
+ if (arg === "--config" || arg === "-c") {
22
+ return true;
23
+ }
24
+ return arg.startsWith("--config=");
25
+ });
26
+ ensureJsxRuntimeShim(process.cwd());
27
+ const launcher = resolvePlaywrightLauncher();
28
+ const env = withRegisterShim(process.env);
29
+ env[COMBINED_COVERAGE_ENV_VAR] = "1";
30
+ if (disableCoverage) {
31
+ env.RB_DISABLE_COVERAGE = "1";
32
+ }
33
+ const runtimeSettings = await resolveFreshWorkerRetrySettings({
34
+ launcher,
35
+ configPath,
36
+ hasCustomConfig,
37
+ userArgs,
38
+ env
39
+ });
40
+ const configuredRetries = runtimeSettings.retries;
41
+ const retryConcurrency = Math.max(1, runtimeSettings.workers ?? 1);
42
+ const resultsMtimeBeforeRun = getFileMtimeMs(PLAYWRIGHT_RESULTS_FILE);
43
+ const initialRunArgs = buildPlaywrightInitialFreshWorkerArgs(userArgs);
44
+ const initialPlaywrightArgs = ["test"];
45
+ if (!hasCustomConfig) {
46
+ initialPlaywrightArgs.push("--config", configPath);
47
+ }
48
+ initialPlaywrightArgs.push(...initialRunArgs);
49
+ try {
50
+ await runPlaywrightOnce({
51
+ launcher,
52
+ args: initialPlaywrightArgs,
53
+ env
54
+ });
55
+ return;
56
+ } catch (error) {
57
+ const summary = await readPlaywrightReportSummary(PLAYWRIGHT_RESULTS_FILE, resultsMtimeBeforeRun);
58
+ if (!summary || configuredRetries <= 0 || summary.failedFiles.length === 0) {
59
+ throw error;
60
+ }
61
+ let lastError = error;
62
+ let failedFiles = summary.failedFiles;
63
+ const maxAttempts = configuredRetries;
64
+ for (let attempt = 1; attempt <= maxAttempts && failedFiles.length > 0; attempt += 1) {
65
+ const activeRetryWorkers = Math.max(1, Math.min(retryConcurrency, failedFiles.length));
66
+ console.warn(`[rb-test] Retrying ${failedFiles.length} failed Playwright file(s) with fresh workers (${attempt}/${maxAttempts}, up to ${activeRetryWorkers} in parallel)`);
67
+ const retryResults = await runPlaywrightRetryAttempt({
68
+ launcher,
69
+ userArgs,
70
+ failedFiles,
71
+ retryConcurrency: activeRetryWorkers,
72
+ configPath,
73
+ hasCustomConfig,
74
+ env,
75
+ attempt
76
+ });
77
+ if (retryResults.lastError) {
78
+ lastError = retryResults.lastError;
79
+ }
80
+ failedFiles = retryResults.failedFiles;
81
+ }
82
+ if (failedFiles.length === 0) {
83
+ return;
84
+ }
85
+ throw lastError;
86
+ }
87
+ }
88
+ function runPlaywrightOnce({
89
+ launcher,
90
+ args,
91
+ env,
92
+ outputMode = "chunk",
93
+ bufferOutput = false,
94
+ successMessage,
95
+ failureMessage,
96
+ stdoutLinePrefix,
97
+ stderrLinePrefix
98
+ }) {
99
+ return spawnWithLogs({
100
+ name: "Playwright",
101
+ launcher,
102
+ args,
103
+ env,
104
+ outputMode,
105
+ bufferOutput,
106
+ successMessage: successMessage === void 0 ? "Playwright suite passed!" : successMessage ?? void 0,
107
+ failureMessage: failureMessage === void 0 ? "Playwright failed" : failureMessage ?? void 0,
108
+ stdoutLinePrefix,
109
+ stderrLinePrefix
110
+ });
121
111
  }
122
112
  function resolvePlaywrightLauncher() {
123
- const cliPath = resolveCliPath();
124
- if (cliPath) return {
125
- command: process.execPath,
126
- args: [cliPath]
127
- };
128
- const localBin = path.resolve(process.cwd(), "node_modules/.bin/playwright");
129
- if (fs.existsSync(localBin)) return {
130
- command: localBin,
131
- args: []
132
- };
133
- return {
134
- command: "playwright",
135
- args: []
136
- };
113
+ const cliPath = resolveCliPath();
114
+ if (cliPath) {
115
+ return {
116
+ command: process.execPath,
117
+ args: [cliPath]
118
+ };
119
+ }
120
+ const localBin = path.resolve(process.cwd(), "node_modules/.bin/playwright");
121
+ if (fs.existsSync(localBin)) {
122
+ return {
123
+ command: localBin,
124
+ args: []
125
+ };
126
+ }
127
+ return {
128
+ command: "playwright",
129
+ args: []
130
+ };
137
131
  }
138
132
  function resolveCliPath() {
139
- const searchRoots = [process.cwd(), moduleDir];
140
- for (const base of searchRoots) try {
141
- const pkgPath = require.resolve("@playwright/test/package.json", { paths: [base] });
142
- const cliPath = path.join(path.dirname(pkgPath), "cli.js");
143
- if (fs.existsSync(cliPath)) return cliPath;
144
- } catch (_error) {}
145
- return null;
133
+ const searchRoots = [process.cwd(), moduleDir];
134
+ for (const base of searchRoots) {
135
+ try {
136
+ const pkgPath = require$1.resolve("@playwright/test/package.json", {
137
+ paths: [base]
138
+ });
139
+ const cliPath = path.join(path.dirname(pkgPath), "cli.js");
140
+ if (fs.existsSync(cliPath)) {
141
+ return cliPath;
142
+ }
143
+ } catch (_error) {
144
+ }
145
+ }
146
+ return null;
146
147
  }
147
148
  function buildPlaywrightWorkerRetryArgs(userArgs, failedFiles, attempt) {
148
- return [
149
- ...removePlaywrightOptions(extractPlaywrightOptionArgs(userArgs), PLAYWRIGHT_OPTIONS_TO_REMOVE_FOR_WORKER_RETRY),
150
- "--retries=0",
151
- "--workers=1",
152
- "--reporter=list",
153
- "--output",
154
- buildPlaywrightRetryOutputDir(attempt, failedFiles),
155
- ...failedFiles
156
- ];
149
+ const optionArgs = extractPlaywrightOptionArgs(userArgs);
150
+ const sanitizedOptions = removePlaywrightOptions(optionArgs, PLAYWRIGHT_OPTIONS_TO_REMOVE_FOR_WORKER_RETRY);
151
+ return [...sanitizedOptions, "--retries=0", "--workers=1", "--reporter=list", "--output", buildPlaywrightRetryOutputDir(attempt, failedFiles), ...failedFiles];
157
152
  }
158
153
  function buildPlaywrightInitialFreshWorkerArgs(userArgs) {
159
- const sanitizedOptions = removePlaywrightOptions(extractPlaywrightOptionArgs(userArgs), PLAYWRIGHT_OPTIONS_TO_REMOVE_FOR_INITIAL_FRESH_RUN);
160
- const positionalArgs = extractPlaywrightPositionalArgs(userArgs);
161
- return [
162
- ...sanitizedOptions,
163
- "--retries=0",
164
- ...positionalArgs
165
- ];
166
- }
167
- async function resolveFreshWorkerRetrySettings({ launcher, configPath, hasCustomConfig, userArgs, env }) {
168
- const configuredSettings = await probeConfiguredPlaywrightSettings({
169
- launcher,
170
- configPath,
171
- hasCustomConfig,
172
- userArgs,
173
- env
174
- });
175
- return {
176
- retries: configuredSettings.retries ?? 0,
177
- workers: configuredSettings.workers
178
- };
179
- }
180
- async function probeConfiguredPlaywrightSettings({ launcher, configPath, hasCustomConfig, userArgs, env }) {
181
- const probeArgs = ["test"];
182
- if (!hasCustomConfig) probeArgs.push("--config", configPath);
183
- probeArgs.push("--list", "--reporter=json", ...extractPlaywrightProjectArgs(userArgs));
184
- try {
185
- const json = parseJsonObjectFromText(await spawnAndCaptureStdout({
186
- name: "Playwright retries probe",
187
- launcher,
188
- args: probeArgs,
189
- env
190
- }));
191
- if (!json) return {
192
- retries: null,
193
- workers: null
194
- };
195
- return {
196
- retries: resolvePlaywrightRetriesFromReport(json),
197
- workers: resolvePlaywrightWorkersFromReport(json)
198
- };
199
- } catch (_error) {
200
- return {
201
- retries: null,
202
- workers: null
203
- };
204
- }
154
+ const optionArgs = extractPlaywrightOptionArgs(userArgs);
155
+ const sanitizedOptions = removePlaywrightOptions(optionArgs, PLAYWRIGHT_OPTIONS_TO_REMOVE_FOR_INITIAL_FRESH_RUN);
156
+ const positionalArgs = extractPlaywrightPositionalArgs(userArgs);
157
+ return [...sanitizedOptions, "--retries=0", ...positionalArgs];
158
+ }
159
+ async function resolveFreshWorkerRetrySettings({
160
+ launcher,
161
+ configPath,
162
+ hasCustomConfig,
163
+ userArgs,
164
+ env
165
+ }) {
166
+ const configuredSettings = await probeConfiguredPlaywrightSettings({
167
+ launcher,
168
+ configPath,
169
+ hasCustomConfig,
170
+ userArgs,
171
+ env
172
+ });
173
+ return {
174
+ retries: configuredSettings.retries ?? 0,
175
+ workers: configuredSettings.workers
176
+ };
177
+ }
178
+ async function probeConfiguredPlaywrightSettings({
179
+ launcher,
180
+ configPath,
181
+ hasCustomConfig,
182
+ userArgs,
183
+ env
184
+ }) {
185
+ const probeArgs = ["test"];
186
+ if (!hasCustomConfig) {
187
+ probeArgs.push("--config", configPath);
188
+ }
189
+ probeArgs.push("--list", "--reporter=json", ...extractPlaywrightProjectArgs(userArgs));
190
+ try {
191
+ const stdout = await spawnAndCaptureStdout({
192
+ name: "Playwright retries probe",
193
+ launcher,
194
+ args: probeArgs,
195
+ env
196
+ });
197
+ const json = parseJsonObjectFromText(stdout);
198
+ if (!json) {
199
+ return {
200
+ retries: null,
201
+ workers: null
202
+ };
203
+ }
204
+ return {
205
+ retries: resolvePlaywrightRetriesFromReport(json),
206
+ workers: resolvePlaywrightWorkersFromReport(json)
207
+ };
208
+ } catch (_error) {
209
+ return {
210
+ retries: null,
211
+ workers: null
212
+ };
213
+ }
205
214
  }
206
215
  function extractPlaywrightProjectArgs(userArgs) {
207
- const output = [];
208
- for (let i = 0; i < userArgs.length; i += 1) {
209
- const arg = userArgs[i];
210
- if (arg === "--") break;
211
- if (arg === "--project") {
212
- const next = userArgs[i + 1];
213
- if (next != null) {
214
- output.push(arg, next);
215
- i += 1;
216
- }
217
- continue;
218
- }
219
- if (arg.startsWith("--project=")) output.push(arg);
220
- }
221
- return output;
216
+ const output = [];
217
+ for (let i = 0; i < userArgs.length; i += 1) {
218
+ const arg = userArgs[i];
219
+ if (arg === "--") {
220
+ break;
221
+ }
222
+ if (arg === "--project") {
223
+ const next = userArgs[i + 1];
224
+ if (next != null) {
225
+ output.push(arg, next);
226
+ i += 1;
227
+ }
228
+ continue;
229
+ }
230
+ if (arg.startsWith("--project=")) {
231
+ output.push(arg);
232
+ }
233
+ }
234
+ return output;
222
235
  }
223
236
  function parseJsonObjectFromText(input) {
224
- try {
225
- return JSON.parse(input);
226
- } catch {
227
- const start = input.indexOf("{");
228
- const end = input.lastIndexOf("}");
229
- if (start === -1 || end === -1 || end <= start) return null;
230
- try {
231
- return JSON.parse(input.slice(start, end + 1));
232
- } catch {
233
- return null;
234
- }
235
- }
237
+ try {
238
+ return JSON.parse(input);
239
+ } catch {
240
+ const start = input.indexOf("{");
241
+ const end = input.lastIndexOf("}");
242
+ if (start === -1 || end === -1 || end <= start) {
243
+ return null;
244
+ }
245
+ try {
246
+ return JSON.parse(input.slice(start, end + 1));
247
+ } catch {
248
+ return null;
249
+ }
250
+ }
236
251
  }
237
252
  function extractPlaywrightPositionalArgs(userArgs) {
238
- const output = [];
239
- for (let i = 0; i < userArgs.length; i += 1) {
240
- const arg = userArgs[i];
241
- if (arg === "--") break;
242
- if (!arg.startsWith("-")) {
243
- output.push(arg);
244
- continue;
245
- }
246
- if (arg.includes("=")) continue;
247
- if (PLAYWRIGHT_OPTIONS_WITH_REQUIRED_VALUE.has(arg)) {
248
- if (userArgs[i + 1] !== void 0) i += 1;
249
- continue;
250
- }
251
- if (PLAYWRIGHT_OPTIONS_WITH_OPTIONAL_VALUE.has(arg)) {
252
- const next = userArgs[i + 1];
253
- if (next !== void 0 && !next.startsWith("-")) i += 1;
254
- }
255
- }
256
- return output;
253
+ const output = [];
254
+ for (let i = 0; i < userArgs.length; i += 1) {
255
+ const arg = userArgs[i];
256
+ if (arg === "--") {
257
+ break;
258
+ }
259
+ if (!arg.startsWith("-")) {
260
+ output.push(arg);
261
+ continue;
262
+ }
263
+ if (arg.includes("=")) {
264
+ continue;
265
+ }
266
+ if (PLAYWRIGHT_OPTIONS_WITH_REQUIRED_VALUE.has(arg)) {
267
+ const next = userArgs[i + 1];
268
+ if (next !== void 0) {
269
+ i += 1;
270
+ }
271
+ continue;
272
+ }
273
+ if (PLAYWRIGHT_OPTIONS_WITH_OPTIONAL_VALUE.has(arg)) {
274
+ const next = userArgs[i + 1];
275
+ if (next !== void 0 && !next.startsWith("-")) {
276
+ i += 1;
277
+ }
278
+ }
279
+ }
280
+ return output;
257
281
  }
258
282
  function removePlaywrightOptions(optionArgs, optionsToRemove) {
259
- const output = [];
260
- for (let i = 0; i < optionArgs.length; i += 1) {
261
- const arg = optionArgs[i];
262
- const normalized = arg.split("=")[0];
263
- if (!arg.startsWith("-") || !optionsToRemove.has(normalized)) {
264
- output.push(arg);
265
- continue;
266
- }
267
- if (arg.includes("=")) continue;
268
- if (PLAYWRIGHT_OPTIONS_WITH_REQUIRED_VALUE.has(normalized)) {
269
- if (optionArgs[i + 1] !== void 0) i += 1;
270
- continue;
271
- }
272
- if (PLAYWRIGHT_OPTIONS_WITH_OPTIONAL_VALUE.has(normalized)) {
273
- const next = optionArgs[i + 1];
274
- if (next !== void 0 && !next.startsWith("-")) i += 1;
275
- }
276
- }
277
- return output;
283
+ const output = [];
284
+ for (let i = 0; i < optionArgs.length; i += 1) {
285
+ const arg = optionArgs[i];
286
+ const normalized = arg.split("=")[0];
287
+ if (!arg.startsWith("-") || !optionsToRemove.has(normalized)) {
288
+ output.push(arg);
289
+ continue;
290
+ }
291
+ if (arg.includes("=")) {
292
+ continue;
293
+ }
294
+ if (PLAYWRIGHT_OPTIONS_WITH_REQUIRED_VALUE.has(normalized)) {
295
+ const next = optionArgs[i + 1];
296
+ if (next !== void 0) {
297
+ i += 1;
298
+ }
299
+ continue;
300
+ }
301
+ if (PLAYWRIGHT_OPTIONS_WITH_OPTIONAL_VALUE.has(normalized)) {
302
+ const next = optionArgs[i + 1];
303
+ if (next !== void 0 && !next.startsWith("-")) {
304
+ i += 1;
305
+ }
306
+ }
307
+ }
308
+ return output;
278
309
  }
279
310
  function extractPlaywrightOptionArgs(userArgs) {
280
- const output = [];
281
- for (let i = 0; i < userArgs.length; i += 1) {
282
- const arg = userArgs[i];
283
- if (arg === "--") break;
284
- if (!arg.startsWith("-")) continue;
285
- output.push(arg);
286
- if (arg.includes("=")) continue;
287
- if (PLAYWRIGHT_OPTIONS_WITH_REQUIRED_VALUE.has(arg)) {
288
- const next = userArgs[i + 1];
289
- if (next !== void 0) {
290
- output.push(next);
291
- i += 1;
292
- }
293
- continue;
294
- }
295
- if (PLAYWRIGHT_OPTIONS_WITH_OPTIONAL_VALUE.has(arg)) {
296
- const next = userArgs[i + 1];
297
- if (next !== void 0 && !next.startsWith("-")) {
298
- output.push(next);
299
- i += 1;
300
- }
301
- }
302
- }
303
- return output;
311
+ const output = [];
312
+ for (let i = 0; i < userArgs.length; i += 1) {
313
+ const arg = userArgs[i];
314
+ if (arg === "--") {
315
+ break;
316
+ }
317
+ if (!arg.startsWith("-")) {
318
+ continue;
319
+ }
320
+ output.push(arg);
321
+ if (arg.includes("=")) {
322
+ continue;
323
+ }
324
+ if (PLAYWRIGHT_OPTIONS_WITH_REQUIRED_VALUE.has(arg)) {
325
+ const next = userArgs[i + 1];
326
+ if (next !== void 0) {
327
+ output.push(next);
328
+ i += 1;
329
+ }
330
+ continue;
331
+ }
332
+ if (PLAYWRIGHT_OPTIONS_WITH_OPTIONAL_VALUE.has(arg)) {
333
+ const next = userArgs[i + 1];
334
+ if (next !== void 0 && !next.startsWith("-")) {
335
+ output.push(next);
336
+ i += 1;
337
+ }
338
+ }
339
+ }
340
+ return output;
304
341
  }
305
342
  async function readPlaywrightReportSummary(resultsFilePath, newerThanMtimeMs) {
306
- const stats = await fsPromises.stat(resultsFilePath).catch(() => null);
307
- if (!stats) return null;
308
- if (newerThanMtimeMs != null && stats.mtimeMs <= newerThanMtimeMs) return null;
309
- const data = await readJson(resultsFilePath);
310
- if (!data || typeof data !== "object") return null;
311
- return { failedFiles: resolveFailedPlaywrightFiles(data) };
343
+ const stats = await fs$1.stat(resultsFilePath).catch(() => null);
344
+ if (!stats) {
345
+ return null;
346
+ }
347
+ if (newerThanMtimeMs != null && stats.mtimeMs <= newerThanMtimeMs) {
348
+ return null;
349
+ }
350
+ const data = await readJson(resultsFilePath);
351
+ if (!data || typeof data !== "object") {
352
+ return null;
353
+ }
354
+ return {
355
+ failedFiles: resolveFailedPlaywrightFiles(data)
356
+ };
312
357
  }
313
358
  function getFileMtimeMs(filePath) {
314
- try {
315
- return fs.statSync(filePath).mtimeMs;
316
- } catch {
317
- return null;
318
- }
359
+ try {
360
+ return fs.statSync(filePath).mtimeMs;
361
+ } catch {
362
+ return null;
363
+ }
319
364
  }
320
365
  function resolvePlaywrightRetriesFromReport(data) {
321
- const retriesFromProjects = (Array.isArray(data?.config?.projects) ? data.config.projects : []).map((project) => Number(project?.retries)).filter((value) => Number.isFinite(value)).map((value) => Math.max(0, Math.floor(value)));
322
- if (retriesFromProjects.length > 0) return Math.max(...retriesFromProjects);
323
- const fallback = Number(data?.config?.retries);
324
- if (Number.isFinite(fallback)) return Math.max(0, Math.floor(fallback));
325
- return 0;
366
+ const projects = Array.isArray(data?.config?.projects) ? data.config.projects : [];
367
+ const retriesFromProjects = projects.map((project) => Number(project?.retries)).filter((value) => Number.isFinite(value)).map((value) => Math.max(0, Math.floor(value)));
368
+ if (retriesFromProjects.length > 0) {
369
+ return Math.max(...retriesFromProjects);
370
+ }
371
+ const fallback = Number(data?.config?.retries);
372
+ if (Number.isFinite(fallback)) {
373
+ return Math.max(0, Math.floor(fallback));
374
+ }
375
+ return 0;
326
376
  }
327
377
  function resolvePlaywrightWorkersFromReport(data) {
328
- const configWorkers = Number(data?.config?.workers);
329
- if (Number.isFinite(configWorkers)) return Math.max(1, Math.floor(configWorkers));
330
- const workersFromProjects = (Array.isArray(data?.config?.projects) ? data.config.projects : []).map((project) => Number(project?.metadata?.actualWorkers ?? project?.workers)).filter((value) => Number.isFinite(value)).map((value) => Math.max(1, Math.floor(value)));
331
- if (workersFromProjects.length > 0) return Math.max(...workersFromProjects);
332
- return null;
378
+ const configWorkers = Number(data?.config?.workers);
379
+ if (Number.isFinite(configWorkers)) {
380
+ return Math.max(1, Math.floor(configWorkers));
381
+ }
382
+ const projects = Array.isArray(data?.config?.projects) ? data.config.projects : [];
383
+ const workersFromProjects = projects.map((project) => Number(project?.metadata?.actualWorkers ?? project?.workers)).filter((value) => Number.isFinite(value)).map((value) => Math.max(1, Math.floor(value)));
384
+ if (workersFromProjects.length > 0) {
385
+ return Math.max(...workersFromProjects);
386
+ }
387
+ return null;
333
388
  }
334
389
  function resolveFailedPlaywrightFiles(data) {
335
- const suites = Array.isArray(data?.suites) ? data.suites : [];
336
- const rootDir = typeof data?.config?.rootDir === "string" ? data.config.rootDir : null;
337
- const failedFiles = /* @__PURE__ */ new Set();
338
- for (const suite of suites) collectFailedPlaywrightFiles(suite, failedFiles, rootDir);
339
- return Array.from(failedFiles).sort();
390
+ const suites = Array.isArray(data?.suites) ? data.suites : [];
391
+ const rootDir = typeof data?.config?.rootDir === "string" ? data.config.rootDir : null;
392
+ const failedFiles = /* @__PURE__ */ new Set();
393
+ for (const suite of suites) {
394
+ collectFailedPlaywrightFiles(suite, failedFiles, rootDir);
395
+ }
396
+ return Array.from(failedFiles).sort();
340
397
  }
341
398
  function collectFailedPlaywrightFiles(suite, output, rootDir) {
342
- const specs = Array.isArray(suite?.specs) ? suite.specs : [];
343
- for (const spec of specs) {
344
- if (isPlaywrightSpecSuccessful(spec)) continue;
345
- const file = normalizePlaywrightReportFile(spec?.file ?? suite?.file, rootDir);
346
- if (file) output.add(file);
347
- }
348
- const innerSuites = Array.isArray(suite?.suites) ? suite.suites : [];
349
- for (const innerSuite of innerSuites) collectFailedPlaywrightFiles(innerSuite, output, rootDir);
399
+ const specs = Array.isArray(suite?.specs) ? suite.specs : [];
400
+ for (const spec of specs) {
401
+ if (isPlaywrightSpecSuccessful(spec)) {
402
+ continue;
403
+ }
404
+ const file = normalizePlaywrightReportFile(spec?.file ?? suite?.file, rootDir);
405
+ if (file) {
406
+ output.add(file);
407
+ }
408
+ }
409
+ const innerSuites = Array.isArray(suite?.suites) ? suite.suites : [];
410
+ for (const innerSuite of innerSuites) {
411
+ collectFailedPlaywrightFiles(innerSuite, output, rootDir);
412
+ }
350
413
  }
351
414
  function isPlaywrightSpecSuccessful(spec) {
352
- if (typeof spec?.ok === "boolean") return spec.ok;
353
- const tests = Array.isArray(spec?.tests) ? spec.tests : [];
354
- if (tests.length === 0) return false;
355
- return tests.every((test) => {
356
- const testStatus = String(test?.status ?? "");
357
- if (testStatus === "expected" || testStatus === "skipped" || testStatus === "flaky") return true;
358
- const results = Array.isArray(test?.results) ? test.results : [];
359
- if (results.length === 0) return false;
360
- return results.every((result) => result?.status === "passed" || result?.status === "skipped");
361
- });
415
+ if (typeof spec?.ok === "boolean") {
416
+ return spec.ok;
417
+ }
418
+ const tests = Array.isArray(spec?.tests) ? spec.tests : [];
419
+ if (tests.length === 0) {
420
+ return false;
421
+ }
422
+ return tests.every((test) => {
423
+ const testStatus = String(test?.status ?? "");
424
+ if (testStatus === "expected" || testStatus === "skipped" || testStatus === "flaky") {
425
+ return true;
426
+ }
427
+ const results = Array.isArray(test?.results) ? test.results : [];
428
+ if (results.length === 0) {
429
+ return false;
430
+ }
431
+ return results.every((result) => result?.status === "passed" || result?.status === "skipped");
432
+ });
362
433
  }
363
434
  function normalizePlaywrightReportFile(filePath, rootDir) {
364
- const raw = String(filePath ?? "").trim();
365
- if (!raw) return null;
366
- let absolutePath;
367
- if (path.isAbsolute(raw)) absolutePath = path.normalize(raw);
368
- else {
369
- const cwdCandidate = path.resolve(process.cwd(), raw);
370
- const rootCandidate = rootDir ? path.resolve(rootDir, raw) : null;
371
- if (rootCandidate && fs.existsSync(rootCandidate)) absolutePath = rootCandidate;
372
- else if (fs.existsSync(cwdCandidate)) absolutePath = cwdCandidate;
373
- else absolutePath = rootCandidate ?? cwdCandidate;
374
- }
375
- const relative = path.relative(process.cwd(), absolutePath);
376
- if (relative === "" || !relative.startsWith("..") && !path.isAbsolute(relative)) return toPosixPath(relative || raw);
377
- return toPosixPath(raw);
435
+ const raw = String(filePath ?? "").trim();
436
+ if (!raw) {
437
+ return null;
438
+ }
439
+ let absolutePath;
440
+ if (path.isAbsolute(raw)) {
441
+ absolutePath = path.normalize(raw);
442
+ } else {
443
+ const cwdCandidate = path.resolve(process.cwd(), raw);
444
+ const rootCandidate = rootDir ? path.resolve(rootDir, raw) : null;
445
+ if (rootCandidate && fs.existsSync(rootCandidate)) {
446
+ absolutePath = rootCandidate;
447
+ } else if (fs.existsSync(cwdCandidate)) {
448
+ absolutePath = cwdCandidate;
449
+ } else {
450
+ absolutePath = rootCandidate ?? cwdCandidate;
451
+ }
452
+ }
453
+ const relative = path.relative(process.cwd(), absolutePath);
454
+ if (relative === "" || !relative.startsWith("..") && !path.isAbsolute(relative)) {
455
+ return toPosixPath(relative || raw);
456
+ }
457
+ return toPosixPath(raw);
378
458
  }
379
459
  function toPosixPath(input) {
380
- return String(input ?? "").replaceAll("\\", "/").split(path.sep).join("/");
460
+ return String(input ?? "").replaceAll("\\", "/").split(path.sep).join("/");
381
461
  }
382
462
  function buildPlaywrightRetryOutputDir(attempt, failedFiles) {
383
- const slug = failedFiles.map((file) => toPosixPath(file).replace(/[^a-zA-Z0-9._/-]+/g, "-").replace(/\//g, "__")).join("--");
384
- return toPosixPath(path.join("build", "playwright", "test-results", "rb-retries", `attempt-${attempt}`, slug));
463
+ const slug = failedFiles.map((file) => toPosixPath(file).replace(/[^a-zA-Z0-9._/-]+/g, "-").replace(/\//g, "__")).join("--");
464
+ return toPosixPath(path.join("build", "playwright", "test-results", "rb-retries", `attempt-${attempt}`, slug));
385
465
  }
386
466
  function createPlaywrightRetryEnv(baseEnv) {
387
- return {
388
- ...baseEnv,
389
- PLAYWRIGHT_FORCE_TTY: "false"
390
- };
467
+ return {
468
+ ...baseEnv,
469
+ PLAYWRIGHT_FORCE_TTY: "false"
470
+ };
391
471
  }
392
472
  function truncatePlaywrightRetryLogLabel(label, maxLength = PLAYWRIGHT_RETRY_LOG_LABEL_MAX_LENGTH) {
393
- if (label.length <= maxLength) return label;
394
- if (maxLength <= 3) return ".".repeat(Math.max(0, maxLength));
395
- const visibleChars = maxLength - 3;
396
- const startLength = Math.ceil(visibleChars / 2);
397
- const endLength = Math.floor(visibleChars / 2);
398
- return `${label.slice(0, startLength)}...${label.slice(-endLength)}`;
473
+ if (label.length <= maxLength) {
474
+ return label;
475
+ }
476
+ if (maxLength <= 3) {
477
+ return ".".repeat(Math.max(0, maxLength));
478
+ }
479
+ const visibleChars = maxLength - 3;
480
+ const startLength = Math.ceil(visibleChars / 2);
481
+ const endLength = Math.floor(visibleChars / 2);
482
+ return `${label.slice(0, startLength)}...${label.slice(-endLength)}`;
399
483
  }
400
484
  function getPlaywrightRetryLogName(failedFile) {
401
- const normalizedFile = toPosixPath(failedFile);
402
- const relativeFile = normalizedFile.startsWith("build/spec/") ? normalizedFile.slice(11) : normalizedFile;
403
- return relativeFile.replace(/\.(spec|test)\.[^.]+$/i, "").replace(/\.[^.]+$/i, "").trim() || relativeFile || normalizedFile;
404
- }
405
- function formatPlaywrightRetryBracketLabel({ failedFile, suffix = "" }) {
406
- return `[${truncatePlaywrightRetryLogLabel(getPlaywrightRetryLogName(failedFile), Math.max(1, PLAYWRIGHT_RETRY_LOG_LABEL_MAX_LENGTH - suffix.length))}${suffix}]`;
407
- }
408
- function formatPlaywrightRetryLogLabel({ failedFile }) {
409
- return formatPlaywrightRetryBracketLabel({ failedFile });
410
- }
411
- function formatPlaywrightRetryLinePrefix({ failedFile, stream }) {
412
- return stream === "stderr" ? `${formatPlaywrightRetryBracketLabel({
413
- failedFile,
414
- suffix: " stderr"
415
- })} ` : `${formatPlaywrightRetryLogLabel({ failedFile })} `;
416
- }
417
- async function runPlaywrightRetryAttempt({ launcher, userArgs, failedFiles, retryConcurrency, configPath, hasCustomConfig, env, attempt }) {
418
- const failedAgain = /* @__PURE__ */ new Set();
419
- let lastError = null;
420
- let nextIndex = 0;
421
- const retryEnv = createPlaywrightRetryEnv(env);
422
- async function runNext() {
423
- while (nextIndex < failedFiles.length) {
424
- const fileIndex = nextIndex;
425
- nextIndex += 1;
426
- const failedFile = failedFiles[fileIndex];
427
- const retryLogLabel = formatPlaywrightRetryLogLabel({ failedFile });
428
- const retryArgs = buildPlaywrightWorkerRetryArgs(userArgs, [failedFile], attempt);
429
- const retryPlaywrightArgs = ["test"];
430
- if (!hasCustomConfig) retryPlaywrightArgs.push("--config", configPath);
431
- retryPlaywrightArgs.push(...retryArgs);
432
- try {
433
- await runPlaywrightOnce({
434
- launcher,
435
- args: retryPlaywrightArgs,
436
- env: retryEnv,
437
- outputMode: "line",
438
- bufferOutput: true,
439
- successMessage: null,
440
- failureMessage: `${retryLogLabel} Playwright failed`,
441
- stdoutLinePrefix: formatPlaywrightRetryLinePrefix({
442
- failedFile,
443
- stream: "stdout"
444
- }),
445
- stderrLinePrefix: formatPlaywrightRetryLinePrefix({
446
- failedFile,
447
- stream: "stderr"
448
- })
449
- });
450
- } catch (retryError) {
451
- lastError = retryError;
452
- failedAgain.add(failedFile);
453
- }
454
- }
455
- }
456
- await Promise.all(Array.from({ length: Math.max(1, Math.min(retryConcurrency, failedFiles.length)) }, () => runNext()));
457
- return {
458
- failedFiles: failedFiles.filter((failedFile) => failedAgain.has(failedFile)),
459
- lastError
460
- };
485
+ const normalizedFile = toPosixPath(failedFile);
486
+ const relativeFile = normalizedFile.startsWith("build/spec/") ? normalizedFile.slice("build/spec/".length) : normalizedFile;
487
+ const strippedBaseName = relativeFile.replace(/\.(spec|test)\.[^.]+$/i, "").replace(/\.[^.]+$/i, "").trim();
488
+ return strippedBaseName || relativeFile || normalizedFile;
489
+ }
490
+ function formatPlaywrightRetryBracketLabel({
491
+ failedFile,
492
+ suffix = ""
493
+ }) {
494
+ const label = truncatePlaywrightRetryLogLabel(getPlaywrightRetryLogName(failedFile), Math.max(1, PLAYWRIGHT_RETRY_LOG_LABEL_MAX_LENGTH - suffix.length));
495
+ return `[${label}${suffix}]`;
496
+ }
497
+ function formatPlaywrightRetryLogLabel({
498
+ failedFile
499
+ }) {
500
+ return formatPlaywrightRetryBracketLabel({
501
+ failedFile
502
+ });
503
+ }
504
+ function formatPlaywrightRetryLinePrefix({
505
+ failedFile,
506
+ stream
507
+ }) {
508
+ return stream === "stderr" ? `${formatPlaywrightRetryBracketLabel({
509
+ failedFile,
510
+ suffix: " stderr"
511
+ })} ` : `${formatPlaywrightRetryLogLabel({
512
+ failedFile
513
+ })} `;
514
+ }
515
+ async function runPlaywrightRetryAttempt({
516
+ launcher,
517
+ userArgs,
518
+ failedFiles,
519
+ retryConcurrency,
520
+ configPath,
521
+ hasCustomConfig,
522
+ env,
523
+ attempt
524
+ }) {
525
+ const failedAgain = /* @__PURE__ */ new Set();
526
+ let lastError = null;
527
+ let nextIndex = 0;
528
+ const retryEnv = createPlaywrightRetryEnv(env);
529
+ async function runNext() {
530
+ while (nextIndex < failedFiles.length) {
531
+ const fileIndex = nextIndex;
532
+ nextIndex += 1;
533
+ const failedFile = failedFiles[fileIndex];
534
+ const retryLogLabel = formatPlaywrightRetryLogLabel({
535
+ failedFile
536
+ });
537
+ const retryArgs = buildPlaywrightWorkerRetryArgs(userArgs, [failedFile], attempt);
538
+ const retryPlaywrightArgs = ["test"];
539
+ if (!hasCustomConfig) {
540
+ retryPlaywrightArgs.push("--config", configPath);
541
+ }
542
+ retryPlaywrightArgs.push(...retryArgs);
543
+ try {
544
+ console.warn(`${retryLogLabel} Starting fresh-worker retry`);
545
+ await runPlaywrightOnce({
546
+ launcher,
547
+ args: retryPlaywrightArgs,
548
+ env: retryEnv,
549
+ outputMode: "line",
550
+ bufferOutput: true,
551
+ successMessage: null,
552
+ failureMessage: `${retryLogLabel} Playwright failed`,
553
+ stdoutLinePrefix: formatPlaywrightRetryLinePrefix({
554
+ failedFile,
555
+ stream: "stdout"
556
+ }),
557
+ stderrLinePrefix: formatPlaywrightRetryLinePrefix({
558
+ failedFile,
559
+ stream: "stderr"
560
+ })
561
+ });
562
+ } catch (retryError) {
563
+ lastError = retryError;
564
+ failedAgain.add(failedFile);
565
+ }
566
+ }
567
+ }
568
+ await Promise.all(Array.from({
569
+ length: Math.max(1, Math.min(retryConcurrency, failedFiles.length))
570
+ }, () => runNext()));
571
+ return {
572
+ failedFiles: failedFiles.filter((failedFile) => failedAgain.has(failedFile)),
573
+ lastError
574
+ };
461
575
  }
462
576
  async function readJson(filePath) {
463
- try {
464
- const raw = await fsPromises.readFile(filePath, "utf8");
465
- return JSON.parse(raw);
466
- } catch {
467
- return null;
468
- }
577
+ try {
578
+ const raw = await fs$1.readFile(filePath, "utf8");
579
+ return JSON.parse(raw);
580
+ } catch {
581
+ return null;
582
+ }
469
583
  }
470
584
  function ensureJsxRuntimeShim(projectRoot) {
471
- const shimDir = path.join(projectRoot, "node_modules", "playwright");
472
- fs.mkdirSync(shimDir, { recursive: true });
473
- for (const { file, target } of [{
474
- file: "jsx-runtime.js",
475
- target: "react/jsx-runtime"
476
- }, {
477
- file: "jsx-dev-runtime.js",
478
- target: "react/jsx-dev-runtime"
479
- }]) {
480
- const filePath = path.join(shimDir, file);
481
- if (!fs.existsSync(filePath)) {
482
- const content = `export * from "${target}";\nexport { default } from "${target}";\n`;
483
- fs.writeFileSync(filePath, content, "utf8");
484
- }
485
- }
486
- }
487
- //#endregion
488
- export { runPlaywright };
489
-
490
- //# sourceMappingURL=playwright.js.map
585
+ const shimDir = path.join(projectRoot, "node_modules", "playwright");
586
+ fs.mkdirSync(shimDir, {
587
+ recursive: true
588
+ });
589
+ const shims = [{
590
+ file: "jsx-runtime.js",
591
+ target: "react/jsx-runtime"
592
+ }, {
593
+ file: "jsx-dev-runtime.js",
594
+ target: "react/jsx-dev-runtime"
595
+ }];
596
+ for (const {
597
+ file,
598
+ target
599
+ } of shims) {
600
+ const filePath = path.join(shimDir, file);
601
+ if (!fs.existsSync(filePath)) {
602
+ const content = `export * from "${target}";
603
+ export { default } from "${target}";
604
+ `;
605
+ fs.writeFileSync(filePath, content, "utf8");
606
+ }
607
+ }
608
+ }
609
+ export {
610
+ createPlaywrightRetryEnv,
611
+ formatPlaywrightRetryLinePrefix,
612
+ formatPlaywrightRetryLogLabel,
613
+ runPlaywright
614
+ };
615
+ //# sourceMappingURL=playwright.js.map