diff options
Diffstat (limited to 'remote/test/puppeteer/packages/puppeteer/src')
6 files changed, 416 insertions, 0 deletions
diff --git a/remote/test/puppeteer/packages/puppeteer/src/getConfiguration.ts b/remote/test/puppeteer/packages/puppeteer/src/getConfiguration.ts new file mode 100644 index 0000000000..28cf026eb7 --- /dev/null +++ b/remote/test/puppeteer/packages/puppeteer/src/getConfiguration.ts @@ -0,0 +1,138 @@ +/** + * @license + * Copyright 2023 Google Inc. + * SPDX-License-Identifier: Apache-2.0 + */ + +import {homedir} from 'os'; +import {join} from 'path'; + +import {cosmiconfigSync} from 'cosmiconfig'; +import type {Configuration, Product} from 'puppeteer-core'; + +/** + * @internal + */ +function isSupportedProduct(product: unknown): product is Product { + switch (product) { + case 'chrome': + case 'firefox': + return true; + default: + return false; + } +} + +/** + * @internal + */ +export const getConfiguration = (): Configuration => { + const result = cosmiconfigSync('puppeteer', { + searchStrategy: 'global', + }).search(); + const configuration: Configuration = result ? result.config : {}; + + configuration.logLevel = (process.env['PUPPETEER_LOGLEVEL'] ?? + process.env['npm_config_LOGLEVEL'] ?? + process.env['npm_package_config_LOGLEVEL'] ?? + configuration.logLevel ?? + 'warn') as 'silent' | 'error' | 'warn'; + + // Merging environment variables. + configuration.defaultProduct = (process.env['PUPPETEER_PRODUCT'] ?? + process.env['npm_config_puppeteer_product'] ?? + process.env['npm_package_config_puppeteer_product'] ?? + configuration.defaultProduct ?? + 'chrome') as Product; + + configuration.executablePath = + process.env['PUPPETEER_EXECUTABLE_PATH'] ?? + process.env['npm_config_puppeteer_executable_path'] ?? + process.env['npm_package_config_puppeteer_executable_path'] ?? + configuration.executablePath; + + // Default to skipDownload if executablePath is set + if (configuration.executablePath) { + configuration.skipDownload = true; + } + + // Set skipDownload explicitly or from default + configuration.skipDownload = Boolean( + process.env['PUPPETEER_SKIP_DOWNLOAD'] ?? + process.env['npm_config_puppeteer_skip_download'] ?? + process.env['npm_package_config_puppeteer_skip_download'] ?? + configuration.skipDownload + ); + + // Set skipChromeDownload explicitly or from default + configuration.skipChromeDownload = Boolean( + process.env['PUPPETEER_SKIP_CHROME_DOWNLOAD'] ?? + process.env['npm_config_puppeteer_skip_chrome_download'] ?? + process.env['npm_package_config_puppeteer_skip_chrome_download'] ?? + configuration.skipChromeDownload + ); + + // Set skipChromeDownload explicitly or from default + configuration.skipChromeHeadlessShellDownload = Boolean( + process.env['PUPPETEER_SKIP_CHROME_HEADLESS_SHELL_DOWNLOAD'] ?? + process.env['npm_config_puppeteer_skip_chrome_headless_shell_download'] ?? + process.env[ + 'npm_package_config_puppeteer_skip_chrome_headless_shell_download' + ] ?? + configuration.skipChromeHeadlessShellDownload + ); + + // Prepare variables used in browser downloading + if (!configuration.skipDownload) { + configuration.browserRevision = + process.env['PUPPETEER_BROWSER_REVISION'] ?? + process.env['npm_config_puppeteer_browser_revision'] ?? + process.env['npm_package_config_puppeteer_browser_revision'] ?? + configuration.browserRevision; + + const downloadHost = + process.env['PUPPETEER_DOWNLOAD_HOST'] ?? + process.env['npm_config_puppeteer_download_host'] ?? + process.env['npm_package_config_puppeteer_download_host']; + + if (downloadHost && configuration.logLevel === 'warn') { + console.warn( + `PUPPETEER_DOWNLOAD_HOST is deprecated. Use PUPPETEER_DOWNLOAD_BASE_URL instead.` + ); + } + + configuration.downloadBaseUrl = + process.env['PUPPETEER_DOWNLOAD_BASE_URL'] ?? + process.env['npm_config_puppeteer_download_base_url'] ?? + process.env['npm_package_config_puppeteer_download_base_url'] ?? + configuration.downloadBaseUrl ?? + downloadHost; + + configuration.downloadPath = + process.env['PUPPETEER_DOWNLOAD_PATH'] ?? + process.env['npm_config_puppeteer_download_path'] ?? + process.env['npm_package_config_puppeteer_download_path'] ?? + configuration.downloadPath; + } + + configuration.cacheDirectory = + process.env['PUPPETEER_CACHE_DIR'] ?? + process.env['npm_config_puppeteer_cache_dir'] ?? + process.env['npm_package_config_puppeteer_cache_dir'] ?? + configuration.cacheDirectory ?? + join(homedir(), '.cache', 'puppeteer'); + configuration.temporaryDirectory = + process.env['PUPPETEER_TMP_DIR'] ?? + process.env['npm_config_puppeteer_tmp_dir'] ?? + process.env['npm_package_config_puppeteer_tmp_dir'] ?? + configuration.temporaryDirectory; + + configuration.experiments ??= {}; + + // Validate configuration. + if (!isSupportedProduct(configuration.defaultProduct)) { + throw new Error(`Unsupported product ${configuration.defaultProduct}`); + } + + return configuration; +}; diff --git a/remote/test/puppeteer/packages/puppeteer/src/node/cli.ts b/remote/test/puppeteer/packages/puppeteer/src/node/cli.ts new file mode 100644 index 0000000000..9a25c59327 --- /dev/null +++ b/remote/test/puppeteer/packages/puppeteer/src/node/cli.ts @@ -0,0 +1,32 @@ +#!/usr/bin/env node + +/** + * @license + * Copyright 2023 Google Inc. + * SPDX-License-Identifier: Apache-2.0 + */ + +import {CLI, Browser} from '@puppeteer/browsers'; +import {PUPPETEER_REVISIONS} from 'puppeteer-core/internal/revisions.js'; + +import puppeteer from '../puppeteer.js'; + +// TODO: deprecate downloadPath in favour of cacheDirectory. +const cacheDir = + puppeteer.configuration.downloadPath ?? + puppeteer.configuration.cacheDirectory!; + +void new CLI({ + cachePath: cacheDir, + scriptName: 'puppeteer', + prefixCommand: { + cmd: 'browsers', + description: 'Manage browsers of this Puppeteer installation', + }, + allowCachePathOverride: false, + pinnedBrowsers: { + [Browser.CHROME]: PUPPETEER_REVISIONS.chrome, + [Browser.FIREFOX]: PUPPETEER_REVISIONS.firefox, + [Browser.CHROMEHEADLESSSHELL]: PUPPETEER_REVISIONS['chrome-headless-shell'], + }, +}).run(process.argv); diff --git a/remote/test/puppeteer/packages/puppeteer/src/node/install.ts b/remote/test/puppeteer/packages/puppeteer/src/node/install.ts new file mode 100644 index 0000000000..76bad868b8 --- /dev/null +++ b/remote/test/puppeteer/packages/puppeteer/src/node/install.ts @@ -0,0 +1,184 @@ +/** + * @license + * Copyright 2020 Google Inc. + * SPDX-License-Identifier: Apache-2.0 + */ + +import { + install, + Browser, + resolveBuildId, + makeProgressCallback, + detectBrowserPlatform, +} from '@puppeteer/browsers'; +import type {Product} from 'puppeteer-core'; +import {PUPPETEER_REVISIONS} from 'puppeteer-core/internal/revisions.js'; + +import {getConfiguration} from '../getConfiguration.js'; + +/** + * @internal + */ +const supportedProducts = { + chrome: 'Chrome', + firefox: 'Firefox Nightly', +} as const; + +/** + * @internal + */ +export async function downloadBrowser(): Promise<void> { + overrideProxy(); + + const configuration = getConfiguration(); + if (configuration.skipDownload) { + logPolitely('**INFO** Skipping browser download as instructed.'); + return; + } + + const downloadBaseUrl = configuration.downloadBaseUrl; + + const platform = detectBrowserPlatform(); + if (!platform) { + throw new Error('The current platform is not supported.'); + } + + const product = configuration.defaultProduct!; + const browser = productToBrowser(product); + + const unresolvedBuildId = + configuration.browserRevision || PUPPETEER_REVISIONS[product] || 'latest'; + const unresolvedShellBuildId = + configuration.browserRevision || + PUPPETEER_REVISIONS['chrome-headless-shell'] || + 'latest'; + + // TODO: deprecate downloadPath in favour of cacheDirectory. + const cacheDir = configuration.downloadPath ?? configuration.cacheDirectory!; + + try { + const installationJobs = []; + + if (configuration.skipChromeDownload) { + logPolitely('**INFO** Skipping Chrome download as instructed.'); + } else { + const buildId = await resolveBuildId( + browser, + platform, + unresolvedBuildId + ); + installationJobs.push( + install({ + browser, + cacheDir, + platform, + buildId, + downloadProgressCallback: makeProgressCallback(browser, buildId), + baseUrl: downloadBaseUrl, + }) + .then(result => { + logPolitely( + `${supportedProducts[product]} (${result.buildId}) downloaded to ${result.path}` + ); + }) + .catch(error => { + throw new Error( + `ERROR: Failed to set up ${supportedProducts[product]} v${buildId}! Set "PUPPETEER_SKIP_DOWNLOAD" env variable to skip download.`, + { + cause: error, + } + ); + }) + ); + } + + if (browser === Browser.CHROME) { + if (configuration.skipChromeHeadlessShellDownload) { + logPolitely('**INFO** Skipping Chrome download as instructed.'); + } else { + const shellBuildId = await resolveBuildId( + browser, + platform, + unresolvedShellBuildId + ); + + installationJobs.push( + install({ + browser: Browser.CHROMEHEADLESSSHELL, + cacheDir, + platform, + buildId: shellBuildId, + downloadProgressCallback: makeProgressCallback( + browser, + shellBuildId + ), + baseUrl: downloadBaseUrl, + }) + .then(result => { + logPolitely( + `${Browser.CHROMEHEADLESSSHELL} (${result.buildId}) downloaded to ${result.path}` + ); + }) + .catch(error => { + throw new Error( + `ERROR: Failed to set up ${Browser.CHROMEHEADLESSSHELL} v${shellBuildId}! Set "PUPPETEER_SKIP_DOWNLOAD" env variable to skip download.`, + { + cause: error, + } + ); + }) + ); + } + } + + await Promise.all(installationJobs); + } catch (error) { + console.error(error); + process.exit(1); + } +} + +function productToBrowser(product?: Product) { + switch (product) { + case 'chrome': + return Browser.CHROME; + case 'firefox': + return Browser.FIREFOX; + } + return Browser.CHROME; +} + +/** + * @internal + */ +function logPolitely(toBeLogged: unknown): void { + const logLevel = process.env['npm_config_loglevel'] || ''; + const logLevelDisplay = ['silent', 'error', 'warn'].indexOf(logLevel) > -1; + + // eslint-disable-next-line no-console + if (!logLevelDisplay) { + console.log(toBeLogged); + } +} + +/** + * @internal + */ +function overrideProxy() { + // Override current environment proxy settings with npm configuration, if any. + const NPM_HTTPS_PROXY = + process.env['npm_config_https_proxy'] || process.env['npm_config_proxy']; + const NPM_HTTP_PROXY = + process.env['npm_config_http_proxy'] || process.env['npm_config_proxy']; + const NPM_NO_PROXY = process.env['npm_config_no_proxy']; + + if (NPM_HTTPS_PROXY) { + process.env['HTTPS_PROXY'] = NPM_HTTPS_PROXY; + } + if (NPM_HTTP_PROXY) { + process.env['HTTP_PROXY'] = NPM_HTTP_PROXY; + } + if (NPM_NO_PROXY) { + process.env['NO_PROXY'] = NPM_NO_PROXY; + } +} diff --git a/remote/test/puppeteer/packages/puppeteer/src/puppeteer.ts b/remote/test/puppeteer/packages/puppeteer/src/puppeteer.ts new file mode 100644 index 0000000000..4f4321bc6c --- /dev/null +++ b/remote/test/puppeteer/packages/puppeteer/src/puppeteer.ts @@ -0,0 +1,48 @@ +/** + * @license + * Copyright 2017 Google Inc. + * SPDX-License-Identifier: Apache-2.0 + */ + +export type {Protocol} from 'puppeteer-core'; + +export * from 'puppeteer-core/internal/puppeteer-core.js'; + +import {PuppeteerNode} from 'puppeteer-core/internal/node/PuppeteerNode.js'; + +import {getConfiguration} from './getConfiguration.js'; + +const configuration = getConfiguration(); + +/** + * @public + */ +const puppeteer = new PuppeteerNode({ + isPuppeteerCore: false, + configuration, +}); + +export const { + /** + * @public + */ + connect, + /** + * @public + */ + defaultArgs, + /** + * @public + */ + executablePath, + /** + * @public + */ + launch, + /** + * @public + */ + trimCache, +} = puppeteer; + +export default puppeteer; diff --git a/remote/test/puppeteer/packages/puppeteer/src/tsconfig.cjs.json b/remote/test/puppeteer/packages/puppeteer/src/tsconfig.cjs.json new file mode 100644 index 0000000000..0cb78dca7f --- /dev/null +++ b/remote/test/puppeteer/packages/puppeteer/src/tsconfig.cjs.json @@ -0,0 +1,8 @@ +{ + "extends": "../../../tsconfig.base.json", + "compilerOptions": { + "module": "NodeNext", + "moduleResolution": "NodeNext", + "outDir": "../lib/cjs/puppeteer" + } +} diff --git a/remote/test/puppeteer/packages/puppeteer/src/tsconfig.esm.json b/remote/test/puppeteer/packages/puppeteer/src/tsconfig.esm.json new file mode 100644 index 0000000000..a848929f4f --- /dev/null +++ b/remote/test/puppeteer/packages/puppeteer/src/tsconfig.esm.json @@ -0,0 +1,6 @@ +{ + "extends": "../../../tsconfig.base.json", + "compilerOptions": { + "outDir": "../lib/esm/puppeteer" + } +} |