Best JavaScript code snippet using playwright-internal
registry.js
Source:registry.js
1"use strict";2Object.defineProperty(exports, "__esModule", {3 value: true4});5exports.Registry = void 0;6exports.buildPlaywrightCLICommand = buildPlaywrightCLICommand;7exports.findChromiumChannel = findChromiumChannel;8exports.installBrowsersForNpmInstall = installBrowsersForNpmInstall;9exports.installDefaultBrowsersForNpmInstall = installDefaultBrowsersForNpmInstall;10exports.registryDirectory = exports.registry = void 0;11var os = _interopRequireWildcard(require("os"));12var _path = _interopRequireDefault(require("path"));13var util = _interopRequireWildcard(require("util"));14var fs = _interopRequireWildcard(require("fs"));15var _properLockfile = _interopRequireDefault(require("proper-lockfile"));16var _ubuntuVersion = require("./ubuntuVersion");17var _utils = require("./utils");18var _dependencies = require("./dependencies");19var _browserFetcher = require("./browserFetcher");20function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }21function _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); }22function _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; }23/**24 * Copyright 2017 Google Inc. All rights reserved.25 * Modifications copyright (c) Microsoft Corporation.26 *27 * Licensed under the Apache License, Version 2.0 (the "License");28 * you may not use this file except in compliance with the License.29 * You may obtain a copy of the License at30 *31 * http://www.apache.org/licenses/LICENSE-2.032 *33 * Unless required by applicable law or agreed to in writing, software34 * distributed under the License is distributed on an "AS IS" BASIS,35 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.36 * See the License for the specific language governing permissions and37 * limitations under the License.38 */39const PACKAGE_PATH = _path.default.join(__dirname, '..', '..');40const BIN_PATH = _path.default.join(__dirname, '..', '..', 'bin');41const EXECUTABLE_PATHS = {42 'chromium': {43 'linux': ['chrome-linux', 'chrome'],44 'mac': ['chrome-mac', 'Chromium.app', 'Contents', 'MacOS', 'Chromium'],45 'win': ['chrome-win', 'chrome.exe']46 },47 'firefox': {48 'linux': ['firefox', 'firefox'],49 'mac': ['firefox', 'Nightly.app', 'Contents', 'MacOS', 'firefox'],50 'win': ['firefox', 'firefox.exe']51 },52 'webkit': {53 'linux': ['pw_run.sh'],54 'mac': ['pw_run.sh'],55 'win': ['Playwright.exe']56 },57 'ffmpeg': {58 'linux': ['ffmpeg-linux'],59 'mac': ['ffmpeg-mac'],60 'win': ['ffmpeg-win64.exe']61 }62};63const DOWNLOAD_PATHS = {64 'chromium': {65 'ubuntu18.04': 'builds/chromium/%s/chromium-linux.zip',66 'ubuntu20.04': 'builds/chromium/%s/chromium-linux.zip',67 'ubuntu18.04-arm64': 'builds/chromium/%s/chromium-linux-arm64.zip',68 'ubuntu20.04-arm64': 'builds/chromium/%s/chromium-linux-arm64.zip',69 'mac10.13': 'builds/chromium/%s/chromium-mac.zip',70 'mac10.14': 'builds/chromium/%s/chromium-mac.zip',71 'mac10.15': 'builds/chromium/%s/chromium-mac.zip',72 'mac11': 'builds/chromium/%s/chromium-mac.zip',73 'mac11-arm64': 'builds/chromium/%s/chromium-mac-arm64.zip',74 'mac12': 'builds/chromium/%s/chromium-mac.zip',75 'mac12-arm64': 'builds/chromium/%s/chromium-mac-arm64.zip',76 'win64': 'builds/chromium/%s/chromium-win64.zip'77 },78 'chromium-with-symbols': {79 'ubuntu18.04': 'builds/chromium/%s/chromium-with-symbols-linux.zip',80 'ubuntu20.04': 'builds/chromium/%s/chromium-with-symbols-linux.zip',81 'ubuntu18.04-arm64': 'builds/chromium/%s/chromium-with-symbols-linux-arm64.zip',82 'ubuntu20.04-arm64': 'builds/chromium/%s/chromium-with-symbols-linux-arm64.zip',83 'mac10.13': 'builds/chromium/%s/chromium-with-symbols-mac.zip',84 'mac10.14': 'builds/chromium/%s/chromium-with-symbols-mac.zip',85 'mac10.15': 'builds/chromium/%s/chromium-with-symbols-mac.zip',86 'mac11': 'builds/chromium/%s/chromium-with-symbols-mac.zip',87 'mac11-arm64': 'builds/chromium/%s/chromium-with-symbols-mac-arm64.zip',88 'mac12': 'builds/chromium/%s/chromium-with-symbols-mac.zip',89 'mac12-arm64': 'builds/chromium/%s/chromium-with-symbols-mac-arm64.zip',90 'win64': 'builds/chromium/%s/chromium-with-symbols-win64.zip'91 },92 'firefox': {93 'ubuntu18.04': 'builds/firefox/%s/firefox-ubuntu-18.04.zip',94 'ubuntu20.04': 'builds/firefox/%s/firefox-ubuntu-20.04.zip',95 'ubuntu18.04-arm64': undefined,96 'ubuntu20.04-arm64': 'builds/firefox/%s/firefox-ubuntu-20.04-arm64.zip',97 'mac10.13': 'builds/firefox/%s/firefox-mac-11.zip',98 'mac10.14': 'builds/firefox/%s/firefox-mac-11.zip',99 'mac10.15': 'builds/firefox/%s/firefox-mac-11.zip',100 'mac11': 'builds/firefox/%s/firefox-mac-11.zip',101 'mac11-arm64': 'builds/firefox/%s/firefox-mac-11-arm64.zip',102 'mac12': 'builds/firefox/%s/firefox-mac-11.zip',103 'mac12-arm64': 'builds/firefox/%s/firefox-mac-11-arm64.zip',104 'win64': 'builds/firefox/%s/firefox-win64.zip'105 },106 'firefox-beta': {107 'ubuntu18.04': 'builds/firefox-beta/%s/firefox-beta-ubuntu-18.04.zip',108 'ubuntu20.04': 'builds/firefox-beta/%s/firefox-beta-ubuntu-20.04.zip',109 'ubuntu18.04-arm64': undefined,110 'ubuntu20.04-arm64': undefined,111 'mac10.13': 'builds/firefox-beta/%s/firefox-beta-mac-11.zip',112 'mac10.14': 'builds/firefox-beta/%s/firefox-beta-mac-11.zip',113 'mac10.15': 'builds/firefox-beta/%s/firefox-beta-mac-11.zip',114 'mac11': 'builds/firefox-beta/%s/firefox-beta-mac-11.zip',115 'mac11-arm64': 'builds/firefox-beta/%s/firefox-beta-mac-11-arm64.zip',116 'mac12': 'builds/firefox-beta/%s/firefox-beta-mac-11.zip',117 'mac12-arm64': 'builds/firefox-beta/%s/firefox-beta-mac-11-arm64.zip',118 'win64': 'builds/firefox-beta/%s/firefox-beta-win64.zip'119 },120 'webkit': {121 'ubuntu18.04': 'builds/webkit/%s/webkit-ubuntu-18.04.zip',122 'ubuntu20.04': 'builds/webkit/%s/webkit-ubuntu-20.04.zip',123 'ubuntu18.04-arm64': undefined,124 'ubuntu20.04-arm64': 'builds/webkit/%s/webkit-ubuntu-20.04-arm64.zip',125 'mac10.13': undefined,126 'mac10.14': 'builds/deprecated-webkit-mac-10.14/%s/deprecated-webkit-mac-10.14.zip',127 'mac10.15': 'builds/webkit/%s/webkit-mac-10.15.zip',128 'mac11': 'builds/webkit/%s/webkit-mac-10.15.zip',129 'mac11-arm64': 'builds/webkit/%s/webkit-mac-11-arm64.zip',130 'mac12': 'builds/webkit/%s/webkit-mac-12.zip',131 'mac12-arm64': 'builds/webkit/%s/webkit-mac-12-arm64.zip',132 'win64': 'builds/webkit/%s/webkit-win64.zip'133 },134 'ffmpeg': {135 'ubuntu18.04': 'builds/ffmpeg/%s/ffmpeg-linux.zip',136 'ubuntu20.04': 'builds/ffmpeg/%s/ffmpeg-linux.zip',137 'ubuntu18.04-arm64': 'builds/ffmpeg/%s/ffmpeg-linux-arm64.zip',138 'ubuntu20.04-arm64': 'builds/ffmpeg/%s/ffmpeg-linux-arm64.zip',139 'mac10.13': 'builds/ffmpeg/%s/ffmpeg-mac.zip',140 'mac10.14': 'builds/ffmpeg/%s/ffmpeg-mac.zip',141 'mac10.15': 'builds/ffmpeg/%s/ffmpeg-mac.zip',142 'mac11': 'builds/ffmpeg/%s/ffmpeg-mac.zip',143 'mac11-arm64': 'builds/ffmpeg/%s/ffmpeg-mac-arm64.zip',144 'mac12': 'builds/ffmpeg/%s/ffmpeg-mac.zip',145 'mac12-arm64': 'builds/ffmpeg/%s/ffmpeg-mac-arm64.zip',146 'win64': 'builds/ffmpeg/%s/ffmpeg-win64.zip'147 }148};149const registryDirectory = (() => {150 let result;151 const envDefined = (0, _utils.getFromENV)('PLAYWRIGHT_BROWSERS_PATH');152 if (envDefined === '0') {153 result = _path.default.join(__dirname, '..', '..', '.local-browsers');154 } else if (envDefined) {155 result = envDefined;156 } else {157 let cacheDirectory;158 if (process.platform === 'linux') cacheDirectory = process.env.XDG_CACHE_HOME || _path.default.join(os.homedir(), '.cache');else if (process.platform === 'darwin') cacheDirectory = _path.default.join(os.homedir(), 'Library', 'Caches');else if (process.platform === 'win32') cacheDirectory = process.env.LOCALAPPDATA || _path.default.join(os.homedir(), 'AppData', 'Local');else throw new Error('Unsupported platform: ' + process.platform);159 result = _path.default.join(cacheDirectory, 'ms-playwright');160 }161 if (!_path.default.isAbsolute(result)) {162 // It is important to resolve to the absolute path:163 // - for unzipping to work correctly;164 // - so that registry directory matches between installation and execution.165 // INIT_CWD points to the root of `npm/yarn install` and is probably what166 // the user meant when typing the relative path.167 result = _path.default.resolve((0, _utils.getFromENV)('INIT_CWD') || process.cwd(), result);168 }169 return result;170})();171exports.registryDirectory = registryDirectory;172function isBrowserDirectory(browserDirectory) {173 const baseName = _path.default.basename(browserDirectory);174 for (const browserName of allDownloadable) {175 if (baseName.startsWith(browserName + '-')) return true;176 }177 return false;178}179function readDescriptors(browsersJSON) {180 return browsersJSON['browsers'].map(obj => {181 const name = obj.name;182 const revisionOverride = (obj.revisionOverrides || {})[_utils.hostPlatform];183 const revision = revisionOverride || obj.revision;184 const browserDirectoryPrefix = revisionOverride ? `${name}_${_utils.hostPlatform}_special` : `${name}`;185 const descriptor = {186 name,187 revision,188 installByDefault: !!obj.installByDefault,189 // Method `isBrowserDirectory` determines directory to be browser iff190 // it starts with some browser name followed by '-'. Some browser names191 // are prefixes of others, e.g. 'webkit' is a prefix of `webkit-technology-preview`.192 // To avoid older registries erroneously removing 'webkit-technology-preview', we have to193 // ensure that browser folders to never include dashes inside.194 dir: _path.default.join(registryDirectory, browserDirectoryPrefix.replace(/-/g, '_') + '-' + revision)195 };196 return descriptor;197 });198}199const allDownloadable = ['chromium', 'firefox', 'webkit', 'ffmpeg', 'firefox-beta', 'chromium-with-symbols'];200class Registry {201 constructor(browsersJSON) {202 this._executables = void 0;203 const descriptors = readDescriptors(browsersJSON);204 const findExecutablePath = (dir, name) => {205 let tokens = undefined;206 if (_utils.hostPlatform.startsWith('ubuntu')) tokens = EXECUTABLE_PATHS[name]['linux'];else if (_utils.hostPlatform.startsWith('mac')) tokens = EXECUTABLE_PATHS[name]['mac'];else if (_utils.hostPlatform.startsWith('win')) tokens = EXECUTABLE_PATHS[name]['win'];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.installDependenciesWindows = installDependenciesWindows;6exports.installDependenciesLinux = installDependenciesLinux;7exports.validateDependenciesWindows = validateDependenciesWindows;8exports.validateDependenciesLinux = validateDependenciesLinux;9var _fs = _interopRequireDefault(require("fs"));10var _path = _interopRequireDefault(require("path"));11var os = _interopRequireWildcard(require("os"));12var _child_process = _interopRequireDefault(require("child_process"));13var _ubuntuVersion = require("./ubuntuVersion");14var utils = _interopRequireWildcard(require("./utils"));15function _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); }16function _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; }17function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }18/**19 * Copyright (c) Microsoft Corporation.20 *21 * Licensed under the Apache License, Version 2.0 (the "License");22 * you may not use this file except in compliance with the License.23 * You may obtain a copy of the License at24 *25 * http://www.apache.org/licenses/LICENSE-2.026 *27 * Unless required by applicable law or agreed to in writing, software28 * distributed under the License is distributed on an "AS IS" BASIS,29 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.30 * See the License for the specific language governing permissions and31 * limitations under the License.32 */33const BIN_DIRECTORY = _path.default.join(__dirname, '..', '..', 'bin');34const checkExecutable = filePath => _fs.default.promises.access(filePath, _fs.default.constants.X_OK).then(() => true).catch(e => false);35function isSupportedWindowsVersion() {36 if (os.platform() !== 'win32' || os.arch() !== 'x64') return false;37 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#4491605038 // The table with versions is taken from: https://docs.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-osversioninfoexw#remarks39 // Windows 7 is not supported and is encoded as `6.1`.40 return major > 6 || major === 6 && minor > 1;41}42async function installDependenciesWindows(targets) {43 if (targets.has('chromium')) {44 const {45 code46 } = await utils.spawnAsync('powershell.exe', [_path.default.join(BIN_DIRECTORY, 'install_media_pack.ps1')], {47 cwd: BIN_DIRECTORY,48 stdio: 'inherit'49 });50 if (code !== 0) throw new Error('Failed to install windows dependencies!');51 }52}53async function installDependenciesLinux(targets) {54 const ubuntuVersion = await (0, _ubuntuVersion.getUbuntuVersion)();55 if (ubuntuVersion !== '18.04' && ubuntuVersion !== '20.04' && ubuntuVersion !== '21.04') {56 console.warn('Cannot install dependencies for this linux distribution!'); // eslint-disable-line no-console57 return;58 }59 const libraries = [];60 const {61 deps62 } = require('../nativeDeps');63 for (const target of targets) {64 if (ubuntuVersion === '18.04') libraries.push(...deps['bionic'][target]);else if (ubuntuVersion === '20.04') libraries.push(...deps['focal'][target]);else if (ubuntuVersion === '21.04') libraries.push(...deps['hirsute'][target]);65 }66 const uniqueLibraries = Array.from(new Set(libraries));67 console.log('Installing Ubuntu dependencies...'); // eslint-disable-line no-console68 const commands = [];69 commands.push('apt-get update');70 commands.push(['apt-get', 'install', '-y', '--no-install-recommends', ...uniqueLibraries].join(' '));71 const isRoot = process.getuid() === 0;72 const child = isRoot ? _child_process.default.spawn('sh', ['-c', `${commands.join('; ')}`], {73 stdio: 'inherit'74 }) : _child_process.default.spawn('sudo', ['--', 'sh', '-c', `${commands.join('; ')}`], {75 stdio: 'inherit'76 });77 await new Promise(f => child.on('exit', f));78}79async function validateDependenciesWindows(windowsExeAndDllDirectories) {80 const directoryPaths = windowsExeAndDllDirectories;81 const lddPaths = [];82 for (const directoryPath of directoryPaths) lddPaths.push(...(await executablesOrSharedLibraries(directoryPath)));83 const allMissingDeps = await Promise.all(lddPaths.map(lddPath => missingFileDependenciesWindows(lddPath)));84 const missingDeps = new Set();85 for (const deps of allMissingDeps) {86 for (const dep of deps) missingDeps.add(dep);87 }88 if (!missingDeps.size) return;89 let isCrtMissing = false;90 let isMediaFoundationMissing = false;91 for (const dep of missingDeps) {92 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;93 }94 const details = [];95 if (isCrtMissing) {96 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`, ``);97 }98 if (isMediaFoundationMissing) {99 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`, ``);100 }101 details.push(`Full list of missing libraries:`, ` ${[...missingDeps].join('\n ')}`, ``);102 const message = `Host system is missing dependencies!\n\n${details.join('\n')}`;103 if (isSupportedWindowsVersion()) {104 throw new Error(message);105 } else {106 console.warn(`WARNING: running on unsupported windows version!`);107 console.warn(message);108 }109}110async function validateDependenciesLinux(linuxLddDirectories, dlOpenLibraries) {111 const directoryPaths = linuxLddDirectories;112 const lddPaths = [];113 for (const directoryPath of directoryPaths) lddPaths.push(...(await executablesOrSharedLibraries(directoryPath)));114 const allMissingDeps = await Promise.all(lddPaths.map(lddPath => missingFileDependencies(lddPath, directoryPaths)));115 const missingDeps = new Set();116 for (const deps of allMissingDeps) {117 for (const dep of deps) missingDeps.add(dep);118 }119 for (const dep of await missingDLOPENLibraries(dlOpenLibraries)) missingDeps.add(dep);120 if (!missingDeps.size) return; // Check Ubuntu version.121 const missingPackages = new Set();122 const ubuntuVersion = await (0, _ubuntuVersion.getUbuntuVersion)();123 let libraryToPackageNameMapping = null;124 if (ubuntuVersion === '18.04') libraryToPackageNameMapping = LIBRARY_TO_PACKAGE_NAME_UBUNTU_18_04;else if (ubuntuVersion === '20.04') libraryToPackageNameMapping = LIBRARY_TO_PACKAGE_NAME_UBUNTU_20_04;else if (ubuntuVersion === '21.04') libraryToPackageNameMapping = LIBRARY_TO_PACKAGE_NAME_UBUNTU_21_04;125 libraryToPackageNameMapping = Object.assign({}, libraryToPackageNameMapping, MANUAL_LIBRARY_TO_PACKAGE_NAME_UBUNTU);126 if (libraryToPackageNameMapping) {127 // Translate missing dependencies to package names to install with apt.128 for (const missingDep of missingDeps) {129 const packageName = libraryToPackageNameMapping[missingDep];130 if (packageName) {131 missingPackages.add(packageName);132 missingDeps.delete(missingDep);133 }134 }135 }136 const maybeSudo = process.getuid() !== 0 && os.platform() !== 'win32' ? 'sudo ' : ''; // Happy path: known dependencies are missing for browsers.137 // Suggest installation with a Playwright CLI.138 if (missingPackages.size && !missingDeps.size) {139 throw new Error('\n' + utils.wrapInASCIIBox([`Host system is missing a few dependencies to run browsers.`, `Please install them with the following command:`, ``, ` ${maybeSudo}npx playwright install-deps`, ``, `<3 Playwright Team`].join('\n'), 1));140 } // Unhappy path - unusual distribution configuration.141 let missingPackagesMessage = '';142 if (missingPackages.size) {143 missingPackagesMessage = [` Install missing packages with:`, ` ${maybeSudo}apt-get install ${[...missingPackages].join('\\\n ')}`, ``, ``].join('\n');144 }145 let missingDependenciesMessage = '';146 if (missingDeps.size) {147 const header = missingPackages.size ? `Missing libraries we didn't find packages for:` : `Missing libraries are:`;148 missingDependenciesMessage = [` ${header}`, ` ${[...missingDeps].join('\n ')}`, ``].join('\n');149 }150 throw new Error('Host system is missing dependencies!\n\n' + missingPackagesMessage + missingDependenciesMessage);151}152function isSharedLib(basename) {153 switch (os.platform()) {154 case 'linux':155 return basename.endsWith('.so') || basename.includes('.so.');156 case 'win32':157 return basename.endsWith('.dll');158 default:159 return false;160 }161}162async function executablesOrSharedLibraries(directoryPath) {163 const allPaths = (await _fs.default.promises.readdir(directoryPath)).map(file => _path.default.resolve(directoryPath, file));164 const allStats = await Promise.all(allPaths.map(aPath => _fs.default.promises.stat(aPath)));165 const filePaths = allPaths.filter((aPath, index) => allStats[index].isFile());166 const executablersOrLibraries = (await Promise.all(filePaths.map(async filePath => {167 const basename = _path.default.basename(filePath).toLowerCase();168 if (isSharedLib(basename)) return filePath;169 if (await checkExecutable(filePath)) return filePath;170 return false;171 }))).filter(Boolean);172 return executablersOrLibraries;173}174async function missingFileDependenciesWindows(filePath) {175 const executable = _path.default.join(__dirname, '..', '..', 'bin', 'PrintDeps.exe');176 const dirname = _path.default.dirname(filePath);177 const {178 stdout,179 code180 } = await utils.spawnAsync(executable, [filePath], {181 cwd: dirname,182 env: { ...process.env,183 LD_LIBRARY_PATH: process.env.LD_LIBRARY_PATH ? `${process.env.LD_LIBRARY_PATH}:${dirname}` : dirname184 }185 });186 if (code !== 0) return [];187 const missingDeps = stdout.split('\n').map(line => line.trim()).filter(line => line.endsWith('not found') && line.includes('=>')).map(line => line.split('=>')[0].trim().toLowerCase());188 return missingDeps;189}190async function missingFileDependencies(filePath, extraLDPaths) {191 const dirname = _path.default.dirname(filePath);192 let LD_LIBRARY_PATH = extraLDPaths.join(':');193 if (process.env.LD_LIBRARY_PATH) LD_LIBRARY_PATH = `${process.env.LD_LIBRARY_PATH}:${LD_LIBRARY_PATH}`;194 const {195 stdout,196 code197 } = await utils.spawnAsync('ldd', [filePath], {198 cwd: dirname,199 env: { ...process.env,200 LD_LIBRARY_PATH201 }202 });203 if (code !== 0) return [];204 const missingDeps = stdout.split('\n').map(line => line.trim()).filter(line => line.endsWith('not found') && line.includes('=>')).map(line => line.split('=>')[0].trim());205 return missingDeps;206}207async function missingDLOPENLibraries(libraries) {208 if (!libraries.length) return []; // NOTE: Using full-qualified path to `ldconfig` since `/sbin` is not part of the209 // default PATH in CRON.210 // @see https://github.com/microsoft/playwright/issues/3397211 const {212 stdout,213 code,214 error215 } = await utils.spawnAsync('/sbin/ldconfig', ['-p'], {});216 if (code !== 0 || error) return [];217 const isLibraryAvailable = library => stdout.toLowerCase().includes(library.toLowerCase());218 return libraries.filter(library => !isLibraryAvailable(library));219} // This list is generted with the following program:220// ./utils/linux-browser-dependencies/run.sh ubuntu:18.04221const LIBRARY_TO_PACKAGE_NAME_UBUNTU_18_04 = {222 'libasound.so.2': 'libasound2',223 'libatk-1.0.so.0': 'libatk1.0-0',224 'libatk-bridge-2.0.so.0': 'libatk-bridge2.0-0',225 'libatspi.so.0': 'libatspi2.0-0',226 'libbrotlidec.so.1': 'libbrotli1',227 'libcairo-gobject.so.2': 'libcairo-gobject2',228 'libcairo.so.2': 'libcairo2',229 'libcups.so.2': 'libcups2',230 'libdbus-1.so.3': 'libdbus-1-3',231 'libdbus-glib-1.so.2': 'libdbus-glib-1-2',232 'libdrm.so.2': 'libdrm2',233 'libEGL.so.1': 'libegl1',234 'libenchant.so.1': 'libenchant1c2a',235 'libepoxy.so.0': 'libepoxy0',236 'libevent-2.1.so.6': 'libevent-2.1-6',237 'libevdev.so.2': 'libevdev2',238 'libfontconfig.so.1': 'libfontconfig1',239 'libfreetype.so.6': 'libfreetype6',240 'libgbm.so.1': 'libgbm1',241 'libgdk_pixbuf-2.0.so.0': 'libgdk-pixbuf2.0-0',242 'libgdk-3.so.0': 'libgtk-3-0',243 'libgdk-x11-2.0.so.0': 'libgtk2.0-0',244 'libgio-2.0.so.0': 'libglib2.0-0',245 'libGL.so.1': 'libgl1',246 'libGLESv2.so.2': 'libgles2',247 'libglib-2.0.so.0': 'libglib2.0-0',248 'libgmodule-2.0.so.0': 'libglib2.0-0',249 'libgobject-2.0.so.0': 'libglib2.0-0',250 'libgstapp-1.0.so.0': 'gstreamer1.0-plugins-base',251 'libgstaudio-1.0.so.0': 'gstreamer1.0-plugins-base',252 'libgstbase-1.0.so.0': 'libgstreamer1.0-0',253 'libgstcodecparsers-1.0.so.0': 'gstreamer1.0-plugins-bad',254 'libgstfft-1.0.so.0': 'gstreamer1.0-plugins-base',255 'libgstgl-1.0.so.0': 'libgstreamer-gl1.0-0',256 'libgstpbutils-1.0.so.0': 'gstreamer1.0-plugins-base',257 'libgstreamer-1.0.so.0': 'libgstreamer1.0-0',258 'libgsttag-1.0.so.0': 'gstreamer1.0-plugins-base',259 'libgstvideo-1.0.so.0': 'gstreamer1.0-plugins-base',260 'libgthread-2.0.so.0': 'libglib2.0-0',261 'libgtk-3.so.0': 'libgtk-3-0',262 'libgtk-x11-2.0.so.0': 'libgtk2.0-0',263 'libharfbuzz-icu.so.0': 'libharfbuzz-icu0',264 'libharfbuzz.so.0': 'libharfbuzz0b',265 'libhyphen.so.0': 'libhyphen0',266 'libicudata.so.60': 'libicu60',267 'libicui18n.so.60': 'libicu60',268 'libicuuc.so.60': 'libicu60',269 'libjpeg.so.8': 'libjpeg-turbo8',270 'libnotify.so.4': 'libnotify4',271 'libnspr4.so': 'libnspr4',272 'libnss3.so': 'libnss3',273 'libnssutil3.so': 'libnss3',274 'libopenjp2.so.7': 'libopenjp2-7',275 'libopus.so.0': 'libopus0',276 'libpango-1.0.so.0': 'libpango-1.0-0',277 'libpangocairo-1.0.so.0': 'libpangocairo-1.0-0',278 'libpangoft2-1.0.so.0': 'libpangoft2-1.0-0',279 'libpng16.so.16': 'libpng16-16',280 'libsecret-1.so.0': 'libsecret-1-0',281 'libsmime3.so': 'libnss3',282 'libvpx.so.5': 'libvpx5',283 'libwayland-client.so.0': 'libwayland-client0',284 'libwayland-egl.so.1': 'libwayland-egl1',285 'libwayland-server.so.0': 'libwayland-server0',286 'libwebp.so.6': 'libwebp6',287 'libwebpdemux.so.2': 'libwebpdemux2',288 'libwoff2dec.so.1.0.2': 'libwoff1',289 'libX11-xcb.so.1': 'libx11-xcb1',290 'libX11.so.6': 'libx11-6',291 'libxcb-dri3.so.0': 'libxcb-dri3-0',292 'libxcb-shm.so.0': 'libxcb-shm0',293 'libxcb.so.1': 'libxcb1',294 'libXcomposite.so.1': 'libxcomposite1',295 'libXcursor.so.1': 'libxcursor1',296 'libXdamage.so.1': 'libxdamage1',297 'libXext.so.6': 'libxext6',298 'libXfixes.so.3': 'libxfixes3',299 'libXi.so.6': 'libxi6',300 'libxkbcommon.so.0': 'libxkbcommon0',301 'libxml2.so.2': 'libxml2',302 'libXrandr.so.2': 'libxrandr2',303 'libXrender.so.1': 'libxrender1',304 'libxslt.so.1': 'libxslt1.1',305 'libXt.so.6': 'libxt6',306 'libXtst.so.6': 'libxtst6'307}; // This list is generted with the following program:308// ./utils/linux-browser-dependencies/run.sh ubuntu:20.04309const LIBRARY_TO_PACKAGE_NAME_UBUNTU_20_04 = {310 'libasound.so.2': 'libasound2',311 'libatk-1.0.so.0': 'libatk1.0-0',312 'libatk-bridge-2.0.so.0': 'libatk-bridge2.0-0',313 'libatspi.so.0': 'libatspi2.0-0',314 'libcairo-gobject.so.2': 'libcairo-gobject2',315 'libcairo.so.2': 'libcairo2',316 'libcups.so.2': 'libcups2',317 'libdbus-1.so.3': 'libdbus-1-3',318 'libdbus-glib-1.so.2': 'libdbus-glib-1-2',319 'libdrm.so.2': 'libdrm2',320 'libEGL.so.1': 'libegl1',321 'libenchant.so.1': 'libenchant1c2a',322 'libevdev.so.2': 'libevdev2',323 'libepoxy.so.0': 'libepoxy0',324 'libfontconfig.so.1': 'libfontconfig1',325 'libfreetype.so.6': 'libfreetype6',326 'libgbm.so.1': 'libgbm1',327 'libgdk_pixbuf-2.0.so.0': 'libgdk-pixbuf2.0-0',328 'libgdk-3.so.0': 'libgtk-3-0',329 'libgdk-x11-2.0.so.0': 'libgtk2.0-0',330 'libgio-2.0.so.0': 'libglib2.0-0',331 'libGL.so.1': 'libgl1',332 'libGLESv2.so.2': 'libgles2',333 'libglib-2.0.so.0': 'libglib2.0-0',334 'libgmodule-2.0.so.0': 'libglib2.0-0',335 'libgobject-2.0.so.0': 'libglib2.0-0',336 'libgstapp-1.0.so.0': 'gstreamer1.0-plugins-base',337 'libgstaudio-1.0.so.0': 'gstreamer1.0-plugins-base',338 'libgstbase-1.0.so.0': 'libgstreamer1.0-0',339 'libgstcodecparsers-1.0.so.0': 'gstreamer1.0-plugins-bad',340 'libgstfft-1.0.so.0': 'gstreamer1.0-plugins-base',341 'libgstgl-1.0.so.0': 'libgstreamer-gl1.0-0',342 'libgstpbutils-1.0.so.0': 'gstreamer1.0-plugins-base',343 'libgstreamer-1.0.so.0': 'libgstreamer1.0-0',344 'libgsttag-1.0.so.0': 'gstreamer1.0-plugins-base',345 'libgstvideo-1.0.so.0': 'gstreamer1.0-plugins-base',346 'libgthread-2.0.so.0': 'libglib2.0-0',347 'libgtk-3.so.0': 'libgtk-3-0',348 'libgtk-x11-2.0.so.0': 'libgtk2.0-0',349 'libharfbuzz-icu.so.0': 'libharfbuzz-icu0',350 'libharfbuzz.so.0': 'libharfbuzz0b',351 'libhyphen.so.0': 'libhyphen0',352 'libicui18n.so.66': 'libicu66',353 'libicuuc.so.66': 'libicu66',354 'libjpeg.so.8': 'libjpeg-turbo8',355 'libnotify.so.4': 'libnotify4',356 'libnspr4.so': 'libnspr4',357 'libnss3.so': 'libnss3',358 'libnssutil3.so': 'libnss3',359 'libopenjp2.so.7': 'libopenjp2-7',360 'libopus.so.0': 'libopus0',361 'libpango-1.0.so.0': 'libpango-1.0-0',362 'libpangocairo-1.0.so.0': 'libpangocairo-1.0-0',363 'libpangoft2-1.0.so.0': 'libpangoft2-1.0-0',364 'libpng16.so.16': 'libpng16-16',365 'libsecret-1.so.0': 'libsecret-1-0',366 'libsmime3.so': 'libnss3',367 'libsoup-2.4.so.1': 'libsoup2.4-1',368 'libvpx.so.6': 'libvpx6',369 'libwayland-client.so.0': 'libwayland-client0',370 'libwayland-egl.so.1': 'libwayland-egl1',371 'libwayland-server.so.0': 'libwayland-server0',372 'libwebp.so.6': 'libwebp6',373 'libwebpdemux.so.2': 'libwebpdemux2',374 'libwoff2dec.so.1.0.2': 'libwoff1',375 'libX11-xcb.so.1': 'libx11-xcb1',376 'libX11.so.6': 'libx11-6',377 'libxcb-dri3.so.0': 'libxcb-dri3-0',378 'libxcb-shm.so.0': 'libxcb-shm0',379 'libxcb.so.1': 'libxcb1',380 'libXcomposite.so.1': 'libxcomposite1',381 'libXcursor.so.1': 'libxcursor1',382 'libXdamage.so.1': 'libxdamage1',383 'libXext.so.6': 'libxext6',384 'libXfixes.so.3': 'libxfixes3',385 'libXi.so.6': 'libxi6',386 'libxkbcommon.so.0': 'libxkbcommon0',387 'libxml2.so.2': 'libxml2',388 'libXrandr.so.2': 'libxrandr2',389 'libXrender.so.1': 'libxrender1',390 'libxslt.so.1': 'libxslt1.1',391 'libXt.so.6': 'libxt6',392 'libXtst.so.6': 'libxtst6',393 'libxshmfence.so.1': 'libxshmfence1'394};395const LIBRARY_TO_PACKAGE_NAME_UBUNTU_21_04 = {396 'libasound.so.2': 'libasound2',397 'libatk-1.0.so.0': 'libatk1.0-0',398 'libatk-bridge-2.0.so.0': 'libatk-bridge2.0-0',399 'libatspi.so.0': 'libatspi2.0-0',400 'libcairo-gobject.so.2': 'libcairo-gobject2',401 'libcairo.so.2': 'libcairo2',402 'libcups.so.2': 'libcups2',403 'libdbus-1.so.3': 'libdbus-1-3',404 'libdbus-glib-1.so.2': 'libdbus-glib-1-2',405 'libdrm.so.2': 'libdrm2',406 'libEGL.so.1': 'libegl1',407 'libepoxy.so.0': 'libepoxy0',408 'libfontconfig.so.1': 'libfontconfig1',409 'libfreetype.so.6': 'libfreetype6',410 'libgbm.so.1': 'libgbm1',411 'libgdk_pixbuf-2.0.so.0': 'libgdk-pixbuf-2.0-0',412 'libgdk-3.so.0': 'libgtk-3-0',413 'libgdk-x11-2.0.so.0': 'libgtk2.0-0',414 'libgio-2.0.so.0': 'libglib2.0-0',415 'libGL.so.1': 'libgl1',416 'libGLESv2.so.2': 'libgles2',417 'libglib-2.0.so.0': 'libglib2.0-0',418 'libgmodule-2.0.so.0': 'libglib2.0-0',419 'libgobject-2.0.so.0': 'libglib2.0-0',420 'libgstapp-1.0.so.0': 'libgstreamer-plugins-base1.0-0',421 'libgstaudio-1.0.so.0': 'libgstreamer-plugins-base1.0-0',422 'libgstbase-1.0.so.0': 'libgstreamer1.0-0',423 'libgstcodecparsers-1.0.so.0': 'libgstreamer-plugins-bad1.0-0',424 'libgstfft-1.0.so.0': 'libgstreamer-plugins-base1.0-0',425 'libgstgl-1.0.so.0': 'libgstreamer-gl1.0-0',426 'libgstpbutils-1.0.so.0': 'libgstreamer-plugins-base1.0-0',427 'libgstreamer-1.0.so.0': 'libgstreamer1.0-0',428 'libgsttag-1.0.so.0': 'libgstreamer-plugins-base1.0-0',429 'libgstvideo-1.0.so.0': 'libgstreamer-plugins-base1.0-0',430 'libgthread-2.0.so.0': 'libglib2.0-0',431 'libgtk-3.so.0': 'libgtk-3-0',432 'libgtk-x11-2.0.so.0': 'libgtk2.0-0',433 'libharfbuzz-icu.so.0': 'libharfbuzz-icu0',434 'libharfbuzz.so.0': 'libharfbuzz0b',435 'libhyphen.so.0': 'libhyphen0',436 'libjavascriptcoregtk-4.0.so.18': 'libjavascriptcoregtk-4.0-18',437 'libjpeg.so.8': 'libjpeg-turbo8',438 'liblcms2.so.2': 'liblcms2-2',439 'libnotify.so.4': 'libnotify4',440 'libnspr4.so': 'libnspr4',441 'libnss3.so': 'libnss3',442 'libnssutil3.so': 'libnss3',443 'libopenjp2.so.7': 'libopenjp2-7',444 'libopus.so.0': 'libopus0',445 'libpango-1.0.so.0': 'libpango-1.0-0',446 'libpangocairo-1.0.so.0': 'libpangocairo-1.0-0',447 'libpangoft2-1.0.so.0': 'libpangoft2-1.0-0',448 'libpng16.so.16': 'libpng16-16',449 'libsecret-1.so.0': 'libsecret-1-0',450 'libsmime3.so': 'libnss3',451 'libsoup-2.4.so.1': 'libsoup2.4-1',452 'libvpx.so.6': 'libvpx6',453 'libwayland-client.so.0': 'libwayland-client0',454 'libwayland-egl.so.1': 'libwayland-egl1',455 'libwayland-server.so.0': 'libwayland-server0',456 'libwebkit2gtk-4.0.so.37': 'libwebkit2gtk-4.0-37',457 'libwebp.so.6': 'libwebp6',458 'libwebpdemux.so.2': 'libwebpdemux2',459 'libwoff2dec.so.1.0.2': 'libwoff1',460 'libwpe-1.0.so.1': 'libwpe-1.0-1',461 'libWPEBackend-fdo-1.0.so.1': 'libwpebackend-fdo-1.0-1',462 'libWPEWebKit-1.0.so.3': 'libwpewebkit-1.0-3',463 'libX11-xcb.so.1': 'libx11-xcb1',464 'libX11.so.6': 'libx11-6',465 'libxcb-shm.so.0': 'libxcb-shm0',466 'libxcb.so.1': 'libxcb1',467 'libXcomposite.so.1': 'libxcomposite1',468 'libXcursor.so.1': 'libxcursor1',469 'libXdamage.so.1': 'libxdamage1',470 'libXext.so.6': 'libxext6',471 'libXfixes.so.3': 'libxfixes3',472 'libXi.so.6': 'libxi6',473 'libxkbcommon.so.0': 'libxkbcommon0',474 'libxml2.so.2': 'libxml2',475 'libXrandr.so.2': 'libxrandr2',476 'libXrender.so.1': 'libxrender1',477 'libxshmfence.so.1': 'libxshmfence1',478 'libxslt.so.1': 'libxslt1.1',479 'libXt.so.6': 'libxt6'480};481const MANUAL_LIBRARY_TO_PACKAGE_NAME_UBUNTU = {482 // libgstlibav.so (the only actual library provided by gstreamer1.0-libav) is not483 // in the ldconfig cache, so we detect the actual library required for playing h.264484 // and if it's missing recommend installing missing gstreamer lib.485 // gstreamer1.0-libav -> libavcodec57 -> libx264-152486 'libx264.so': 'gstreamer1.0-libav'...
index.js
Source:index.js
...258async function run() {259 try {260 if (os.platform() === 'linux') {261 await exec('sudo', ['apt-get', 'update']);262 const ubuntuVersion = await getUbuntuVersion();263 let deps = [];264 if (ubuntuVersion === '18.04')265 deps = DEPENDENCIES['ubuntu18.04'];266 else if (ubuntuVersion === '20.04')267 deps = DEPENDENCIES['ubuntu20.04'];268 else269 throw new Error('Cannot install dependencies for this linux distribution!');270 await exec('sudo', ['apt-get', 'install', '-y', '--no-install-recommends',271 ...deps.chromium,272 ...deps.firefox,273 ...deps.webkit,274 ...deps.tools,275 ]);276 }277 }278 catch (error) {279 core.setFailed(error.message);280 }281}282async function getUbuntuVersion() {283 if (os.platform() !== 'linux')284 return '';285 const osReleaseText = await readFileAsync('/etc/os-release', 'utf8').catch(() => {});286 if (!osReleaseText)287 return '';288 const fields = new Map();289 for (const line of osReleaseText.split('\n')) {290 const tokens = line.split('=');291 const name = tokens.shift();292 let value = tokens.join('=').trim();293 if (value.startsWith('"') && value.endsWith('"'))294 value = value.substring(1, value.length - 1);295 if (!name)296 continue;...
ubuntuVersion.js
Source:ubuntuVersion.js
...26 * See the License for the specific language governing permissions and27 * limitations under the License.28 */29let ubuntuVersionCached;30async function getUbuntuVersion() {31 if (ubuntuVersionCached === undefined) ubuntuVersionCached = await getUbuntuVersionAsyncInternal();32 return ubuntuVersionCached;33}34function getUbuntuVersionSync() {35 if (ubuntuVersionCached === undefined) ubuntuVersionCached = getUbuntuVersionSyncInternal();36 return ubuntuVersionCached;37}38async function getUbuntuVersionAsyncInternal() {39 if (os.platform() !== 'linux') return '';40 let osReleaseText = await _fs.default.promises.readFile('/etc/upstream-release/lsb-release', 'utf8').catch(e => '');41 if (!osReleaseText) osReleaseText = await _fs.default.promises.readFile('/etc/os-release', 'utf8').catch(e => '');42 if (!osReleaseText) return '';43 return parseUbuntuVersion(osReleaseText);44}...
Using AI Code Generation
1const { getUbuntuVersion } = require('playwright/lib/server/utils');2console.log(await getUbuntuVersion());3const { getUbuntuVersion } = require('playwright/lib/utils/utils');4console.log(await getUbuntuVersion());5const { getUbuntuVersion } = require('playwright/lib/utils/utils');6console.log(await getUbuntuVersion());7const { getUbuntuVersion } = require('playwright/lib/server/utils');8console.log(await getUbuntuVersion());9const { getUbuntuVersion } = require('playwright/lib/server/utils');10console.log(await getUbuntuVersion());11const { getUbuntuVersion } = require('playwright/lib/server/utils');12console.log(await getUbuntuVersion());13const { getUbuntuVersion } = require('playwright/lib/utils/utils');14console.log(await getUbuntuVersion());15const { getUbuntuVersion } = require('playwright/lib/server/utils');16console.log(await getUbuntuVersion());17const { getUbuntuVersion } = require('playwright/lib/server/utils');18console.log(await getUbuntuVersion());19const { getUbuntuVersion } = require('playwright/lib/server/utils');20console.log(await getUbuntuVersion());21const { getUbuntuVersion } = require('playwright/lib/server/utils');22console.log(await getUbuntuVersion());23const { getUbuntuVersion } = require('playwright/lib/server/utils');24console.log(await getUbuntuVersion());
Using AI Code Generation
1const browser = await chromium.launch();2const context = await browser.newContext();3const page = await context.newPage();4const version = await page._internal_api_getUbuntuVersion();5console.log(version);6await browser.close();
Using AI Code Generation
1const { getUbuntuVersion } = require('playwright-chromium/lib/server/playwright.js');2const ubuntuVersion = await getUbuntuVersion();3console.log(ubuntuVersion);4const { getUbuntuVersion } = require('playwright-chromium/lib/server/playwright.js');5const ubuntuVersion = await getUbuntuVersion();6console.log(ubuntuVersion);7const { getUbuntuVersion } = require('playwright-chromium/lib/server/playwright.js');8const ubuntuVersion = await getUbuntuVersion();9console.log(ubuntuVersion);10const { getUbuntuVersion } = require('playwright-chromium/lib/server/playwright.js');11const ubuntuVersion = await getUbuntuVersion();12console.log(ubuntuVersion);13const { getUbuntuVersion } = require('playwright-chromium/lib/server/playwright.js');14const ubuntuVersion = await getUbuntuVersion();15console.log(ubuntuVersion);16const { getUbuntuVersion } = require('playwright-chromium/lib/server/playwright.js');17const ubuntuVersion = await getUbuntuVersion();18console.log(ubuntuVersion);19const { getUbuntuVersion } = require('playwright-chromium/lib/server/playwright.js');20const ubuntuVersion = await getUbuntuVersion();21console.log(ubuntuVersion);22const { getUbuntuVersion } = require('playwright-chromium/lib/server/playwright.js');23const ubuntuVersion = await getUbuntuVersion();24console.log(ubuntuVersion);25const { getUbuntuVersion } = require('playwright-chromium/lib/server/playwright.js');26const ubuntuVersion = await getUbuntuVersion();27console.log(ubuntuVersion);28const { getUbuntuVersion } = require('playwright-chromium/lib/server/playwright.js');
Using AI Code Generation
1const { getUbuntuVersion } = require('playwright-core/lib/server/playwright');2const version = getUbuntuVersion();3console.log(version);4const playwright = require('playwright');5const { getUbuntuVersion } = require('playwright-core/lib/server/playwright');6(async () => {7 const browser = await playwright.chromium.launch();8 const page = await browser.newPage();9 const version = await page.evaluate(getUbuntuVersion);10 console.log(version);11 await browser.close();12})();
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!!