Best JavaScript code snippet using playwright-internal
index.js
Source:index.js
...236 return tokens ? _path.default.join(dir, ...tokens) : undefined;237 };238 const executablePathOrDie = (name, e, installByDefault, sdkLanguage) => {239 if (!e) throw new Error(`${name} is not supported on ${_hostPlatform.hostPlatform}`);240 const installCommand = buildPlaywrightCLICommand(sdkLanguage, `install${installByDefault ? '' : ' ' + name}`);241 if (!(0, _fileUtils.canAccessFile)(e)) {242 const prettyMessage = [`Looks like Playwright Test or Playwright was just installed or updated.`, `Please run the following command to download new browser${installByDefault ? 's' : ''}:`, ``, ` ${installCommand}`, ``, `<3 Playwright Team`].join('\n');243 throw new Error(`Executable doesn't exist at ${e}\n${(0, _utils.wrapInASCIIBox)(prettyMessage, 1)}`);244 }245 return e;246 };247 this._executables = [];248 const chromium = descriptors.find(d => d.name === 'chromium');249 const chromiumExecutable = findExecutablePath(chromium.dir, 'chromium');250 this._executables.push({251 type: 'browser',252 name: 'chromium',253 browserName: 'chromium',254 directory: chromium.dir,255 executablePath: () => chromiumExecutable,256 executablePathOrDie: sdkLanguage => executablePathOrDie('chromium', chromiumExecutable, chromium.installByDefault, sdkLanguage),257 installType: chromium.installByDefault ? 'download-by-default' : 'download-on-demand',258 validateHostRequirements: sdkLanguage => this._validateHostRequirements(sdkLanguage, 'chromium', chromium.dir, ['chrome-linux'], [], ['chrome-win']),259 _install: () => this._downloadExecutable(chromium, chromiumExecutable, DOWNLOAD_PATHS['chromium'][_hostPlatform.hostPlatform], 'PLAYWRIGHT_CHROMIUM_DOWNLOAD_HOST'),260 _dependencyGroup: 'chromium',261 _isHermeticInstallation: true262 });263 const chromiumWithSymbols = descriptors.find(d => d.name === 'chromium-with-symbols');264 const chromiumWithSymbolsExecutable = findExecutablePath(chromiumWithSymbols.dir, 'chromium');265 this._executables.push({266 type: 'tool',267 name: 'chromium-with-symbols',268 browserName: 'chromium',269 directory: chromiumWithSymbols.dir,270 executablePath: () => chromiumWithSymbolsExecutable,271 executablePathOrDie: sdkLanguage => executablePathOrDie('chromium-with-symbols', chromiumWithSymbolsExecutable, chromiumWithSymbols.installByDefault, sdkLanguage),272 installType: chromiumWithSymbols.installByDefault ? 'download-by-default' : 'download-on-demand',273 validateHostRequirements: sdkLanguage => this._validateHostRequirements(sdkLanguage, 'chromium', chromiumWithSymbols.dir, ['chrome-linux'], [], ['chrome-win']),274 _install: () => this._downloadExecutable(chromiumWithSymbols, chromiumWithSymbolsExecutable, DOWNLOAD_PATHS['chromium-with-symbols'][_hostPlatform.hostPlatform], 'PLAYWRIGHT_CHROMIUM_DOWNLOAD_HOST'),275 _dependencyGroup: 'chromium',276 _isHermeticInstallation: true277 });278 this._executables.push(this._createChromiumChannel('chrome', {279 'linux': '/opt/google/chrome/chrome',280 'darwin': '/Applications/Google Chrome.app/Contents/MacOS/Google Chrome',281 'win32': `\\Google\\Chrome\\Application\\chrome.exe`282 }, () => this._installChromiumChannel('chrome', {283 'linux': 'reinstall_chrome_stable_linux.sh',284 'darwin': 'reinstall_chrome_stable_mac.sh',285 'win32': 'reinstall_chrome_stable_win.ps1'286 })));287 this._executables.push(this._createChromiumChannel('chrome-beta', {288 'linux': '/opt/google/chrome-beta/chrome',289 'darwin': '/Applications/Google Chrome Beta.app/Contents/MacOS/Google Chrome Beta',290 'win32': `\\Google\\Chrome Beta\\Application\\chrome.exe`291 }, () => this._installChromiumChannel('chrome-beta', {292 'linux': 'reinstall_chrome_beta_linux.sh',293 'darwin': 'reinstall_chrome_beta_mac.sh',294 'win32': 'reinstall_chrome_beta_win.ps1'295 })));296 this._executables.push(this._createChromiumChannel('chrome-dev', {297 'linux': '/opt/google/chrome-unstable/chrome',298 'darwin': '/Applications/Google Chrome Dev.app/Contents/MacOS/Google Chrome Dev',299 'win32': `\\Google\\Chrome Dev\\Application\\chrome.exe`300 }));301 this._executables.push(this._createChromiumChannel('chrome-canary', {302 'linux': '',303 'darwin': '/Applications/Google Chrome Canary.app/Contents/MacOS/Google Chrome Canary',304 'win32': `\\Google\\Chrome SxS\\Application\\chrome.exe`305 }));306 this._executables.push(this._createChromiumChannel('msedge', {307 'linux': '/opt/microsoft/msedge/msedge',308 'darwin': '/Applications/Microsoft Edge.app/Contents/MacOS/Microsoft Edge',309 'win32': `\\Microsoft\\Edge\\Application\\msedge.exe`310 }, () => this._installMSEdgeChannel('msedge', {311 'linux': 'reinstall_msedge_stable_linux.sh',312 'darwin': 'reinstall_msedge_stable_mac.sh',313 'win32': 'reinstall_msedge_stable_win.ps1'314 })));315 this._executables.push(this._createChromiumChannel('msedge-beta', {316 'linux': '/opt/microsoft/msedge-beta/msedge',317 'darwin': '/Applications/Microsoft Edge Beta.app/Contents/MacOS/Microsoft Edge Beta',318 'win32': `\\Microsoft\\Edge Beta\\Application\\msedge.exe`319 }, () => this._installMSEdgeChannel('msedge-beta', {320 'darwin': 'reinstall_msedge_beta_mac.sh',321 'linux': 'reinstall_msedge_beta_linux.sh',322 'win32': 'reinstall_msedge_beta_win.ps1'323 })));324 this._executables.push(this._createChromiumChannel('msedge-dev', {325 'linux': '/opt/microsoft/msedge-dev/msedge',326 'darwin': '/Applications/Microsoft Edge Dev.app/Contents/MacOS/Microsoft Edge Dev',327 'win32': `\\Microsoft\\Edge Dev\\Application\\msedge.exe`328 }, () => this._installMSEdgeChannel('msedge-dev', {329 'darwin': 'reinstall_msedge_dev_mac.sh',330 'linux': 'reinstall_msedge_dev_linux.sh',331 'win32': 'reinstall_msedge_dev_win.ps1'332 })));333 this._executables.push(this._createChromiumChannel('msedge-canary', {334 'linux': '',335 'darwin': '/Applications/Microsoft Edge Canary.app/Contents/MacOS/Microsoft Edge Canary',336 'win32': `\\Microsoft\\Edge SxS\\Application\\msedge.exe`337 }));338 const firefox = descriptors.find(d => d.name === 'firefox');339 const firefoxExecutable = findExecutablePath(firefox.dir, 'firefox');340 this._executables.push({341 type: 'browser',342 name: 'firefox',343 browserName: 'firefox',344 directory: firefox.dir,345 executablePath: () => firefoxExecutable,346 executablePathOrDie: sdkLanguage => executablePathOrDie('firefox', firefoxExecutable, firefox.installByDefault, sdkLanguage),347 installType: firefox.installByDefault ? 'download-by-default' : 'download-on-demand',348 validateHostRequirements: sdkLanguage => this._validateHostRequirements(sdkLanguage, 'firefox', firefox.dir, ['firefox'], [], ['firefox']),349 _install: () => this._downloadExecutable(firefox, firefoxExecutable, DOWNLOAD_PATHS['firefox'][_hostPlatform.hostPlatform], 'PLAYWRIGHT_FIREFOX_DOWNLOAD_HOST'),350 _dependencyGroup: 'firefox',351 _isHermeticInstallation: true352 });353 const firefoxBeta = descriptors.find(d => d.name === 'firefox-beta');354 const firefoxBetaExecutable = findExecutablePath(firefoxBeta.dir, 'firefox');355 this._executables.push({356 type: 'tool',357 name: 'firefox-beta',358 browserName: 'firefox',359 directory: firefoxBeta.dir,360 executablePath: () => firefoxBetaExecutable,361 executablePathOrDie: sdkLanguage => executablePathOrDie('firefox-beta', firefoxBetaExecutable, firefoxBeta.installByDefault, sdkLanguage),362 installType: firefoxBeta.installByDefault ? 'download-by-default' : 'download-on-demand',363 validateHostRequirements: sdkLanguage => this._validateHostRequirements(sdkLanguage, 'firefox', firefoxBeta.dir, ['firefox'], [], ['firefox']),364 _install: () => this._downloadExecutable(firefoxBeta, firefoxBetaExecutable, DOWNLOAD_PATHS['firefox-beta'][_hostPlatform.hostPlatform], 'PLAYWRIGHT_FIREFOX_DOWNLOAD_HOST'),365 _dependencyGroup: 'firefox',366 _isHermeticInstallation: true367 });368 const webkit = descriptors.find(d => d.name === 'webkit');369 const webkitExecutable = findExecutablePath(webkit.dir, 'webkit');370 const webkitLinuxLddDirectories = [_path.default.join('minibrowser-gtk'), _path.default.join('minibrowser-gtk', 'bin'), _path.default.join('minibrowser-gtk', 'lib'), _path.default.join('minibrowser-gtk', 'sys', 'lib'), _path.default.join('minibrowser-wpe'), _path.default.join('minibrowser-wpe', 'bin'), _path.default.join('minibrowser-wpe', 'lib'), _path.default.join('minibrowser-wpe', 'sys', 'lib')];371 this._executables.push({372 type: 'browser',373 name: 'webkit',374 browserName: 'webkit',375 directory: webkit.dir,376 executablePath: () => webkitExecutable,377 executablePathOrDie: sdkLanguage => executablePathOrDie('webkit', webkitExecutable, webkit.installByDefault, sdkLanguage),378 installType: webkit.installByDefault ? 'download-by-default' : 'download-on-demand',379 validateHostRequirements: sdkLanguage => this._validateHostRequirements(sdkLanguage, 'webkit', webkit.dir, webkitLinuxLddDirectories, ['libGLESv2.so.2', 'libx264.so'], ['']),380 _install: () => this._downloadExecutable(webkit, webkitExecutable, DOWNLOAD_PATHS['webkit'][_hostPlatform.hostPlatform], 'PLAYWRIGHT_WEBKIT_DOWNLOAD_HOST'),381 _dependencyGroup: 'webkit',382 _isHermeticInstallation: true383 });384 const ffmpeg = descriptors.find(d => d.name === 'ffmpeg');385 const ffmpegExecutable = findExecutablePath(ffmpeg.dir, 'ffmpeg');386 this._executables.push({387 type: 'tool',388 name: 'ffmpeg',389 browserName: undefined,390 directory: ffmpeg.dir,391 executablePath: () => ffmpegExecutable,392 executablePathOrDie: sdkLanguage => executablePathOrDie('ffmpeg', ffmpegExecutable, ffmpeg.installByDefault, sdkLanguage),393 installType: ffmpeg.installByDefault ? 'download-by-default' : 'download-on-demand',394 validateHostRequirements: () => Promise.resolve(),395 _install: () => this._downloadExecutable(ffmpeg, ffmpegExecutable, DOWNLOAD_PATHS['ffmpeg'][_hostPlatform.hostPlatform], 'PLAYWRIGHT_FFMPEG_DOWNLOAD_HOST'),396 _dependencyGroup: 'tools',397 _isHermeticInstallation: true398 });399 }400 _createChromiumChannel(name, lookAt, install) {401 const executablePath = (sdkLanguage, shouldThrow) => {402 const suffix = lookAt[process.platform];403 if (!suffix) {404 if (shouldThrow) throw new Error(`Chromium distribution '${name}' is not supported on ${process.platform}`);405 return undefined;406 }407 const prefixes = process.platform === 'win32' ? [process.env.LOCALAPPDATA, process.env.PROGRAMFILES, process.env['PROGRAMFILES(X86)']].filter(Boolean) : [''];408 for (const prefix of prefixes) {409 const executablePath = _path.default.join(prefix, suffix);410 if ((0, _fileUtils.canAccessFile)(executablePath)) return executablePath;411 }412 if (!shouldThrow) return undefined;413 const location = prefixes.length ? ` at ${_path.default.join(prefixes[0], suffix)}` : ``; // TODO: language-specific error message414 const installation = install ? `\nRun "${buildPlaywrightCLICommand(sdkLanguage, 'install ' + name)}"` : '';415 throw new Error(`Chromium distribution '${name}' is not found${location}${installation}`);416 };417 return {418 type: 'channel',419 name,420 browserName: 'chromium',421 directory: undefined,422 executablePath: sdkLanguage => executablePath(sdkLanguage, false),423 executablePathOrDie: sdkLanguage => executablePath(sdkLanguage, true),424 installType: install ? 'install-script' : 'none',425 validateHostRequirements: () => Promise.resolve(),426 _isHermeticInstallation: false,427 _install: install428 };429 }430 executables() {431 return this._executables;432 }433 findExecutable(name) {434 return this._executables.find(b => b.name === name);435 }436 defaultExecutables() {437 return this._executables.filter(e => e.installType === 'download-by-default');438 }439 _addRequirementsAndDedupe(executables) {440 const set = new Set();441 for (const executable of executables) {442 set.add(executable);443 if (executable.browserName === 'chromium') set.add(this.findExecutable('ffmpeg'));444 }445 return Array.from(set);446 }447 async _validateHostRequirements(sdkLanguage, browserName, browserDirectory, linuxLddDirectories, dlOpenLibraries, windowsExeAndDllDirectories) {448 if ((0, _utils.getAsBooleanFromENV)('PLAYWRIGHT_SKIP_VALIDATE_HOST_REQUIREMENTS')) {449 process.stdout.write('Skipping host requirements validation logic because `PLAYWRIGHT_SKIP_VALIDATE_HOST_REQUIREMENTS` env variable is set.\n');450 return;451 }452 const ubuntuVersion = await (0, _ubuntuVersion.getUbuntuVersion)();453 if (browserName === 'firefox' && ubuntuVersion === '16.04') throw new Error(`Cannot launch Firefox on Ubuntu 16.04! Minimum required Ubuntu version for Firefox browser is 18.04`);454 if (os.platform() === 'linux') return await (0, _dependencies.validateDependenciesLinux)(sdkLanguage, linuxLddDirectories.map(d => _path.default.join(browserDirectory, d)), dlOpenLibraries);455 if (os.platform() === 'win32' && os.arch() === 'x64') return await (0, _dependencies.validateDependenciesWindows)(windowsExeAndDllDirectories.map(d => _path.default.join(browserDirectory, d)));456 }457 async installDeps(executablesToInstallDeps, dryRun) {458 const executables = this._addRequirementsAndDedupe(executablesToInstallDeps);459 const targets = new Set();460 for (const executable of executables) {461 if (executable._dependencyGroup) targets.add(executable._dependencyGroup);462 }463 targets.add('tools');464 if (os.platform() === 'win32') return await (0, _dependencies.installDependenciesWindows)(targets, dryRun);465 if (os.platform() === 'linux') return await (0, _dependencies.installDependenciesLinux)(targets, dryRun);466 }467 async install(executablesToInstall, forceReinstall) {468 const executables = this._addRequirementsAndDedupe(executablesToInstall);469 await fs.promises.mkdir(registryDirectory, {470 recursive: true471 });472 const lockfilePath = _path.default.join(registryDirectory, '__dirlock');473 const linksDir = _path.default.join(registryDirectory, '.links');474 let releaseLock;475 try {476 releaseLock = await _properLockfile.default.lock(registryDirectory, {477 retries: {478 // Retry 20 times during 10 minutes with479 // exponential back-off.480 // See documentation at: https://www.npmjs.com/package/retry#retrytimeoutsoptions481 retries: 20,482 factor: 1.27579483 },484 onCompromised: err => {485 throw new Error(`${err.message} Path: ${lockfilePath}`);486 },487 lockfilePath488 }); // Create a link first, so that cache validation does not remove our own browsers.489 await fs.promises.mkdir(linksDir, {490 recursive: true491 });492 await fs.promises.writeFile(_path.default.join(linksDir, (0, _utils.calculateSha1)(PACKAGE_PATH)), PACKAGE_PATH); // Remove stale browsers.493 await this._validateInstallationCache(linksDir); // Install browsers for this package.494 for (const executable of executables) {495 if (!executable._install) throw new Error(`ERROR: Playwright does not support installing ${executable.name}`);496 const {497 langName498 } = (0, _userAgent.getClientLanguage)();499 if (!(0, _utils.getAsBooleanFromENV)('CI') && !executable._isHermeticInstallation && !forceReinstall && executable.executablePath(langName)) {500 const command = buildPlaywrightCLICommand(langName, 'install --force ' + executable.name);501 throw new Error('\n' + (0, _utils.wrapInASCIIBox)([`ATTENTION: "${executable.name}" is already installed on the system!`, ``, `"${executable.name}" installation is not hermetic; installing newer version`, `requires *removal* of a current installation first.`, ``, `To *uninstall* current version and re-install latest "${executable.name}":`, ``, `- Close all running instances of "${executable.name}", if any`, `- Use "--force" to install browser:`, ``, ` ${command}`, ``, `<3 Playwright Team`].join('\n'), 1));502 }503 await executable._install();504 }505 } catch (e) {506 if (e.code === 'ELOCKED') {507 const rmCommand = process.platform === 'win32' ? 'rm -R' : 'rm -rf';508 throw new Error('\n' + (0, _utils.wrapInASCIIBox)([`An active lockfile is found at:`, ``, ` ${lockfilePath}`, ``, `Either:`, `- wait a few minutes if other Playwright is installing browsers in parallel`, `- remove lock manually with:`, ``, ` ${rmCommand} ${lockfilePath}`, ``, `<3 Playwright Team`].join('\n'), 1));509 } else {510 throw e;511 }512 } finally {513 if (releaseLock) await releaseLock();514 }515 }516 async _downloadExecutable(descriptor, executablePath, downloadPathTemplate, downloadHostEnv) {517 if (!downloadPathTemplate || !executablePath) throw new Error(`ERROR: Playwright does not support ${descriptor.name} on ${_hostPlatform.hostPlatform}`);518 if (_hostPlatform.hostPlatform === 'generic-linux' || _hostPlatform.hostPlatform === 'generic-linux-arm64') (0, _browserFetcher.logPolitely)('BEWARE: your OS is not officially supported by Playwright; downloading Ubuntu build as a fallback.');519 const downloadHost = downloadHostEnv && (0, _utils.getFromENV)(downloadHostEnv) || (0, _utils.getFromENV)('PLAYWRIGHT_DOWNLOAD_HOST') || 'https://playwright.azureedge.net';520 const downloadPath = util.format(downloadPathTemplate, descriptor.revision);521 const downloadURL = `${downloadHost}/${downloadPath}`;522 const title = `${descriptor.name} v${descriptor.revision}`;523 const downloadFileName = `playwright-download-${descriptor.name}-${_hostPlatform.hostPlatform}-${descriptor.revision}.zip`;524 await (0, _browserFetcher.downloadBrowserWithProgressBar)(title, descriptor.dir, executablePath, downloadURL, downloadFileName).catch(e => {525 throw new Error(`Failed to download ${title}, caused by\n${e.stack}`);526 });527 await fs.promises.writeFile(markerFilePath(descriptor.dir), '');528 }529 async _installMSEdgeChannel(channel, scripts) {530 const scriptArgs = [];531 if (process.platform !== 'linux') {532 const products = JSON.parse(await (0, _netUtils.fetchData)({533 url: 'https://edgeupdates.microsoft.com/api/products'534 }));535 const productName = {536 'msedge': 'Stable',537 'msedge-beta': 'Beta',538 'msedge-dev': 'Dev'539 }[channel];540 const product = products.find(product => product.Product === productName);541 const searchConfig = {542 darwin: {543 platform: 'MacOS',544 arch: 'universal',545 artifact: 'pkg'546 },547 win32: {548 platform: 'Windows',549 arch: 'x64',550 artifact: 'msi'551 }552 }[process.platform];553 const release = searchConfig ? product.Releases.find(release => release.Platform === searchConfig.platform && release.Architecture === searchConfig.arch) : null;554 const artifact = release ? release.Artifacts.find(artifact => artifact.ArtifactName === searchConfig.artifact) : null;555 if (artifact) scriptArgs.push(artifact.Location556 /* url */557 );else throw new Error(`Cannot install ${channel} on ${process.platform}`);558 }559 await this._installChromiumChannel(channel, scripts, scriptArgs);560 }561 async _installChromiumChannel(channel, scripts, scriptArgs = []) {562 const scriptName = scripts[process.platform];563 if (!scriptName) throw new Error(`Cannot install ${channel} on ${process.platform}`);564 const cwd = BIN_PATH;565 const isPowerShell = scriptName.endsWith('.ps1');566 if (isPowerShell) {567 const args = ['-ExecutionPolicy', 'Bypass', '-File', _path.default.join(BIN_PATH, scriptName), ...scriptArgs];568 const {569 code570 } = await (0, _spawnAsync.spawnAsync)('powershell.exe', args, {571 cwd,572 stdio: 'inherit'573 });574 if (code !== 0) throw new Error(`Failed to install ${channel}`);575 } else {576 const {577 command,578 args,579 elevatedPermissions580 } = await (0, _dependencies.transformCommandsForRoot)([`bash "${_path.default.join(BIN_PATH, scriptName)}" ${scriptArgs.join('')}`]);581 if (elevatedPermissions) console.log('Switching to root user to install dependencies...'); // eslint-disable-line no-console582 const {583 code584 } = await (0, _spawnAsync.spawnAsync)(command, args, {585 cwd,586 stdio: 'inherit'587 });588 if (code !== 0) throw new Error(`Failed to install ${channel}`);589 }590 }591 async _validateInstallationCache(linksDir) {592 // 1. Collect used downloads and package descriptors.593 const usedBrowserPaths = new Set();594 for (const fileName of await fs.promises.readdir(linksDir)) {595 const linkPath = _path.default.join(linksDir, fileName);596 let linkTarget = '';597 try {598 linkTarget = (await fs.promises.readFile(linkPath)).toString();599 const browsersJSON = require(_path.default.join(linkTarget, 'browsers.json'));600 const descriptors = readDescriptors(browsersJSON);601 for (const browserName of allDownloadable) {602 // We retain browsers if they are found in the descriptor.603 // Note, however, that there are older versions out in the wild that rely on604 // the "download" field in the browser descriptor and use its value605 // to retain and download browsers.606 // As of v1.10, we decided to abandon "download" field.607 const descriptor = descriptors.find(d => d.name === browserName);608 if (!descriptor) continue;609 const usedBrowserPath = descriptor.dir;610 const browserRevision = parseInt(descriptor.revision, 10); // Old browser installations don't have marker file.611 const shouldHaveMarkerFile = browserName === 'chromium' && browserRevision >= 786218 || browserName === 'firefox' && browserRevision >= 1128 || browserName === 'webkit' && browserRevision >= 1307 || // All new applications have a marker file right away.612 browserName !== 'firefox' && browserName !== 'chromium' && browserName !== 'webkit';613 if (!shouldHaveMarkerFile || (await (0, _fileUtils.existsAsync)(markerFilePath(usedBrowserPath)))) usedBrowserPaths.add(usedBrowserPath);614 }615 } catch (e) {616 await fs.promises.unlink(linkPath).catch(e => {});617 }618 } // 2. Delete all unused browsers.619 if (!(0, _utils.getAsBooleanFromENV)('PLAYWRIGHT_SKIP_BROWSER_GC')) {620 let downloadedBrowsers = (await fs.promises.readdir(registryDirectory)).map(file => _path.default.join(registryDirectory, file));621 downloadedBrowsers = downloadedBrowsers.filter(file => isBrowserDirectory(file));622 const directories = new Set(downloadedBrowsers);623 for (const browserDirectory of usedBrowserPaths) directories.delete(browserDirectory);624 for (const directory of directories) (0, _browserFetcher.logPolitely)('Removing unused browser at ' + directory);625 await (0, _fileUtils.removeFolders)([...directories]);626 }627 }628}629exports.Registry = Registry;630function markerFilePath(browserDirectory) {631 return _path.default.join(browserDirectory, 'INSTALLATION_COMPLETE');632}633function buildPlaywrightCLICommand(sdkLanguage, parameters) {634 switch (sdkLanguage) {635 case 'python':636 return `playwright ${parameters}`;637 case 'java':638 return `mvn exec:java -e -Dexec.mainClass=com.microsoft.playwright.CLI -Dexec.args="${parameters}"`;639 case 'csharp':640 return `pwsh bin\\Debug\\netX\\playwright.ps1 ${parameters}`;641 default:642 return `npx playwright ${parameters}`;643 }644}645async function installDefaultBrowsersForNpmInstall() {646 const defaultBrowserNames = registry.defaultExecutables().map(e => e.name);647 return installBrowsersForNpmInstall(defaultBrowserNames);648}649async function installBrowsersForNpmInstall(browsers) {650 // PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD should have a value of 0 or 1651 if ((0, _utils.getAsBooleanFromENV)('PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD')) {652 (0, _browserFetcher.logPolitely)('Skipping browsers download because `PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD` env variable is set');653 return false;654 }655 const executables = [];656 for (const browserName of browsers) {657 const executable = registry.findExecutable(browserName);658 if (!executable || executable.installType === 'none') throw new Error(`Cannot install ${browserName}`);659 executables.push(executable);660 }661 await registry.install(executables, false662 /* forceReinstall */663 );664}665function findChromiumChannel(sdkLanguage) {666 // Fall back to the stable channels of popular vendors to work out of the box.667 // Null means no installation and no channels found.668 let channel = null;669 for (const name of ['chromium', 'chrome', 'msedge']) {670 try {671 registry.findExecutable(name).executablePathOrDie(sdkLanguage);672 channel = name === 'chromium' ? undefined : name;673 break;674 } catch (e) {}675 }676 if (channel === null) {677 const installCommand = buildPlaywrightCLICommand(sdkLanguage, `install chromium`);678 const prettyMessage = [`No chromium-based browser found on the system.`, `Please run the following command to download one:`, ``, ` ${installCommand}`, ``, `<3 Playwright Team`].join('\n');679 throw new Error('\n' + (0, _utils.wrapInASCIIBox)(prettyMessage, 1));680 }681 return channel;682}683const registry = new Registry(require('../../../browsers.json'));...
registry.js
Source:registry.js
...207 return tokens ? _path.default.join(dir, ...tokens) : undefined;208 };209 const executablePathOrDie = (name, e, installByDefault, sdkLanguage) => {210 if (!e) throw new Error(`${name} is not supported on ${_utils.hostPlatform}`);211 const installCommand = buildPlaywrightCLICommand(sdkLanguage, `install${installByDefault ? '' : ' ' + name}`);212 if (!(0, _utils.canAccessFile)(e)) {213 const prettyMessage = [`Looks like Playwright Test or Playwright was just installed or updated.`, `Please run the following command to download new browser${installByDefault ? 's' : ''}:`, ``, ` ${installCommand}`, ``, `<3 Playwright Team`].join('\n');214 throw new Error(`Executable doesn't exist at ${e}\n${(0, _utils.wrapInASCIIBox)(prettyMessage, 1)}`);215 }216 return e;217 };218 this._executables = [];219 const chromium = descriptors.find(d => d.name === 'chromium');220 const chromiumExecutable = findExecutablePath(chromium.dir, 'chromium');221 this._executables.push({222 type: 'browser',223 name: 'chromium',224 browserName: 'chromium',225 directory: chromium.dir,226 executablePath: () => chromiumExecutable,227 executablePathOrDie: sdkLanguage => executablePathOrDie('chromium', chromiumExecutable, chromium.installByDefault, sdkLanguage),228 installType: chromium.installByDefault ? 'download-by-default' : 'download-on-demand',229 validateHostRequirements: sdkLanguage => this._validateHostRequirements(sdkLanguage, 'chromium', chromium.dir, ['chrome-linux'], [], ['chrome-win']),230 _install: () => this._downloadExecutable(chromium, chromiumExecutable, DOWNLOAD_PATHS['chromium'][_utils.hostPlatform], 'PLAYWRIGHT_CHROMIUM_DOWNLOAD_HOST'),231 _dependencyGroup: 'chromium'232 });233 const chromiumWithSymbols = descriptors.find(d => d.name === 'chromium-with-symbols');234 const chromiumWithSymbolsExecutable = findExecutablePath(chromiumWithSymbols.dir, 'chromium');235 this._executables.push({236 type: 'tool',237 name: 'chromium-with-symbols',238 browserName: 'chromium',239 directory: chromiumWithSymbols.dir,240 executablePath: () => chromiumWithSymbolsExecutable,241 executablePathOrDie: sdkLanguage => executablePathOrDie('chromium-with-symbols', chromiumWithSymbolsExecutable, chromiumWithSymbols.installByDefault, sdkLanguage),242 installType: chromiumWithSymbols.installByDefault ? 'download-by-default' : 'download-on-demand',243 validateHostRequirements: sdkLanguage => this._validateHostRequirements(sdkLanguage, 'chromium', chromiumWithSymbols.dir, ['chrome-linux'], [], ['chrome-win']),244 _install: () => this._downloadExecutable(chromiumWithSymbols, chromiumWithSymbolsExecutable, DOWNLOAD_PATHS['chromium-with-symbols'][_utils.hostPlatform], 'PLAYWRIGHT_CHROMIUM_DOWNLOAD_HOST'),245 _dependencyGroup: 'chromium'246 });247 this._executables.push(this._createChromiumChannel('chrome', {248 'linux': '/opt/google/chrome/chrome',249 'darwin': '/Applications/Google Chrome.app/Contents/MacOS/Google Chrome',250 'win32': `\\Google\\Chrome\\Application\\chrome.exe`251 }, () => this._installChromiumChannel('chrome', {252 'linux': 'reinstall_chrome_stable_linux.sh',253 'darwin': 'reinstall_chrome_stable_mac.sh',254 'win32': 'reinstall_chrome_stable_win.ps1'255 })));256 this._executables.push(this._createChromiumChannel('chrome-beta', {257 'linux': '/opt/google/chrome-beta/chrome',258 'darwin': '/Applications/Google Chrome Beta.app/Contents/MacOS/Google Chrome Beta',259 'win32': `\\Google\\Chrome Beta\\Application\\chrome.exe`260 }, () => this._installChromiumChannel('chrome-beta', {261 'linux': 'reinstall_chrome_beta_linux.sh',262 'darwin': 'reinstall_chrome_beta_mac.sh',263 'win32': 'reinstall_chrome_beta_win.ps1'264 })));265 this._executables.push(this._createChromiumChannel('chrome-dev', {266 'linux': '/opt/google/chrome-unstable/chrome',267 'darwin': '/Applications/Google Chrome Dev.app/Contents/MacOS/Google Chrome Dev',268 'win32': `\\Google\\Chrome Dev\\Application\\chrome.exe`269 }));270 this._executables.push(this._createChromiumChannel('chrome-canary', {271 'linux': '',272 'darwin': '/Applications/Google Chrome Canary.app/Contents/MacOS/Google Chrome Canary',273 'win32': `\\Google\\Chrome SxS\\Application\\chrome.exe`274 }));275 this._executables.push(this._createChromiumChannel('msedge', {276 'linux': '/opt/microsoft/msedge/msedge',277 'darwin': '/Applications/Microsoft Edge.app/Contents/MacOS/Microsoft Edge',278 'win32': `\\Microsoft\\Edge\\Application\\msedge.exe`279 }, () => this._installMSEdgeChannel('msedge', {280 'linux': 'reinstall_msedge_stable_linux.sh',281 'darwin': 'reinstall_msedge_stable_mac.sh',282 'win32': 'reinstall_msedge_stable_win.ps1'283 })));284 this._executables.push(this._createChromiumChannel('msedge-beta', {285 'linux': '/opt/microsoft/msedge-beta/msedge',286 'darwin': '/Applications/Microsoft Edge Beta.app/Contents/MacOS/Microsoft Edge Beta',287 'win32': `\\Microsoft\\Edge Beta\\Application\\msedge.exe`288 }, () => this._installMSEdgeChannel('msedge-beta', {289 'darwin': 'reinstall_msedge_beta_mac.sh',290 'linux': 'reinstall_msedge_beta_linux.sh',291 'win32': 'reinstall_msedge_beta_win.ps1'292 })));293 this._executables.push(this._createChromiumChannel('msedge-dev', {294 'linux': '/opt/microsoft/msedge-dev/msedge',295 'darwin': '/Applications/Microsoft Edge Dev.app/Contents/MacOS/Microsoft Edge Dev',296 'win32': `\\Microsoft\\Edge Dev\\Application\\msedge.exe`297 }, () => this._installMSEdgeChannel('msedge-dev', {298 'darwin': 'reinstall_msedge_dev_mac.sh',299 'linux': 'reinstall_msedge_dev_linux.sh',300 'win32': 'reinstall_msedge_dev_win.ps1'301 })));302 this._executables.push(this._createChromiumChannel('msedge-canary', {303 'linux': '',304 'darwin': '/Applications/Microsoft Edge Canary.app/Contents/MacOS/Microsoft Edge Canary',305 'win32': `\\Microsoft\\Edge SxS\\Application\\msedge.exe`306 }));307 const firefox = descriptors.find(d => d.name === 'firefox');308 const firefoxExecutable = findExecutablePath(firefox.dir, 'firefox');309 this._executables.push({310 type: 'browser',311 name: 'firefox',312 browserName: 'firefox',313 directory: firefox.dir,314 executablePath: () => firefoxExecutable,315 executablePathOrDie: sdkLanguage => executablePathOrDie('firefox', firefoxExecutable, firefox.installByDefault, sdkLanguage),316 installType: firefox.installByDefault ? 'download-by-default' : 'download-on-demand',317 validateHostRequirements: sdkLanguage => this._validateHostRequirements(sdkLanguage, 'firefox', firefox.dir, ['firefox'], [], ['firefox']),318 _install: () => this._downloadExecutable(firefox, firefoxExecutable, DOWNLOAD_PATHS['firefox'][_utils.hostPlatform], 'PLAYWRIGHT_FIREFOX_DOWNLOAD_HOST'),319 _dependencyGroup: 'firefox'320 });321 const firefoxBeta = descriptors.find(d => d.name === 'firefox-beta');322 const firefoxBetaExecutable = findExecutablePath(firefoxBeta.dir, 'firefox');323 this._executables.push({324 type: 'tool',325 name: 'firefox-beta',326 browserName: 'firefox',327 directory: firefoxBeta.dir,328 executablePath: () => firefoxBetaExecutable,329 executablePathOrDie: sdkLanguage => executablePathOrDie('firefox-beta', firefoxBetaExecutable, firefoxBeta.installByDefault, sdkLanguage),330 installType: firefoxBeta.installByDefault ? 'download-by-default' : 'download-on-demand',331 validateHostRequirements: sdkLanguage => this._validateHostRequirements(sdkLanguage, 'firefox', firefoxBeta.dir, ['firefox'], [], ['firefox']),332 _install: () => this._downloadExecutable(firefoxBeta, firefoxBetaExecutable, DOWNLOAD_PATHS['firefox-beta'][_utils.hostPlatform], 'PLAYWRIGHT_FIREFOX_DOWNLOAD_HOST'),333 _dependencyGroup: 'firefox'334 });335 const webkit = descriptors.find(d => d.name === 'webkit');336 const webkitExecutable = findExecutablePath(webkit.dir, 'webkit');337 const webkitLinuxLddDirectories = [_path.default.join('minibrowser-gtk'), _path.default.join('minibrowser-gtk', 'bin'), _path.default.join('minibrowser-gtk', 'lib'), _path.default.join('minibrowser-wpe'), _path.default.join('minibrowser-wpe', 'bin'), _path.default.join('minibrowser-wpe', 'lib')];338 this._executables.push({339 type: 'browser',340 name: 'webkit',341 browserName: 'webkit',342 directory: webkit.dir,343 executablePath: () => webkitExecutable,344 executablePathOrDie: sdkLanguage => executablePathOrDie('webkit', webkitExecutable, webkit.installByDefault, sdkLanguage),345 installType: webkit.installByDefault ? 'download-by-default' : 'download-on-demand',346 validateHostRequirements: sdkLanguage => this._validateHostRequirements(sdkLanguage, 'webkit', webkit.dir, webkitLinuxLddDirectories, ['libGLESv2.so.2', 'libx264.so'], ['']),347 _install: () => this._downloadExecutable(webkit, webkitExecutable, DOWNLOAD_PATHS['webkit'][_utils.hostPlatform], 'PLAYWRIGHT_WEBKIT_DOWNLOAD_HOST'),348 _dependencyGroup: 'webkit'349 });350 const ffmpeg = descriptors.find(d => d.name === 'ffmpeg');351 const ffmpegExecutable = findExecutablePath(ffmpeg.dir, 'ffmpeg');352 this._executables.push({353 type: 'tool',354 name: 'ffmpeg',355 browserName: undefined,356 directory: ffmpeg.dir,357 executablePath: () => ffmpegExecutable,358 executablePathOrDie: sdkLanguage => executablePathOrDie('ffmpeg', ffmpegExecutable, ffmpeg.installByDefault, sdkLanguage),359 installType: ffmpeg.installByDefault ? 'download-by-default' : 'download-on-demand',360 validateHostRequirements: () => Promise.resolve(),361 _install: () => this._downloadExecutable(ffmpeg, ffmpegExecutable, DOWNLOAD_PATHS['ffmpeg'][_utils.hostPlatform], 'PLAYWRIGHT_FFMPEG_DOWNLOAD_HOST'),362 _dependencyGroup: 'tools'363 });364 }365 _createChromiumChannel(name, lookAt, install) {366 const executablePath = (sdkLanguage, shouldThrow) => {367 const suffix = lookAt[process.platform];368 if (!suffix) {369 if (shouldThrow) throw new Error(`Chromium distribution '${name}' is not supported on ${process.platform}`);370 return undefined;371 }372 const prefixes = process.platform === 'win32' ? [process.env.LOCALAPPDATA, process.env.PROGRAMFILES, process.env['PROGRAMFILES(X86)']].filter(Boolean) : [''];373 for (const prefix of prefixes) {374 const executablePath = _path.default.join(prefix, suffix);375 if ((0, _utils.canAccessFile)(executablePath)) return executablePath;376 }377 if (!shouldThrow) return undefined;378 const location = prefixes.length ? ` at ${_path.default.join(prefixes[0], suffix)}` : ``; // TODO: language-specific error message379 const installation = install ? `\nRun "${buildPlaywrightCLICommand(sdkLanguage, 'install ' + name)}"` : '';380 throw new Error(`Chromium distribution '${name}' is not found${location}${installation}`);381 };382 return {383 type: 'channel',384 name,385 browserName: 'chromium',386 directory: undefined,387 executablePath: sdkLanguage => executablePath(sdkLanguage, false),388 executablePathOrDie: sdkLanguage => executablePath(sdkLanguage, true),389 installType: install ? 'install-script' : 'none',390 validateHostRequirements: () => Promise.resolve(),391 _install: install392 };393 }394 executables() {395 return this._executables;396 }397 findExecutable(name) {398 return this._executables.find(b => b.name === name);399 }400 defaultExecutables() {401 return this._executables.filter(e => e.installType === 'download-by-default');402 }403 _addRequirementsAndDedupe(executables) {404 const set = new Set();405 for (const executable of executables) {406 set.add(executable);407 if (executable.browserName === 'chromium') set.add(this.findExecutable('ffmpeg'));408 }409 return Array.from(set);410 }411 async _validateHostRequirements(sdkLanguage, browserName, browserDirectory, linuxLddDirectories, dlOpenLibraries, windowsExeAndDllDirectories) {412 if ((0, _utils.getAsBooleanFromENV)('PLAYWRIGHT_SKIP_VALIDATE_HOST_REQUIREMENTS')) {413 process.stdout.write('Skipping host requirements validation logic because `PLAYWRIGHT_SKIP_VALIDATE_HOST_REQUIREMENTS` env variable is set.\n');414 return;415 }416 const ubuntuVersion = await (0, _ubuntuVersion.getUbuntuVersion)();417 if (browserName === 'firefox' && ubuntuVersion === '16.04') throw new Error(`Cannot launch Firefox on Ubuntu 16.04! Minimum required Ubuntu version for Firefox browser is 18.04`);418 if (os.platform() === 'linux') return await (0, _dependencies.validateDependenciesLinux)(sdkLanguage, linuxLddDirectories.map(d => _path.default.join(browserDirectory, d)), dlOpenLibraries);419 if (os.platform() === 'win32' && os.arch() === 'x64') return await (0, _dependencies.validateDependenciesWindows)(windowsExeAndDllDirectories.map(d => _path.default.join(browserDirectory, d)));420 }421 async installDeps(executablesToInstallDeps, dryRun) {422 const executables = this._addRequirementsAndDedupe(executablesToInstallDeps);423 const targets = new Set();424 for (const executable of executables) {425 if (executable._dependencyGroup) targets.add(executable._dependencyGroup);426 }427 targets.add('tools');428 if (os.platform() === 'win32') return await (0, _dependencies.installDependenciesWindows)(targets, dryRun);429 if (os.platform() === 'linux') return await (0, _dependencies.installDependenciesLinux)(targets, dryRun);430 }431 async install(executablesToInstall) {432 const executables = this._addRequirementsAndDedupe(executablesToInstall);433 await fs.promises.mkdir(registryDirectory, {434 recursive: true435 });436 const lockfilePath = _path.default.join(registryDirectory, '__dirlock');437 const linksDir = _path.default.join(registryDirectory, '.links');438 let releaseLock;439 try {440 releaseLock = await _properLockfile.default.lock(registryDirectory, {441 retries: {442 // Retry 20 times during 10 minutes with443 // exponential back-off.444 // See documentation at: https://www.npmjs.com/package/retry#retrytimeoutsoptions445 retries: 20,446 factor: 1.27579447 },448 onCompromised: err => {449 throw new Error(`${err.message} Path: ${lockfilePath}`);450 },451 lockfilePath452 }); // Create a link first, so that cache validation does not remove our own browsers.453 await fs.promises.mkdir(linksDir, {454 recursive: true455 });456 await fs.promises.writeFile(_path.default.join(linksDir, (0, _utils.calculateSha1)(PACKAGE_PATH)), PACKAGE_PATH); // Remove stale browsers.457 await this._validateInstallationCache(linksDir); // Install browsers for this package.458 for (const executable of executables) {459 if (executable._install) await executable._install();else throw new Error(`ERROR: Playwright does not support installing ${executable.name}`);460 }461 } catch (e) {462 if (e.code === 'ELOCKED') {463 const rmCommand = process.platform === 'win32' ? 'rm -R' : 'rm -rf';464 throw new Error('\n' + (0, _utils.wrapInASCIIBox)([`An active lockfile is found at:`, ``, ` ${lockfilePath}`, ``, `Either:`, `- wait a few minutes if other Playwright is installing browsers in parallel`, `- remove lock manually with:`, ``, ` ${rmCommand} ${lockfilePath}`, ``, `<3 Playwright Team`].join('\n'), 1));465 } else {466 throw e;467 }468 } finally {469 if (releaseLock) await releaseLock();470 }471 }472 async _downloadExecutable(descriptor, executablePath, downloadPathTemplate, downloadHostEnv) {473 if (!downloadPathTemplate || !executablePath) throw new Error(`ERROR: Playwright does not support ${descriptor.name} on ${_utils.hostPlatform}`);474 const downloadHost = downloadHostEnv && (0, _utils.getFromENV)(downloadHostEnv) || (0, _utils.getFromENV)('PLAYWRIGHT_DOWNLOAD_HOST') || 'https://playwright.azureedge.net';475 const downloadPath = util.format(downloadPathTemplate, descriptor.revision);476 const downloadURL = `${downloadHost}/${downloadPath}`;477 const title = `${descriptor.name} v${descriptor.revision}`;478 const downloadFileName = `playwright-download-${descriptor.name}-${_utils.hostPlatform}-${descriptor.revision}.zip`;479 await (0, _browserFetcher.downloadBrowserWithProgressBar)(title, descriptor.dir, executablePath, downloadURL, downloadFileName).catch(e => {480 throw new Error(`Failed to download ${title}, caused by\n${e.stack}`);481 });482 await fs.promises.writeFile(markerFilePath(descriptor.dir), '');483 }484 async _installMSEdgeChannel(channel, scripts) {485 const scriptArgs = [];486 if (process.platform !== 'linux') {487 const products = JSON.parse(await (0, _utils.fetchData)({488 url: 'https://edgeupdates.microsoft.com/api/products'489 }));490 const productName = {491 'msedge': 'Stable',492 'msedge-beta': 'Beta',493 'msedge-dev': 'Dev'494 }[channel];495 const product = products.find(product => product.Product === productName);496 const searchConfig = {497 darwin: {498 platform: 'MacOS',499 arch: 'universal',500 artifact: 'pkg'501 },502 win32: {503 platform: 'Windows',504 arch: 'x64',505 artifact: 'msi'506 }507 }[process.platform];508 const release = searchConfig ? product.Releases.find(release => release.Platform === searchConfig.platform && release.Architecture === searchConfig.arch) : null;509 const artifact = release ? release.Artifacts.find(artifact => artifact.ArtifactName === searchConfig.artifact) : null;510 if (artifact) scriptArgs.push(artifact.Location511 /* url */512 );else throw new Error(`Cannot install ${channel} on ${process.platform}`);513 }514 await this._installChromiumChannel(channel, scripts, scriptArgs);515 }516 async _installChromiumChannel(channel, scripts, scriptArgs = []) {517 const scriptName = scripts[process.platform];518 if (!scriptName) throw new Error(`Cannot install ${channel} on ${process.platform}`);519 const cwd = BIN_PATH;520 const isPowerShell = scriptName.endsWith('.ps1');521 if (isPowerShell) {522 const args = ['-ExecutionPolicy', 'Bypass', '-File', _path.default.join(BIN_PATH, scriptName), ...scriptArgs];523 const {524 code525 } = await (0, _utils.spawnAsync)('powershell.exe', args, {526 cwd,527 stdio: 'inherit'528 });529 if (code !== 0) throw new Error(`Failed to install ${channel}`);530 } else {531 const {532 command,533 args,534 elevatedPermissions535 } = await (0, _utils.transformCommandsForRoot)([`bash ${_path.default.join(BIN_PATH, scriptName)} ${scriptArgs.join('')}`]);536 if (elevatedPermissions) console.log('Switching to root user to install dependencies...'); // eslint-disable-line no-console537 const {538 code539 } = await (0, _utils.spawnAsync)(command, args, {540 cwd,541 stdio: 'inherit'542 });543 if (code !== 0) throw new Error(`Failed to install ${channel}`);544 }545 }546 async _validateInstallationCache(linksDir) {547 // 1. Collect used downloads and package descriptors.548 const usedBrowserPaths = new Set();549 for (const fileName of await fs.promises.readdir(linksDir)) {550 const linkPath = _path.default.join(linksDir, fileName);551 let linkTarget = '';552 try {553 linkTarget = (await fs.promises.readFile(linkPath)).toString();554 const browsersJSON = require(_path.default.join(linkTarget, 'browsers.json'));555 const descriptors = readDescriptors(browsersJSON);556 for (const browserName of allDownloadable) {557 // We retain browsers if they are found in the descriptor.558 // Note, however, that there are older versions out in the wild that rely on559 // the "download" field in the browser descriptor and use its value560 // to retain and download browsers.561 // As of v1.10, we decided to abandon "download" field.562 const descriptor = descriptors.find(d => d.name === browserName);563 if (!descriptor) continue;564 const usedBrowserPath = descriptor.dir;565 const browserRevision = parseInt(descriptor.revision, 10); // Old browser installations don't have marker file.566 const shouldHaveMarkerFile = browserName === 'chromium' && browserRevision >= 786218 || browserName === 'firefox' && browserRevision >= 1128 || browserName === 'webkit' && browserRevision >= 1307 || // All new applications have a marker file right away.567 browserName !== 'firefox' && browserName !== 'chromium' && browserName !== 'webkit';568 if (!shouldHaveMarkerFile || (await (0, _utils.existsAsync)(markerFilePath(usedBrowserPath)))) usedBrowserPaths.add(usedBrowserPath);569 }570 } catch (e) {571 await fs.promises.unlink(linkPath).catch(e => {});572 }573 } // 2. Delete all unused browsers.574 if (!(0, _utils.getAsBooleanFromENV)('PLAYWRIGHT_SKIP_BROWSER_GC')) {575 let downloadedBrowsers = (await fs.promises.readdir(registryDirectory)).map(file => _path.default.join(registryDirectory, file));576 downloadedBrowsers = downloadedBrowsers.filter(file => isBrowserDirectory(file));577 const directories = new Set(downloadedBrowsers);578 for (const browserDirectory of usedBrowserPaths) directories.delete(browserDirectory);579 for (const directory of directories) (0, _browserFetcher.logPolitely)('Removing unused browser at ' + directory);580 await (0, _utils.removeFolders)([...directories]);581 }582 }583}584exports.Registry = Registry;585function markerFilePath(browserDirectory) {586 return _path.default.join(browserDirectory, 'INSTALLATION_COMPLETE');587}588function buildPlaywrightCLICommand(sdkLanguage, parameters) {589 switch (sdkLanguage) {590 case 'python':591 return `playwright ${parameters}`;592 case 'java':593 return `mvn exec:java -e -Dexec.mainClass=com.microsoft.playwright.CLI -Dexec.args="${parameters}"`;594 case 'csharp':595 return `playwright ${parameters}`;596 default:597 return `npx playwright ${parameters}`;598 }599}600async function installDefaultBrowsersForNpmInstall() {601 const defaultBrowserNames = registry.defaultExecutables().map(e => e.name);602 return installBrowsersForNpmInstall(defaultBrowserNames);603}604async function installBrowsersForNpmInstall(browsers) {605 // PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD should have a value of 0 or 1606 if ((0, _utils.getAsBooleanFromENV)('PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD')) {607 (0, _browserFetcher.logPolitely)('Skipping browsers download because `PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD` env variable is set');608 return false;609 }610 const executables = [];611 for (const browserName of browsers) {612 const executable = registry.findExecutable(browserName);613 if (!executable || executable.installType === 'none') throw new Error(`Cannot install ${browserName}`);614 executables.push(executable);615 }616 await registry.install(executables);617}618function findChromiumChannel(sdkLanguage) {619 // Fall back to the stable channels of popular vendors to work out of the box.620 // Null means no installation and no channels found.621 let channel = null;622 for (const name of ['chromium', 'chrome', 'msedge']) {623 try {624 registry.findExecutable(name).executablePathOrDie(sdkLanguage);625 channel = name === 'chromium' ? undefined : name;626 break;627 } catch (e) {}628 }629 if (channel === null) {630 const installCommand = buildPlaywrightCLICommand(sdkLanguage, `install chromium`);631 const prettyMessage = [`No chromium-based browser found on the system.`, `Please run the following command to download one:`, ``, ` ${installCommand}`, ``, `<3 Playwright Team`].join('\n');632 throw new Error('\n' + (0, _utils.wrapInASCIIBox)(prettyMessage, 1));633 }634 return channel;635}636const registry = new Registry(require('../../browsers.json'));...
dependencies.js
Source:dependencies.js
1"use strict";2Object.defineProperty(exports, "__esModule", {3 value: true4});5exports.installDependenciesLinux = installDependenciesLinux;6exports.installDependenciesWindows = installDependenciesWindows;7exports.transformCommandsForRoot = transformCommandsForRoot;8exports.validateDependenciesLinux = validateDependenciesLinux;9exports.validateDependenciesWindows = validateDependenciesWindows;10exports.writeDockerVersion = writeDockerVersion;11var _fs = _interopRequireDefault(require("fs"));12var _path = _interopRequireDefault(require("path"));13var os = _interopRequireWildcard(require("os"));14var _child_process = _interopRequireDefault(require("child_process"));15var utils = _interopRequireWildcard(require("../../utils"));16var _spawnAsync = require("../../utils/spawnAsync");17var _hostPlatform = require("../../utils/hostPlatform");18var _ = require(".");19var _nativeDeps = require("./nativeDeps");20var _ubuntuVersion = require("../../utils/ubuntuVersion");21var _userAgent = require("../../common/userAgent");22function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function (nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }23function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }24function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }25/**26 * Copyright (c) Microsoft Corporation.27 *28 * Licensed under the Apache License, Version 2.0 (the "License");29 * you may not use this file except in compliance with the License.30 * You may obtain a copy of the License at31 *32 * http://www.apache.org/licenses/LICENSE-2.033 *34 * Unless required by applicable law or agreed to in writing, software35 * distributed under the License is distributed on an "AS IS" BASIS,36 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.37 * See the License for the specific language governing permissions and38 * limitations under the License.39 */40const BIN_DIRECTORY = _path.default.join(__dirname, '..', '..', '..', 'bin');41const packageJSON = require('../../../package.json');42const dockerVersionFilePath = '/ms-playwright/.docker-info';43async function writeDockerVersion(dockerImageNameTemplate) {44 await _fs.default.promises.mkdir(_path.default.dirname(dockerVersionFilePath), {45 recursive: true46 });47 await _fs.default.promises.writeFile(dockerVersionFilePath, JSON.stringify({48 driverVersion: packageJSON.version,49 dockerImageName: dockerImageNameTemplate.replace('%version%', packageJSON.version)50 }, null, 2), 'utf8'); // Make sure version file is globally accessible.51 await _fs.default.promises.chmod(dockerVersionFilePath, 0o777);52}53async function readDockerVersion() {54 return await _fs.default.promises.readFile(dockerVersionFilePath, 'utf8').then(text => JSON.parse(text)).catch(e => null);55}56const checkExecutable = filePath => _fs.default.promises.access(filePath, _fs.default.constants.X_OK).then(() => true).catch(e => false);57function isSupportedWindowsVersion() {58 if (os.platform() !== 'win32' || os.arch() !== 'x64') return false;59 const [major, minor] = os.release().split('.').map(token => parseInt(token, 10)); // This is based on: https://stackoverflow.com/questions/42524606/how-to-get-windows-version-using-node-js/44916050#4491605060 // The table with versions is taken from: https://docs.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-osversioninfoexw#remarks61 // Windows 7 is not supported and is encoded as `6.1`.62 return major > 6 || major === 6 && minor > 1;63}64async function installDependenciesWindows(targets, dryRun) {65 if (targets.has('chromium')) {66 const command = 'powershell.exe';67 const args = ['-ExecutionPolicy', 'Bypass', '-File', _path.default.join(BIN_DIRECTORY, 'install_media_pack.ps1')];68 if (dryRun) {69 console.log(`${command} ${quoteProcessArgs(args).join(' ')}`); // eslint-disable-line no-console70 return;71 }72 const {73 code74 } = await (0, _spawnAsync.spawnAsync)(command, args, {75 cwd: BIN_DIRECTORY,76 stdio: 'inherit'77 });78 if (code !== 0) throw new Error('Failed to install windows dependencies!');79 }80}81async function installDependenciesLinux(targets, dryRun) {82 if ((await (0, _ubuntuVersion.getUbuntuVersion)()) === '') throw new Error(`Unsupported Linux distribution, only Ubuntu is supported!`);83 const libraries = [];84 for (const target of targets) {85 const info = _nativeDeps.deps[_hostPlatform.hostPlatform];86 if (!info) {87 console.warn('Cannot install dependencies for this linux distribution!'); // eslint-disable-line no-console88 return;89 }90 libraries.push(...info[target]);91 }92 const uniqueLibraries = Array.from(new Set(libraries));93 if (!dryRun) console.log('Installing Ubuntu dependencies...'); // eslint-disable-line no-console94 const commands = [];95 commands.push('apt-get update');96 commands.push(['apt-get', 'install', '-y', '--no-install-recommends', ...uniqueLibraries].join(' '));97 const {98 command,99 args,100 elevatedPermissions101 } = await transformCommandsForRoot(commands);102 if (dryRun) {103 console.log(`${command} ${quoteProcessArgs(args).join(' ')}`); // eslint-disable-line no-console104 return;105 }106 if (elevatedPermissions) console.log('Switching to root user to install dependencies...'); // eslint-disable-line no-console107 const child = _child_process.default.spawn(command, args, {108 stdio: 'inherit'109 });110 await new Promise((resolve, reject) => {111 child.on('exit', code => code === 0 ? resolve() : reject(new Error(`Installation process exited with code: ${code}`)));112 child.on('error', reject);113 });114}115async function validateDependenciesWindows(windowsExeAndDllDirectories) {116 const directoryPaths = windowsExeAndDllDirectories;117 const lddPaths = [];118 for (const directoryPath of directoryPaths) lddPaths.push(...(await executablesOrSharedLibraries(directoryPath)));119 const allMissingDeps = await Promise.all(lddPaths.map(lddPath => missingFileDependenciesWindows(lddPath)));120 const missingDeps = new Set();121 for (const deps of allMissingDeps) {122 for (const dep of deps) missingDeps.add(dep);123 }124 if (!missingDeps.size) return;125 let isCrtMissing = false;126 let isMediaFoundationMissing = false;127 for (const dep of missingDeps) {128 if (dep.startsWith('api-ms-win-crt') || dep === 'vcruntime140.dll' || dep === 'vcruntime140_1.dll' || dep === 'msvcp140.dll') isCrtMissing = true;else if (dep === 'mf.dll' || dep === 'mfplat.dll' || dep === 'msmpeg2vdec.dll' || dep === 'evr.dll' || dep === 'avrt.dll') isMediaFoundationMissing = true;129 }130 const details = [];131 if (isCrtMissing) {132 details.push(`Some of the Universal C Runtime files cannot be found on the system. You can fix`, `that by installing Microsoft Visual C++ Redistributable for Visual Studio from:`, `https://support.microsoft.com/en-us/help/2977003/the-latest-supported-visual-c-downloads`, ``);133 }134 if (isMediaFoundationMissing) {135 details.push(`Some of the Media Foundation files cannot be found on the system. If you are`, `on Windows Server try fixing this by running the following command in PowerShell`, `as Administrator:`, ``, ` Install-WindowsFeature Server-Media-Foundation`, ``, `For Windows N editions visit:`, `https://support.microsoft.com/en-us/help/3145500/media-feature-pack-list-for-windows-n-editions`, ``);136 }137 details.push(`Full list of missing libraries:`, ` ${[...missingDeps].join('\n ')}`, ``);138 const message = `Host system is missing dependencies!\n\n${details.join('\n')}`;139 if (isSupportedWindowsVersion()) {140 throw new Error(message);141 } else {142 // eslint-disable-next-line no-console143 console.warn(`WARNING: running on unsupported windows version!`); // eslint-disable-next-line no-console144 console.warn(message);145 }146}147async function validateDependenciesLinux(sdkLanguage, linuxLddDirectories, dlOpenLibraries) {148 var _deps$hostPlatform;149 const directoryPaths = linuxLddDirectories;150 const lddPaths = [];151 for (const directoryPath of directoryPaths) lddPaths.push(...(await executablesOrSharedLibraries(directoryPath)));152 const missingDepsPerFile = await Promise.all(lddPaths.map(lddPath => missingFileDependencies(lddPath, directoryPaths)));153 const missingDeps = new Set();154 for (const deps of missingDepsPerFile) {155 for (const dep of deps) missingDeps.add(dep);156 }157 for (const dep of await missingDLOPENLibraries(dlOpenLibraries)) missingDeps.add(dep);158 if (!missingDeps.size) return;159 const allMissingDeps = new Set(missingDeps); // Check Ubuntu version.160 const missingPackages = new Set();161 const libraryToPackageNameMapping = { ...(((_deps$hostPlatform = _nativeDeps.deps[_hostPlatform.hostPlatform]) === null || _deps$hostPlatform === void 0 ? void 0 : _deps$hostPlatform.lib2package) || {}),162 ...MANUAL_LIBRARY_TO_PACKAGE_NAME_UBUNTU163 }; // Translate missing dependencies to package names to install with apt.164 for (const missingDep of missingDeps) {165 const packageName = libraryToPackageNameMapping[missingDep];166 if (packageName) {167 missingPackages.add(packageName);168 missingDeps.delete(missingDep);169 }170 }171 const maybeSudo = process.getuid() !== 0 && os.platform() !== 'win32' ? 'sudo ' : '';172 const dockerInfo = await readDockerVersion();173 const errorLines = [`Host system is missing dependencies to run browsers.`]; // Ignore patch versions when comparing docker container version and Playwright version:174 // we **NEVER** roll browsers in patch releases, so native dependencies do not change.175 if (dockerInfo && !dockerInfo.driverVersion.startsWith((0, _userAgent.getPlaywrightVersion)(true176 /* majorMinorOnly */177 ) + '.')) {178 // We are running in a docker container with unmatching version.179 // In this case, we know how to install dependencies in it.180 const pwVersion = (0, _userAgent.getPlaywrightVersion)();181 const requiredDockerImage = dockerInfo.dockerImageName.replace(dockerInfo.driverVersion, pwVersion);182 errorLines.push(...[`This is most likely due to docker image version not matching Playwright version:`, `- Playwright: ${pwVersion}`, `- Docker: ${dockerInfo.driverVersion}`, ``, `Either:`, `- (recommended) use docker image "${requiredDockerImage}"`, `- (alternative 1) run the following command inside docker to install missing dependencies:`, ``, ` ${maybeSudo}${(0, _.buildPlaywrightCLICommand)(sdkLanguage, 'install-deps')}`, ``, `- (alternative 2) use Aptitude inside docker:`, ``, ` ${maybeSudo}apt-get install ${[...missingPackages].join('\\\n ')}`, ``, `<3 Playwright Team`]);183 } else if (missingPackages.size && !missingDeps.size) {184 // Only known dependencies are missing for browsers.185 // Suggest installation with a Playwright CLI.186 errorLines.push(...[`Please install them with the following command:`, ``, ` ${maybeSudo}${(0, _.buildPlaywrightCLICommand)(sdkLanguage, 'install-deps')}`, ``, `Alternatively, use Aptitude:`, ` ${maybeSudo}apt-get install ${[...missingPackages].join('\\\n ')}`, ``, `<3 Playwright Team`]);187 } else {188 // Unhappy path: we either run on unknown distribution, or we failed to resolve all missing189 // libraries to package names.190 // Print missing libraries only:191 errorLines.push(...[`Missing libraries:`, ...[...allMissingDeps].map(dep => ' ' + dep)]);192 }193 throw new Error('\n' + utils.wrapInASCIIBox(errorLines.join('\n'), 1));194}195function isSharedLib(basename) {196 switch (os.platform()) {197 case 'linux':198 return basename.endsWith('.so') || basename.includes('.so.');199 case 'win32':200 return basename.endsWith('.dll');201 default:202 return false;203 }204}205async function executablesOrSharedLibraries(directoryPath) {206 if (!_fs.default.existsSync(directoryPath)) return [];207 const allPaths = (await _fs.default.promises.readdir(directoryPath)).map(file => _path.default.resolve(directoryPath, file));208 const allStats = await Promise.all(allPaths.map(aPath => _fs.default.promises.stat(aPath)));209 const filePaths = allPaths.filter((aPath, index) => allStats[index].isFile());210 const executablersOrLibraries = (await Promise.all(filePaths.map(async filePath => {211 const basename = _path.default.basename(filePath).toLowerCase();212 if (isSharedLib(basename)) return filePath;213 if (await checkExecutable(filePath)) return filePath;214 return false;215 }))).filter(Boolean);216 return executablersOrLibraries;217}218async function missingFileDependenciesWindows(filePath) {219 const executable = _path.default.join(__dirname, '..', '..', '..', 'bin', 'PrintDeps.exe');220 const dirname = _path.default.dirname(filePath);221 const {222 stdout,223 code224 } = await (0, _spawnAsync.spawnAsync)(executable, [filePath], {225 cwd: dirname,226 env: { ...process.env,227 LD_LIBRARY_PATH: process.env.LD_LIBRARY_PATH ? `${process.env.LD_LIBRARY_PATH}:${dirname}` : dirname228 }229 });230 if (code !== 0) return [];231 const missingDeps = stdout.split('\n').map(line => line.trim()).filter(line => line.endsWith('not found') && line.includes('=>')).map(line => line.split('=>')[0].trim().toLowerCase());232 return missingDeps;233}234async function missingFileDependencies(filePath, extraLDPaths) {235 const dirname = _path.default.dirname(filePath);236 let LD_LIBRARY_PATH = extraLDPaths.join(':');237 if (process.env.LD_LIBRARY_PATH) LD_LIBRARY_PATH = `${process.env.LD_LIBRARY_PATH}:${LD_LIBRARY_PATH}`;238 const {239 stdout,240 code241 } = await (0, _spawnAsync.spawnAsync)('ldd', [filePath], {242 cwd: dirname,243 env: { ...process.env,244 LD_LIBRARY_PATH245 }246 });247 if (code !== 0) return [];248 const missingDeps = stdout.split('\n').map(line => line.trim()).filter(line => line.endsWith('not found') && line.includes('=>')).map(line => line.split('=>')[0].trim());249 return missingDeps;250}251async function missingDLOPENLibraries(libraries) {252 if (!libraries.length) return []; // NOTE: Using full-qualified path to `ldconfig` since `/sbin` is not part of the253 // default PATH in CRON.254 // @see https://github.com/microsoft/playwright/issues/3397255 const {256 stdout,257 code,258 error259 } = await (0, _spawnAsync.spawnAsync)('/sbin/ldconfig', ['-p'], {});260 if (code !== 0 || error) return [];261 const isLibraryAvailable = library => stdout.toLowerCase().includes(library.toLowerCase());262 return libraries.filter(library => !isLibraryAvailable(library));263}264const MANUAL_LIBRARY_TO_PACKAGE_NAME_UBUNTU = {265 // libgstlibav.so (the only actual library provided by gstreamer1.0-libav) is not266 // in the ldconfig cache, so we detect the actual library required for playing h.264267 // and if it's missing recommend installing missing gstreamer lib.268 // gstreamer1.0-libav -> libavcodec57 -> libx264-152269 'libx264.so': 'gstreamer1.0-libav'270};271function quoteProcessArgs(args) {272 return args.map(arg => {273 if (arg.includes(' ')) return `"${arg}"`;274 return arg;275 });276}277async function transformCommandsForRoot(commands) {278 const isRoot = process.getuid() === 0;279 if (isRoot) return {280 command: 'sh',281 args: ['-c', `${commands.join('&& ')}`],282 elevatedPermissions: false283 };284 const sudoExists = await (0, _spawnAsync.spawnAsync)('which', ['sudo']);285 if (sudoExists.code === 0) return {286 command: 'sudo',287 args: ['--', 'sh', '-c', `${commands.join('&& ')}`],288 elevatedPermissions: true289 };290 return {291 command: 'su',292 args: ['root', '-c', `${commands.join('&& ')}`],293 elevatedPermissions: true294 };...
Using AI Code Generation
1const { buildPlaywrightCLICommand } = require('playwright/lib/utils/build');2const { chromium } = require('playwright');3(async () => {4 const browser = await chromium.launch();5 const context = await browser.newContext();6 const page = await context.newPage();7 const cliCommand = buildPlaywrightCLICommand(page);8 console.log(cliCommand);9 await browser.close();10})();11const { buildPlaywrightCLICommand } = require('playwright-internal-api');12const { test, expect } = require('@playwright/test');13test('should generate a CLI command', async ({ page }) => {14 const cliCommand = buildPlaywrightCLICommand(page);15});16Playwright is an open source project and we welcome contributions. Please read the [Contributing Guide](
Using AI Code Generation
1const { buildPlaywrightCLICommand } = require('@playwright/test/lib/utils/cliProcess');2const { test } = require('@playwright/test');3test('test', async ({ page }) => {4 const cliCommand = buildPlaywrightCLICommand('open', {5 });6 await page.goto(cliCommand);7});
Using AI Code Generation
1const { buildPlaywrightCLICommand } = require('@playwright/test/lib/cli/cli');2const { Playwright } = require('@playwright/test');3const playwright = new Playwright();4const browserType = playwright.chromium;5const { devices } = require('playwright');6const device = devices['iPhone 11 Pro'];7const options = {8 browserName: browserType.name(),9};10const args = buildPlaywrightCLICommand(options);11console.log(args);
Using AI Code Generation
1const { buildPlaywrightCLICommand } = require('@playwright/test/lib/cli/cli');2const { test } = require('@playwright/test');3const path = require('path');4test('test', async ({}) => {5 const config = {6 {7 use: {8 viewport: { width: 1280, height: 720 },9 },10 },11 use: {12 },13 testDir: path.join(__dirname, 'tests'),14 };15 const cliOptions = {16 config: JSON.stringify(config),17 };18 const cliCommand = buildPlaywrightCLICommand(cliOptions);19 console.log(cliCommand);20});
Using AI Code Generation
1const { buildPlaywrightCLICommand } = require('@playwright/test/lib/utils/cliProcess');2const { chromium } = require('playwright');3const path = require('path');4const { test } = require('@playwright/test');5const { expect } = require('@playwright/test');6test('test', async ({ page }) => {7 const pwRun = buildPlaywrightCLICommand(process.argv.slice(2), process.cwd());8 const browser = await chromium.launch({9 args: pwRun.browserArguments(),10 env: pwRun.browserEnvironment(),11 executablePath: pwRun.executablePath(),12 });13 const context = await browser.newContext();14 const page = await context.newPage();15 await page.screenshot({ path: `example.png` });16 await browser.close();17});18![Output](
Using AI Code Generation
1const playwright = require('playwright');2const playwrightCli = require('playwright-cli');3const { buildPlaywrightCLICommand } = playwrightCli;4const { chromium } = playwright;5const browser = await chromium.launch();6const newContext = await browser.newContext();7const page = await newContext.newPage();8const cliCommand = buildPlaywrightCLICommand(page);9console.log(cliCommand);10await browser.close();11import { chromium } from 'playwright';12import { buildPlaywrightCLICommand } from 'playwright-cli';13const browser = await chromium.launch();14const newContext = await browser.newContext();15const page = await newContext.newPage();16const cliCommand = buildPlaywrightCLICommand(page);17console.log(cliCommand);18await browser.close();19const playwright = require('playwright');20const playwrightCli = require('playwright-cli');21const { chromium } = playwright;22const browser = await chromium.launch();23const newContext = await browser.newContext();24const page = await newContext.newPage();25await playwrightCli.run(['codegen', page.url()], page);26await browser.close();27import { chromium } from 'playwright';28import { run } from 'playwright-cli';29const browser = await chromium.launch();30const newContext = await browser.newContext();31const page = await newContext.newPage();32await run(['codegen', page.url()], page);33await browser.close();34const playwright = require('playwright');35const playwrightTest = require('@playwright/test');36const { chromium } = playwright;37const browser = await chromium.launch();38const newContext = await browser.newContext();39const page = await newContext.newPage();40await playwrightTest.runWithTestDir(['test.spec.js'], {41 launchOptions: {42 },43});44await browser.close();
Using AI Code Generation
1const { buildPlaywrightCLICommand } = require('@playwright/test/lib/cli/cli');2const cliCommand = buildPlaywrightCLICommand([ 'test', '--workers=1', '--config=playwright.config.ts' ]);3console.log(cliCommand);4const { runPlaywrightCLIMethod } = require('@playwright/test/lib/cli/cli');5runPlaywrightCLIMethod([ 'test', '--workers=1', '--config=playwright.config.ts' ]);6const { runPlaywrightCLIMethod } = require('@playwright/test/lib/cli/cli');7runPlaywrightCLIMethod([ 'test', '--workers=1', '--config=playwright.config.ts' ], { stdio: 'inherit' });
Using AI Code Generation
1const { buildPlaywrightCLICommand } = require('@playwright/test/lib/utils/buildCLICommand');2const playwright = require('playwright');3const { chromium } = playwright;4const { devices } = require('playwright');5const { iPhone11 } = devices;6(async () => {7 const browser = await chromium.launch();8 const context = await browser.newContext({9 geolocation: { longitude: 12.492507, latitude: 41.889938 },10 });11 const page = await context.newPage();12 await page.click('text="Your location"');13 await page.screenshot({ path: `colosseum-iphone.png` });14 await browser.close();15})();16const cliCommand = buildPlaywrightCLICommand({17 {18 use: {19 viewport: { width: 1280, height: 720 }20 }21 }22 config: {23 }24});25console.log(cliCommand);26- [Playwright Internal Library](
LambdaTest’s Playwright tutorial will give you a broader idea about the Playwright automation framework, its unique features, and use cases with examples to exceed your understanding of Playwright testing. This tutorial will give A to Z guidance, from installing the Playwright framework to some best practices and advanced concepts.
Get 100 minutes of automation test minutes FREE!!