UNPKG

playwright

Version:

A high-level API to automate web browsers

1,214 lines (1,200 loc) • 114 kB
"use strict"; var __create = Object.create; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __getProtoOf = Object.getPrototypeOf; var __hasOwnProp = Object.prototype.hasOwnProperty; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( // If the importer is in node compatibility mode or this is not an ESM // file that has been converted to a CommonJS file using a Babel- // compatible transform (i.e. "__esModule" has not been set), then set // "default" to the CommonJS "module.exports" for node compatibility. isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, mod )); var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); // packages/playwright/src/common/index.ts var index_exports = {}; __export(index_exports, { FullConfigInternal: () => FullConfigInternal, ProcessRunner: () => ProcessRunner, builtInReporters: () => builtInReporters, cc: () => compilationCache_exports, config: () => config_exports, configLoader: () => configLoader_exports, defineConfig: () => defineConfig, esm: () => esmLoaderHost_exports, fixtures: () => fixtures_exports, ipc: () => ipc_exports, mergeTests: () => mergeTests, poolBuilder: () => poolBuilder_exports, processRunner: () => process_exports, startProcessRunner: () => startProcessRunner, suiteUtils: () => suiteUtils_exports, test: () => test_exports, testLoader: () => testLoader_exports, testType: () => testType_exports, transform: () => transform_exports }); module.exports = __toCommonJS(index_exports); // packages/playwright/src/transform/compilationCache.ts var compilationCache_exports = {}; __export(compilationCache_exports, { addToCompilationCache: () => addToCompilationCache, affectedTestFiles: () => affectedTestFiles, belongsToNodeModules: () => belongsToNodeModules, cacheDir: () => cacheDir, collectAffectedTestFiles: () => collectAffectedTestFiles, currentFileDepsCollector: () => currentFileDepsCollector, dependenciesForTestFile: () => dependenciesForTestFile, fileDependenciesForTest: () => fileDependenciesForTest, getFromCompilationCache: () => getFromCompilationCache, getUserData: () => getUserData, installSourceMapSupport: () => installSourceMapSupport, internalDependenciesForTestFile: () => internalDependenciesForTestFile, serializeCompilationCache: () => serializeCompilationCache, setExternalDependencies: () => setExternalDependencies, startCollectingFileDeps: () => startCollectingFileDeps, stopCollectingFileDeps: () => stopCollectingFileDeps }); var import_fs = __toESM(require("fs")); var import_os = __toESM(require("os")); var import_path = __toESM(require("path")); var import_globals = require("../globals"); var import_package = require("../package"); var sourceMapSupport = require("playwright-core/lib/utilsBundle").sourceMapSupport; var { calculateSha1 } = require("playwright-core/lib/coreBundle").utils; var { isUnderTest } = require("playwright-core/lib/coreBundle").utils; var cacheDir = process.env.PWTEST_CACHE_DIR || (() => { if (process.platform === "win32") return import_path.default.join(import_os.default.tmpdir(), `playwright-transform-cache`); return import_path.default.join(import_os.default.tmpdir(), `playwright-transform-cache-` + process.geteuid?.()); })(); var sourceMaps = /* @__PURE__ */ new Map(); var memoryCache = /* @__PURE__ */ new Map(); var fileDependencies = /* @__PURE__ */ new Map(); var externalDependencies = /* @__PURE__ */ new Map(); var devSourceInfix = import_path.default.sep + "playwright" + import_path.default.sep + "packages" + import_path.default.sep; function installSourceMapSupport() { Error.stackTraceLimit = 200; sourceMapSupport.install({ environment: "node", handleUncaughtExceptions: false, retrieveSourceMap(source) { if (!process.env.PWDEBUGIMPL && isUnderTest() && source.includes(devSourceInfix)) return { map: identitySourceMap(source), url: source }; if (!sourceMaps.has(source)) return null; const sourceMapPath = sourceMaps.get(source); try { return { map: JSON.parse(import_fs.default.readFileSync(sourceMapPath, "utf-8")), url: source }; } catch { return null; } } }); } function identitySourceMap(source) { const lineCount = import_fs.default.readFileSync(source, "utf8").split("\n").length; return { version: 3, sources: [source], mappings: lineCount ? "AAAA" + ";AACA".repeat(lineCount - 1) : "" }; } function _innerAddToCompilationCacheAndSerialize(filename, entry) { sourceMaps.set(entry.moduleUrl || filename, entry.sourceMapPath); memoryCache.set(filename, entry); return { sourceMaps: [[entry.moduleUrl || filename, entry.sourceMapPath]], memoryCache: [[filename, entry]], fileDependencies: [], externalDependencies: [] }; } function getFromCompilationCache(filename, contentHash, moduleUrl) { const cache = memoryCache.get(filename); if (cache?.codePath) { try { return { cachedCode: import_fs.default.readFileSync(cache.codePath, "utf-8") }; } catch { } } const filePathHash = calculateFilePathHash(filename); const hashPrefix = filePathHash + "_" + contentHash.substring(0, 7); const cacheFolderName = filePathHash.substring(0, 2); const cachePath = calculateCachePath(filename, cacheFolderName, hashPrefix); const codePath = cachePath + ".js"; const sourceMapPath = cachePath + ".map"; const dataPath = cachePath + ".data"; try { const cachedCode = import_fs.default.readFileSync(codePath, "utf8"); const serializedCache = _innerAddToCompilationCacheAndSerialize(filename, { codePath, sourceMapPath, dataPath, moduleUrl }); return { cachedCode, serializedCache }; } catch { } return { addToCache: (code, map, data) => { if ((0, import_globals.isWorkerProcess)()) return {}; clearOldCacheEntries(cacheFolderName, filePathHash); import_fs.default.mkdirSync(import_path.default.dirname(cachePath), { recursive: true }); if (map) import_fs.default.writeFileSync(sourceMapPath, JSON.stringify(map), "utf8"); if (data.size) import_fs.default.writeFileSync(dataPath, JSON.stringify(Object.fromEntries(data.entries()), void 0, 2), "utf8"); import_fs.default.writeFileSync(codePath, code, "utf8"); const serializedCache = _innerAddToCompilationCacheAndSerialize(filename, { codePath, sourceMapPath, dataPath, moduleUrl }); return { serializedCache }; } }; } function serializeCompilationCache() { return { sourceMaps: [...sourceMaps.entries()], memoryCache: [...memoryCache.entries()], fileDependencies: [...fileDependencies.entries()].map(([filename, deps]) => [filename, [...deps]]), externalDependencies: [...externalDependencies.entries()].map(([filename, deps]) => [filename, [...deps]]) }; } function addToCompilationCache(payload) { for (const entry of payload.sourceMaps) sourceMaps.set(entry[0], entry[1]); for (const entry of payload.memoryCache) memoryCache.set(entry[0], entry[1]); for (const entry of payload.fileDependencies) { const existing = fileDependencies.get(entry[0]) || []; fileDependencies.set(entry[0], /* @__PURE__ */ new Set([...entry[1], ...existing])); } for (const entry of payload.externalDependencies) { const existing = externalDependencies.get(entry[0]) || []; externalDependencies.set(entry[0], /* @__PURE__ */ new Set([...entry[1], ...existing])); } } function calculateFilePathHash(filePath) { return calculateSha1(filePath).substring(0, 10); } function calculateCachePath(filePath, cacheFolderName, hashPrefix) { const fileName2 = hashPrefix + "_" + import_path.default.basename(filePath, import_path.default.extname(filePath)).replace(/\W/g, ""); return import_path.default.join(cacheDir, cacheFolderName, fileName2); } function clearOldCacheEntries(cacheFolderName, filePathHash) { const cachePath = import_path.default.join(cacheDir, cacheFolderName); try { const cachedRelevantFiles = import_fs.default.readdirSync(cachePath).filter((file2) => file2.startsWith(filePathHash)); for (const file2 of cachedRelevantFiles) import_fs.default.rmSync(import_path.default.join(cachePath, file2), { force: true }); } catch { } } var depsCollector2; function startCollectingFileDeps() { depsCollector2 = /* @__PURE__ */ new Set(); } function stopCollectingFileDeps(filename) { if (!depsCollector2) return; depsCollector2.delete(filename); for (const dep of depsCollector2) { if (belongsToNodeModules(dep)) depsCollector2.delete(dep); } fileDependencies.set(filename, depsCollector2); depsCollector2 = void 0; } function currentFileDepsCollector() { return depsCollector2; } function setExternalDependencies(filename, deps) { const depsSet = new Set(deps.filter((dep) => !belongsToNodeModules(dep) && dep !== filename)); externalDependencies.set(filename, depsSet); } function fileDependenciesForTest() { return Object.fromEntries([...fileDependencies.entries()].map((entry) => [import_path.default.basename(entry[0]), [...entry[1]].map((f) => import_path.default.basename(f)).sort()])); } function collectAffectedTestFiles(changedFile, testFileCollector) { const isTestFile = (file2) => fileDependencies.has(file2); if (isTestFile(changedFile)) testFileCollector.add(changedFile); for (const [testFile, deps] of fileDependencies) { if (deps.has(changedFile)) testFileCollector.add(testFile); } for (const [importingFile, depsOfImportingFile] of externalDependencies) { if (depsOfImportingFile.has(changedFile)) { if (isTestFile(importingFile)) testFileCollector.add(importingFile); for (const [testFile, depsOfTestFile] of fileDependencies) { if (depsOfTestFile.has(importingFile)) testFileCollector.add(testFile); } } } } function affectedTestFiles(changes) { const result2 = /* @__PURE__ */ new Set(); for (const change of changes) collectAffectedTestFiles(change, result2); return [...result2]; } function internalDependenciesForTestFile(filename) { return fileDependencies.get(filename); } function dependenciesForTestFile(filename) { const result2 = /* @__PURE__ */ new Set(); for (const testDependency of fileDependencies.get(filename) || []) { result2.add(testDependency); for (const externalDependency of externalDependencies.get(testDependency) || []) result2.add(externalDependency); } for (const dep of externalDependencies.get(filename) || []) result2.add(dep); return result2; } var kPlaywrightInternalPrefix = import_package.packageRoot; function belongsToNodeModules(file2) { if (file2.includes(`${import_path.default.sep}node_modules${import_path.default.sep}`)) return true; if (file2.startsWith(kPlaywrightInternalPrefix) && (file2.endsWith(".js") || file2.endsWith(".mjs"))) return true; return false; } async function getUserData(pluginName) { const result2 = /* @__PURE__ */ new Map(); for (const [fileName2, cache] of memoryCache) { if (!cache.dataPath) continue; if (!import_fs.default.existsSync(cache.dataPath)) continue; const data = JSON.parse(await import_fs.default.promises.readFile(cache.dataPath, "utf8")); if (data[pluginName]) result2.set(fileName2, data[pluginName]); } return result2; } // packages/playwright/src/common/config.ts var config_exports = {}; __export(config_exports, { FullConfigInternal: () => FullConfigInternal, FullProjectInternal: () => FullProjectInternal, builtInReporters: () => builtInReporters, defaultGrep: () => defaultGrep, defaultReporter: () => defaultReporter, defaultTimeout: () => defaultTimeout, getProjectId: () => getProjectId, toReporters: () => toReporters }); var import_fs3 = __toESM(require("fs")); var import_os2 = __toESM(require("os")); var import_path3 = __toESM(require("path")); var import_package2 = require("../package"); // packages/playwright/src/util.ts var import_fs2 = __toESM(require("fs")); var import_path2 = __toESM(require("path")); var import_url = __toESM(require("url")); var import_util = __toESM(require("util")); var debug = require("playwright-core/lib/utilsBundle").debug; var mime = require("playwright-core/lib/utilsBundle").mime; var minimatch = require("playwright-core/lib/utilsBundle").minimatch; var { calculateSha1: calculateSha12 } = require("playwright-core/lib/coreBundle").utils; var { sanitizeForFilePath } = require("playwright-core/lib/coreBundle").utils; var { isRegExp } = require("playwright-core/lib/coreBundle").iso; var { parseStackFrame, stringifyStackFrames } = require("playwright-core/lib/coreBundle").iso; var { ansiRegex, isString, stripAnsiEscapes } = require("playwright-core/lib/coreBundle").iso; var PLAYWRIGHT_TEST_PATH = import_path2.default.join(__dirname, ".."); var PLAYWRIGHT_CORE_PATH = import_path2.default.dirname(require.resolve("playwright-core/package.json")); function filterStackTrace(e) { const name = e.name ? e.name + ": " : ""; const cause = e.cause instanceof Error ? filterStackTrace(e.cause) : void 0; if (process.env.PWDEBUGIMPL) return { message: name + e.message, stack: e.stack || "", cause }; const stackLines = stringifyStackFrames(filteredStackTrace(e.stack?.split("\n") || [])); return { message: name + e.message, stack: `${name}${e.message}${stackLines.map((line) => "\n" + line).join("")}`, cause }; } function filterStackFile(file2) { if (process.env.PWDEBUGIMPL) return true; if (file2.startsWith(PLAYWRIGHT_TEST_PATH)) return false; if (file2.startsWith(PLAYWRIGHT_CORE_PATH)) return false; return true; } function filteredStackTrace(rawStack) { const frames = []; for (const line of rawStack) { const frame = parseStackFrame(line, import_path2.default.sep, !!process.env.PWDEBUGIMPL); if (!frame || !frame.file) continue; if (!filterStackFile(frame.file)) continue; frames.push(frame); } return frames; } function serializeError(error) { if (error instanceof Error) return filterStackTrace(error); return { value: import_util.default.inspect(error) }; } function parseLocationArg(arg) { const match = /^(.*?):(\d+):?(\d+)?$/.exec(arg); return { file: match ? match[1] : arg, line: match ? parseInt(match[2], 10) : null, column: match?.[3] ? parseInt(match[3], 10) : null }; } function createFileMatcher(patterns) { const reList = []; const filePatterns = []; for (const pattern of Array.isArray(patterns) ? patterns : [patterns]) { if (isRegExp(pattern)) { reList.push(pattern); } else { if (!pattern.startsWith("**/")) filePatterns.push("**/" + pattern); else filePatterns.push(pattern); } } return (filePath) => { for (const re of reList) { re.lastIndex = 0; if (re.test(filePath)) return true; } if (import_path2.default.sep === "\\") { const fileURL = import_url.default.pathToFileURL(filePath).href; for (const re of reList) { re.lastIndex = 0; if (re.test(fileURL)) return true; } } for (const pattern of filePatterns) { if (minimatch(filePath, pattern, { nocase: true, dot: true })) return true; } return false; }; } function mergeObjects(a, b, c) { const result2 = { ...a }; for (const x of [b, c].filter(Boolean)) { for (const [name, value] of Object.entries(x)) { if (!Object.is(value, void 0)) result2[name] = value; } } return result2; } function forceRegExp(pattern) { const match = pattern.match(/^\/(.*)\/([gi]*)$/); if (match) return new RegExp(match[1], match[2]); return new RegExp(pattern, "gi"); } function relativeFilePath(file2) { if (!import_path2.default.isAbsolute(file2)) return file2; return import_path2.default.relative(process.cwd(), file2); } function formatLocation(location) { return relativeFilePath(location.file) + ":" + location.line + ":" + location.column; } function errorWithFile(file2, message) { return new Error(`${relativeFilePath(file2)}: ${message}`); } var debugTest = debug("pw:test"); var folderToPackageJsonPath = /* @__PURE__ */ new Map(); function getPackageJsonPath(folderPath) { const cached = folderToPackageJsonPath.get(folderPath); if (cached !== void 0) return cached; const packageJsonPath = import_path2.default.join(folderPath, "package.json"); if (import_fs2.default.existsSync(packageJsonPath)) { folderToPackageJsonPath.set(folderPath, packageJsonPath); return packageJsonPath; } const parentFolder = import_path2.default.dirname(folderPath); if (folderPath === parentFolder) { folderToPackageJsonPath.set(folderPath, ""); return ""; } const result2 = getPackageJsonPath(parentFolder); folderToPackageJsonPath.set(folderPath, result2); return result2; } function fileIsModule(file2) { if (file2.endsWith(".mjs") || file2.endsWith(".mts")) return true; if (file2.endsWith(".cjs") || file2.endsWith(".cts")) return false; const folder = import_path2.default.dirname(file2); return folderIsModule(folder); } function folderIsModule(folder) { const packageJsonPath = getPackageJsonPath(folder); if (!packageJsonPath) return false; return require(packageJsonPath).type === "module"; } var packageJsonMainFieldCache = /* @__PURE__ */ new Map(); function getMainFieldFromPackageJson(packageJsonPath) { if (!packageJsonMainFieldCache.has(packageJsonPath)) { let mainField; try { mainField = JSON.parse(import_fs2.default.readFileSync(packageJsonPath, "utf8")).main; } catch { } packageJsonMainFieldCache.set(packageJsonPath, mainField); } return packageJsonMainFieldCache.get(packageJsonPath); } var kExtLookups = /* @__PURE__ */ new Map([ [".js", [".jsx", ".ts", ".tsx"]], [".jsx", [".tsx"]], [".cjs", [".cts"]], [".mjs", [".mts"]], ["", [".js", ".ts", ".jsx", ".tsx", ".cjs", ".mjs", ".cts", ".mts"]] ]); function resolveImportSpecifierExtension(resolved) { if (fileExists(resolved)) return resolved; for (const [ext, others] of kExtLookups) { if (!resolved.endsWith(ext)) continue; for (const other of others) { const modified = resolved.substring(0, resolved.length - ext.length) + other; if (fileExists(modified)) return modified; } break; } } function resolveImportSpecifierAfterMapping(resolved, afterPathMapping) { const resolvedFile = resolveImportSpecifierExtension(resolved); if (resolvedFile) return resolvedFile; if (dirExists(resolved)) { const packageJsonPath = import_path2.default.join(resolved, "package.json"); if (afterPathMapping) { const mainField = getMainFieldFromPackageJson(packageJsonPath); const mainFieldResolved = mainField ? resolveImportSpecifierExtension(import_path2.default.resolve(resolved, mainField)) : void 0; return mainFieldResolved || resolveImportSpecifierExtension(import_path2.default.join(resolved, "index")); } if (fileExists(packageJsonPath)) return resolved; const dirImport = import_path2.default.join(resolved, "index"); return resolveImportSpecifierExtension(dirImport); } } function fileExists(resolved) { return import_fs2.default.statSync(resolved, { throwIfNoEntry: false })?.isFile(); } function dirExists(resolved) { return import_fs2.default.statSync(resolved, { throwIfNoEntry: false })?.isDirectory(); } function takeFirst(...args) { for (const arg of args) { if (arg !== void 0) return arg; } return void 0; } // packages/playwright/src/common/config.ts var defaultTimeout = 3e4; var FullConfigInternal = class { constructor(location, userConfig, configCLIOverrides, metadata) { this.projects = []; this.defineConfigWasUsed = false; this.globalSetups = []; this.globalTeardowns = []; if (configCLIOverrides.projects && userConfig.projects) throw new Error(`Cannot use --browser option when configuration file defines projects. Specify browserName in the projects instead.`); const { resolvedConfigFile, configDir } = location; const packageJsonPath = getPackageJsonPath(configDir); const packageJsonDir = packageJsonPath ? import_path3.default.dirname(packageJsonPath) : process.cwd(); this.configDir = configDir; this.configCLIOverrides = configCLIOverrides; const privateConfiguration = userConfig["@playwright/test"]; this.plugins = (privateConfiguration?.plugins || []).map((p) => ({ factory: p })); this.singleTSConfigPath = pathResolve(configDir, userConfig.tsconfig); this.captureGitInfo = userConfig.captureGitInfo; this.failOnFlakyTests = takeFirst(configCLIOverrides.failOnFlakyTests, userConfig.failOnFlakyTests, false); this.globalSetups = (Array.isArray(userConfig.globalSetup) ? userConfig.globalSetup : [userConfig.globalSetup]).map((s) => resolveScript(s, configDir)).filter((script) => script !== void 0); this.globalTeardowns = (Array.isArray(userConfig.globalTeardown) ? userConfig.globalTeardown : [userConfig.globalTeardown]).map((s) => resolveScript(s, configDir)).filter((script) => script !== void 0); userConfig.metadata = userConfig.metadata || {}; const globalTags = Array.isArray(userConfig.tag) ? userConfig.tag : userConfig.tag ? [userConfig.tag] : []; for (const tag of globalTags) { if (tag[0] !== "@") throw new Error(`Tag must start with "@" symbol, got "${tag}" instead.`); } this.config = { configFile: resolvedConfigFile, rootDir: pathResolve(configDir, userConfig.testDir) || configDir, forbidOnly: takeFirst(configCLIOverrides.forbidOnly, userConfig.forbidOnly, false), fullyParallel: takeFirst(configCLIOverrides.fullyParallel, userConfig.fullyParallel, false), globalSetup: this.globalSetups[0] ?? null, globalTeardown: this.globalTeardowns[0] ?? null, globalTimeout: takeFirst(configCLIOverrides.debug ? 0 : void 0, configCLIOverrides.globalTimeout, userConfig.globalTimeout, 0), grep: takeFirst(userConfig.grep, defaultGrep), grepInvert: takeFirst(userConfig.grepInvert, null), maxFailures: takeFirst(configCLIOverrides.debug ? 1 : void 0, configCLIOverrides.maxFailures, userConfig.maxFailures, 0), metadata: metadata ?? userConfig.metadata, preserveOutput: takeFirst(userConfig.preserveOutput, "always"), projects: [], quiet: takeFirst(configCLIOverrides.quiet, userConfig.quiet, false), reporter: takeFirst(configCLIOverrides.reporter, resolveReporters(userConfig.reporter, configDir), [[defaultReporter]]), reportSlowTests: takeFirst(userConfig.reportSlowTests, { max: 5, threshold: 3e5 /* 5 minutes */ }), shard: takeFirst(configCLIOverrides.shard, userConfig.shard, null), tags: globalTags, updateSnapshots: takeFirst(configCLIOverrides.updateSnapshots, userConfig.updateSnapshots, "missing"), updateSourceMethod: takeFirst(configCLIOverrides.updateSourceMethod, userConfig.updateSourceMethod, "patch"), version: import_package2.packageJSON.version, workers: resolveWorkers(takeFirst(configCLIOverrides.debug || configCLIOverrides.pause ? 1 : void 0, configCLIOverrides.workers, userConfig.workers, "50%")), webServer: null }; for (const key in userConfig) { if (key.startsWith("@")) this.config[key] = userConfig[key]; } this.config[configInternalSymbol] = this; const webServers = takeFirst(userConfig.webServer, null); if (Array.isArray(webServers)) { this.config.webServer = null; this.webServers = webServers; } else if (webServers) { this.config.webServer = webServers; this.webServers = [webServers]; } else { this.webServers = []; } const projectConfigs = configCLIOverrides.projects || userConfig.projects || [{ ...userConfig, workers: void 0 }]; this.projects = projectConfigs.map((p) => new FullProjectInternal(configDir, userConfig, this, p, this.configCLIOverrides, packageJsonDir)); resolveProjectDependencies(this.projects); this._assignUniqueProjectIds(this.projects); this.config.projects = this.projects.map((p) => p.project); } _assignUniqueProjectIds(projects) { const usedNames = /* @__PURE__ */ new Set(); for (const p of projects) { const name = p.project.name || ""; for (let i = 0; i < projects.length; ++i) { const candidate = name + (i ? i : ""); if (usedNames.has(candidate)) continue; p.id = candidate; p.project.__projectId = p.id; usedNames.add(candidate); break; } } } }; var FullProjectInternal = class { constructor(configDir, config, fullConfig, projectConfig, configCLIOverrides, packageJsonDir) { this.id = ""; this.deps = []; this.fullConfig = fullConfig; const testDir = takeFirst(pathResolve(configDir, projectConfig.testDir), pathResolve(configDir, config.testDir), fullConfig.configDir); this.snapshotPathTemplate = takeFirst(projectConfig.snapshotPathTemplate, config.snapshotPathTemplate); this.project = { grep: takeFirst(projectConfig.grep, config.grep, defaultGrep), grepInvert: takeFirst(projectConfig.grepInvert, config.grepInvert, null), outputDir: takeFirst(configCLIOverrides.outputDir, pathResolve(configDir, projectConfig.outputDir), pathResolve(configDir, config.outputDir), import_path3.default.join(packageJsonDir, "test-results")), // Note: we either apply the cli override for repeatEach or not, depending on whether the // project is top-level vs dependency. See collectProjectsAndTestFiles in loadUtils. repeatEach: takeFirst(projectConfig.repeatEach, config.repeatEach, 1), retries: takeFirst(configCLIOverrides.retries, projectConfig.retries, config.retries, 0), metadata: takeFirst(projectConfig.metadata, config.metadata, {}), name: takeFirst(projectConfig.name, config.name, ""), testDir, snapshotDir: takeFirst(pathResolve(configDir, projectConfig.snapshotDir), pathResolve(configDir, config.snapshotDir), testDir), testIgnore: takeFirst(projectConfig.testIgnore, config.testIgnore, []), testMatch: takeFirst(projectConfig.testMatch, config.testMatch, "**/*.@(spec|test).?(c|m)[jt]s?(x)"), timeout: takeFirst(configCLIOverrides.debug === "inspector" ? 0 : void 0, configCLIOverrides.timeout, projectConfig.timeout, config.timeout, defaultTimeout), use: mergeObjects(config.use, projectConfig.use, configCLIOverrides.use), dependencies: projectConfig.dependencies || [], teardown: projectConfig.teardown, ignoreSnapshots: takeFirst(configCLIOverrides.ignoreSnapshots, projectConfig.ignoreSnapshots, config.ignoreSnapshots, false) }; this.fullyParallel = takeFirst(configCLIOverrides.fullyParallel, projectConfig.fullyParallel, config.fullyParallel, void 0); this.expect = takeFirst(projectConfig.expect, config.expect, {}); if (this.expect.toHaveScreenshot?.stylePath) { const stylePaths = Array.isArray(this.expect.toHaveScreenshot.stylePath) ? this.expect.toHaveScreenshot.stylePath : [this.expect.toHaveScreenshot.stylePath]; this.expect.toHaveScreenshot.stylePath = stylePaths.map((stylePath) => import_path3.default.resolve(configDir, stylePath)); } this.respectGitIgnore = takeFirst(projectConfig.respectGitIgnore, config.respectGitIgnore, !projectConfig.testDir && !config.testDir); this.workers = projectConfig.workers ? resolveWorkers(projectConfig.workers) : void 0; if (configCLIOverrides.debug && this.workers) this.workers = 1; } }; function pathResolve(baseDir, relative) { if (!relative) return void 0; return import_path3.default.resolve(baseDir, relative); } function resolveReporters(reporters, rootDir) { return toReporters(reporters)?.map(([id, arg]) => { if (builtInReporters.includes(id)) return [id, arg]; return [require.resolve(id, { paths: [rootDir] }), arg]; }); } function resolveWorkers(workers) { if (typeof workers === "string") { if (workers.endsWith("%")) { const cpus = import_os2.default.cpus().length; return Math.max(1, Math.floor(cpus * (parseInt(workers, 10) / 100))); } const parsedWorkers = parseInt(workers, 10); if (isNaN(parsedWorkers)) throw new Error(`Workers ${workers} must be a number or percentage.`); if (parsedWorkers < 1) throw new Error(`Workers must be a positive number, received ${parsedWorkers}.`); return parsedWorkers; } if (workers < 1) throw new Error(`Workers must be a positive number, received ${workers}.`); return workers; } function resolveProjectDependencies(projects) { const teardownSet = /* @__PURE__ */ new Set(); for (const project of projects) { for (const dependencyName of project.project.dependencies) { const dependencies = projects.filter((p) => p.project.name === dependencyName); if (!dependencies.length) throw new Error(`Project '${project.project.name}' depends on unknown project '${dependencyName}'`); if (dependencies.length > 1) throw new Error(`Project dependencies should have unique names, reading ${dependencyName}`); project.deps.push(...dependencies); } if (project.project.teardown) { const teardowns = projects.filter((p) => p.project.name === project.project.teardown); if (!teardowns.length) throw new Error(`Project '${project.project.name}' has unknown teardown project '${project.project.teardown}'`); if (teardowns.length > 1) throw new Error(`Project teardowns should have unique names, reading ${project.project.teardown}`); const teardown = teardowns[0]; project.teardown = teardown; teardownSet.add(teardown); } } for (const teardown of teardownSet) { if (teardown.deps.length) throw new Error(`Teardown project ${teardown.project.name} must not have dependencies`); } for (const project of projects) { for (const dep of project.deps) { if (teardownSet.has(dep)) throw new Error(`Project ${project.project.name} must not depend on a teardown project ${dep.project.name}`); } } } function toReporters(reporters) { if (!reporters) return; if (typeof reporters === "string") return [[reporters]]; return reporters; } var builtInReporters = ["list", "line", "dot", "json", "junit", "null", "github", "html", "blob"]; function resolveScript(id, rootDir) { if (!id) return void 0; const localPath = import_path3.default.resolve(rootDir, id); if (import_fs3.default.existsSync(localPath)) return localPath; return require.resolve(id, { paths: [rootDir] }); } var defaultGrep = /.*/; var defaultReporter = process.env.CI ? "dot" : "list"; var configInternalSymbol = Symbol("configInternalSymbol"); function getProjectId(project) { return project.__projectId; } // packages/playwright/src/common/configLoader.ts var configLoader_exports = {}; __export(configLoader_exports, { defineConfig: () => defineConfig, deserializeConfig: () => deserializeConfig, loadConfig: () => loadConfig, loadConfigFromFile: () => loadConfigFromFile, loadEmptyConfigForMergeReports: () => loadEmptyConfigForMergeReports, resolveConfigLocation: () => resolveConfigLocation }); var import_fs6 = __toESM(require("fs")); var import_path7 = __toESM(require("path")); // packages/playwright/src/transform/transform.ts var transform_exports = {}; __export(transform_exports, { requireOrImport: () => requireOrImport, resolveHook: () => resolveHook, setSingleTSConfig: () => setSingleTSConfig, setTransformConfig: () => setTransformConfig, setTransformData: () => setTransformData, shouldTransform: () => shouldTransform, singleTSConfig: () => singleTSConfig, transformConfig: () => transformConfig, transformHook: () => transformHook, wrapFunctionWithLocation: () => wrapFunctionWithLocation }); var import_fs5 = __toESM(require("fs")); var import_module2 = __toESM(require("module")); var import_path6 = __toESM(require("path")); var import_url2 = __toESM(require("url")); var import_crypto = __toESM(require("crypto")); // packages/playwright/src/transform/tsconfig-loader.ts var import_path4 = __toESM(require("path")); var import_fs4 = __toESM(require("fs")); var json5 = require("playwright-core/lib/utilsBundle").json5; function loadTsConfig(configPath) { try { const references = []; const config = innerLoadTsConfig(configPath, references); return [config, ...references]; } catch (e) { throw new Error(`Failed to load tsconfig file at ${configPath}: ${e.message}`); } } function resolveConfigFile(baseConfigFile, referencedConfigFile) { if (!referencedConfigFile.endsWith(".json")) referencedConfigFile += ".json"; const currentDir = import_path4.default.dirname(baseConfigFile); let resolvedConfigFile = import_path4.default.resolve(currentDir, referencedConfigFile); if (referencedConfigFile.includes("/") && referencedConfigFile.includes(".") && !import_fs4.default.existsSync(resolvedConfigFile)) resolvedConfigFile = import_path4.default.join(currentDir, "node_modules", referencedConfigFile); return resolvedConfigFile; } function innerLoadTsConfig(configFilePath, references, visited = /* @__PURE__ */ new Map()) { if (visited.has(configFilePath)) return visited.get(configFilePath); let result2 = { tsConfigPath: configFilePath }; visited.set(configFilePath, result2); if (!import_fs4.default.existsSync(configFilePath)) return result2; const configString = import_fs4.default.readFileSync(configFilePath, "utf-8"); const cleanedJson = StripBom(configString); const parsedConfig = json5.parse(cleanedJson); const extendsArray = Array.isArray(parsedConfig.extends) ? parsedConfig.extends : parsedConfig.extends ? [parsedConfig.extends] : []; for (const extendedConfig of extendsArray) { const extendedConfigPath = resolveConfigFile(configFilePath, extendedConfig); const base = innerLoadTsConfig(extendedConfigPath, references, visited); Object.assign(result2, base, { tsConfigPath: configFilePath }); } if (parsedConfig.compilerOptions?.allowJs !== void 0) result2.allowJs = parsedConfig.compilerOptions.allowJs; if (parsedConfig.compilerOptions?.paths !== void 0) { result2.paths = { mapping: parsedConfig.compilerOptions.paths, pathsBasePath: import_path4.default.dirname(configFilePath) }; } if (parsedConfig.compilerOptions?.baseUrl !== void 0) { result2.absoluteBaseUrl = import_path4.default.resolve(import_path4.default.dirname(configFilePath), parsedConfig.compilerOptions.baseUrl); } for (const ref of parsedConfig.references || []) references.push(innerLoadTsConfig(resolveConfigFile(configFilePath, ref.path), references, visited)); if (import_path4.default.basename(configFilePath) === "jsconfig.json" && result2.allowJs === void 0) result2.allowJs = true; return result2; } function StripBom(string) { if (typeof string !== "string") { throw new TypeError(`Expected a string, got ${typeof string}`); } if (string.charCodeAt(0) === 65279) { return string.slice(1); } return string; } // packages/playwright/src/transform/transform.ts var import_package3 = require("../package"); // packages/playwright/src/transform/pirates.ts var import_module = __toESM(require("module")); var import_path5 = __toESM(require("path")); function addHook(transformHook2, shouldTransform2, extensions) { const extensionsToOverwrite = extensions.filter((e) => e !== ".cjs"); const allSupportedExtensions = new Set(extensions); const loaders = import_module.default._extensions; const jsLoader = loaders[".js"]; for (const extension of extensionsToOverwrite) { let newLoader2 = function(mod, filename, ...loaderArgs) { if (allSupportedExtensions.has(import_path5.default.extname(filename)) && shouldTransform2(filename)) { let newCompile2 = function(code, file2, ...ignoredArgs) { mod._compile = oldCompile; return oldCompile.call(this, transformHook2(code, filename), file2); }; var newCompile = newCompile2; const oldCompile = mod._compile; mod._compile = newCompile2; } originalLoader.call(this, mod, filename, ...loaderArgs); }; var newLoader = newLoader2; const originalLoader = loaders[extension] || jsLoader; loaders[extension] = newLoader2; } } // packages/playwright/src/transform/transform.ts var sourceMapSupport2 = require("playwright-core/lib/utilsBundle").sourceMapSupport; var version = import_package3.packageJSON.version; var cachedTSConfigs = /* @__PURE__ */ new Map(); var _transformConfig = { babelPlugins: [], external: [] }; var _externalMatcher = () => false; function setTransformConfig(config) { _transformConfig = config; _externalMatcher = createFileMatcher(_transformConfig.external); } function transformConfig() { return _transformConfig; } var _singleTSConfigPath; var _singleTSConfig; function setSingleTSConfig(value) { _singleTSConfigPath = value; } function singleTSConfig() { return _singleTSConfigPath; } function validateTsConfig(tsconfig) { const pathsBase = tsconfig.absoluteBaseUrl ?? tsconfig.paths?.pathsBasePath; const pathsFallback = tsconfig.absoluteBaseUrl ? [{ key: "*", values: ["*"] }] : []; return { allowJs: !!tsconfig.allowJs, pathsBase, paths: Object.entries(tsconfig.paths?.mapping || {}).map(([key, values]) => ({ key, values })).concat(pathsFallback) }; } function loadAndValidateTsconfigsForFile(file2) { if (_singleTSConfigPath && !_singleTSConfig) _singleTSConfig = loadTsConfig(_singleTSConfigPath).map(validateTsConfig); if (_singleTSConfig) return _singleTSConfig; return loadAndValidateTsconfigsForFolder(import_path6.default.dirname(file2)); } function loadAndValidateTsconfigsForFolder(folder) { const foldersWithConfig = []; let currentFolder = import_path6.default.resolve(folder); let result2; while (true) { const cached = cachedTSConfigs.get(currentFolder); if (cached) { result2 = cached; break; } foldersWithConfig.push(currentFolder); for (const name of ["tsconfig.json", "jsconfig.json"]) { const configPath = import_path6.default.join(currentFolder, name); if (import_fs5.default.existsSync(configPath)) { const loaded = loadTsConfig(configPath); result2 = loaded.map(validateTsConfig); break; } } if (result2) break; const parentFolder = import_path6.default.resolve(currentFolder, "../"); if (currentFolder === parentFolder) break; currentFolder = parentFolder; } result2 = result2 || []; for (const folder2 of foldersWithConfig) cachedTSConfigs.set(folder2, result2); return result2; } var pathSeparator = process.platform === "win32" ? ";" : ":"; var builtins = new Set(import_module2.default.builtinModules); function resolveHook(filename, specifier) { if (specifier.startsWith("node:") || builtins.has(specifier)) return; if (!shouldTransform(filename)) return; if (isRelativeSpecifier(specifier)) return resolveImportSpecifierAfterMapping(import_path6.default.resolve(import_path6.default.dirname(filename), specifier), false); const isTypeScript = filename.endsWith(".ts") || filename.endsWith(".tsx"); const tsconfigs = loadAndValidateTsconfigsForFile(filename); for (const tsconfig of tsconfigs) { if (!isTypeScript && !tsconfig.allowJs) continue; let longestPrefixLength = -1; let pathMatchedByLongestPrefix; for (const { key, values } of tsconfig.paths) { let matchedPartOfSpecifier = specifier; const [keyPrefix, keySuffix] = key.split("*"); if (key.includes("*")) { if (keyPrefix) { if (!specifier.startsWith(keyPrefix)) continue; matchedPartOfSpecifier = matchedPartOfSpecifier.substring(keyPrefix.length, matchedPartOfSpecifier.length); } if (keySuffix) { if (!specifier.endsWith(keySuffix)) continue; matchedPartOfSpecifier = matchedPartOfSpecifier.substring(0, matchedPartOfSpecifier.length - keySuffix.length); } } else { if (specifier !== key) continue; matchedPartOfSpecifier = specifier; } if (keyPrefix.length <= longestPrefixLength) continue; for (const value of values) { let candidate = value; if (value.includes("*")) candidate = candidate.replace("*", matchedPartOfSpecifier); candidate = import_path6.default.resolve(tsconfig.pathsBase, candidate); const existing = resolveImportSpecifierAfterMapping(candidate, true); if (existing) { longestPrefixLength = keyPrefix.length; pathMatchedByLongestPrefix = existing; } } } if (pathMatchedByLongestPrefix) return pathMatchedByLongestPrefix; } if (import_path6.default.isAbsolute(specifier)) { return resolveImportSpecifierAfterMapping(specifier, false); } } function shouldTransform(filename) { if (_externalMatcher(filename)) return false; return !belongsToNodeModules(filename); } var transformData; function setTransformData(pluginName, value) { transformData.set(pluginName, value); } function transformHook(originalCode, filename, moduleUrl) { const hasPreprocessor = process.env.PW_TEST_SOURCE_TRANSFORM && process.env.PW_TEST_SOURCE_TRANSFORM_SCOPE && process.env.PW_TEST_SOURCE_TRANSFORM_SCOPE.split(pathSeparator).some((f) => filename.startsWith(f)); const pluginsPrologue = _transformConfig.babelPlugins; const pluginsEpilogue = hasPreprocessor ? [[process.env.PW_TEST_SOURCE_TRANSFORM]] : []; const hash = calculateHash(originalCode, filename, !!moduleUrl, pluginsPrologue, pluginsEpilogue); const { cachedCode, addToCache, serializedCache } = getFromCompilationCache(filename, hash, moduleUrl); if (cachedCode !== void 0) return { code: cachedCode, serializedCache }; process.env.BROWSERSLIST_IGNORE_OLD_DATA = "true"; const { babelTransform } = require((0, import_package3.libPath)("transform", "babelBundle")); transformData = /* @__PURE__ */ new Map(); const setTransformDataForPlugin = (key, value) => transformData.set(key, value); const wrappedPrologue = pluginsPrologue.map(([name, opts]) => [ name, { ...opts || {}, setTransformData: setTransformDataForPlugin } ]); const babelResult = babelTransform(originalCode, filename, !!moduleUrl, wrappedPrologue, pluginsEpilogue, _transformConfig.jsxImportSource); if (!babelResult?.code) return { code: originalCode, serializedCache }; const { code, map } = babelResult; const added = addToCache(code, map, transformData); return { code, serializedCache: added.serializedCache }; } function calculateHash(content, filePath, isModule2, pluginsPrologue, pluginsEpilogue) { const hash = import_crypto.default.createHash("sha1").update(isModule2 ? "esm" : "no_esm").update(content).update(filePath).update(version).update(pluginsPrologue.map((p) => p[0]).join(",")).update(pluginsEpilogue.map((p) => p[0]).join(",")).digest("hex"); return hash; } async function requireOrImport(file) { installTransformIfNeeded(); const isModule = fileIsModule(file); if (isModule) { const fileName = import_url2.default.pathToFileURL(file); const esmImport = () => eval(`import(${JSON.stringify(fileName)})`); await eval(`import(${JSON.stringify(fileName + ".esm.preflight")})`).catch((error) => debugTest("Failed to load preflight for " + file + ", source maps may be missing for errors thrown during loading.", error)).finally(nextTask); return await esmImport().finally(nextTask); } const result = require(file); const depsCollector = currentFileDepsCollector(); if (depsCollector) { const module2 = require.cache[file]; if (module2) collectCJSDependencies(module2, depsCollector); } return result; } var transformInstalled = false; function installTransformIfNeeded() { if (transformInstalled) return; transformInstalled = true; installSourceMapSupport(); const originalResolveFilename = import_module2.default._resolveFilename; function resolveFilename(specifier, parent, ...rest) { if (parent) { const resolved = resolveHook(parent.filename, specifier); if (resolved !== void 0) specifier = resolved; } return originalResolveFilename.call(this, specifier, parent, ...rest); } import_module2.default._resolveFilename = resolveFilename; addHook((code, filename) => { return transformHook(code, filename).code; }, shouldTransform, [".ts", ".tsx", ".js", ".jsx", ".mjs", ".mts", ".cjs", ".cts"]); } var collectCJSDependencies = (module2, dependencies) => { module2.children.forEach((child) => { if (!belongsToNodeModules(child.filename) && !dependencies.has(child.filename)) { dependencies.add(child.filename); collectCJSDependencies(child, dependencies); } }); }; function wrapFunctionWithLocation(func) { return (...args) => { const oldPrepareStackTrace = Error.prepareStackTrace; Error.prepareStackTrace = (error, stackFrames) => { const frame = sourceMapSupport2.wrapCallSite(stackFrames[1]); const fileName2 = frame.getFileName(); const file2 = fileName2 && fileName2.startsWith("file://") ? import_url2.default.fileURLToPath(fileName2) : fileName2; return { file: file2, line: frame.getLineNumber(), column: frame.getColumnNumber() }; }; const oldStackTraceLimit = Error.stackTraceLimit; Error.stackTraceLimit = 2; const obj = {}; Error.captureStackTrace(obj); const location = obj.stack; Error.stackTraceLimit = oldStackTraceLimit; Error.prepareStackTrace = oldPrepareStackTrace; return func(location, ...args); }; } function isRelativeSpecifier(specifier) { return specifier === "." || specifier === ".." || specifier.startsWith("./") || specifier.startsWith("../"); } async function nextTask() { return new Promise((resolve) => setTimeout(resolve, 0)); } // packages/playwright/src/common/esmLoaderHost.ts var esmLoaderHost_exports = {}; __export(esmLoaderHost_exports, { configureESMLoader: () => configureESMLoader, configureESMLoaderTransformConfig: () => configureESMLoaderTransformConfig, incorporateCompilationCache: () => incorporateCompilationCache, registerESMLoader: () => registerESMLoader, startCollectingFileDeps: () => startCollectingFileDeps2, stopCollectingFileDeps: () => stopCollectingFileDeps2 }); var import_url3 = __toESM(require("url")); // packages/playwright/src/transform/portTransport.ts var PortTransport = class { constructor(port, handler) { this._lastId = 0; this._callbacks = /* @__PURE__ */ new Map(); this._port = port; port.addEventListener("message", async (event) => { const message = event.data; const { id, ackId, method, params, result: result2 } = message; if (ackId) { const callback = this._callbacks.get(ackId); this._callbacks.delete(ackId); this._resetRef(); callback?.(result2); return; } const handlerResult = await handler(method, params); if (id) this._port.postMessage({ ackId: id, result: handlerResult }); }); this._resetRef(); } post(method, params) { this._port.postMessage({ method, params }); } async send(method, params) { return await new Promise((f) => { const id = ++this._lastId; this._callbacks.set(id, f); this._resetRef(); this._port.postMessage({ id, method, params }); }); } _resetRef() { if (this._callbacks.size) { this._port.ref(); } else { this._port.unref(); } } }; // packages/playwright/src/common/esmLoaderHost.ts var loaderChannel; function registerESMLoader() { if (process.env.PW_DISABLE_TS_ESM) return true; if ("Bun" in globalThis) return true; if (loaderChannel) return true; const register = require("node:module").register; if (!register) return false; const { port1, port2 } = new MessageChannel(); register(import_url3.default.pathToFileURL(require.resolve("../transform/esmLoader.js")), { data: { port: port2 }, transferList: [port2] }); loaderChannel = createPortTransport(port1); return true; } function createPortTransport(port) { return new PortTransport(port, async (method, params) => { if (method === "pushToCompilationCache") addToCompilationCache(params.cache); }); } async function startCollectingFileDeps2() { if (!loaderChannel) return; await loaderChannel.send("startCollectingFileDeps", {}); } async function stopCollectingFileDeps2(file2) { if (!loaderChannel) return; await loaderChannel.send("stopCollectingFileDeps", { file: file2 }); } async function incorporateCompilationCache() { if (!loaderChannel) return; const result2 = await loaderChannel.send("getCompilationCache