| "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( |
| |
| |
| |
| |
| isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, |
| mod |
| )); |
| var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); |
|
|
| |
| 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); |
|
|
| |
| 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 = new Map(); |
| var memoryCache = new Map(); |
| var fileDependencies = new Map(); |
| var externalDependencies = 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], new Set([...entry[1], ...existing])); |
| } |
| for (const entry of payload.externalDependencies) { |
| const existing = externalDependencies.get(entry[0]) || []; |
| externalDependencies.set(entry[0], 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 = 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 = new Set(); |
| for (const change of changes) |
| collectAffectedTestFiles(change, result2); |
| return [...result2]; |
| } |
| function internalDependenciesForTestFile(filename) { |
| return fileDependencies.get(filename); |
| } |
| function dependenciesForTestFile(filename) { |
| const result2 = 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 = 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; |
| } |
|
|
| |
| 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"); |
|
|
| |
| 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 = 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 = 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 = 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; |
| } |
|
|
| |
| 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 |
| |
| }), |
| 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 = 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")), |
| |
| |
| 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 = 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; |
| } |
|
|
| |
| 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")); |
|
|
| |
| 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")); |
|
|
| |
| 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 = 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; |
| } |
|
|
| |
| var import_package3 = require("../package"); |
|
|
| |
| 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; |
| } |
| } |
|
|
| |
| var sourceMapSupport2 = require("playwright-core/lib/utilsBundle").sourceMapSupport; |
| var version = import_package3.packageJSON.version; |
| var cachedTSConfigs = 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 = 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)); |
| } |
|
|
| |
| var esmLoaderHost_exports = {}; |
| __export(esmLoaderHost_exports, { |
| configureESMLoader: () => configureESMLoader, |
| configureESMLoaderTransformConfig: () => configureESMLoaderTransformConfig, |
| incorporateCompilationCache: () => incorporateCompilationCache, |
| registerESMLoader: () => registerESMLoader, |
| startCollectingFileDeps: () => startCollectingFileDeps2, |
| stopCollectingFileDeps: () => stopCollectingFileDeps2 |
| }); |
| var import_url3 = __toESM(require("url")); |
|
|
| |
| var PortTransport = class { |
| constructor(port, handler) { |
| this._lastId = 0; |
| this._callbacks = 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(); |
| } |
| } |
| }; |
|
|
| |
| 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", {}); |
| addToCompilationCache(result2.cache); |
| } |
| async function configureESMLoader() { |
| if (!loaderChannel) |
| return; |
| await loaderChannel.send("setSingleTSConfig", { tsconfig: singleTSConfig() }); |
| await loaderChannel.send("addToCompilationCache", { cache: serializeCompilationCache() }); |
| } |
| async function configureESMLoaderTransformConfig() { |
| if (!loaderChannel) |
| return; |
| await loaderChannel.send("setSingleTSConfig", { tsconfig: singleTSConfig() }); |
| await loaderChannel.send("setTransformConfig", { config: transformConfig() }); |
| } |
|
|
| |
| var { isRegExp: isRegExp2 } = require("playwright-core/lib/coreBundle").iso; |
| var kDefineConfigWasUsed = Symbol("defineConfigWasUsed"); |
| var defineConfig = (...configs) => { |
| let result2 = configs[0]; |
| for (let i = 1; i < configs.length; ++i) { |
| const config = configs[i]; |
| const prevProjects = result2.projects; |
| result2 = { |
| ...result2, |
| ...config, |
| expect: { |
| ...result2.expect, |
| ...config.expect |
| }, |
| use: { |
| ...result2.use, |
| ...config.use |
| }, |
| build: { |
| ...result2.build, |
| ...config.build |
| }, |
| webServer: [ |
| ...Array.isArray(result2.webServer) ? result2.webServer : result2.webServer ? [result2.webServer] : [], |
| ...Array.isArray(config.webServer) ? config.webServer : config.webServer ? [config.webServer] : [] |
| ] |
| }; |
| if (!result2.projects && !config.projects) |
| continue; |
| const projectOverrides = new Map(); |
| for (const project of config.projects || []) |
| projectOverrides.set(project.name, project); |
| const projects = []; |
| for (const project of prevProjects || []) { |
| const projectOverride = projectOverrides.get(project.name); |
| if (projectOverride) { |
| projects.push({ |
| ...project, |
| ...projectOverride, |
| use: { |
| ...project.use, |
| ...projectOverride.use |
| } |
| }); |
| projectOverrides.delete(project.name); |
| } else { |
| projects.push(project); |
| } |
| } |
| projects.push(...projectOverrides.values()); |
| result2.projects = projects; |
| } |
| result2[kDefineConfigWasUsed] = true; |
| return result2; |
| }; |
| async function deserializeConfig(data) { |
| if (data.compilationCache) |
| addToCompilationCache(data.compilationCache); |
| return await loadConfig(data.location, data.configCLIOverrides, void 0, data.metadata ? JSON.parse(data.metadata) : void 0); |
| } |
| async function loadUserConfig(location) { |
| let object = location.resolvedConfigFile ? await requireOrImport(location.resolvedConfigFile) : {}; |
| if (object && typeof object === "object" && "default" in object) |
| object = object["default"]; |
| return object; |
| } |
| async function loadConfig(location, overrides, ignoreProjectDependencies = false, metadata) { |
| if (!registerESMLoader()) { |
| if (location.resolvedConfigFile && fileIsModule(location.resolvedConfigFile)) |
| throw errorWithFile(location.resolvedConfigFile, `Playwright requires Node.js 18.19 or higher to load esm modules. Please update your version of Node.js.`); |
| } |
| setSingleTSConfig(overrides?.tsconfig); |
| await configureESMLoader(); |
| const userConfig = await loadUserConfig(location); |
| validateConfig(location.resolvedConfigFile || "<default config>", userConfig); |
| const fullConfig = new FullConfigInternal(location, userConfig, overrides || {}, metadata); |
| fullConfig.defineConfigWasUsed = !!userConfig[kDefineConfigWasUsed]; |
| if (ignoreProjectDependencies) { |
| for (const project of fullConfig.projects) { |
| project.deps = []; |
| project.teardown = void 0; |
| } |
| } |
| const babelPlugins = userConfig["@playwright/test"]?.babelPlugins || []; |
| const external = userConfig.build?.external || []; |
| const jsxImportSource = import_path7.default.dirname(require.resolve("playwright")); |
| setTransformConfig({ babelPlugins, external, jsxImportSource }); |
| if (!overrides?.tsconfig) |
| setSingleTSConfig(fullConfig?.singleTSConfigPath); |
| await configureESMLoaderTransformConfig(); |
| return fullConfig; |
| } |
| function validateConfig(file2, config) { |
| if (typeof config !== "object" || !config) |
| throw errorWithFile(file2, `Configuration file must export a single object`); |
| validateProject(file2, config, "config"); |
| if ("forbidOnly" in config && config.forbidOnly !== void 0) { |
| if (typeof config.forbidOnly !== "boolean") |
| throw errorWithFile(file2, `config.forbidOnly must be a boolean`); |
| } |
| if ("globalSetup" in config && config.globalSetup !== void 0) { |
| if (Array.isArray(config.globalSetup)) { |
| config.globalSetup.forEach((item, index) => { |
| if (typeof item !== "string") |
| throw errorWithFile(file2, `config.globalSetup[${index}] must be a string`); |
| }); |
| } else if (typeof config.globalSetup !== "string") { |
| throw errorWithFile(file2, `config.globalSetup must be a string`); |
| } |
| } |
| if ("globalTeardown" in config && config.globalTeardown !== void 0) { |
| if (Array.isArray(config.globalTeardown)) { |
| config.globalTeardown.forEach((item, index) => { |
| if (typeof item !== "string") |
| throw errorWithFile(file2, `config.globalTeardown[${index}] must be a string`); |
| }); |
| } else if (typeof config.globalTeardown !== "string") { |
| throw errorWithFile(file2, `config.globalTeardown must be a string`); |
| } |
| } |
| if ("globalTimeout" in config && config.globalTimeout !== void 0) { |
| if (typeof config.globalTimeout !== "number" || config.globalTimeout < 0) |
| throw errorWithFile(file2, `config.globalTimeout must be a non-negative number`); |
| } |
| if ("grep" in config && config.grep !== void 0) { |
| if (Array.isArray(config.grep)) { |
| config.grep.forEach((item, index) => { |
| if (!isRegExp2(item)) |
| throw errorWithFile(file2, `config.grep[${index}] must be a RegExp`); |
| }); |
| } else if (!isRegExp2(config.grep)) { |
| throw errorWithFile(file2, `config.grep must be a RegExp`); |
| } |
| } |
| if ("grepInvert" in config && config.grepInvert !== void 0) { |
| if (Array.isArray(config.grepInvert)) { |
| config.grepInvert.forEach((item, index) => { |
| if (!isRegExp2(item)) |
| throw errorWithFile(file2, `config.grepInvert[${index}] must be a RegExp`); |
| }); |
| } else if (!isRegExp2(config.grepInvert)) { |
| throw errorWithFile(file2, `config.grepInvert must be a RegExp`); |
| } |
| } |
| if ("maxFailures" in config && config.maxFailures !== void 0) { |
| if (typeof config.maxFailures !== "number" || config.maxFailures < 0) |
| throw errorWithFile(file2, `config.maxFailures must be a non-negative number`); |
| } |
| if ("preserveOutput" in config && config.preserveOutput !== void 0) { |
| if (typeof config.preserveOutput !== "string" || !["always", "never", "failures-only"].includes(config.preserveOutput)) |
| throw errorWithFile(file2, `config.preserveOutput must be one of "always", "never" or "failures-only"`); |
| } |
| if ("projects" in config && config.projects !== void 0) { |
| if (!Array.isArray(config.projects)) |
| throw errorWithFile(file2, `config.projects must be an array`); |
| config.projects.forEach((project, index) => { |
| validateProject(file2, project, `config.projects[${index}]`); |
| }); |
| } |
| if ("quiet" in config && config.quiet !== void 0) { |
| if (typeof config.quiet !== "boolean") |
| throw errorWithFile(file2, `config.quiet must be a boolean`); |
| } |
| if ("reporter" in config && config.reporter !== void 0) { |
| if (Array.isArray(config.reporter)) { |
| config.reporter.forEach((item, index) => { |
| if (!Array.isArray(item) || item.length <= 0 || item.length > 2 || typeof item[0] !== "string") |
| throw errorWithFile(file2, `config.reporter[${index}] must be a tuple [name, optionalArgument]`); |
| }); |
| } else if (typeof config.reporter !== "string") { |
| throw errorWithFile(file2, `config.reporter must be a string`); |
| } |
| } |
| if ("reportSlowTests" in config && config.reportSlowTests !== void 0 && config.reportSlowTests !== null) { |
| if (!config.reportSlowTests || typeof config.reportSlowTests !== "object") |
| throw errorWithFile(file2, `config.reportSlowTests must be an object`); |
| if (!("max" in config.reportSlowTests) || typeof config.reportSlowTests.max !== "number" || config.reportSlowTests.max < 0) |
| throw errorWithFile(file2, `config.reportSlowTests.max must be a non-negative number`); |
| if (!("threshold" in config.reportSlowTests) || typeof config.reportSlowTests.threshold !== "number" || config.reportSlowTests.threshold < 0) |
| throw errorWithFile(file2, `config.reportSlowTests.threshold must be a non-negative number`); |
| } |
| if ("shard" in config && config.shard !== void 0 && config.shard !== null) { |
| if (!config.shard || typeof config.shard !== "object") |
| throw errorWithFile(file2, `config.shard must be an object`); |
| if (!("total" in config.shard) || typeof config.shard.total !== "number" || config.shard.total < 1) |
| throw errorWithFile(file2, `config.shard.total must be a positive number`); |
| if (!("current" in config.shard) || typeof config.shard.current !== "number" || config.shard.current < 1 || config.shard.current > config.shard.total) |
| throw errorWithFile(file2, `config.shard.current must be a positive number, not greater than config.shard.total`); |
| } |
| if ("updateSnapshots" in config && config.updateSnapshots !== void 0) { |
| if (typeof config.updateSnapshots !== "string" || !["all", "changed", "missing", "none"].includes(config.updateSnapshots)) |
| throw errorWithFile(file2, `config.updateSnapshots must be one of "all", "changed", "missing" or "none"`); |
| } |
| if ("tsconfig" in config && config.tsconfig !== void 0) { |
| if (typeof config.tsconfig !== "string") |
| throw errorWithFile(file2, `config.tsconfig must be a string`); |
| if (!import_fs6.default.existsSync(import_path7.default.resolve(file2, "..", config.tsconfig))) |
| throw errorWithFile(file2, `config.tsconfig does not exist`); |
| } |
| } |
| function validateProject(file2, project, title) { |
| if (typeof project !== "object" || !project) |
| throw errorWithFile(file2, `${title} must be an object`); |
| if ("name" in project && project.name !== void 0) { |
| if (typeof project.name !== "string") |
| throw errorWithFile(file2, `${title}.name must be a string`); |
| } |
| if ("outputDir" in project && project.outputDir !== void 0) { |
| if (typeof project.outputDir !== "string") |
| throw errorWithFile(file2, `${title}.outputDir must be a string`); |
| } |
| if ("repeatEach" in project && project.repeatEach !== void 0) { |
| if (typeof project.repeatEach !== "number" || project.repeatEach < 0) |
| throw errorWithFile(file2, `${title}.repeatEach must be a non-negative number`); |
| } |
| if ("retries" in project && project.retries !== void 0) { |
| if (typeof project.retries !== "number" || project.retries < 0) |
| throw errorWithFile(file2, `${title}.retries must be a non-negative number`); |
| } |
| if ("testDir" in project && project.testDir !== void 0) { |
| if (typeof project.testDir !== "string") |
| throw errorWithFile(file2, `${title}.testDir must be a string`); |
| } |
| for (const prop of ["testIgnore", "testMatch"]) { |
| if (prop in project && project[prop] !== void 0) { |
| const value = project[prop]; |
| if (Array.isArray(value)) { |
| value.forEach((item, index) => { |
| if (typeof item !== "string" && !isRegExp2(item)) |
| throw errorWithFile(file2, `${title}.${prop}[${index}] must be a string or a RegExp`); |
| }); |
| } else if (typeof value !== "string" && !isRegExp2(value)) { |
| throw errorWithFile(file2, `${title}.${prop} must be a string or a RegExp`); |
| } |
| } |
| } |
| if ("timeout" in project && project.timeout !== void 0) { |
| if (typeof project.timeout !== "number" || project.timeout < 0) |
| throw errorWithFile(file2, `${title}.timeout must be a non-negative number`); |
| } |
| if ("use" in project && project.use !== void 0) { |
| if (!project.use || typeof project.use !== "object") |
| throw errorWithFile(file2, `${title}.use must be an object`); |
| } |
| if ("ignoreSnapshots" in project && project.ignoreSnapshots !== void 0) { |
| if (typeof project.ignoreSnapshots !== "boolean") |
| throw errorWithFile(file2, `${title}.ignoreSnapshots must be a boolean`); |
| } |
| if ("workers" in project && project.workers !== void 0) { |
| if (typeof project.workers === "number" && project.workers <= 0) |
| throw errorWithFile(file2, `${title}.workers must be a positive number`); |
| else if (typeof project.workers === "string" && !project.workers.endsWith("%")) |
| throw errorWithFile(file2, `${title}.workers must be a number or percentage`); |
| } |
| } |
| function resolveConfigLocation(configFile) { |
| const configFileOrDirectory = configFile ? import_path7.default.resolve(process.cwd(), configFile) : process.cwd(); |
| const resolvedConfigFile = resolveConfigFile2(configFileOrDirectory); |
| return { |
| resolvedConfigFile, |
| configDir: resolvedConfigFile ? import_path7.default.dirname(resolvedConfigFile) : configFileOrDirectory |
| }; |
| } |
| function resolveConfigFile2(configFileOrDirectory) { |
| const resolveConfig = (configFile) => { |
| if (import_fs6.default.existsSync(configFile)) |
| return configFile; |
| }; |
| const resolveConfigFileFromDirectory = (directory) => { |
| for (const ext of [".ts", ".js", ".mts", ".mjs", ".cts", ".cjs"]) { |
| const configFile = resolveConfig(import_path7.default.resolve(directory, "playwright.config" + ext)); |
| if (configFile) |
| return configFile; |
| } |
| }; |
| if (!import_fs6.default.existsSync(configFileOrDirectory)) |
| throw new Error(`${configFileOrDirectory} does not exist`); |
| if (import_fs6.default.statSync(configFileOrDirectory).isDirectory()) { |
| const configFile = resolveConfigFileFromDirectory(configFileOrDirectory); |
| if (configFile) |
| return configFile; |
| return void 0; |
| } |
| return configFileOrDirectory; |
| } |
| async function loadConfigFromFile(configFile, overrides, ignoreDeps) { |
| return await loadConfig(resolveConfigLocation(configFile), overrides, ignoreDeps); |
| } |
| async function loadEmptyConfigForMergeReports() { |
| return await loadConfig({ configDir: process.cwd() }); |
| } |
|
|
| |
| var fixtures_exports = {}; |
| __export(fixtures_exports, { |
| FixturePool: () => FixturePool, |
| fixtureParameterNames: () => fixtureParameterNames, |
| formatPotentiallyInternalLocation: () => formatPotentiallyInternalLocation, |
| inheritFixtureNames: () => inheritFixtureNames |
| }); |
| var import_crypto2 = __toESM(require("crypto")); |
| var kScopeOrder = ["test", "worker"]; |
| function isFixtureTuple(value) { |
| return Array.isArray(value) && typeof value[1] === "object"; |
| } |
| function isFixtureOption(value) { |
| return isFixtureTuple(value) && !!value[1].option; |
| } |
| var FixturePool = class { |
| constructor(fixturesList, onLoadError, parentPool, disallowWorkerFixtures, optionOverrides) { |
| this._registrations = new Map(parentPool ? parentPool._registrations : []); |
| this._onLoadError = onLoadError; |
| const allOverrides = optionOverrides?.overrides ?? {}; |
| const overrideKeys = new Set(Object.keys(allOverrides)); |
| for (const list of fixturesList) { |
| this._appendFixtureList(list, !!disallowWorkerFixtures, false); |
| const selectedOverrides = {}; |
| for (const [key, value] of Object.entries(list.fixtures)) { |
| if (isFixtureOption(value) && overrideKeys.has(key)) |
| selectedOverrides[key] = [allOverrides[key], value[1]]; |
| } |
| if (Object.entries(selectedOverrides).length) |
| this._appendFixtureList({ fixtures: selectedOverrides, location: optionOverrides.location }, !!disallowWorkerFixtures, true); |
| } |
| if (optionOverrides) { |
| for (const key of overrideKeys) { |
| const registration = this._registrations.get(key); |
| if (registration && !registration.option) |
| this._addLoadError(`Fixture "${key}" cannot be overridden in the configuration "use" section. Only fixtures registered with { option: true } can be set in the config.`, optionOverrides.location); |
| } |
| } |
| this.digest = this.validate(); |
| } |
| _appendFixtureList(list, disallowWorkerFixtures, isOptionsOverride) { |
| const { fixtures, location } = list; |
| for (const entry of Object.entries(fixtures)) { |
| const name = entry[0]; |
| let value = entry[1]; |
| let options; |
| if (isFixtureTuple(value)) { |
| options = { |
| auto: value[1].auto ?? false, |
| scope: value[1].scope || "test", |
| option: !!value[1].option, |
| timeout: value[1].timeout, |
| customTitle: value[1].title, |
| box: value[1].box |
| }; |
| value = value[0]; |
| } |
| let fn = value; |
| const previous = this._registrations.get(name); |
| if (previous && options) { |
| if (previous.scope !== options.scope) { |
| this._addLoadError(`Fixture "${name}" has already been registered as a { scope: '${previous.scope}' } fixture defined in ${formatLocation(previous.location)}.`, location); |
| continue; |
| } |
| if (previous.auto !== options.auto) { |
| this._addLoadError(`Fixture "${name}" has already been registered as a { auto: '${previous.scope}' } fixture defined in ${formatLocation(previous.location)}.`, location); |
| continue; |
| } |
| } else if (previous) { |
| options = { auto: previous.auto, scope: previous.scope, option: previous.option, timeout: previous.timeout, customTitle: previous.customTitle }; |
| } else if (!options) { |
| options = { auto: false, scope: "test", option: false, timeout: void 0 }; |
| } |
| if (!kScopeOrder.includes(options.scope)) { |
| this._addLoadError(`Fixture "${name}" has unknown { scope: '${options.scope}' }.`, location); |
| continue; |
| } |
| if (options.scope === "worker" && disallowWorkerFixtures) { |
| this._addLoadError(`Cannot use({ ${name} }) in a describe group, because it forces a new worker. |
| Make it top-level in the test file or put in the configuration file.`, location); |
| continue; |
| } |
| if (fn === void 0 && options.option && previous) { |
| let original = previous; |
| while (!original.optionOverride && original.super) |
| original = original.super; |
| fn = original.fn; |
| } |
| const deps = fixtureParameterNames(fn, location, (e) => this._onLoadError(e)); |
| const registration = { id: "", name, location, scope: options.scope, fn, auto: options.auto, option: options.option, timeout: options.timeout, customTitle: options.customTitle, box: options.box, deps, super: previous, optionOverride: isOptionsOverride }; |
| registrationId(registration); |
| this._registrations.set(name, registration); |
| } |
| } |
| validate() { |
| const markers = new Map(); |
| const stack = []; |
| let hasDependencyErrors = false; |
| const addDependencyError = (message, location) => { |
| hasDependencyErrors = true; |
| this._addLoadError(message, location); |
| }; |
| const visit = (registration, boxedOnly) => { |
| markers.set(registration, "visiting"); |
| stack.push(registration); |
| for (const name of registration.deps) { |
| const dep = this.resolve(name, registration); |
| if (!dep) { |
| if (name === registration.name) |
| addDependencyError(`Fixture "${registration.name}" references itself, but does not have a base implementation.`, registration.location); |
| else |
| addDependencyError(`Fixture "${registration.name}" has unknown parameter "${name}".`, registration.location); |
| continue; |
| } |
| if (kScopeOrder.indexOf(registration.scope) > kScopeOrder.indexOf(dep.scope)) { |
| addDependencyError(`${registration.scope} fixture "${registration.name}" cannot depend on a ${dep.scope} fixture "${name}" defined in ${formatPotentiallyInternalLocation(dep.location)}.`, registration.location); |
| continue; |
| } |
| if (!markers.has(dep)) { |
| visit(dep, boxedOnly); |
| } else if (markers.get(dep) === "visiting") { |
| const index = stack.indexOf(dep); |
| const allRegs = stack.slice(index, stack.length); |
| const filteredRegs = allRegs.filter((r) => !r.box); |
| const regs = boxedOnly ? filteredRegs : allRegs; |
| const names2 = regs.map((r) => `"${r.name}"`); |
| addDependencyError(`Fixtures ${names2.join(" -> ")} -> "${dep.name}" form a dependency cycle: ${regs.map((r) => formatPotentiallyInternalLocation(r.location)).join(" -> ")} -> ${formatPotentiallyInternalLocation(dep.location)}`, dep.location); |
| continue; |
| } |
| } |
| markers.set(registration, "visited"); |
| stack.pop(); |
| }; |
| const names = Array.from(this._registrations.keys()).sort(); |
| for (const name of names) { |
| const registration = this._registrations.get(name); |
| if (!registration.box) |
| visit(registration, true); |
| } |
| if (!hasDependencyErrors) { |
| for (const name of names) { |
| const registration = this._registrations.get(name); |
| if (registration.box) |
| visit(registration, false); |
| } |
| } |
| const hash = import_crypto2.default.createHash("sha1"); |
| for (const name of names) { |
| const registration = this._registrations.get(name); |
| if (registration.scope === "worker") |
| hash.update(registration.id + ";"); |
| } |
| return hash.digest("hex"); |
| } |
| validateFunction(fn, prefix, location) { |
| for (const name of fixtureParameterNames(fn, location, (e) => this._onLoadError(e))) { |
| const registration = this._registrations.get(name); |
| if (!registration) |
| this._addLoadError(`${prefix} has unknown parameter "${name}".`, location); |
| } |
| } |
| resolve(name, forFixture) { |
| if (name === forFixture?.name) |
| return forFixture.super; |
| return this._registrations.get(name); |
| } |
| autoFixtures() { |
| return [...this._registrations.values()].filter((r) => r.auto !== false); |
| } |
| _addLoadError(message, location) { |
| this._onLoadError({ message, location }); |
| } |
| }; |
| var signatureSymbol = Symbol("signature"); |
| function formatPotentiallyInternalLocation(location) { |
| const isUserFixture = location && filterStackFile(location.file); |
| return isUserFixture ? formatLocation(location) : "<builtin>"; |
| } |
| function fixtureParameterNames(fn, location, onError) { |
| if (typeof fn !== "function") |
| return []; |
| if (!fn[signatureSymbol]) |
| fn[signatureSymbol] = innerFixtureParameterNames(fn, location, onError); |
| return fn[signatureSymbol]; |
| } |
| function inheritFixtureNames(from, to) { |
| to[signatureSymbol] = from[signatureSymbol]; |
| } |
| function innerFixtureParameterNames(fn, location, onError) { |
| const text = filterOutComments(fn.toString()); |
| const match = text.match(/(?:async)?(?:\s+function)?[^(]*\(([^)]*)/); |
| if (!match) |
| return []; |
| const trimmedParams = match[1].trim(); |
| if (!trimmedParams) |
| return []; |
| const [firstParam] = splitByComma(trimmedParams); |
| if (firstParam[0] !== "{" || firstParam[firstParam.length - 1] !== "}") { |
| onError({ message: "First argument must use the object destructuring pattern: " + firstParam, location }); |
| return []; |
| } |
| const props = splitByComma(firstParam.substring(1, firstParam.length - 1)).map((prop) => { |
| const colon = prop.indexOf(":"); |
| return colon === -1 ? prop.trim() : prop.substring(0, colon).trim(); |
| }); |
| const restProperty = props.find((prop) => prop.startsWith("...")); |
| if (restProperty) { |
| onError({ message: `Rest property "${restProperty}" is not supported. List all used fixtures explicitly, separated by comma.`, location }); |
| return []; |
| } |
| return props; |
| } |
| function filterOutComments(s) { |
| const result2 = []; |
| let commentState = "none"; |
| for (let i = 0; i < s.length; ++i) { |
| if (commentState === "singleline") { |
| if (s[i] === "\n") |
| commentState = "none"; |
| } else if (commentState === "multiline") { |
| if (s[i - 1] === "*" && s[i] === "/") |
| commentState = "none"; |
| } else if (commentState === "none") { |
| if (s[i] === "/" && s[i + 1] === "/") { |
| commentState = "singleline"; |
| } else if (s[i] === "/" && s[i + 1] === "*") { |
| commentState = "multiline"; |
| i += 2; |
| } else { |
| result2.push(s[i]); |
| } |
| } |
| } |
| return result2.join(""); |
| } |
| function splitByComma(s) { |
| const result2 = []; |
| const stack = []; |
| let start = 0; |
| for (let i = 0; i < s.length; i++) { |
| if (s[i] === "{" || s[i] === "[") { |
| stack.push(s[i] === "{" ? "}" : "]"); |
| } else if (s[i] === stack[stack.length - 1]) { |
| stack.pop(); |
| } else if (!stack.length && s[i] === ",") { |
| const token = s.substring(start, i).trim(); |
| if (token) |
| result2.push(token); |
| start = i + 1; |
| } |
| } |
| const lastToken = s.substring(start).trim(); |
| if (lastToken) |
| result2.push(lastToken); |
| return result2; |
| } |
| var registrationIdMap = new Map(); |
| var lastId = 0; |
| function registrationId(registration) { |
| if (registration.id) |
| return registration.id; |
| const key = registration.name + "@@@" + (registration.super ? registrationId(registration.super) : ""); |
| let map = registrationIdMap.get(key); |
| if (!map) { |
| map = new Map(); |
| registrationIdMap.set(key, map); |
| } |
| if (!map.has(registration.fn)) |
| map.set(registration.fn, String(lastId++)); |
| registration.id = map.get(registration.fn); |
| return registration.id; |
| } |
|
|
| |
| var ipc_exports = {}; |
| __export(ipc_exports, { |
| serializeConfig: () => serializeConfig, |
| stdioChunkToParams: () => stdioChunkToParams, |
| toTestInfoErrorPayload: () => toTestInfoErrorPayload |
| }); |
| var import_util6 = __toESM(require("util")); |
| function serializeConfig(config, passCompilationCache) { |
| const result2 = { |
| location: { configDir: config.configDir, resolvedConfigFile: config.config.configFile }, |
| configCLIOverrides: config.configCLIOverrides, |
| compilationCache: passCompilationCache ? serializeCompilationCache() : void 0 |
| }; |
| try { |
| result2.metadata = JSON.stringify(config.config.metadata); |
| } catch (error) { |
| } |
| return result2; |
| } |
| function stdioChunkToParams(chunk) { |
| if (chunk instanceof Uint8Array) |
| return { buffer: Buffer.from(chunk).toString("base64") }; |
| if (typeof chunk !== "string") |
| return { text: import_util6.default.inspect(chunk) }; |
| return { text: chunk }; |
| } |
| function toTestInfoErrorPayload(error) { |
| const result2 = {}; |
| if (error.message !== void 0) |
| result2.message = error.message; |
| if (error.stack !== void 0) |
| result2.stack = error.stack; |
| if (error.value !== void 0) |
| result2.value = error.value; |
| if (error.cause !== void 0) |
| result2.cause = toTestInfoErrorPayload(error.cause); |
| return result2; |
| } |
|
|
| |
| var poolBuilder_exports = {}; |
| __export(poolBuilder_exports, { |
| PoolBuilder: () => PoolBuilder |
| }); |
| var PoolBuilder = class _PoolBuilder { |
| constructor(type, project) { |
| this._testTypePools = new Map(); |
| this._type = type; |
| this._project = project; |
| } |
| static createForLoader() { |
| return new _PoolBuilder("loader"); |
| } |
| static createForWorker(project) { |
| return new _PoolBuilder("worker", project); |
| } |
| buildPools(suite, testErrors) { |
| suite.forEachTest((test) => { |
| const pool = this._buildPoolForTest(test, testErrors); |
| if (this._type === "loader") |
| test._poolDigest = pool.digest; |
| if (this._type === "worker") |
| test._pool = pool; |
| }); |
| } |
| _buildPoolForTest(test, testErrors) { |
| let pool = this._buildTestTypePool(test._testType, testErrors); |
| const parents = []; |
| for (let parent = test.parent; parent; parent = parent.parent) |
| parents.push(parent); |
| parents.reverse(); |
| for (const parent of parents) { |
| if (parent._use.length) |
| pool = new FixturePool(parent._use, (e) => this._handleLoadError(e, testErrors), pool, parent._type === "describe"); |
| for (const hook of parent._hooks) |
| pool.validateFunction(hook.fn, hook.type + " hook", hook.location); |
| for (const modifier of parent._modifiers) |
| pool.validateFunction(modifier.fn, modifier.type + " modifier", modifier.location); |
| } |
| pool.validateFunction(test.fn, "Test", test.location); |
| return pool; |
| } |
| _buildTestTypePool(testType, testErrors) { |
| if (!this._testTypePools.has(testType)) { |
| const optionOverrides = { |
| overrides: this._project?.project?.use ?? {}, |
| location: { file: `project#${this._project?.id}`, line: 1, column: 1 } |
| }; |
| const pool = new FixturePool(testType.fixtures, (e) => this._handleLoadError(e, testErrors), void 0, void 0, optionOverrides); |
| this._testTypePools.set(testType, pool); |
| } |
| return this._testTypePools.get(testType); |
| } |
| _handleLoadError(e, testErrors) { |
| if (testErrors) |
| testErrors.push(e); |
| else |
| throw new Error(`${formatLocation(e.location)}: ${e.message}`); |
| } |
| }; |
|
|
| |
| var process_exports = {}; |
| __export(process_exports, { |
| ProcessRunner: () => ProcessRunner, |
| startProcessRunner: () => startProcessRunner |
| }); |
| var import_bootstrap = require("playwright-core/lib/bootstrap"); |
| var { ManualPromise } = require("playwright-core/lib/coreBundle").iso; |
| var { setTimeOrigin } = require("playwright-core/lib/coreBundle").iso; |
| var { startProfiling, stopProfiling } = require("playwright-core/lib/coreBundle").utils; |
| var ProcessRunner = class { |
| async gracefullyClose() { |
| } |
| dispatchEvent(method, params) { |
| const response = { method, params }; |
| sendMessageToParent({ method: "__dispatch__", params: response }); |
| } |
| async sendRequest(method, params) { |
| return await sendRequestToParent(method, params); |
| } |
| async sendMessageNoReply(method, params) { |
| void sendRequestToParent(method, params).catch(() => { |
| }); |
| } |
| }; |
| var gracefullyCloseCalled = false; |
| var forceExitInitiated = false; |
| var processRunner; |
| var processName; |
| var startingEnv = { ...process.env }; |
| function startProcessRunner(create) { |
| sendMessageToParent({ method: "ready" }); |
| process.on("disconnect", () => gracefullyCloseAndExit(true)); |
| process.on("SIGINT", () => { |
| }); |
| process.on("SIGTERM", () => { |
| }); |
| process.on("message", async (message) => { |
| if (message.method === "__init__") { |
| const { processParams, runnerParams } = message.params; |
| void startProfiling(); |
| setTimeOrigin(processParams.timeOrigin); |
| processRunner = create(runnerParams); |
| processName = processParams.processName; |
| return; |
| } |
| if (message.method === "__stop__") { |
| const keys = new Set([...Object.keys(process.env), ...Object.keys(startingEnv)]); |
| const producedEnv = [...keys].filter((key) => startingEnv[key] !== process.env[key]).map((key) => [key, process.env[key] ?? null]); |
| sendMessageToParent({ method: "__env_produced__", params: producedEnv }); |
| await gracefullyCloseAndExit(false); |
| return; |
| } |
| if (message.method === "__dispatch__") { |
| const { id, method, params } = message.params; |
| try { |
| const result2 = await processRunner[method](params); |
| const response = { id, result: result2 }; |
| sendMessageToParent({ method: "__dispatch__", params: response }); |
| } catch (e) { |
| const response = { id, error: serializeError(e) }; |
| sendMessageToParent({ method: "__dispatch__", params: response }); |
| } |
| } |
| if (message.method === "__response__") |
| handleResponseFromParent(message.params); |
| }); |
| } |
| var kForceExitTimeout = +(process.env.PWTEST_FORCE_EXIT_TIMEOUT || 3e4); |
| async function gracefullyCloseAndExit(forceExit) { |
| if (forceExit && !forceExitInitiated) { |
| forceExitInitiated = true; |
| setTimeout(() => process.exit(0), kForceExitTimeout); |
| } |
| if (!gracefullyCloseCalled) { |
| gracefullyCloseCalled = true; |
| await processRunner?.gracefullyClose().catch(() => { |
| }); |
| if (processName) |
| await stopProfiling(processName).catch(() => { |
| }); |
| process.exit(0); |
| } |
| } |
| function sendMessageToParent(message) { |
| try { |
| process.send(message); |
| } catch (e) { |
| try { |
| JSON.stringify(message); |
| } catch { |
| throw e; |
| } |
| } |
| } |
| var lastId2 = 0; |
| var requestCallbacks = new Map(); |
| async function sendRequestToParent(method, params) { |
| const id = ++lastId2; |
| sendMessageToParent({ method: "__request__", params: { id, method, params } }); |
| const promise = new ManualPromise(); |
| requestCallbacks.set(id, promise); |
| return promise; |
| } |
| function handleResponseFromParent(response) { |
| const promise = requestCallbacks.get(response.id); |
| if (!promise) |
| return; |
| requestCallbacks.delete(response.id); |
| if (response.error) |
| promise.reject(new Error(response.error.message)); |
| else |
| promise.resolve(response.result); |
| } |
|
|
| |
| var suiteUtils_exports = {}; |
| __export(suiteUtils_exports, { |
| applyRepeatEachIndex: () => applyRepeatEachIndex, |
| bindFileSuiteToProject: () => bindFileSuiteToProject, |
| createFiltersFromArguments: () => createFiltersFromArguments, |
| filterOnly: () => filterOnly, |
| filterTestsRemoveEmptySuites: () => filterTestsRemoveEmptySuites |
| }); |
| var import_path8 = __toESM(require("path")); |
| var { calculateSha1: calculateSha13 } = require("playwright-core/lib/coreBundle").utils; |
| var { toPosixPath } = require("playwright-core/lib/coreBundle").utils; |
| function filterTestsRemoveEmptySuites(suite, filter) { |
| const filteredSuites = suite.suites.filter((child) => filterTestsRemoveEmptySuites(child, filter)); |
| const filteredTests = suite.tests.filter(filter); |
| const entries = new Set([...filteredSuites, ...filteredTests]); |
| suite._entries = suite._entries.filter((e) => entries.has(e)); |
| return !!suite._entries.length; |
| } |
| function bindFileSuiteToProject(project, suite) { |
| const relativeFile = import_path8.default.relative(project.project.testDir, suite.location.file); |
| const fileId = calculateSha13(toPosixPath(relativeFile)).slice(0, 20); |
| const result2 = suite._deepClone(); |
| result2._fileId = fileId; |
| result2.forEachTest((test, suite2) => { |
| suite2._fileId = fileId; |
| const [file2, ...titles] = test.titlePath(); |
| const testIdExpression = `[project=${project.id}]${toPosixPath(file2)}${titles.join("")}`; |
| const testId = fileId + "-" + calculateSha13(testIdExpression).slice(0, 20); |
| test.id = testId; |
| test._projectId = project.id; |
| let inheritedRetries; |
| let inheritedTimeout; |
| for (let parentSuite = suite2; parentSuite; parentSuite = parentSuite.parent) { |
| if (parentSuite._staticAnnotations.length) |
| test.annotations.unshift(...parentSuite._staticAnnotations); |
| if (inheritedRetries === void 0 && parentSuite._retries !== void 0) |
| inheritedRetries = parentSuite._retries; |
| if (inheritedTimeout === void 0 && parentSuite._timeout !== void 0) |
| inheritedTimeout = parentSuite._timeout; |
| } |
| test.retries = inheritedRetries ?? project.project.retries; |
| test.timeout = inheritedTimeout ?? project.project.timeout; |
| if (test.annotations.some((a) => a.type === "skip" || a.type === "fixme")) |
| test.expectedStatus = "skipped"; |
| if (test._poolDigest) |
| test._workerHash = `${project.id}-${test._poolDigest}-0`; |
| }); |
| return result2; |
| } |
| function applyRepeatEachIndex(project, fileSuite, repeatEachIndex) { |
| fileSuite.forEachTest((test, suite) => { |
| if (repeatEachIndex) { |
| const [file2, ...titles] = test.titlePath(); |
| const testIdExpression = `[project=${project.id}]${toPosixPath(file2)}${titles.join("")} (repeat:${repeatEachIndex})`; |
| const testId = suite._fileId + "-" + calculateSha13(testIdExpression).slice(0, 20); |
| test.id = testId; |
| test.repeatEachIndex = repeatEachIndex; |
| if (test._poolDigest) |
| test._workerHash = `${project.id}-${test._poolDigest}-${repeatEachIndex}`; |
| } |
| }); |
| } |
| function filterOnly(suite) { |
| if (!suite._getOnlyItems().length) |
| return; |
| const suiteFilter = (suite2) => suite2._only; |
| const testFilter = (test) => test._only; |
| return filterSuiteWithOnlySemantics(suite, suiteFilter, testFilter); |
| } |
| function filterSuiteWithOnlySemantics(suite, suiteFilter, testFilter) { |
| const onlySuites = suite.suites.filter((child) => filterSuiteWithOnlySemantics(child, suiteFilter, testFilter) || suiteFilter(child)); |
| const onlyTests = suite.tests.filter(testFilter); |
| const onlyEntries = new Set([...onlySuites, ...onlyTests]); |
| if (onlyEntries.size) { |
| suite._entries = suite._entries.filter((e) => onlyEntries.has(e)); |
| return true; |
| } |
| return false; |
| } |
| function createFiltersFromArguments(args) { |
| const matchers = args.map((arg) => { |
| const parsed = parseLocationArg(arg); |
| const fileMatcher = createFileMatcher(forceRegExp(parsed.file)); |
| const locationMatcher2 = (file2, line, column) => fileMatcher(file2) && (parsed.line === line || parsed.line === null) && (parsed.column === column || parsed.column === null); |
| return { fileMatcher, locationMatcher: locationMatcher2 }; |
| }); |
| const fileFilter = (file2) => matchers.some((m) => m.fileMatcher(file2)); |
| const locationMatcher = (file2, line, column) => matchers.some((m) => m.locationMatcher(file2, line, column)); |
| const testFilter = (test) => { |
| for (let suite = test.parent; suite; suite = suite.parent) { |
| if (suite.location && locationMatcher(suite.location.file, suite.location.line, suite.location.column)) |
| return true; |
| } |
| return locationMatcher(test.location.file, test.location.line, test.location.column); |
| }; |
| return { fileFilter, testFilter }; |
| } |
|
|
| |
| var test_exports = {}; |
| __export(test_exports, { |
| Suite: () => Suite, |
| TestCase: () => TestCase |
| }); |
|
|
| |
| var testType_exports = {}; |
| __export(testType_exports, { |
| TestTypeImpl: () => TestTypeImpl, |
| mergeTests: () => mergeTests, |
| rootTestType: () => rootTestType |
| }); |
| var import_globals2 = require("../globals"); |
| var import_expect = require("../matchers/expect"); |
|
|
| |
| var { validate } = require("playwright-core/lib/coreBundle").iso; |
| var testAnnotationSchema = { |
| type: "object", |
| properties: { |
| type: { type: "string" }, |
| description: { type: "string" } |
| }, |
| required: ["type"] |
| }; |
| var testDetailsSchema = { |
| type: "object", |
| properties: { |
| tag: { |
| oneOf: [ |
| { type: "string", pattern: "^@", patternError: "Tag must start with '@'" }, |
| { type: "array", items: { type: "string", pattern: "^@", patternError: "Tag must start with '@'" } } |
| ] |
| }, |
| annotation: { |
| oneOf: [ |
| testAnnotationSchema, |
| { type: "array", items: testAnnotationSchema } |
| ] |
| } |
| } |
| }; |
| function validateTestDetails(details, location) { |
| const errors = validate(details, testDetailsSchema, "details"); |
| if (errors.length) |
| throw new Error(errors.join("\n")); |
| const obj = details; |
| const tag = obj.tag; |
| const tags = tag === void 0 ? [] : typeof tag === "string" ? [tag] : tag; |
| const annotation = obj.annotation; |
| const annotations = annotation === void 0 ? [] : Array.isArray(annotation) ? annotation : [annotation]; |
| return { |
| annotations: annotations.map((a) => ({ ...a, location })), |
| tags, |
| location |
| }; |
| } |
|
|
| |
| var { monotonicTime } = require("playwright-core/lib/coreBundle").iso; |
| var { raceAgainstDeadline } = require("playwright-core/lib/coreBundle").iso; |
| var { getPackageManagerExecCommand } = require("playwright-core/lib/coreBundle").utils; |
| var { currentZone } = require("playwright-core/lib/coreBundle").utils; |
| var testTypeSymbol = Symbol("testType"); |
| var TestTypeImpl = class _TestTypeImpl { |
| constructor(fixtures) { |
| this.fixtures = fixtures; |
| const test = wrapFunctionWithLocation(this._createTest.bind(this, "default")); |
| test[testTypeSymbol] = this; |
| test.expect = import_expect.expect; |
| test.only = wrapFunctionWithLocation(this._createTest.bind(this, "only")); |
| test.describe = wrapFunctionWithLocation(this._describe.bind(this, "default")); |
| test.describe.only = wrapFunctionWithLocation(this._describe.bind(this, "only")); |
| test.describe.configure = wrapFunctionWithLocation(this._configure.bind(this)); |
| test.describe.fixme = wrapFunctionWithLocation(this._describe.bind(this, "fixme")); |
| test.describe.parallel = wrapFunctionWithLocation(this._describe.bind(this, "parallel")); |
| test.describe.parallel.only = wrapFunctionWithLocation(this._describe.bind(this, "parallel.only")); |
| test.describe.serial = wrapFunctionWithLocation(this._describe.bind(this, "serial")); |
| test.describe.serial.only = wrapFunctionWithLocation(this._describe.bind(this, "serial.only")); |
| test.describe.skip = wrapFunctionWithLocation(this._describe.bind(this, "skip")); |
| test.beforeEach = wrapFunctionWithLocation(this._hook.bind(this, "beforeEach")); |
| test.afterEach = wrapFunctionWithLocation(this._hook.bind(this, "afterEach")); |
| test.beforeAll = wrapFunctionWithLocation(this._hook.bind(this, "beforeAll")); |
| test.afterAll = wrapFunctionWithLocation(this._hook.bind(this, "afterAll")); |
| test.skip = wrapFunctionWithLocation(this._modifier.bind(this, "skip")); |
| test.fixme = wrapFunctionWithLocation(this._modifier.bind(this, "fixme")); |
| test.fail = wrapFunctionWithLocation(this._modifier.bind(this, "fail")); |
| test.abort = wrapFunctionWithLocation(this._abort.bind(this)); |
| test.fail.only = wrapFunctionWithLocation(this._createTest.bind(this, "fail.only")); |
| test.slow = wrapFunctionWithLocation(this._modifier.bind(this, "slow")); |
| test.setTimeout = wrapFunctionWithLocation(this._setTimeout.bind(this)); |
| test.step = this._step.bind(this, "pass"); |
| test.step.skip = this._step.bind(this, "skip"); |
| test.use = wrapFunctionWithLocation(this._use.bind(this)); |
| test.extend = wrapFunctionWithLocation(this._extend.bind(this)); |
| test.info = () => { |
| const result2 = (0, import_globals2.currentTestInfo)(); |
| if (!result2) |
| throw new Error("test.info() can only be called while test is running"); |
| return result2; |
| }; |
| this.test = test; |
| } |
| _currentSuite(location, title) { |
| const suite = (0, import_globals2.currentlyLoadingFileSuite)(); |
| if (!suite) { |
| throw new Error([ |
| `Playwright Test did not expect ${title} to be called here.`, |
| `Most common reasons include:`, |
| `- You are calling ${title} in a configuration file.`, |
| `- You are calling ${title} in a file that is imported by the configuration file.`, |
| `- You have two different versions of @playwright/test. This usually happens`, |
| ` when one of the dependencies in your package.json depends on @playwright/test.` |
| ].join("\n")); |
| } |
| return suite; |
| } |
| _createTest(type, location, title, fnOrDetails, fn) { |
| throwIfRunningInsideJest(); |
| const suite = this._currentSuite(location, "test()"); |
| if (!suite) |
| return; |
| let details; |
| let body; |
| if (typeof fnOrDetails === "function") { |
| body = fnOrDetails; |
| details = {}; |
| } else { |
| body = fn; |
| details = fnOrDetails; |
| } |
| const validatedDetails = validateTestDetails(details, location); |
| const test = new TestCase(title, body, this, location); |
| test._requireFile = suite._requireFile; |
| test.annotations.push(...validatedDetails.annotations); |
| test._tags.push(...validatedDetails.tags); |
| suite._addTest(test); |
| if (type === "only" || type === "fail.only") |
| test._only = true; |
| if (type === "skip" || type === "fixme" || type === "fail") |
| test.annotations.push({ type, location }); |
| else if (type === "fail.only") |
| test.annotations.push({ type: "fail", location }); |
| } |
| _describe(type, location, titleOrFn, fnOrDetails, fn) { |
| throwIfRunningInsideJest(); |
| const suite = this._currentSuite(location, "test.describe()"); |
| if (!suite) |
| return; |
| let title; |
| let body; |
| let details; |
| if (typeof titleOrFn === "function") { |
| title = ""; |
| details = {}; |
| body = titleOrFn; |
| } else if (typeof fnOrDetails === "function") { |
| title = titleOrFn; |
| details = {}; |
| body = fnOrDetails; |
| } else { |
| title = titleOrFn; |
| details = fnOrDetails; |
| body = fn; |
| } |
| const validatedDetails = validateTestDetails(details, location); |
| const child = new Suite(title, "describe"); |
| child._requireFile = suite._requireFile; |
| child.location = location; |
| child._staticAnnotations.push(...validatedDetails.annotations); |
| child._tags.push(...validatedDetails.tags); |
| suite._addSuite(child); |
| if (type === "only" || type === "serial.only" || type === "parallel.only") |
| child._only = true; |
| if (type === "serial" || type === "serial.only") |
| child._parallelMode = "serial"; |
| if (type === "parallel" || type === "parallel.only") |
| child._parallelMode = "parallel"; |
| if (type === "skip" || type === "fixme") |
| child._staticAnnotations.push({ type, location }); |
| for (let parent = suite; parent; parent = parent.parent) { |
| if (parent._parallelMode === "serial" && child._parallelMode === "parallel") |
| throw new Error("describe.parallel cannot be nested inside describe.serial"); |
| if (parent._parallelMode === "default" && child._parallelMode === "parallel") |
| throw new Error("describe.parallel cannot be nested inside describe with default mode"); |
| } |
| (0, import_globals2.setCurrentlyLoadingFileSuite)(child); |
| body(); |
| (0, import_globals2.setCurrentlyLoadingFileSuite)(suite); |
| } |
| _hook(name, location, title, fn) { |
| const suite = this._currentSuite(location, `test.${name}()`); |
| if (!suite) |
| return; |
| if (typeof title === "function") { |
| fn = title; |
| title = `${name} hook`; |
| } |
| suite._hooks.push({ type: name, fn, title, location }); |
| } |
| _configure(location, options) { |
| throwIfRunningInsideJest(); |
| const suite = this._currentSuite(location, `test.describe.configure()`); |
| if (!suite) |
| return; |
| if (options.timeout !== void 0) |
| suite._timeout = options.timeout; |
| if (options.retries !== void 0) |
| suite._retries = options.retries; |
| if (options.mode !== void 0) { |
| if (suite._parallelMode !== "none") |
| throw new Error(`"${suite._parallelMode}" mode is already assigned for the enclosing scope.`); |
| suite._parallelMode = options.mode; |
| for (let parent = suite.parent; parent; parent = parent.parent) { |
| if (parent._parallelMode === "serial" && suite._parallelMode === "parallel") |
| throw new Error("describe with parallel mode cannot be nested inside describe with serial mode"); |
| if (parent._parallelMode === "default" && suite._parallelMode === "parallel") |
| throw new Error("describe with parallel mode cannot be nested inside describe with default mode"); |
| } |
| } |
| } |
| _modifier(type, location, ...modifierArgs) { |
| const suite = (0, import_globals2.currentlyLoadingFileSuite)(); |
| if (suite) { |
| if (typeof modifierArgs[0] === "string" && typeof modifierArgs[1] === "function" && (type === "skip" || type === "fixme" || type === "fail")) { |
| this._createTest(type, location, modifierArgs[0], modifierArgs[1]); |
| return; |
| } |
| if (typeof modifierArgs[0] === "string" && typeof modifierArgs[1] === "object" && typeof modifierArgs[2] === "function" && (type === "skip" || type === "fixme" || type === "fail")) { |
| this._createTest(type, location, modifierArgs[0], modifierArgs[1], modifierArgs[2]); |
| return; |
| } |
| if (typeof modifierArgs[0] === "function") { |
| suite._modifiers.push({ type, fn: modifierArgs[0], location, description: modifierArgs[1] }); |
| } else { |
| if (modifierArgs.length >= 1 && !modifierArgs[0]) |
| return; |
| const description = modifierArgs[1]; |
| suite._staticAnnotations.push({ type, description, location }); |
| } |
| return; |
| } |
| const testInfo = (0, import_globals2.currentTestInfo)(); |
| if (!testInfo) |
| throw new Error(`test.${type}() can only be called inside test, describe block or fixture`); |
| if (typeof modifierArgs[0] === "function") |
| throw new Error(`test.${type}() with a function can only be called inside describe block`); |
| testInfo._modifier(type, location, modifierArgs); |
| } |
| _abort(location, message) { |
| const testInfo = (0, import_globals2.currentTestInfo)(); |
| if (!testInfo) |
| throw new Error(`test.abort() can only be called inside a test or fixture`); |
| testInfo._abort(location, message); |
| } |
| _setTimeout(location, timeout) { |
| const suite = (0, import_globals2.currentlyLoadingFileSuite)(); |
| if (suite) { |
| suite._timeout = timeout; |
| return; |
| } |
| const testInfo = (0, import_globals2.currentTestInfo)(); |
| if (!testInfo) |
| throw new Error(`test.setTimeout() can only be called from a test`); |
| testInfo.setTimeout(timeout); |
| } |
| _use(location, fixtures) { |
| const suite = this._currentSuite(location, `test.use()`); |
| if (!suite) |
| return; |
| suite._use.push({ fixtures, location }); |
| } |
| async _step(expectation, title, body, options = {}) { |
| const testInfo = (0, import_globals2.currentTestInfo)(); |
| if (!testInfo) |
| throw new Error(`test.step() can only be called from a test`); |
| await testInfo._onUserStepBegin?.(title); |
| const step = testInfo._addStep({ category: "test.step", title, location: options.location, box: options.box }); |
| return await currentZone().with("stepZone", step).run(async () => { |
| try { |
| let result2 = void 0; |
| result2 = await raceAgainstDeadline(async () => { |
| try { |
| return await step.info._runStepBody(expectation === "skip", body, step.location); |
| } catch (e) { |
| if (result2?.timedOut) |
| testInfo._failWithError(e); |
| throw e; |
| } |
| }, options.timeout ? monotonicTime() + options.timeout : 0); |
| if (result2.timedOut) |
| throw new TimeoutError(`Step timeout of ${options.timeout}ms exceeded.`); |
| step.complete({}); |
| return result2.result; |
| } catch (error) { |
| step.complete({ error }); |
| throw error; |
| } finally { |
| await testInfo._onUserStepEnd?.(); |
| } |
| }); |
| } |
| _extend(location, fixtures) { |
| if (fixtures[testTypeSymbol]) |
| throw new Error(`test.extend() accepts fixtures object, not a test object. |
| Did you mean to call mergeTests()?`); |
| const fixturesWithLocation = { fixtures, location }; |
| return new _TestTypeImpl([...this.fixtures, fixturesWithLocation]).test; |
| } |
| }; |
| function throwIfRunningInsideJest() { |
| if (process.env.JEST_WORKER_ID) { |
| const packageManagerCommand = getPackageManagerExecCommand(); |
| throw new Error( |
| `Playwright Test needs to be invoked via '${packageManagerCommand} playwright test' and excluded from Jest test runs. |
| Creating one directory for Playwright tests and one for Jest is the recommended way of doing it. |
| See https://playwright.dev/docs/intro for more information about Playwright Test.` |
| ); |
| } |
| } |
| var rootTestType = new TestTypeImpl([]); |
| function mergeTests(...tests) { |
| let result2 = rootTestType; |
| for (const t of tests) { |
| const testTypeImpl = t[testTypeSymbol]; |
| if (!testTypeImpl) |
| throw new Error(`mergeTests() accepts "test" functions as parameters. |
| Did you mean to call test.extend() with fixtures instead?`); |
| const newFixtures = testTypeImpl.fixtures.filter((theirs) => !result2.fixtures.find((ours) => ours.fixtures === theirs.fixtures)); |
| result2 = new TestTypeImpl([...result2.fixtures, ...newFixtures]); |
| } |
| return result2.test; |
| } |
| var TimeoutError = class extends Error { |
| constructor(message) { |
| super(message); |
| this.name = "TimeoutError"; |
| } |
| }; |
|
|
| |
| var baseFullConfig = { |
| forbidOnly: false, |
| fullyParallel: false, |
| globalSetup: null, |
| globalTeardown: null, |
| globalTimeout: 0, |
| grep: /.*/, |
| grepInvert: null, |
| maxFailures: 0, |
| metadata: {}, |
| preserveOutput: "always", |
| projects: [], |
| reporter: [[process.env.CI ? "dot" : "list"]], |
| reportSlowTests: { |
| max: 5, |
| threshold: 3e5 |
| |
| }, |
| configFile: "", |
| rootDir: "", |
| quiet: false, |
| shard: null, |
| tags: [], |
| updateSnapshots: "missing", |
| updateSourceMethod: "patch", |
| version: "", |
| workers: 0, |
| webServer: null |
| }; |
| function computeTestCaseOutcome(test) { |
| let skipped = 0; |
| let didNotRun = 0; |
| let expected = 0; |
| let interrupted = 0; |
| let unexpected = 0; |
| for (const result2 of test.results) { |
| if (result2.status === "interrupted") { |
| ++interrupted; |
| } else if (result2.status === "skipped" && test.expectedStatus === "skipped") { |
| ++skipped; |
| } else if (result2.status === "skipped") { |
| ++didNotRun; |
| } else if (result2.status === test.expectedStatus) { |
| ++expected; |
| } else { |
| ++unexpected; |
| } |
| } |
| if (expected === 0 && unexpected === 0) |
| return "skipped"; |
| if (unexpected === 0) |
| return "expected"; |
| if (expected === 0 && skipped === 0) |
| return "unexpected"; |
| return "flaky"; |
| } |
|
|
| |
| var Base = class { |
| constructor(title) { |
| this._only = false; |
| this._requireFile = ""; |
| this.title = title; |
| } |
| }; |
| var Suite = class _Suite extends Base { |
| constructor(title, type) { |
| super(title); |
| this._use = []; |
| this._entries = []; |
| this._hooks = []; |
| |
| this._staticAnnotations = []; |
| |
| this._tags = []; |
| this._modifiers = []; |
| this._parallelMode = "none"; |
| this._type = type; |
| } |
| get type() { |
| return this._type; |
| } |
| entries() { |
| return this._entries; |
| } |
| get suites() { |
| return this._entries.filter((entry) => entry instanceof _Suite); |
| } |
| get tests() { |
| return this._entries.filter((entry) => entry instanceof TestCase); |
| } |
| _addTest(test) { |
| test.parent = this; |
| this._entries.push(test); |
| } |
| _addSuite(suite) { |
| suite.parent = this; |
| this._entries.push(suite); |
| } |
| _prependSuite(suite) { |
| suite.parent = this; |
| this._entries.unshift(suite); |
| } |
| allTests() { |
| const result2 = []; |
| const visit = (suite) => { |
| for (const entry of suite._entries) { |
| if (entry instanceof _Suite) |
| visit(entry); |
| else |
| result2.push(entry); |
| } |
| }; |
| visit(this); |
| return result2; |
| } |
| _hasTests() { |
| let result2 = false; |
| const visit = (suite) => { |
| for (const entry of suite._entries) { |
| if (result2) |
| return; |
| if (entry instanceof _Suite) |
| visit(entry); |
| else |
| result2 = true; |
| } |
| }; |
| visit(this); |
| return result2; |
| } |
| titlePath() { |
| const titlePath = this.parent ? this.parent.titlePath() : []; |
| if (this.title || this._type !== "describe") |
| titlePath.push(this.title); |
| return titlePath; |
| } |
| _collectGrepTitlePath(path10) { |
| if (this.parent) |
| this.parent._collectGrepTitlePath(path10); |
| if (this.title || this._type !== "describe") |
| path10.push(this.title); |
| path10.push(...this._tags); |
| } |
| _collectTagTitlePath(path10) { |
| this.parent?._collectTagTitlePath(path10); |
| if (this._type === "describe") |
| path10.push(this.title); |
| path10.push(...this._tags); |
| } |
| _getOnlyItems() { |
| const items = []; |
| if (this._only) |
| items.push(this); |
| for (const suite of this.suites) |
| items.push(...suite._getOnlyItems()); |
| items.push(...this.tests.filter((test) => test._only)); |
| return items; |
| } |
| _deepClone() { |
| const suite = this._clone(); |
| for (const entry of this._entries) { |
| if (entry instanceof _Suite) |
| suite._addSuite(entry._deepClone()); |
| else |
| suite._addTest(entry._clone()); |
| } |
| return suite; |
| } |
| _deepSerialize() { |
| const suite = this._serialize(); |
| suite.entries = []; |
| for (const entry of this._entries) { |
| if (entry instanceof _Suite) |
| suite.entries.push(entry._deepSerialize()); |
| else |
| suite.entries.push(entry._serialize()); |
| } |
| return suite; |
| } |
| static _deepParse(data) { |
| const suite = _Suite._parse(data); |
| for (const entry of data.entries) { |
| if (entry.kind === "suite") |
| suite._addSuite(_Suite._deepParse(entry)); |
| else |
| suite._addTest(TestCase._parse(entry)); |
| } |
| return suite; |
| } |
| forEachTest(visitor) { |
| for (const entry of this._entries) { |
| if (entry instanceof _Suite) |
| entry.forEachTest(visitor); |
| else |
| visitor(entry, this); |
| } |
| } |
| _serialize() { |
| return { |
| kind: "suite", |
| title: this.title, |
| type: this._type, |
| location: this.location, |
| only: this._only, |
| requireFile: this._requireFile, |
| timeout: this._timeout, |
| retries: this._retries, |
| staticAnnotations: this._staticAnnotations.slice(), |
| tags: this._tags.slice(), |
| modifiers: this._modifiers.slice(), |
| parallelMode: this._parallelMode, |
| hooks: this._hooks.map((h) => ({ type: h.type, location: h.location, title: h.title })), |
| fileId: this._fileId |
| }; |
| } |
| static _parse(data) { |
| const suite = new _Suite(data.title, data.type); |
| suite.location = data.location; |
| suite._only = data.only; |
| suite._requireFile = data.requireFile; |
| suite._timeout = data.timeout; |
| suite._retries = data.retries; |
| suite._staticAnnotations = data.staticAnnotations; |
| suite._tags = data.tags; |
| suite._modifiers = data.modifiers; |
| suite._parallelMode = data.parallelMode; |
| suite._hooks = data.hooks.map((h) => ({ type: h.type, location: h.location, title: h.title, fn: () => { |
| } })); |
| suite._fileId = data.fileId; |
| return suite; |
| } |
| _clone() { |
| const data = this._serialize(); |
| const suite = _Suite._parse(data); |
| suite._use = this._use.slice(); |
| suite._hooks = this._hooks.slice(); |
| suite._fullProject = this._fullProject; |
| return suite; |
| } |
| project() { |
| return this._fullProject?.project || this.parent?.project(); |
| } |
| }; |
| var TestCase = class _TestCase extends Base { |
| constructor(title, fn, testType, location) { |
| super(title); |
| this.results = []; |
| this.type = "test"; |
| this.expectedStatus = "passed"; |
| this.timeout = 0; |
| this.annotations = []; |
| this.retries = 0; |
| this.repeatEachIndex = 0; |
| this.id = ""; |
| this._poolDigest = ""; |
| this._workerHash = ""; |
| this._projectId = ""; |
| |
| this._tags = []; |
| this.fn = fn; |
| this._testType = testType; |
| this.location = location; |
| } |
| titlePath() { |
| const titlePath = this.parent ? this.parent.titlePath() : []; |
| titlePath.push(this.title); |
| return titlePath; |
| } |
| outcome() { |
| return computeTestCaseOutcome(this); |
| } |
| ok() { |
| const status = this.outcome(); |
| return status === "expected" || status === "flaky" || status === "skipped"; |
| } |
| get tags() { |
| const path10 = []; |
| this.parent._collectTagTitlePath(path10); |
| path10.push(this.title); |
| const titleTags = path10.join(" ").match(/@[\S]+/g) || []; |
| return [ |
| ...titleTags, |
| ...this._tags |
| ]; |
| } |
| _serialize() { |
| return { |
| kind: "test", |
| id: this.id, |
| title: this.title, |
| retries: this.retries, |
| timeout: this.timeout, |
| expectedStatus: this.expectedStatus, |
| location: this.location, |
| only: this._only, |
| requireFile: this._requireFile, |
| poolDigest: this._poolDigest, |
| workerHash: this._workerHash, |
| annotations: this.annotations.slice(), |
| tags: this._tags.slice(), |
| projectId: this._projectId |
| }; |
| } |
| static _parse(data) { |
| const test = new _TestCase(data.title, () => { |
| }, rootTestType, data.location); |
| test.id = data.id; |
| test.retries = data.retries; |
| test.timeout = data.timeout; |
| test.expectedStatus = data.expectedStatus; |
| test._only = data.only; |
| test._requireFile = data.requireFile; |
| test._poolDigest = data.poolDigest; |
| test._workerHash = data.workerHash; |
| test.annotations = data.annotations; |
| test._tags = data.tags; |
| test._projectId = data.projectId; |
| return test; |
| } |
| _clone() { |
| const data = this._serialize(); |
| const test = _TestCase._parse(data); |
| test._testType = this._testType; |
| test.fn = this.fn; |
| return test; |
| } |
| _appendTestResult() { |
| const result2 = { |
| retry: this.results.length, |
| parallelIndex: -1, |
| workerIndex: -1, |
| duration: 0, |
| startTime: new Date(), |
| stdout: [], |
| stderr: [], |
| attachments: [], |
| status: "skipped", |
| steps: [], |
| errors: [], |
| annotations: [] |
| }; |
| this.results.push(result2); |
| return result2; |
| } |
| _grepBaseTitlePath() { |
| const path10 = []; |
| this.parent._collectGrepTitlePath(path10); |
| path10.push(this.title); |
| return path10; |
| } |
| _grepTitleWithTags() { |
| const path10 = this._grepBaseTitlePath(); |
| path10.push(...this._tags); |
| return path10.join(" "); |
| } |
| }; |
|
|
| |
| var testLoader_exports = {}; |
| __export(testLoader_exports, { |
| defaultTimeout: () => defaultTimeout2, |
| loadTestFile: () => loadTestFile |
| }); |
| var import_path9 = __toESM(require("path")); |
| var import_util10 = __toESM(require("util")); |
| var import_globals3 = require("../globals"); |
| var defaultTimeout2 = 3e4; |
| var cachedFileSuites = new Map(); |
| async function loadTestFile(file2, config, testErrors) { |
| if (cachedFileSuites.has(file2)) |
| return cachedFileSuites.get(file2); |
| const suite = new Suite(import_path9.default.relative(config.config.rootDir, file2) || import_path9.default.basename(file2), "file"); |
| suite._requireFile = file2; |
| suite.location = { file: file2, line: 0, column: 0 }; |
| suite._tags = [...config.config.tags]; |
| (0, import_globals3.setCurrentlyLoadingFileSuite)(suite); |
| if (!(0, import_globals3.isWorkerProcess)()) { |
| startCollectingFileDeps(); |
| await startCollectingFileDeps2(); |
| } |
| try { |
| await requireOrImport(file2); |
| cachedFileSuites.set(file2, suite); |
| } catch (e) { |
| if (!testErrors) |
| throw e; |
| testErrors.push(serializeLoadError(file2, e)); |
| } finally { |
| (0, import_globals3.setCurrentlyLoadingFileSuite)(void 0); |
| if (!(0, import_globals3.isWorkerProcess)()) { |
| stopCollectingFileDeps(file2); |
| await stopCollectingFileDeps2(file2); |
| } |
| } |
| { |
| const files = new Set(); |
| suite.allTests().map((t) => files.add(t.location.file)); |
| if (files.size === 1) { |
| const mappedFile = files.values().next().value; |
| if (suite.location.file !== mappedFile) { |
| if (import_path9.default.extname(mappedFile) !== import_path9.default.extname(suite.location.file)) |
| suite.location.file = mappedFile; |
| } |
| } |
| } |
| return suite; |
| } |
| function serializeLoadError(file2, error) { |
| if (error instanceof Error) { |
| const result2 = filterStackTrace(error); |
| const loc = error.loc; |
| result2.location = loc ? { |
| file: file2, |
| line: loc.line || 0, |
| column: loc.column || 0 |
| } : void 0; |
| return result2; |
| } |
| return { value: import_util10.default.inspect(error) }; |
| } |
| |
| 0 && (module.exports = { |
| FullConfigInternal, |
| ProcessRunner, |
| builtInReporters, |
| cc, |
| config, |
| configLoader, |
| defineConfig, |
| esm, |
| fixtures, |
| ipc, |
| mergeTests, |
| poolBuilder, |
| processRunner, |
| startProcessRunner, |
| suiteUtils, |
| test, |
| testLoader, |
| testType, |
| transform |
| }); |
|
|