ScuttleBot

Blame History Raw 283 lines
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

Keyboard Shortcuts

Open search /
Next entry (timeline) j
Previous entry (timeline) k
Open focused entry Enter
Show this help ?
Toggle theme Top nav button