UNPKG

playwright

Version:

A high-level API to automate web browsers

2,955 lines • 117 kB
"use strict";
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
  for (var name in all)
    __defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
  if (from && typeof from === "object" || typeof from === "function") {
    for (let key of __getOwnPropNames(from))
      if (!__hasOwnProp.call(to, key) && key !== except)
        __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
  }
  return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
  // If the importer is in node compatibility mode or this is not an ESM
  // file that has been converted to a CommonJS file using a Babel-
  // compatible transform (i.e. "__esModule" has not been set), then set
  // "default" to the CommonJS "module.exports" for node compatibility.
  isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
  mod
));
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);

// packages/playwright/src/common/index.ts
var index_exports = {};
__export(index_exports, {
  FullConfigInternal: () => FullConfigInternal,
  ProcessRunner: () => ProcessRunner,
  builtInReporters: () => builtInReporters,
  cc: () => compilationCache_exports,
  config: () => config_exports,
  configLoader: () => configLoader_exports,
  defineConfig: () => defineConfig,
  fixtures: () => fixtures_exports,
  ipc: () => ipc_exports,
  mergeTests: () => mergeTests,
  poolBuilder: () => poolBuilder_exports,
  processRunner: () => process_exports,
  startProcessRunner: () => startProcessRunner,
  suiteUtils: () => suiteUtils_exports,
  test: () => test_exports,
  testLoader: () => testLoader_exports,
  testType: () => testType_exports,
  transform: () => transform_exports
});
module.exports = __toCommonJS(index_exports);

// packages/playwright/src/transform/compilationCache.ts
var compilationCache_exports = {};
__export(compilationCache_exports, {
  addToCompilationCache: () => addToCompilationCache,
  affectedTestFiles: () => affectedTestFiles,
  belongsToNodeModules: () => belongsToNodeModules,
  cacheDir: () => cacheDir,
  collectAffectedTestFiles: () => collectAffectedTestFiles,
  currentFileDepsCollector: () => currentFileDepsCollector,
  dependenciesForTestFile: () => dependenciesForTestFile,
  fileDependenciesForTest: () => fileDependenciesForTest,
  getFromCompilationCache: () => getFromCompilationCache,
  getUserData: () => getUserData,
  installSourceMapSupport: () => installSourceMapSupport,
  internalDependenciesForTestFile: () => internalDependenciesForTestFile,
  serializeCompilationCache: () => serializeCompilationCache,
  setExternalDependencies: () => setExternalDependencies,
  startCollectingFileDeps: () => startCollectingFileDeps,
  stopCollectingFileDeps: () => stopCollectingFileDeps
});
var import_fs = __toESM(require("fs"));
var import_os = __toESM(require("os"));
var import_path = __toESM(require("path"));
var import_globals = require("../globals");
var import_package = require("../package");
var sourceMapSupport = require("playwright-core/lib/utilsBundle").sourceMapSupport;
var { calculateSha1 } = require("playwright-core/lib/coreBundle").utils;
var cacheDir = process.env.PWTEST_CACHE_DIR || (() => {
  if (process.platform === "win32")
    return import_path.default.join(import_os.default.tmpdir(), `playwright-transform-cache`);
  return import_path.default.join(import_os.default.tmpdir(), `playwright-transform-cache-` + process.geteuid?.());
})();
var sourceMaps = /* @__PURE__ */ new Map();
var memoryCache = /* @__PURE__ */ new Map();
var fileDependencies = /* @__PURE__ */ new Map();
var externalDependencies = /* @__PURE__ */ new Map();
function installSourceMapSupport() {
  Error.stackTraceLimit = 200;
  sourceMapSupport.install({
    environment: "node",
    handleUncaughtExceptions: false,
    retrieveSourceMap(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 _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 writeCodeCache(codePath, code) {
  import_fs.default.writeFileSync(codePath, `// ${calculateSha1(code)}
${code}`, "utf8");
}
function readCodeCache(codePath) {
  const content = import_fs.default.readFileSync(codePath, "utf8");
  const newLineIndex = content.indexOf("\n");
  if (newLineIndex === -1)
    throw new Error(`Cache file is missing the hash header`);
  const firstLine = content.substring(0, newLineIndex);
  const sha1Length = 40;
  if (firstLine.length !== "// ".length + sha1Length || !firstLine.startsWith("// "))
    throw new Error(`Cache file has a malformed hash header`);
  const code = content.substring(newLineIndex + 1);
  if (calculateSha1(code) !== firstLine.substring("// ".length))
    throw new Error(`Cache file content does not match the hash header`);
  return code;
}
function getFromCompilationCache(filename, contentHash, moduleUrl) {
  const cache = memoryCache.get(filename);
  if (cache?.codePath) {
    try {
      return { cachedCode: readCodeCache(cache.codePath) };
    } 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 = readCodeCache(codePath);
    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");
      writeCodeCache(codePath, code);
      const serializedCache = _innerAddToCompilationCacheAndSerialize(filename, { codePath, sourceMapPath, dataPath, moduleUrl });
      return { serializedCache };
    }
  };
}
function serializeCompilationCache() {
  return {
    sourceMaps: [...sourceMaps.entries()],
    memoryCache: [...memoryCache.entries()],
    fileDependencies: [...fileDependencies.entries()].map(([filename, deps]) => [filename, [...deps]]),
    externalDependencies: [...externalDependencies.entries()].map(([filename, deps]) => [filename, [...deps]])
  };
}
function addToCompilationCache(payload) {
  for (const entry of payload.sourceMaps)
    sourceMaps.set(entry[0], entry[1]);
  for (const entry of payload.memoryCache)
    memoryCache.set(entry[0], entry[1]);
  for (const entry of payload.fileDependencies) {
    const existing = fileDependencies.get(entry[0]) || [];
    fileDependencies.set(entry[0], /* @__PURE__ */ new Set([...entry[1], ...existing]));
  }
  for (const entry of payload.externalDependencies) {
    const existing = externalDependencies.get(entry[0]) || [];
    externalDependencies.set(entry[0], /* @__PURE__ */ new Set([...entry[1], ...existing]));
  }
}
function calculateFilePathHash(filePath) {
  return calculateSha1(filePath).substring(0, 10);
}
function calculateCachePath(filePath, cacheFolderName, hashPrefix) {
  const fileName2 = hashPrefix + "_" + import_path.default.basename(filePath, import_path.default.extname(filePath)).replace(/\W/g, "");
  return import_path.default.join(cacheDir, cacheFolderName, fileName2);
}
function clearOldCacheEntries(cacheFolderName, filePathHash) {
  const cachePath = import_path.default.join(cacheDir, cacheFolderName);
  try {
    const cachedRelevantFiles = import_fs.default.readdirSync(cachePath).filter((file2) => file2.startsWith(filePathHash));
    for (const file2 of cachedRelevantFiles)
      import_fs.default.rmSync(import_path.default.join(cachePath, file2), { force: true });
  } catch {
  }
}
var depsCollector2;
function startCollectingFileDeps() {
  depsCollector2 = /* @__PURE__ */ new Set();
}
function stopCollectingFileDeps(filename) {
  if (!depsCollector2)
    return;
  depsCollector2.delete(filename);
  for (const dep of depsCollector2) {
    if (belongsToNodeModules(dep))
      depsCollector2.delete(dep);
  }
  fileDependencies.set(filename, depsCollector2);
  depsCollector2 = void 0;
}
function currentFileDepsCollector() {
  return depsCollector2;
}
function setExternalDependencies(filename, deps) {
  const depsSet = new Set(deps.filter((dep) => !belongsToNodeModules(dep) && dep !== filename));
  externalDependencies.set(filename, depsSet);
}
function fileDependenciesForTest() {
  return Object.fromEntries([...fileDependencies.entries()].map((entry) => [import_path.default.basename(entry[0]), [...entry[1]].map((f) => import_path.default.basename(f)).sort()]));
}
function collectAffectedTestFiles(changedFile, testFileCollector) {
  const isTestFile = (file2) => fileDependencies.has(file2);
  if (isTestFile(changedFile))
    testFileCollector.add(changedFile);
  for (const [testFile, deps] of fileDependencies) {
    if (deps.has(changedFile))
      testFileCollector.add(testFile);
  }
  for (const [importingFile, depsOfImportingFile] of externalDependencies) {
    if (depsOfImportingFile.has(changedFile)) {
      if (isTestFile(importingFile))
        testFileCollector.add(importingFile);
      for (const [testFile, depsOfTestFile] of fileDependencies) {
        if (depsOfTestFile.has(importingFile))
          testFileCollector.add(testFile);
      }
    }
  }
}
function affectedTestFiles(changes) {
  const result2 = /* @__PURE__ */ new Set();
  for (const change of changes)
    collectAffectedTestFiles(change, result2);
  return [...result2];
}
function internalDependenciesForTestFile(filename) {
  return fileDependencies.get(filename);
}
function dependenciesForTestFile(filename) {
  const result2 = /* @__PURE__ */ new Set();
  for (const testDependency of fileDependencies.get(filename) || []) {
    result2.add(testDependency);
    for (const externalDependency of externalDependencies.get(testDependency) || [])
      result2.add(externalDependency);
  }
  for (const dep of externalDependencies.get(filename) || [])
    result2.add(dep);
  return result2;
}
var kPlaywrightInternalPrefix = import_package.packageRoot;
function belongsToNodeModules(file2) {
  if (file2.includes(`${import_path.default.sep}node_modules${import_path.default.sep}`))
    return true;
  if (file2.startsWith(kPlaywrightInternalPrefix) && (file2.endsWith(".js") || file2.endsWith(".mjs")))
    return true;
  return false;
}
async function getUserData(pluginName) {
  const result2 = /* @__PURE__ */ new Map();
  for (const [fileName2, cache] of memoryCache) {
    if (!cache.dataPath)
      continue;
    if (!import_fs.default.existsSync(cache.dataPath))
      continue;
    const data = JSON.parse(await import_fs.default.promises.readFile(cache.dataPath, "utf8"));
    if (data[pluginName])
      result2.set(fileName2, data[pluginName]);
  }
  return result2;
}

// packages/playwright/src/common/config.ts
var config_exports = {};
__export(config_exports, {
  FullConfigInternal: () => FullConfigInternal,
  FullProjectInternal: () => FullProjectInternal,
  builtInReporters: () => builtInReporters,
  defaultGrep: () => defaultGrep,
  defaultReporter: () => defaultReporter,
  defaultTimeout: () => defaultTimeout,
  getProjectId: () => getProjectId,
  toReporters: () => toReporters
});
var import_fs3 = __toESM(require("fs"));
var import_os2 = __toESM(require("os"));
var import_path3 = __toESM(require("path"));
var import_package2 = require("../package");

// packages/playwright/src/util.ts
var import_fs2 = __toESM(require("fs"));
var import_path2 = __toESM(require("path"));
var import_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");
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 { stringifyStackFrames, filteredStackTrace } = require("playwright-core/lib/coreBundle").utils;
var { ansiRegex, isString, stripAnsiEscapes } = require("playwright-core/lib/coreBundle").iso;
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 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 unixPath = filePath.split(import_path2.default.sep).join("/");
      for (const re of reList) {
        re.lastIndex = 0;
        if (re.test(unixPath))
          return true;
      }
    }
    for (const pattern of filePatterns) {
      if (minimatch(filePath, pattern, { nocase: true, dot: true }))
        return true;
    }
    return false;
  };
}
function mergeObjects(a, b, c) {
  const result2 = { ...a };
  for (const x of [b, c].filter(Boolean)) {
    for (const [name, value] of Object.entries(x)) {
      if (!Object.is(value, void 0))
        result2[name] = value;
    }
  }
  return result2;
}
function forceRegExp(pattern) {
  const match = pattern.match(/^\/(.*)\/([gi]*)$/);
  if (match)
    return new RegExp(match[1], match[2]);
  return new RegExp(pattern, "gi");
}
function relativeFilePath(file2) {
  if (!import_path2.default.isAbsolute(file2))
    return file2;
  return import_path2.default.relative(process.cwd(), file2);
}
function formatLocation(location) {
  return relativeFilePath(location.file) + ":" + location.line + ":" + location.column;
}
function errorWithFile(file2, message) {
  return new Error(`${relativeFilePath(file2)}: ${message}`);
}
var debugTest = debug("pw:test");
var folderToPackageJsonPath = /* @__PURE__ */ new Map();
function getPackageJsonPath(folderPath) {
  const cached = folderToPackageJsonPath.get(folderPath);
  if (cached !== void 0)
    return cached;
  const packageJsonPath = import_path2.default.join(folderPath, "package.json");
  if (import_fs2.default.existsSync(packageJsonPath)) {
    folderToPackageJsonPath.set(folderPath, packageJsonPath);
    return packageJsonPath;
  }
  const parentFolder = import_path2.default.dirname(folderPath);
  if (folderPath === parentFolder) {
    folderToPackageJsonPath.set(folderPath, "");
    return "";
  }
  const result2 = getPackageJsonPath(parentFolder);
  folderToPackageJsonPath.set(folderPath, result2);
  return result2;
}
function fileIsModule(file2) {
  if (file2.endsWith(".mjs") || file2.endsWith(".mts"))
    return true;
  if (file2.endsWith(".cjs") || file2.endsWith(".cts"))
    return false;
  const folder = import_path2.default.dirname(file2);
  return folderIsModule(folder);
}
var packageJsonIsModuleCache = /* @__PURE__ */ new Map();
function folderIsModule(folder) {
  const packageJsonPath = getPackageJsonPath(folder);
  if (!packageJsonPath)
    return false;
  if (!packageJsonIsModuleCache.has(packageJsonPath)) {
    let isModule2 = false;
    try {
      isModule2 = JSON.parse(import_fs2.default.readFileSync(packageJsonPath, "utf8")).type === "module";
    } catch {
    }
    packageJsonIsModuleCache.set(packageJsonPath, isModule2);
  }
  return packageJsonIsModuleCache.get(packageJsonPath);
}
var packageJsonMainFieldCache = /* @__PURE__ */ new Map();
function getMainFieldFromPackageJson(packageJsonPath) {
  if (!packageJsonMainFieldCache.has(packageJsonPath)) {
    let mainField;
    try {
      mainField = JSON.parse(import_fs2.default.readFileSync(packageJsonPath, "utf8")).main;
    } catch {
    }
    packageJsonMainFieldCache.set(packageJsonPath, mainField);
  }
  return packageJsonMainFieldCache.get(packageJsonPath);
}
var kExtLookups = /* @__PURE__ */ new Map([
  [".js", [".jsx", ".ts", ".tsx"]],
  [".jsx", [".tsx"]],
  [".cjs", [".cts"]],
  [".mjs", [".mts"]],
  ["", [".js", ".ts", ".jsx", ".tsx", ".cjs", ".mjs", ".cts", ".mts"]]
]);
function resolveImportSpecifierExtension(resolved) {
  if (fileExists(resolved))
    return resolved;
  for (const [ext, others] of kExtLookups) {
    if (!resolved.endsWith(ext))
      continue;
    for (const other of others) {
      const modified = resolved.substring(0, resolved.length - ext.length) + other;
      if (fileExists(modified))
        return modified;
    }
    break;
  }
}
function resolveImportSpecifierAfterMapping(resolved, afterPathMapping) {
  const resolvedFile = resolveImportSpecifierExtension(resolved);
  if (resolvedFile)
    return resolvedFile;
  if (dirExists(resolved)) {
    const packageJsonPath = import_path2.default.join(resolved, "package.json");
    if (afterPathMapping) {
      const mainField = getMainFieldFromPackageJson(packageJsonPath);
      const mainFieldResolved = mainField ? resolveImportSpecifierExtension(import_path2.default.resolve(resolved, mainField)) : void 0;
      return mainFieldResolved || resolveImportSpecifierExtension(import_path2.default.join(resolved, "index"));
    }
    if (fileExists(packageJsonPath))
      return resolved;
    const dirImport = import_path2.default.join(resolved, "index");
    return resolveImportSpecifierExtension(dirImport);
  }
}
function fileExists(resolved) {
  return import_fs2.default.statSync(resolved, { throwIfNoEntry: false })?.isFile();
}
function dirExists(resolved) {
  return import_fs2.default.statSync(resolved, { throwIfNoEntry: false })?.isDirectory();
}
function takeFirst(...args) {
  for (const arg of args) {
    if (arg !== void 0)
      return arg;
  }
  return void 0;
}

// packages/playwright/src/common/config.ts
var defaultTimeout = 3e4;
var FullConfigInternal = class {
  constructor(location, userConfig, configCLIOverrides, metadata) {
    this.projects = [];
    this.defineConfigWasUsed = false;
    this.globalSetups = [];
    this.globalTeardowns = [];
    if (configCLIOverrides.projects && userConfig.projects)
      throw new Error(`Cannot use --browser option when configuration file defines projects. Specify browserName in the projects instead.`);
    const { resolvedConfigFile, configDir } = location;
    const packageJsonPath = getPackageJsonPath(configDir);
    const packageJsonDir = packageJsonPath ? import_path3.default.dirname(packageJsonPath) : process.cwd();
    this.configDir = configDir;
    this.configCLIOverrides = configCLIOverrides;
    const privateConfiguration = userConfig["@playwright/test"];
    this.plugins = (privateConfiguration?.plugins || []).map((p) => ({ factory: p }));
    this.singleTSConfigPath = pathResolve(configDir, userConfig.tsconfig);
    this.captureGitInfo = userConfig.captureGitInfo;
    this.retryStrategy = takeFirst(userConfig.retryStrategy, "immediate");
    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 = {
      argv: configCLIOverrides.argv ?? [],
      configFile: resolvedConfigFile,
      rootDir: pathResolve(configDir, userConfig.testDir) || configDir,
      failOnFlakyTests: takeFirst(configCLIOverrides.failOnFlakyTests, userConfig.failOnFlakyTests, false),
      forbidOnly: takeFirst(configCLIOverrides.forbidOnly, userConfig.forbidOnly, false),
      fullyParallel: takeFirst(configCLIOverrides.fullyParallel, userConfig.fullyParallel, false),
      globalSetup: this.globalSetups[0] ?? null,
      globalTeardown: this.globalTeardowns[0] ?? null,
      globalTimeout: takeFirst(configCLIOverrides.debug ? 0 : void 0, configCLIOverrides.globalTimeout, userConfig.globalTimeout, 0),
      grep: takeFirst(userConfig.grep, defaultGrep),
      grepInvert: takeFirst(userConfig.grepInvert, null),
      maxFailures: takeFirst(configCLIOverrides.debug ? 1 : void 0, configCLIOverrides.maxFailures, userConfig.maxFailures, 0),
      metadata: metadata ?? userConfig.metadata,
      preserveOutput: takeFirst(userConfig.preserveOutput, "always"),
      projects: [],
      quiet: takeFirst(configCLIOverrides.quiet, userConfig.quiet, false),
      reporter: takeFirst(configCLIOverrides.reporter, resolveReporters(userConfig.reporter, configDir), [[defaultReporter]]),
      reportSlowTests: takeFirst(userConfig.reportSlowTests, {
        max: 5,
        threshold: 3e5
        /* 5 minutes */
      }),
      shard: takeFirst(configCLIOverrides.shard, userConfig.shard, null),
      tags: globalTags,
      updateSnapshots: takeFirst(configCLIOverrides.updateSnapshots, userConfig.updateSnapshots, "missing"),
      updateSourceMethod: takeFirst(configCLIOverrides.updateSourceMethod, userConfig.updateSourceMethod, "patch"),
      version: import_package2.packageJSON.version,
      workers: resolveWorkers(takeFirst(configCLIOverrides.debug || configCLIOverrides.pause ? 1 : void 0, configCLIOverrides.workers, userConfig.workers, "50%")),
      webServer: null
    };
    for (const key in userConfig) {
      if (key.startsWith("@"))
        this.config[key] = userConfig[key];
    }
    this.config[configInternalSymbol] = this;
    const webServers = takeFirst(userConfig.webServer, null);
    if (Array.isArray(webServers)) {
      this.config.webServer = null;
      this.webServers = webServers;
    } else if (webServers) {
      this.config.webServer = webServers;
      this.webServers = [webServers];
    } else {
      this.webServers = [];
    }
    const projectConfigs = configCLIOverrides.projects || userConfig.projects || [{ ...userConfig, workers: void 0 }];
    this.projects = projectConfigs.map((p) => new FullProjectInternal(configDir, userConfig, this, p, this.configCLIOverrides, packageJsonDir));
    resolveProjectDependencies(this.projects);
    this._assignUniqueProjectIds(this.projects);
    this.config.projects = this.projects.map((p) => p.project);
  }
  _assignUniqueProjectIds(projects) {
    const usedNames = /* @__PURE__ */ new Set();
    for (const p of projects) {
      const name = p.project.name || "";
      for (let i = 0; i < projects.length; ++i) {
        const candidate = name + (i ? i : "");
        if (usedNames.has(candidate))
          continue;
        p.id = candidate;
        p.project.__projectId = p.id;
        usedNames.add(candidate);
        break;
      }
    }
  }
};
var FullProjectInternal = class {
  constructor(configDir, config, fullConfig, projectConfig, configCLIOverrides, packageJsonDir) {
    this.id = "";
    this.deps = [];
    this.fullConfig = fullConfig;
    const testDir = takeFirst(pathResolve(configDir, projectConfig.testDir), pathResolve(configDir, config.testDir), fullConfig.configDir);
    this.snapshotPathTemplate = takeFirst(projectConfig.snapshotPathTemplate, config.snapshotPathTemplate);
    this.project = {
      grep: takeFirst(projectConfig.grep, config.grep, defaultGrep),
      grepInvert: takeFirst(projectConfig.grepInvert, config.grepInvert, null),
      outputDir: takeFirst(configCLIOverrides.outputDir, pathResolve(configDir, projectConfig.outputDir), pathResolve(configDir, config.outputDir), import_path3.default.join(packageJsonDir, "test-results")),
      // Note: we either apply the cli override for repeatEach or not, depending on whether the
      // project is top-level vs dependency. See collectProjectsAndTestFiles in loadUtils.
      repeatEach: takeFirst(projectConfig.repeatEach, config.repeatEach, 1),
      retries: takeFirst(configCLIOverrides.retries, projectConfig.retries, config.retries, 0),
      metadata: takeFirst(projectConfig.metadata, config.metadata, {}),
      name: takeFirst(projectConfig.name, config.name, ""),
      testDir,
      snapshotDir: takeFirst(pathResolve(configDir, projectConfig.snapshotDir), pathResolve(configDir, config.snapshotDir), testDir),
      testIgnore: takeFirst(projectConfig.testIgnore, config.testIgnore, []),
      testMatch: takeFirst(projectConfig.testMatch, config.testMatch, "**/*.@(spec|test).?(c|m)[jt]s?(x)"),
      timeout: takeFirst(configCLIOverrides.debug === "inspector" ? 0 : void 0, configCLIOverrides.timeout, projectConfig.timeout, config.timeout, defaultTimeout),
      use: mergeObjects(config.use, projectConfig.use, configCLIOverrides.use),
      dependencies: projectConfig.dependencies || [],
      teardown: projectConfig.teardown,
      ignoreSnapshots: takeFirst(configCLIOverrides.ignoreSnapshots, projectConfig.ignoreSnapshots, config.ignoreSnapshots, false)
    };
    this.fullyParallel = takeFirst(configCLIOverrides.fullyParallel, projectConfig.fullyParallel, config.fullyParallel, void 0);
    this.expect = takeFirst(projectConfig.expect, config.expect, {});
    if (this.expect.toHaveScreenshot?.stylePath) {
      const stylePaths = Array.isArray(this.expect.toHaveScreenshot.stylePath) ? this.expect.toHaveScreenshot.stylePath : [this.expect.toHaveScreenshot.stylePath];
      this.expect.toHaveScreenshot.stylePath = stylePaths.map((stylePath) => import_path3.default.resolve(configDir, stylePath));
    }
    this.respectGitIgnore = takeFirst(projectConfig.respectGitIgnore, config.respectGitIgnore, !projectConfig.testDir && !config.testDir);
    this.workers = projectConfig.workers ? resolveWorkers(projectConfig.workers) : void 0;
    if (configCLIOverrides.debug && this.workers)
      this.workers = 1;
  }
};
function pathResolve(baseDir, relative) {
  if (!relative)
    return void 0;
  return import_path3.default.resolve(baseDir, relative);
}
function resolveReporters(reporters, rootDir) {
  return toReporters(reporters)?.map(([id, arg]) => {
    if (builtInReporters.includes(id))
      return [id, arg];
    return [require.resolve(id, { paths: [rootDir] }), arg];
  });
}
function resolveWorkers(workers) {
  if (typeof workers === "string") {
    if (workers.endsWith("%")) {
      const percent = parseInt(workers, 10);
      if (isNaN(percent))
        throw new Error(`Workers ${workers} must be a number or percentage.`);
      if (percent < 1)
        throw new Error(`Workers must be a positive number, received ${percent}.`);
      const cpus = import_os2.default.cpus().length;
      return Math.max(1, Math.floor(cpus * (percent / 100)));
    }
    const parsedWorkers = parseInt(workers, 10);
    if (isNaN(parsedWorkers))
      throw new Error(`Workers ${workers} must be a number or percentage.`);
    if (parsedWorkers < 1)
      throw new Error(`Workers must be a positive number, received ${parsedWorkers}.`);
    return parsedWorkers;
  }
  if (workers < 1)
    throw new Error(`Workers must be a positive number, received ${workers}.`);
  return workers;
}
function resolveProjectDependencies(projects) {
  const teardownSet = /* @__PURE__ */ new Set();
  for (const project of projects) {
    for (const dependencyName of project.project.dependencies) {
      const dependencies = projects.filter((p) => p.project.name === dependencyName);
      if (!dependencies.length)
        throw new Error(`Project '${project.project.name}' depends on unknown project '${dependencyName}'`);
      if (dependencies.length > 1)
        throw new Error(`Project dependencies should have unique names, reading ${dependencyName}`);
      project.deps.push(...dependencies);
    }
    if (project.project.teardown) {
      const teardowns = projects.filter((p) => p.project.name === project.project.teardown);
      if (!teardowns.length)
        throw new Error(`Project '${project.project.name}' has unknown teardown project '${project.project.teardown}'`);
      if (teardowns.length > 1)
        throw new Error(`Project teardowns should have unique names, reading ${project.project.teardown}`);
      const teardown = teardowns[0];
      project.teardown = teardown;
      teardownSet.add(teardown);
    }
  }
  for (const teardown of teardownSet) {
    if (teardown.deps.length)
      throw new Error(`Teardown project ${teardown.project.name} must not have dependencies`);
  }
  for (const project of projects) {
    for (const dep of project.deps) {
      if (teardownSet.has(dep))
        throw new Error(`Project ${project.project.name} must not depend on a teardown project ${dep.project.name}`);
    }
  }
}
function toReporters(reporters) {
  if (!reporters)
    return;
  if (typeof reporters === "string")
    return [[reporters]];
  return reporters;
}
var builtInReporters = ["list", "line", "dot", "json", "junit", "null", "github", "html", "blob"];
function resolveScript(id, rootDir) {
  if (!id)
    return void 0;
  const localPath = import_path3.default.resolve(rootDir, id);
  if (import_fs3.default.existsSync(localPath))
    return localPath;
  return require.resolve(id, { paths: [rootDir] });
}
var defaultGrep = /.*/;
var defaultReporter = process.env.CI ? "dot" : "list";
var configInternalSymbol = /* @__PURE__ */ Symbol("configInternalSymbol");
function getProjectId(project) {
  return project.__projectId;
}

// packages/playwright/src/common/configLoader.ts
var configLoader_exports = {};
__export(configLoader_exports, {
  defineConfig: () => defineConfig,
  deserializeConfig: () => deserializeConfig,
  loadConfig: () => loadConfig,
  loadConfigFromFile: () => loadConfigFromFile,
  loadEmptyConfigForMergeReports: () => loadEmptyConfigForMergeReports,
  resolveConfigLocation: () => resolveConfigLocation
});
var import_fs7 = __toESM(require("fs"));
var import_path7 = __toESM(require("path"));

// packages/playwright/src/transform/transform.ts
var transform_exports = {};
__export(transform_exports, {
  incorporateCompilationCache: () => incorporateCompilationCache,
  requireOrImport: () => requireOrImport,
  resolveHook: () => resolveHook,
  setSingleTSConfig: () => setSingleTSConfig,
  setTransformConfig: () => setTransformConfig,
  setTransformData: () => setTransformData,
  shouldTransform: () => shouldTransform,
  startCollectingFileDeps: () => startCollectingFileDeps2,
  stopCollectingFileDeps: () => stopCollectingFileDeps2,
  transformHook: () => transformHook,
  wrapFunctionWithLocation: () => wrapFunctionWithLocation
});
var import_fs6 = __toESM(require("fs"));
var import_module2 = __toESM(require("module"));
var import_path6 = __toESM(require("path"));
var import_url2 = __toESM(require("url"));
var import_crypto = __toESM(require("crypto"));

// packages/playwright/src/transform/tsconfig-loader.ts
var import_path4 = __toESM(require("path"));
var import_fs4 = __toESM(require("fs"));
var json5 = require("playwright-core/lib/utilsBundle").json5;
function loadTsConfig(configPath) {
  try {
    const references = [];
    const config = innerLoadTsConfig(configPath, references);
    return [config, ...references];
  } catch (e) {
    throw new Error(`Failed to load tsconfig file at ${configPath}:
${e.message}`);
  }
}
function resolveConfigFile(baseConfigFile, referencedConfigFile) {
  if (!referencedConfigFile.endsWith(".json"))
    referencedConfigFile += ".json";
  const currentDir = import_path4.default.dirname(baseConfigFile);
  let resolvedConfigFile = import_path4.default.resolve(currentDir, referencedConfigFile);
  if (referencedConfigFile.includes("/") && referencedConfigFile.includes(".") && !import_fs4.default.existsSync(resolvedConfigFile))
    resolvedConfigFile = import_path4.default.join(currentDir, "node_modules", referencedConfigFile);
  return resolvedConfigFile;
}
function innerLoadTsConfig(configFilePath, references, visited = /* @__PURE__ */ new Map()) {
  if (visited.has(configFilePath))
    return visited.get(configFilePath);
  let result2 = {
    tsConfigPath: configFilePath
  };
  visited.set(configFilePath, result2);
  if (!import_fs4.default.existsSync(configFilePath))
    return result2;
  const configString = import_fs4.default.readFileSync(configFilePath, "utf-8");
  const cleanedJson = StripBom(configString);
  const parsedConfig = json5.parse(cleanedJson);
  const extendsArray = Array.isArray(parsedConfig.extends) ? parsedConfig.extends : parsedConfig.extends ? [parsedConfig.extends] : [];
  for (const extendedConfig of extendsArray) {
    const extendedConfigPath = resolveConfigFile(configFilePath, extendedConfig);
    const base = innerLoadTsConfig(extendedConfigPath, references, visited);
    Object.assign(result2, base, { tsConfigPath: configFilePath });
  }
  if (parsedConfig.compilerOptions?.allowJs !== void 0)
    result2.allowJs = parsedConfig.compilerOptions.allowJs;
  if (parsedConfig.compilerOptions?.paths !== void 0) {
    result2.paths = {
      mapping: parsedConfig.compilerOptions.paths,
      pathsBasePath: import_path4.default.dirname(configFilePath)
    };
  }
  if (parsedConfig.compilerOptions?.baseUrl !== void 0) {
    result2.absoluteBaseUrl = import_path4.default.resolve(import_path4.default.dirname(configFilePath), parsedConfig.compilerOptions.baseUrl);
  }
  for (const ref of parsedConfig.references || [])
    references.push(innerLoadTsConfig(resolveConfigFile(configFilePath, ref.path), references, visited));
  if (import_path4.default.basename(configFilePath) === "jsconfig.json" && result2.allowJs === void 0)
    result2.allowJs = true;
  return result2;
}
function StripBom(string) {
  if (typeof string !== "string") {
    throw new TypeError(`Expected a string, got ${typeof string}`);
  }
  if (string.charCodeAt(0) === 65279) {
    return string.slice(1);
  }
  return string;
}

// packages/playwright/src/transform/transform.ts
var import_package3 = require("../package");

// packages/playwright/src/transform/esmLoaderSync.ts
var import_fs5 = __toESM(require("fs"));
var import_url = __toESM(require("url"));
function resolve(specifier, context, nextResolve) {
  if (context.parentURL && context.parentURL.startsWith("file://")) {
    const filename = import_url.default.fileURLToPath(context.parentURL);
    const resolved = resolveHook(filename, specifier);
    if (resolved !== void 0) {
      specifier = new Set(context.conditions).has("import") ? import_url.default.pathToFileURL(resolved).toString() : resolved;
    }
  }
  const result2 = nextResolve(specifier, context);
  if (result2?.url && result2.url.startsWith("file://"))
    currentFileDepsCollector()?.add(import_url.default.fileURLToPath(result2.url));
  return result2;
}
var kSupportedFormats = /* @__PURE__ */ new Map([
  ["commonjs", "commonjs"],
  ["module", "module"],
  ["commonjs-typescript", "commonjs"],
  ["module-typescript", "module"],
  ["typescript", null],
  [null, null],
  [void 0, void 0]
]);
function load(moduleUrl, context, nextLoad) {
  if (!kSupportedFormats.has(context.format))
    return nextLoad(moduleUrl, context);
  if (!moduleUrl.startsWith("file://"))
    return nextLoad(moduleUrl, context);
  const filename = import_url.default.fileURLToPath(moduleUrl);
  if (!shouldTransform(filename))
    return nextLoad(moduleUrl, context);
  const isRequire = !new Set(context.conditions).has("import");
  const format = isRequire ? "commonjs" : kSupportedFormats.get(context.format) || (fileIsModule(filename) ? "module" : "commonjs");
  const code = import_fs5.default.readFileSync(filename, "utf-8");
  const transformed = transformHook(code, filename, format === "module" ? moduleUrl : void 0);
  return {
    format,
    source: transformed.code,
    shortCircuit: true
  };
}

// packages/playwright/src/transform/pirates.ts
var import_module = __toESM(require("module"));
var import_path5 = __toESM(require("path"));
function addHook(transformHook2, shouldTransform2, extensions) {
  const extensionsToOverwrite = extensions.filter((e) => e !== ".cjs");
  const allSupportedExtensions = new Set(extensions);
  const loaders = import_module.default._extensions;
  const jsLoader = loaders[".js"];
  for (const extension of extensionsToOverwrite) {
    let newLoader2 = function(mod, filename, ...loaderArgs) {
      if (allSupportedExtensions.has(import_path5.default.extname(filename)) && shouldTransform2(filename)) {
        let newCompile2 = function(code, file2, ...ignoredArgs) {
          mod._compile = oldCompile;
          return oldCompile.call(this, transformHook2(code, filename), file2);
        };
        var newCompile = newCompile2;
        const oldCompile = mod._compile;
        mod._compile = newCompile2;
      }
      originalLoader.call(this, mod, filename, ...loaderArgs);
    };
    var newLoader = newLoader2;
    const originalLoader = loaders[extension] || jsLoader;
    loaders[extension] = newLoader2;
  }
}

// packages/playwright/src/transform/portTransport.ts
var PortTransport = class {
  constructor(port, handler) {
    this._lastId = 0;
    this._callbacks = /* @__PURE__ */ new Map();
    this._port = port;
    port.addEventListener("message", async (event) => {
      const message = event.data;
      const { id, ackId, method, params, result: result2 } = message;
      if (ackId) {
        const callback = this._callbacks.get(ackId);
        this._callbacks.delete(ackId);
        this._resetRef();
        callback?.(result2);
        return;
      }
      const handlerResult = await handler(method, params);
      if (id)
        this._port.postMessage({ ackId: id, result: handlerResult });
    });
    this._resetRef();
  }
  post(method, params) {
    this._port.postMessage({ method, params });
  }
  async send(method, params) {
    return await new Promise((f) => {
      const id = ++this._lastId;
      this._callbacks.set(id, f);
      this._resetRef();
      this._port.postMessage({ id, method, params });
    });
  }
  _resetRef() {
    if (this._callbacks.size) {
      this._port.ref();
    } else {
      this._port.unref();
    }
  }
};

// packages/playwright/src/transform/transform.ts
var sourceMapSupport2 = require("playwright-core/lib/utilsBundle").sourceMapSupport;
var version = import_package3.packageJSON.version;
var cachedTSConfigs = /* @__PURE__ */ new Map();
var _transformConfig = {
  babelPlugins: [],
  external: []
};
var _externalMatcher = () => false;
async function setTransformConfig(config) {
  _transformConfig = config;
  _externalMatcher = createFileMatcher(_transformConfig.external);
  if (loaderChannel)
    await loaderChannel.send("setTransformConfig", { config });
}
var _singleTSConfigPath;
var _singleTSConfig;
async function setSingleTSConfig(value) {
  _singleTSConfigPath = value;
  if (loaderChannel)
    await loaderChannel.send("setSingleTSConfig", { tsconfig: value });
}
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_fs6.default.existsSync(configPath)) {
        const loaded = loadTsConfig(configPath);
        result2 = loaded.map(validateTsConfig);
        break;
      }
    }
    if (result2)
      break;
    const parentFolder = import_path6.default.resolve(currentFolder, "../");
    if (currentFolder === parentFolder)
      break;
    currentFolder = parentFolder;
  }
  result2 = result2 || [];
  for (const folder2 of foldersWithConfig)
    cachedTSConfigs.set(folder2, result2);
  return result2;
}
var pathSeparator = process.platform === "win32" ? ";" : ":";
var builtins = new Set(import_module2.default.builtinModules);
function resolveHook(filename, specifier) {
  if (specifier.startsWith("node:") || builtins.has(specifier))
    return;
  if (!shouldTransform(filename))
    return;
  if (isRelativeSpecifier(specifier))
    return resolveImportSpecifierAfterMapping(import_path6.default.resolve(import_path6.default.dirname(filename), specifier), false);
  const isTypeScript = filename.endsWith(".ts") || filename.endsWith(".tsx");
  const tsconfigs = loadAndValidateTsconfigsForFile(filename);
  for (const tsconfig of tsconfigs) {
    if (!isTypeScript && !tsconfig.allowJs)
      continue;
    let longestPrefixLength = -1;
    let pathMatchedByLongestPrefix;
    for (const { key, values } of tsconfig.paths) {
      let matchedPartOfSpecifier = specifier;
      const [keyPrefix, keySuffix] = key.split("*");
      if (key.includes("*")) {
        if (keyPrefix) {
          if (!specifier.startsWith(keyPrefix))
            continue;
          matchedPartOfSpecifier = matchedPartOfSpecifier.substring(keyPrefix.length, matchedPartOfSpecifier.length);
        }
        if (keySuffix) {
          if (!specifier.endsWith(keySuffix))
            continue;
          matchedPartOfSpecifier = matchedPartOfSpecifier.substring(0, matchedPartOfSpecifier.length - keySuffix.length);
        }
      } else {
        if (specifier !== key)
          continue;
        matchedPartOfSpecifier = specifier;
      }
      if (keyPrefix.length <= longestPrefixLength)
        continue;
      for (const value of values) {
        let candidate = value;
        if (value.includes("*"))
          candidate = candidate.replace("*", matchedPartOfSpecifier);
        candidate = import_path6.default.resolve(tsconfig.pathsBase, candidate);
        const existing = resolveImportSpecifierAfterMapping(candidate, true);
        if (existing) {
          longestPrefixLength = keyPrefix.length;
          pathMatchedByLongestPrefix = existing;
        }
      }
    }
    if (pathMatchedByLongestPrefix)
      return pathMatchedByLongestPrefix;
  }
  if (import_path6.default.isAbsolute(specifier)) {
    return resolveImportSpecifierAfterMapping(specifier, false);
  }
}
function shouldTransform(filename) {
  if (_externalMatcher(filename))
    return false;
  return !belongsToNodeModules(filename);
}
var transformData;
function setTransformData(pluginName, value) {
  transformData.set(pluginName, value);
}
function transformHook(originalCode, filename, moduleUrl) {
  const hasPreprocessor = process.env.PW_TEST_SOURCE_TRANSFORM && process.env.PW_TEST_SOURCE_TRANSFORM_SCOPE && process.env.PW_TEST_SOURCE_TRANSFORM_SCOPE.split(pathSeparator).some((f) => filename.startsWith(f));
  const pluginsPrologue = _transformConfig.babelPlugins;
  const pluginsEpilogue = hasPreprocessor ? [[process.env.PW_TEST_SOURCE_TRANSFORM]] : [];
  const hash = calculateHash(originalCode, filename, !!moduleUrl, pluginsPrologue, pluginsEpilogue);
  const { cachedCode, addToCache, serializedCache } = getFromCompilationCache(filename, hash, moduleUrl);
  if (cachedCode !== void 0)
    return { code: cachedCode, serializedCache };
  process.env.BROWSERSLIST_IGNORE_OLD_DATA = "true";
  const { babelTransform } = require((0, import_package3.libPath)("transform", "babelBundle"));
  transformData = /* @__PURE__ */ new Map();
  const setTransformDataForPlugin = (key, value) => transformData.set(key, value);
  const wrappedPrologue = pluginsPrologue.map(([name, opts]) => [
    name,
    { ...opts || {}, setTransformData: setTransformDataForPlugin }
  ]);
  const babelResult = babelTransform(originalCode, filename, !!moduleUrl, wrappedPrologue, pluginsEpilogue, _transformConfig.jsxImportSource);
  if (!babelResult?.code)
    return { code: originalCode, serializedCache };
  const { code, map } = babelResult;
  const added = addToCache(code, map, transformData);
  return { code, serializedCache: added.serializedCache };
}
function calculateHash(content, filePath, isModule2, pluginsPrologue, pluginsEpilogue) {
  const hash = import_crypto.default.createHash("sha1").update(isModule2 ? "esm" : "no_esm").update(content).update(filePath).update(version).update(pluginsPrologue.map((p) => p[0]).join(",")).update(pluginsEpilogue.map((p) => p[0]).join(",")).digest("hex");
  return hash;
}
async function requireOrImport(file) {
  installTransformIfNeeded();
  const isModule = fileIsModule(file);
  if (isModule) {
    const fileName = import_url2.default.pathToFileURL(file);
    const esmImport = () => eval(`import(${JSON.stringify(fileName)})`);
    if (loaderChannel) {
      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) {
      const cjsDeps = /* @__PURE__ */ new Set();
      collectCJSDependencies(module2, cjsDeps);
      for (const dep of cjsDeps)
        depsCollector.add(dep);
    }
  }
  return result;
}
var transformInstalled = false;
function installTransformIfNeeded() {
  if (transformInstalled)
    return;
  transformInstalled = true;
  registerESMLoader();
  installSourceMapSupport();
  if (loaderChannel) {
    installCJSHooks();
    return;
  }
  const extensions = import_module2.default._extensions;
  for (const ext of [".ts", ".cts", ".tsx", ".jsx"])
    extensions[ext] = extensions[".js"];
}
function installCJSHooks() {
  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((resolve2) => setTimeout(resolve2, 0));
}
var loaderChannel;
function registerESMLoader() {
  if (process.env.PW_DISABLE_TS_ESM)
    return;
  if ("Bun" in globalThis)
    return;
  const nodeModule = require("node:module");
  if (nodeModule.registerHooks && !process.env.PLAYWRIGHT_FORCE_ASYNC_LOADER) {
    nodeModule.registerHooks({ resolve, load });
    return;
  }
  if (!nodeModule.register)
    return;
  const { port1, port2 } = new MessageChannel();
  nodeModule.register(import_url2.default.pathToFileURL(require.resolve("../transform/esmLoader.js")), {
    data: { port: port2 },
    transferList: [port2]
  });
  loaderChannel = new PortTransport(port1, async (method, params) => {
    if (method === "pushToCompilationCache")
      addToCompilationCache(params.cache);
  });
  void loaderChannel.send("setSingleTSConfig", { tsconfig: _singleTSConfigPath });
  void loaderChannel.send("setTransformConfig", { config: _transformConfig });
  void loaderChannel.send("addToCompilationCache", { cache: serializeCompilationCache() });
}
async function startCollectingFileDeps2() {
  startCollectingFileDeps();
  if (loaderChannel)
    await loaderChannel.send("startCollectingFileDeps", {});
}
async function stopCollectingFileDeps2(file2) {
  stopCollectingFileDeps(file2);
  if (loaderChannel)
    await loaderChannel.send("stopCollectingFileDeps", { file: file2 });
}
async function incorporateCompilationCache() {
  if (!loaderChannel)
    return;
  const result2 = await loaderChannel.send("getCompilationCache", {});
  addToCompilationCache(result2.cache);
}

// packages/playwright/src/common/configLoader.ts
var { isRegExp: isRegExp2 } = require("playwright-core/lib/coreBundle").iso;
var kDefineConfigWasUsed = /* @__PURE__ */ 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 = /* @__PURE__ */ 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) {
  await setSingleTSConfig(overrides?.tsconfig);
  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"));
  await setTransformConfig({ babelPlugins, external, jsxImportSource });
  if (!overrides?.tsconfig)
    await setSingleTSConfig(fullConfig?.singleTSConfigPath);
  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 ("retryStrategy" in config && config.retryStrategy !== void 0) {
    if (typeof config.retryStrategy !== "string" || !["immediate", "isolated"].includes(config.retryStrategy))
      throw errorWithFile(file2, `config.retryStrategy must be one of "immediate" or "isolated"`);
  }
  if ("tsconfig" in config && config.tsconfig !== void 0) {
    if (typeof config.tsconfig !== "string")
      throw errorWithFile(file2, `config.tsconfig must be a string`);
    if (!import_fs7.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_fs7.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_fs7.default.existsSync(configFileOrDirectory))
    throw new Error(`${configFileOrDirectory} does not exist`);
  if (import_fs7.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() });
}

// packages/playwright/src/common/fixtures.ts
var fixtures_exports = {};
__export(fixtures_exports, {
  FixturePool: () => FixturePool,
  fixtureParameterNames: () => fixtureParameterNames,
  formatPotentiallyInternalLocation: () => formatPotentiallyInternalLocation,
  inheritFixtureNames: () => inheritFixtureNames
});
var import_crypto2 = __toESM(require("crypto"));
var { filterStackFile } = require("playwright-core/lib/coreBundle").utils;
var kScopeOrder = ["test", "worker"];
function isFixtureTuple(value) {
  return Array.isArray(value) && typeof value[1] === "object";
}
function isFixtureOption(value) {
  return isFixtureTuple(value) && !!value[1].option;
}
function isOptionFixture(registration) {
  while (!registration.option && registration.super)
    registration = registration.super;
  return registration.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 && !isOptionFixture(registration))
          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;
        }
        if (previous.option !== options.option && options.option !== void 0) {
          this._addLoadError(`Fixture "${name}" has already been registered as a { option: ${previous.option} } 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 && previous && isOptionFixture(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 = /* @__PURE__ */ 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 = /* @__PURE__ */ 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 = /* @__PURE__ */ 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 = /* @__PURE__ */ 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;
}

// packages/playwright/src/common/ipc.ts
var ipc_exports = {};
__export(ipc_exports, {
  serializeConfig: () => serializeConfig,
  stdioChunkToParams: () => stdioChunkToParams,
  toTestInfoErrorPayload: () => toTestInfoErrorPayload
});
var import_util7 = __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_util7.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;
}

// packages/playwright/src/common/poolBuilder.ts
var poolBuilder_exports = {};
__export(poolBuilder_exports, {
  PoolBuilder: () => PoolBuilder
});
var PoolBuilder = class _PoolBuilder {
  constructor(type, project) {
    this._testTypePools = /* @__PURE__ */ 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}`);
  }
};

// packages/playwright/src/common/process.ts
var process_exports = {};
__export(process_exports, {
  ProcessRunner: () => ProcessRunner,
  startProcessRunner: () => startProcessRunner
});
var import_bootstrap = require("playwright-core/lib/bootstrap");
var import_package4 = require("../package");
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 { setBoxedStackPrefixes } = 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 };
setBoxedStackPrefixes([import_package4.packageRoot]);
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 = /* @__PURE__ */ 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 = /* @__PURE__ */ 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);
}

// packages/playwright/src/common/suiteUtils.ts
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 = /* @__PURE__ */ 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 = /* @__PURE__ */ 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 };
}

// packages/playwright/src/common/test.ts
var test_exports = {};
__export(test_exports, {
  Suite: () => Suite,
  TestCase: () => TestCase
});

// packages/playwright/src/common/testType.ts
var testType_exports = {};
__export(testType_exports, {
  TestTypeImpl: () => TestTypeImpl,
  mergeTests: () => mergeTests,
  rootTestType: () => rootTestType
});
var import_globals2 = require("../globals");
var import_expect = require("../matchers/expect");

// packages/playwright/src/common/validators.ts
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
  };
}

// packages/playwright/src/common/testType.ts
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 = /* @__PURE__ */ 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.`,
        `- You are calling ${title} from an async test.describe() block. Only sync ones are supported.`
      ].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";
  }
};

// packages/playwright/src/isomorphic/teleReceiver.ts
var baseFullConfig = {
  argv: [],
  failOnFlakyTests: false,
  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
    /* 5 minutes */
  },
  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";
}

// packages/playwright/src/common/test.ts
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 = [];
    // Annotations known statically before running the test, e.g. `test.describe.skip()` or `test.describe({ annotation }, body)`.
    this._staticAnnotations = [];
    // Explicitly declared tags that are not a part of the title.
    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);
  }
  _detach(child) {
    const idx = this._entries.indexOf(child);
    if (idx !== -1)
      this._entries.splice(idx, 1);
    if (this._entries.length === 0)
      this.parent?._detach(this);
  }
  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 = "";
    // Explicitly declared tags that are not a part of the title.
    this._tags = [];
    this._planAnnotations = [];
    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
    ];
  }
  _applyPlanAnnotation(annotation) {
    this.annotations.push(annotation);
    this._planAnnotations.push(annotation);
    if (annotation.type === "skip" || annotation.type === "fixme")
      this.expectedStatus = "skipped";
    else if (annotation.type === "fail" && this.expectedStatus !== "skipped")
      this.expectedStatus = "failed";
  }
  _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: /* @__PURE__ */ 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(" ");
  }
};

// packages/playwright/src/common/testLoader.ts
var testLoader_exports = {};
__export(testLoader_exports, {
  defaultTimeout: () => defaultTimeout2,
  loadTestFile: () => loadTestFile
});
var import_path9 = __toESM(require("path"));
var import_util11 = __toESM(require("util"));
var import_globals3 = require("../globals");
var defaultTimeout2 = 3e4;
var cachedFileSuites = /* @__PURE__ */ 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)())
    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)())
      await stopCollectingFileDeps2(file2);
  }
  {
    const files = /* @__PURE__ */ 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_util11.default.inspect(error) };
}
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
  FullConfigInternal,
  ProcessRunner,
  builtInReporters,
  cc,
  config,
  configLoader,
  defineConfig,
  fixtures,
  ipc,
  mergeTests,
  poolBuilder,
  processRunner,
  startProcessRunner,
  suiteUtils,
  test,
  testLoader,
  testType,
  transform
});