|
1
|
"use strict"; |
|
2
|
var __create = Object.create; |
|
3
|
var __defProp = Object.defineProperty; |
|
4
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor; |
|
5
|
var __getOwnPropNames = Object.getOwnPropertyNames; |
|
6
|
var __getProtoOf = Object.getPrototypeOf; |
|
7
|
var __hasOwnProp = Object.prototype.hasOwnProperty; |
|
8
|
var __export = (target, all) => { |
|
9
|
for (var name in all) |
|
10
|
__defProp(target, name, { get: all[name], enumerable: true }); |
|
11
|
}; |
|
12
|
var __copyProps = (to, from, except, desc) => { |
|
13
|
if (from && typeof from === "object" || typeof from === "function") { |
|
14
|
for (let key of __getOwnPropNames(from)) |
|
15
|
if (!__hasOwnProp.call(to, key) && key !== except) |
|
16
|
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); |
|
17
|
} |
|
18
|
return to; |
|
19
|
}; |
|
20
|
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( |
|
21
|
// If the importer is in node compatibility mode or this is not an ESM |
|
22
|
// file that has been converted to a CommonJS file using a Babel- |
|
23
|
// compatible transform (i.e. "__esModule" has not been set), then set |
|
24
|
// "default" to the CommonJS "module.exports" for node compatibility. |
|
25
|
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, |
|
26
|
mod |
|
27
|
)); |
|
28
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); |
|
29
|
var config_exports = {}; |
|
30
|
__export(config_exports, { |
|
31
|
FullConfigInternal: () => FullConfigInternal, |
|
32
|
FullProjectInternal: () => FullProjectInternal, |
|
33
|
builtInReporters: () => builtInReporters, |
|
34
|
defaultGrep: () => defaultGrep, |
|
35
|
defaultReporter: () => defaultReporter, |
|
36
|
defaultTimeout: () => defaultTimeout, |
|
37
|
getProjectId: () => getProjectId, |
|
38
|
takeFirst: () => takeFirst, |
|
39
|
toReporters: () => toReporters |
|
40
|
}); |
|
41
|
module.exports = __toCommonJS(config_exports); |
|
42
|
var import_fs = __toESM(require("fs")); |
|
43
|
var import_os = __toESM(require("os")); |
|
44
|
var import_path = __toESM(require("path")); |
|
45
|
var import_util = require("../util"); |
|
46
|
const defaultTimeout = 3e4; |
|
47
|
class FullConfigInternal { |
|
48
|
constructor(location, userConfig, configCLIOverrides, metadata) { |
|
49
|
this.projects = []; |
|
50
|
this.cliArgs = []; |
|
51
|
this.cliListOnly = false; |
|
52
|
this.preOnlyTestFilters = []; |
|
53
|
this.postShardTestFilters = []; |
|
54
|
this.defineConfigWasUsed = false; |
|
55
|
this.globalSetups = []; |
|
56
|
this.globalTeardowns = []; |
|
57
|
if (configCLIOverrides.projects && userConfig.projects) |
|
58
|
throw new Error(`Cannot use --browser option when configuration file defines projects. Specify browserName in the projects instead.`); |
|
59
|
const { resolvedConfigFile, configDir } = location; |
|
60
|
const packageJsonPath = (0, import_util.getPackageJsonPath)(configDir); |
|
61
|
const packageJsonDir = packageJsonPath ? import_path.default.dirname(packageJsonPath) : process.cwd(); |
|
62
|
this.configDir = configDir; |
|
63
|
this.configCLIOverrides = configCLIOverrides; |
|
64
|
const privateConfiguration = userConfig["@playwright/test"]; |
|
65
|
this.plugins = (privateConfiguration?.plugins || []).map((p) => ({ factory: p })); |
|
66
|
this.singleTSConfigPath = pathResolve(configDir, userConfig.tsconfig); |
|
67
|
this.captureGitInfo = userConfig.captureGitInfo; |
|
68
|
this.failOnFlakyTests = takeFirst(configCLIOverrides.failOnFlakyTests, userConfig.failOnFlakyTests, false); |
|
69
|
this.globalSetups = (Array.isArray(userConfig.globalSetup) ? userConfig.globalSetup : [userConfig.globalSetup]).map((s) => resolveScript(s, configDir)).filter((script) => script !== void 0); |
|
70
|
this.globalTeardowns = (Array.isArray(userConfig.globalTeardown) ? userConfig.globalTeardown : [userConfig.globalTeardown]).map((s) => resolveScript(s, configDir)).filter((script) => script !== void 0); |
|
71
|
userConfig.metadata = userConfig.metadata || {}; |
|
72
|
const globalTags = Array.isArray(userConfig.tag) ? userConfig.tag : userConfig.tag ? [userConfig.tag] : []; |
|
73
|
for (const tag of globalTags) { |
|
74
|
if (tag[0] !== "@") |
|
75
|
throw new Error(`Tag must start with "@" symbol, got "${tag}" instead.`); |
|
76
|
} |
|
77
|
this.config = { |
|
78
|
configFile: resolvedConfigFile, |
|
79
|
rootDir: pathResolve(configDir, userConfig.testDir) || configDir, |
|
80
|
forbidOnly: takeFirst(configCLIOverrides.forbidOnly, userConfig.forbidOnly, false), |
|
81
|
fullyParallel: takeFirst(configCLIOverrides.fullyParallel, userConfig.fullyParallel, false), |
|
82
|
globalSetup: this.globalSetups[0] ?? null, |
|
83
|
globalTeardown: this.globalTeardowns[0] ?? null, |
|
84
|
globalTimeout: takeFirst(configCLIOverrides.debug ? 0 : void 0, configCLIOverrides.globalTimeout, userConfig.globalTimeout, 0), |
|
85
|
grep: takeFirst(userConfig.grep, defaultGrep), |
|
86
|
grepInvert: takeFirst(userConfig.grepInvert, null), |
|
87
|
maxFailures: takeFirst(configCLIOverrides.debug ? 1 : void 0, configCLIOverrides.maxFailures, userConfig.maxFailures, 0), |
|
88
|
metadata: metadata ?? userConfig.metadata, |
|
89
|
preserveOutput: takeFirst(userConfig.preserveOutput, "always"), |
|
90
|
projects: [], |
|
91
|
quiet: takeFirst(configCLIOverrides.quiet, userConfig.quiet, false), |
|
92
|
reporter: takeFirst(configCLIOverrides.reporter, resolveReporters(userConfig.reporter, configDir), [[defaultReporter]]), |
|
93
|
reportSlowTests: takeFirst(userConfig.reportSlowTests, { |
|
94
|
max: 5, |
|
95
|
threshold: 3e5 |
|
96
|
/* 5 minutes */ |
|
97
|
}), |
|
98
|
// @ts-expect-error runAgents is hidden |
|
99
|
runAgents: takeFirst(configCLIOverrides.runAgents, "none"), |
|
100
|
shard: takeFirst(configCLIOverrides.shard, userConfig.shard, null), |
|
101
|
tags: globalTags, |
|
102
|
updateSnapshots: takeFirst(configCLIOverrides.updateSnapshots, userConfig.updateSnapshots, "missing"), |
|
103
|
updateSourceMethod: takeFirst(configCLIOverrides.updateSourceMethod, userConfig.updateSourceMethod, "patch"), |
|
104
|
version: require("../../package.json").version, |
|
105
|
workers: resolveWorkers(takeFirst(configCLIOverrides.debug || configCLIOverrides.pause ? 1 : void 0, configCLIOverrides.workers, userConfig.workers, "50%")), |
|
106
|
webServer: null |
|
107
|
}; |
|
108
|
for (const key in userConfig) { |
|
109
|
if (key.startsWith("@")) |
|
110
|
this.config[key] = userConfig[key]; |
|
111
|
} |
|
112
|
this.config[configInternalSymbol] = this; |
|
113
|
const webServers = takeFirst(userConfig.webServer, null); |
|
114
|
if (Array.isArray(webServers)) { |
|
115
|
this.config.webServer = null; |
|
116
|
this.webServers = webServers; |
|
117
|
} else if (webServers) { |
|
118
|
this.config.webServer = webServers; |
|
119
|
this.webServers = [webServers]; |
|
120
|
} else { |
|
121
|
this.webServers = []; |
|
122
|
} |
|
123
|
const projectConfigs = configCLIOverrides.projects || userConfig.projects || [{ ...userConfig, workers: void 0 }]; |
|
124
|
this.projects = projectConfigs.map((p) => new FullProjectInternal(configDir, userConfig, this, p, this.configCLIOverrides, packageJsonDir)); |
|
125
|
resolveProjectDependencies(this.projects); |
|
126
|
this._assignUniqueProjectIds(this.projects); |
|
127
|
this.config.projects = this.projects.map((p) => p.project); |
|
128
|
} |
|
129
|
_assignUniqueProjectIds(projects) { |
|
130
|
const usedNames = /* @__PURE__ */ new Set(); |
|
131
|
for (const p of projects) { |
|
132
|
const name = p.project.name || ""; |
|
133
|
for (let i = 0; i < projects.length; ++i) { |
|
134
|
const candidate = name + (i ? i : ""); |
|
135
|
if (usedNames.has(candidate)) |
|
136
|
continue; |
|
137
|
p.id = candidate; |
|
138
|
p.project.__projectId = p.id; |
|
139
|
usedNames.add(candidate); |
|
140
|
break; |
|
141
|
} |
|
142
|
} |
|
143
|
} |
|
144
|
} |
|
145
|
class FullProjectInternal { |
|
146
|
constructor(configDir, config, fullConfig, projectConfig, configCLIOverrides, packageJsonDir) { |
|
147
|
this.id = ""; |
|
148
|
this.deps = []; |
|
149
|
this.fullConfig = fullConfig; |
|
150
|
const testDir = takeFirst(pathResolve(configDir, projectConfig.testDir), pathResolve(configDir, config.testDir), fullConfig.configDir); |
|
151
|
this.snapshotPathTemplate = takeFirst(projectConfig.snapshotPathTemplate, config.snapshotPathTemplate); |
|
152
|
this.project = { |
|
153
|
grep: takeFirst(projectConfig.grep, config.grep, defaultGrep), |
|
154
|
grepInvert: takeFirst(projectConfig.grepInvert, config.grepInvert, null), |
|
155
|
outputDir: takeFirst(configCLIOverrides.outputDir, pathResolve(configDir, projectConfig.outputDir), pathResolve(configDir, config.outputDir), import_path.default.join(packageJsonDir, "test-results")), |
|
156
|
// Note: we either apply the cli override for repeatEach or not, depending on whether the |
|
157
|
// project is top-level vs dependency. See collectProjectsAndTestFiles in loadUtils. |
|
158
|
repeatEach: takeFirst(projectConfig.repeatEach, config.repeatEach, 1), |
|
159
|
retries: takeFirst(configCLIOverrides.retries, projectConfig.retries, config.retries, 0), |
|
160
|
metadata: takeFirst(projectConfig.metadata, config.metadata, {}), |
|
161
|
name: takeFirst(projectConfig.name, config.name, ""), |
|
162
|
testDir, |
|
163
|
snapshotDir: takeFirst(pathResolve(configDir, projectConfig.snapshotDir), pathResolve(configDir, config.snapshotDir), testDir), |
|
164
|
testIgnore: takeFirst(projectConfig.testIgnore, config.testIgnore, []), |
|
165
|
testMatch: takeFirst(projectConfig.testMatch, config.testMatch, "**/*.@(spec|test).?(c|m)[jt]s?(x)"), |
|
166
|
timeout: takeFirst(configCLIOverrides.debug ? 0 : void 0, configCLIOverrides.timeout, projectConfig.timeout, config.timeout, defaultTimeout), |
|
167
|
use: (0, import_util.mergeObjects)(config.use, projectConfig.use, configCLIOverrides.use), |
|
168
|
dependencies: projectConfig.dependencies || [], |
|
169
|
teardown: projectConfig.teardown |
|
170
|
}; |
|
171
|
this.fullyParallel = takeFirst(configCLIOverrides.fullyParallel, projectConfig.fullyParallel, config.fullyParallel, void 0); |
|
172
|
this.expect = takeFirst(projectConfig.expect, config.expect, {}); |
|
173
|
if (this.expect.toHaveScreenshot?.stylePath) { |
|
174
|
const stylePaths = Array.isArray(this.expect.toHaveScreenshot.stylePath) ? this.expect.toHaveScreenshot.stylePath : [this.expect.toHaveScreenshot.stylePath]; |
|
175
|
this.expect.toHaveScreenshot.stylePath = stylePaths.map((stylePath) => import_path.default.resolve(configDir, stylePath)); |
|
176
|
} |
|
177
|
this.respectGitIgnore = takeFirst(projectConfig.respectGitIgnore, config.respectGitIgnore, !projectConfig.testDir && !config.testDir); |
|
178
|
this.ignoreSnapshots = takeFirst(configCLIOverrides.ignoreSnapshots, projectConfig.ignoreSnapshots, config.ignoreSnapshots, false); |
|
179
|
this.workers = projectConfig.workers ? resolveWorkers(projectConfig.workers) : void 0; |
|
180
|
if (configCLIOverrides.debug && this.workers) |
|
181
|
this.workers = 1; |
|
182
|
} |
|
183
|
} |
|
184
|
function takeFirst(...args) { |
|
185
|
for (const arg of args) { |
|
186
|
if (arg !== void 0) |
|
187
|
return arg; |
|
188
|
} |
|
189
|
return void 0; |
|
190
|
} |
|
191
|
function pathResolve(baseDir, relative) { |
|
192
|
if (!relative) |
|
193
|
return void 0; |
|
194
|
return import_path.default.resolve(baseDir, relative); |
|
195
|
} |
|
196
|
function resolveReporters(reporters, rootDir) { |
|
197
|
return toReporters(reporters)?.map(([id, arg]) => { |
|
198
|
if (builtInReporters.includes(id)) |
|
199
|
return [id, arg]; |
|
200
|
return [require.resolve(id, { paths: [rootDir] }), arg]; |
|
201
|
}); |
|
202
|
} |
|
203
|
function resolveWorkers(workers) { |
|
204
|
if (typeof workers === "string") { |
|
205
|
if (workers.endsWith("%")) { |
|
206
|
const cpus = import_os.default.cpus().length; |
|
207
|
return Math.max(1, Math.floor(cpus * (parseInt(workers, 10) / 100))); |
|
208
|
} |
|
209
|
const parsedWorkers = parseInt(workers, 10); |
|
210
|
if (isNaN(parsedWorkers)) |
|
211
|
throw new Error(`Workers ${workers} must be a number or percentage.`); |
|
212
|
return parsedWorkers; |
|
213
|
} |
|
214
|
return workers; |
|
215
|
} |
|
216
|
function resolveProjectDependencies(projects) { |
|
217
|
const teardownSet = /* @__PURE__ */ new Set(); |
|
218
|
for (const project of projects) { |
|
219
|
for (const dependencyName of project.project.dependencies) { |
|
220
|
const dependencies = projects.filter((p) => p.project.name === dependencyName); |
|
221
|
if (!dependencies.length) |
|
222
|
throw new Error(`Project '${project.project.name}' depends on unknown project '${dependencyName}'`); |
|
223
|
if (dependencies.length > 1) |
|
224
|
throw new Error(`Project dependencies should have unique names, reading ${dependencyName}`); |
|
225
|
project.deps.push(...dependencies); |
|
226
|
} |
|
227
|
if (project.project.teardown) { |
|
228
|
const teardowns = projects.filter((p) => p.project.name === project.project.teardown); |
|
229
|
if (!teardowns.length) |
|
230
|
throw new Error(`Project '${project.project.name}' has unknown teardown project '${project.project.teardown}'`); |
|
231
|
if (teardowns.length > 1) |
|
232
|
throw new Error(`Project teardowns should have unique names, reading ${project.project.teardown}`); |
|
233
|
const teardown = teardowns[0]; |
|
234
|
project.teardown = teardown; |
|
235
|
teardownSet.add(teardown); |
|
236
|
} |
|
237
|
} |
|
238
|
for (const teardown of teardownSet) { |
|
239
|
if (teardown.deps.length) |
|
240
|
throw new Error(`Teardown project ${teardown.project.name} must not have dependencies`); |
|
241
|
} |
|
242
|
for (const project of projects) { |
|
243
|
for (const dep of project.deps) { |
|
244
|
if (teardownSet.has(dep)) |
|
245
|
throw new Error(`Project ${project.project.name} must not depend on a teardown project ${dep.project.name}`); |
|
246
|
} |
|
247
|
} |
|
248
|
} |
|
249
|
function toReporters(reporters) { |
|
250
|
if (!reporters) |
|
251
|
return; |
|
252
|
if (typeof reporters === "string") |
|
253
|
return [[reporters]]; |
|
254
|
return reporters; |
|
255
|
} |
|
256
|
const builtInReporters = ["list", "line", "dot", "json", "junit", "null", "github", "html", "blob"]; |
|
257
|
function resolveScript(id, rootDir) { |
|
258
|
if (!id) |
|
259
|
return void 0; |
|
260
|
const localPath = import_path.default.resolve(rootDir, id); |
|
261
|
if (import_fs.default.existsSync(localPath)) |
|
262
|
return localPath; |
|
263
|
return require.resolve(id, { paths: [rootDir] }); |
|
264
|
} |
|
265
|
const defaultGrep = /.*/; |
|
266
|
const defaultReporter = process.env.CI ? "dot" : "list"; |
|
267
|
const configInternalSymbol = Symbol("configInternalSymbol"); |
|
268
|
function getProjectId(project) { |
|
269
|
return project.__projectId; |
|
270
|
} |
|
271
|
// Annotate the CommonJS export names for ESM import in node: |
|
272
|
0 && (module.exports = { |
|
273
|
FullConfigInternal, |
|
274
|
FullProjectInternal, |
|
275
|
builtInReporters, |
|
276
|
defaultGrep, |
|
277
|
defaultReporter, |
|
278
|
defaultTimeout, |
|
279
|
getProjectId, |
|
280
|
takeFirst, |
|
281
|
toReporters |
|
282
|
}); |
|
283
|
|