mirror of
https://github.com/microsoft/playwright.git
synced 2025-06-26 21:40:17 +00:00
chore: validate deps during install (#28932)
Motivation: On Windows we call around 50 times `PrintDeps.exe` which takes on a very fast machine 500+ms. On Linux we do it around 120 times (`ldd`) which takes around 150ms. This change validates the dependencies once on browser install (`npx playwright install`). In case its failing, it will emit a warning, in case of a success, it will create a marker file that the binary has been validated. For future `launch()` calls, we'll read this file and if exists, we'll not validate again. Otherwise we'll validate again. Note: If the marker file is older than 30 days, the browser will be validated again.
This commit is contained in:
parent
6a14b1dc51
commit
4c4789c740
@ -160,6 +160,10 @@ program
|
|||||||
} else {
|
} else {
|
||||||
const forceReinstall = hasNoArguments ? false : !!options.force;
|
const forceReinstall = hasNoArguments ? false : !!options.force;
|
||||||
await registry.install(executables, forceReinstall);
|
await registry.install(executables, forceReinstall);
|
||||||
|
await registry.validateHostRequirementsForExecutablesIfNeeded(executables, process.env.PW_LANG_NAME || 'javascript').catch((e: Error) => {
|
||||||
|
e.name = 'Playwright Host validation warning';
|
||||||
|
console.error(e);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.log(`Failed to install browsers\n${e}`);
|
console.log(`Failed to install browsers\n${e}`);
|
||||||
|
@ -180,7 +180,7 @@ export abstract class BrowserType extends SdkObject {
|
|||||||
if (!registryExecutable || registryExecutable.browserName !== this._name)
|
if (!registryExecutable || registryExecutable.browserName !== this._name)
|
||||||
throw new Error(`Unsupported ${this._name} channel "${options.channel}"`);
|
throw new Error(`Unsupported ${this._name} channel "${options.channel}"`);
|
||||||
executable = registryExecutable.executablePathOrDie(this.attribution.playwright.options.sdkLanguage);
|
executable = registryExecutable.executablePathOrDie(this.attribution.playwright.options.sdkLanguage);
|
||||||
await registryExecutable.validateHostRequirements(this.attribution.playwright.options.sdkLanguage);
|
await registry.validateHostRequirementsForExecutablesIfNeeded([registryExecutable], this.attribution.playwright.options.sdkLanguage);
|
||||||
}
|
}
|
||||||
|
|
||||||
const waitForWSEndpoint = (options.useWebSocket || options.args?.some(a => a.startsWith('--remote-debugging-port'))) ? new ManualPromise<string>() : undefined;
|
const waitForWSEndpoint = (options.useWebSocket || options.args?.some(a => a.startsWith('--remote-debugging-port'))) ? new ManualPromise<string>() : undefined;
|
||||||
|
@ -230,17 +230,17 @@ export async function validateDependenciesLinux(sdkLanguage: string, linuxLddDir
|
|||||||
const pwVersion = getPlaywrightVersion();
|
const pwVersion = getPlaywrightVersion();
|
||||||
const requiredDockerImage = dockerInfo.dockerImageName.replace(dockerInfo.driverVersion, pwVersion);
|
const requiredDockerImage = dockerInfo.dockerImageName.replace(dockerInfo.driverVersion, pwVersion);
|
||||||
errorLines.push(...[
|
errorLines.push(...[
|
||||||
`This is most likely due to docker image version not matching Playwright version:`,
|
`This is most likely due to Docker image version not matching Playwright version:`,
|
||||||
`- Playwright : ${pwVersion}`,
|
`- Playwright : ${pwVersion}`,
|
||||||
`- Docker: ${dockerInfo.driverVersion}`,
|
`- Docker image: ${dockerInfo.driverVersion}`,
|
||||||
``,
|
``,
|
||||||
`Either:`,
|
`Either:`,
|
||||||
`- (recommended) use docker image "${requiredDockerImage}"`,
|
`- (recommended) use Docker image "${requiredDockerImage}"`,
|
||||||
`- (alternative 1) run the following command inside docker to install missing dependencies:`,
|
`- (alternative 1) run the following command inside Docker to install missing dependencies:`,
|
||||||
``,
|
``,
|
||||||
` ${maybeSudo}${buildPlaywrightCLICommand(sdkLanguage, 'install-deps')}`,
|
` ${maybeSudo}${buildPlaywrightCLICommand(sdkLanguage, 'install-deps')}`,
|
||||||
``,
|
``,
|
||||||
`- (alternative 2) use apt inside docker:`,
|
`- (alternative 2) use apt inside Docker:`,
|
||||||
``,
|
``,
|
||||||
` ${maybeSudo}apt-get install ${[...missingPackages].join('\\\n ')}`,
|
` ${maybeSudo}apt-get install ${[...missingPackages].join('\\\n ')}`,
|
||||||
``,
|
``,
|
||||||
|
@ -20,7 +20,6 @@ import path from 'path';
|
|||||||
import * as util from 'util';
|
import * as util from 'util';
|
||||||
import * as fs from 'fs';
|
import * as fs from 'fs';
|
||||||
import { lockfile } from '../../utilsBundle';
|
import { lockfile } from '../../utilsBundle';
|
||||||
import { getLinuxDistributionInfo } from '../../utils/linuxUtils';
|
|
||||||
import { fetchData } from '../../utils/network';
|
import { fetchData } from '../../utils/network';
|
||||||
import { getEmbedderName } from '../../utils/userAgent';
|
import { getEmbedderName } from '../../utils/userAgent';
|
||||||
import { getFromENV, getAsBooleanFromENV, calculateSha1, wrapInASCIIBox, getPackageManagerExecCommand } from '../../utils';
|
import { getFromENV, getAsBooleanFromENV, calculateSha1, wrapInASCIIBox, getPackageManagerExecCommand } from '../../utils';
|
||||||
@ -32,6 +31,7 @@ import { transformCommandsForRoot, dockerVersion, readDockerVersionSync } from '
|
|||||||
import { installDependenciesLinux, installDependenciesWindows, validateDependenciesLinux, validateDependenciesWindows } from './dependencies';
|
import { installDependenciesLinux, installDependenciesWindows, validateDependenciesLinux, validateDependenciesWindows } from './dependencies';
|
||||||
import { downloadBrowserWithProgressBar, logPolitely } from './browserFetcher';
|
import { downloadBrowserWithProgressBar, logPolitely } from './browserFetcher';
|
||||||
export { writeDockerVersion } from './dependencies';
|
export { writeDockerVersion } from './dependencies';
|
||||||
|
import { debugLogger } from '../../common/debugLogger';
|
||||||
|
|
||||||
const PACKAGE_PATH = path.join(__dirname, '..', '..', '..');
|
const PACKAGE_PATH = path.join(__dirname, '..', '..', '..');
|
||||||
const BIN_PATH = path.join(__dirname, '..', '..', '..', 'bin');
|
const BIN_PATH = path.join(__dirname, '..', '..', '..', 'bin');
|
||||||
@ -382,7 +382,7 @@ export interface Executable {
|
|||||||
browserVersion?: string,
|
browserVersion?: string,
|
||||||
executablePathOrDie(sdkLanguage: string): string;
|
executablePathOrDie(sdkLanguage: string): string;
|
||||||
executablePath(sdkLanguage: string): string | undefined;
|
executablePath(sdkLanguage: string): string | undefined;
|
||||||
validateHostRequirements(sdkLanguage: string): Promise<void>;
|
_validateHostRequirements(sdkLanguage: string): Promise<void>;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface ExecutableImpl extends Executable {
|
interface ExecutableImpl extends Executable {
|
||||||
@ -445,7 +445,7 @@ export class Registry {
|
|||||||
executablePath: () => chromiumExecutable,
|
executablePath: () => chromiumExecutable,
|
||||||
executablePathOrDie: (sdkLanguage: string) => executablePathOrDie('chromium', chromiumExecutable, chromium.installByDefault, sdkLanguage),
|
executablePathOrDie: (sdkLanguage: string) => executablePathOrDie('chromium', chromiumExecutable, chromium.installByDefault, sdkLanguage),
|
||||||
installType: chromium.installByDefault ? 'download-by-default' : 'download-on-demand',
|
installType: chromium.installByDefault ? 'download-by-default' : 'download-on-demand',
|
||||||
validateHostRequirements: (sdkLanguage: string) => this._validateHostRequirements(sdkLanguage, 'chromium', chromium.dir, ['chrome-linux'], [], ['chrome-win']),
|
_validateHostRequirements: (sdkLanguage: string) => this._validateHostRequirements(sdkLanguage, 'chromium', chromium.dir, ['chrome-linux'], [], ['chrome-win']),
|
||||||
downloadURLs: this._downloadURLs(chromium),
|
downloadURLs: this._downloadURLs(chromium),
|
||||||
browserVersion: chromium.browserVersion,
|
browserVersion: chromium.browserVersion,
|
||||||
_install: () => this._downloadExecutable(chromium, chromiumExecutable),
|
_install: () => this._downloadExecutable(chromium, chromiumExecutable),
|
||||||
@ -463,7 +463,7 @@ export class Registry {
|
|||||||
executablePath: () => chromiumWithSymbolsExecutable,
|
executablePath: () => chromiumWithSymbolsExecutable,
|
||||||
executablePathOrDie: (sdkLanguage: string) => executablePathOrDie('chromium-with-symbols', chromiumWithSymbolsExecutable, chromiumWithSymbols.installByDefault, sdkLanguage),
|
executablePathOrDie: (sdkLanguage: string) => executablePathOrDie('chromium-with-symbols', chromiumWithSymbolsExecutable, chromiumWithSymbols.installByDefault, sdkLanguage),
|
||||||
installType: chromiumWithSymbols.installByDefault ? 'download-by-default' : 'download-on-demand',
|
installType: chromiumWithSymbols.installByDefault ? 'download-by-default' : 'download-on-demand',
|
||||||
validateHostRequirements: (sdkLanguage: string) => this._validateHostRequirements(sdkLanguage, 'chromium', chromiumWithSymbols.dir, ['chrome-linux'], [], ['chrome-win']),
|
_validateHostRequirements: (sdkLanguage: string) => this._validateHostRequirements(sdkLanguage, 'chromium', chromiumWithSymbols.dir, ['chrome-linux'], [], ['chrome-win']),
|
||||||
downloadURLs: this._downloadURLs(chromiumWithSymbols),
|
downloadURLs: this._downloadURLs(chromiumWithSymbols),
|
||||||
browserVersion: chromiumWithSymbols.browserVersion,
|
browserVersion: chromiumWithSymbols.browserVersion,
|
||||||
_install: () => this._downloadExecutable(chromiumWithSymbols, chromiumWithSymbolsExecutable),
|
_install: () => this._downloadExecutable(chromiumWithSymbols, chromiumWithSymbolsExecutable),
|
||||||
@ -481,7 +481,7 @@ export class Registry {
|
|||||||
executablePath: () => chromiumTipOfTreeExecutable,
|
executablePath: () => chromiumTipOfTreeExecutable,
|
||||||
executablePathOrDie: (sdkLanguage: string) => executablePathOrDie('chromium-tip-of-tree', chromiumTipOfTreeExecutable, chromiumTipOfTree.installByDefault, sdkLanguage),
|
executablePathOrDie: (sdkLanguage: string) => executablePathOrDie('chromium-tip-of-tree', chromiumTipOfTreeExecutable, chromiumTipOfTree.installByDefault, sdkLanguage),
|
||||||
installType: chromiumTipOfTree.installByDefault ? 'download-by-default' : 'download-on-demand',
|
installType: chromiumTipOfTree.installByDefault ? 'download-by-default' : 'download-on-demand',
|
||||||
validateHostRequirements: (sdkLanguage: string) => this._validateHostRequirements(sdkLanguage, 'chromium', chromiumTipOfTree.dir, ['chrome-linux'], [], ['chrome-win']),
|
_validateHostRequirements: (sdkLanguage: string) => this._validateHostRequirements(sdkLanguage, 'chromium', chromiumTipOfTree.dir, ['chrome-linux'], [], ['chrome-win']),
|
||||||
downloadURLs: this._downloadURLs(chromiumTipOfTree),
|
downloadURLs: this._downloadURLs(chromiumTipOfTree),
|
||||||
browserVersion: chromiumTipOfTree.browserVersion,
|
browserVersion: chromiumTipOfTree.browserVersion,
|
||||||
_install: () => this._downloadExecutable(chromiumTipOfTree, chromiumTipOfTreeExecutable),
|
_install: () => this._downloadExecutable(chromiumTipOfTree, chromiumTipOfTreeExecutable),
|
||||||
@ -567,7 +567,7 @@ export class Registry {
|
|||||||
executablePath: () => firefoxExecutable,
|
executablePath: () => firefoxExecutable,
|
||||||
executablePathOrDie: (sdkLanguage: string) => executablePathOrDie('firefox', firefoxExecutable, firefox.installByDefault, sdkLanguage),
|
executablePathOrDie: (sdkLanguage: string) => executablePathOrDie('firefox', firefoxExecutable, firefox.installByDefault, sdkLanguage),
|
||||||
installType: firefox.installByDefault ? 'download-by-default' : 'download-on-demand',
|
installType: firefox.installByDefault ? 'download-by-default' : 'download-on-demand',
|
||||||
validateHostRequirements: (sdkLanguage: string) => this._validateHostRequirements(sdkLanguage, 'firefox', firefox.dir, ['firefox'], [], ['firefox']),
|
_validateHostRequirements: (sdkLanguage: string) => this._validateHostRequirements(sdkLanguage, 'firefox', firefox.dir, ['firefox'], [], ['firefox']),
|
||||||
downloadURLs: this._downloadURLs(firefox),
|
downloadURLs: this._downloadURLs(firefox),
|
||||||
browserVersion: firefox.browserVersion,
|
browserVersion: firefox.browserVersion,
|
||||||
_install: () => this._downloadExecutable(firefox, firefoxExecutable),
|
_install: () => this._downloadExecutable(firefox, firefoxExecutable),
|
||||||
@ -585,7 +585,7 @@ export class Registry {
|
|||||||
executablePath: () => firefoxAsanExecutable,
|
executablePath: () => firefoxAsanExecutable,
|
||||||
executablePathOrDie: (sdkLanguage: string) => executablePathOrDie('firefox-asan', firefoxAsanExecutable, firefoxAsan.installByDefault, sdkLanguage),
|
executablePathOrDie: (sdkLanguage: string) => executablePathOrDie('firefox-asan', firefoxAsanExecutable, firefoxAsan.installByDefault, sdkLanguage),
|
||||||
installType: firefoxAsan.installByDefault ? 'download-by-default' : 'download-on-demand',
|
installType: firefoxAsan.installByDefault ? 'download-by-default' : 'download-on-demand',
|
||||||
validateHostRequirements: (sdkLanguage: string) => this._validateHostRequirements(sdkLanguage, 'firefox', firefoxAsan.dir, ['firefox'], [], ['firefox']),
|
_validateHostRequirements: (sdkLanguage: string) => this._validateHostRequirements(sdkLanguage, 'firefox', firefoxAsan.dir, ['firefox'], [], ['firefox']),
|
||||||
downloadURLs: this._downloadURLs(firefoxAsan),
|
downloadURLs: this._downloadURLs(firefoxAsan),
|
||||||
browserVersion: firefoxAsan.browserVersion,
|
browserVersion: firefoxAsan.browserVersion,
|
||||||
_install: () => this._downloadExecutable(firefoxAsan, firefoxAsanExecutable),
|
_install: () => this._downloadExecutable(firefoxAsan, firefoxAsanExecutable),
|
||||||
@ -603,7 +603,7 @@ export class Registry {
|
|||||||
executablePath: () => firefoxBetaExecutable,
|
executablePath: () => firefoxBetaExecutable,
|
||||||
executablePathOrDie: (sdkLanguage: string) => executablePathOrDie('firefox-beta', firefoxBetaExecutable, firefoxBeta.installByDefault, sdkLanguage),
|
executablePathOrDie: (sdkLanguage: string) => executablePathOrDie('firefox-beta', firefoxBetaExecutable, firefoxBeta.installByDefault, sdkLanguage),
|
||||||
installType: firefoxBeta.installByDefault ? 'download-by-default' : 'download-on-demand',
|
installType: firefoxBeta.installByDefault ? 'download-by-default' : 'download-on-demand',
|
||||||
validateHostRequirements: (sdkLanguage: string) => this._validateHostRequirements(sdkLanguage, 'firefox', firefoxBeta.dir, ['firefox'], [], ['firefox']),
|
_validateHostRequirements: (sdkLanguage: string) => this._validateHostRequirements(sdkLanguage, 'firefox', firefoxBeta.dir, ['firefox'], [], ['firefox']),
|
||||||
downloadURLs: this._downloadURLs(firefoxBeta),
|
downloadURLs: this._downloadURLs(firefoxBeta),
|
||||||
browserVersion: firefoxBeta.browserVersion,
|
browserVersion: firefoxBeta.browserVersion,
|
||||||
_install: () => this._downloadExecutable(firefoxBeta, firefoxBetaExecutable),
|
_install: () => this._downloadExecutable(firefoxBeta, firefoxBetaExecutable),
|
||||||
@ -631,7 +631,7 @@ export class Registry {
|
|||||||
executablePath: () => webkitExecutable,
|
executablePath: () => webkitExecutable,
|
||||||
executablePathOrDie: (sdkLanguage: string) => executablePathOrDie('webkit', webkitExecutable, webkit.installByDefault, sdkLanguage),
|
executablePathOrDie: (sdkLanguage: string) => executablePathOrDie('webkit', webkitExecutable, webkit.installByDefault, sdkLanguage),
|
||||||
installType: webkit.installByDefault ? 'download-by-default' : 'download-on-demand',
|
installType: webkit.installByDefault ? 'download-by-default' : 'download-on-demand',
|
||||||
validateHostRequirements: (sdkLanguage: string) => this._validateHostRequirements(sdkLanguage, 'webkit', webkit.dir, webkitLinuxLddDirectories, ['libGLESv2.so.2', 'libx264.so'], ['']),
|
_validateHostRequirements: (sdkLanguage: string) => this._validateHostRequirements(sdkLanguage, 'webkit', webkit.dir, webkitLinuxLddDirectories, ['libGLESv2.so.2', 'libx264.so'], ['']),
|
||||||
downloadURLs: this._downloadURLs(webkit),
|
downloadURLs: this._downloadURLs(webkit),
|
||||||
browserVersion: webkit.browserVersion,
|
browserVersion: webkit.browserVersion,
|
||||||
_install: () => this._downloadExecutable(webkit, webkitExecutable),
|
_install: () => this._downloadExecutable(webkit, webkitExecutable),
|
||||||
@ -649,7 +649,7 @@ export class Registry {
|
|||||||
executablePath: () => ffmpegExecutable,
|
executablePath: () => ffmpegExecutable,
|
||||||
executablePathOrDie: (sdkLanguage: string) => executablePathOrDie('ffmpeg', ffmpegExecutable, ffmpeg.installByDefault, sdkLanguage),
|
executablePathOrDie: (sdkLanguage: string) => executablePathOrDie('ffmpeg', ffmpegExecutable, ffmpeg.installByDefault, sdkLanguage),
|
||||||
installType: ffmpeg.installByDefault ? 'download-by-default' : 'download-on-demand',
|
installType: ffmpeg.installByDefault ? 'download-by-default' : 'download-on-demand',
|
||||||
validateHostRequirements: () => Promise.resolve(),
|
_validateHostRequirements: () => Promise.resolve(),
|
||||||
downloadURLs: this._downloadURLs(ffmpeg),
|
downloadURLs: this._downloadURLs(ffmpeg),
|
||||||
_install: () => this._downloadExecutable(ffmpeg, ffmpegExecutable),
|
_install: () => this._downloadExecutable(ffmpeg, ffmpegExecutable),
|
||||||
_dependencyGroup: 'tools',
|
_dependencyGroup: 'tools',
|
||||||
@ -664,7 +664,7 @@ export class Registry {
|
|||||||
executablePath: () => undefined,
|
executablePath: () => undefined,
|
||||||
executablePathOrDie: () => '',
|
executablePathOrDie: () => '',
|
||||||
installType: 'download-on-demand',
|
installType: 'download-on-demand',
|
||||||
validateHostRequirements: () => Promise.resolve(),
|
_validateHostRequirements: () => Promise.resolve(),
|
||||||
downloadURLs: this._downloadURLs(android),
|
downloadURLs: this._downloadURLs(android),
|
||||||
_install: () => this._downloadExecutable(android),
|
_install: () => this._downloadExecutable(android),
|
||||||
_dependencyGroup: 'tools',
|
_dependencyGroup: 'tools',
|
||||||
@ -704,7 +704,7 @@ export class Registry {
|
|||||||
executablePath: (sdkLanguage: string) => executablePath(sdkLanguage, false),
|
executablePath: (sdkLanguage: string) => executablePath(sdkLanguage, false),
|
||||||
executablePathOrDie: (sdkLanguage: string) => executablePath(sdkLanguage, true)!,
|
executablePathOrDie: (sdkLanguage: string) => executablePath(sdkLanguage, true)!,
|
||||||
installType: install ? 'install-script' : 'none',
|
installType: install ? 'install-script' : 'none',
|
||||||
validateHostRequirements: () => Promise.resolve(),
|
_validateHostRequirements: () => Promise.resolve(),
|
||||||
_isHermeticInstallation: false,
|
_isHermeticInstallation: false,
|
||||||
_install: install,
|
_install: install,
|
||||||
};
|
};
|
||||||
@ -735,14 +735,6 @@ export class Registry {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private async _validateHostRequirements(sdkLanguage: string, browserName: BrowserName, browserDirectory: string, linuxLddDirectories: string[], dlOpenLibraries: string[], windowsExeAndDllDirectories: string[]) {
|
private async _validateHostRequirements(sdkLanguage: string, browserName: BrowserName, browserDirectory: string, linuxLddDirectories: string[], dlOpenLibraries: string[], windowsExeAndDllDirectories: string[]) {
|
||||||
if (getAsBooleanFromENV('PLAYWRIGHT_SKIP_VALIDATE_HOST_REQUIREMENTS')) {
|
|
||||||
process.stderr.write('Skipping host requirements validation logic because `PLAYWRIGHT_SKIP_VALIDATE_HOST_REQUIREMENTS` env variable is set.\n');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const distributionInfo = await getLinuxDistributionInfo();
|
|
||||||
if (browserName === 'firefox' && distributionInfo?.id === 'ubuntu' && distributionInfo?.version === '16.04')
|
|
||||||
throw new Error(`Cannot launch Firefox on Ubuntu 16.04! Minimum required Ubuntu version for Firefox browser is 20.04`);
|
|
||||||
|
|
||||||
if (os.platform() === 'linux')
|
if (os.platform() === 'linux')
|
||||||
return await validateDependenciesLinux(sdkLanguage, linuxLddDirectories.map(d => path.join(browserDirectory, d)), dlOpenLibraries);
|
return await validateDependenciesLinux(sdkLanguage, linuxLddDirectories.map(d => path.join(browserDirectory, d)), dlOpenLibraries);
|
||||||
if (os.platform() === 'win32' && os.arch() === 'x64')
|
if (os.platform() === 'win32' && os.arch() === 'x64')
|
||||||
@ -859,6 +851,37 @@ export class Registry {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async validateHostRequirementsForExecutablesIfNeeded(executables: Executable[], sdkLanguage: string) {
|
||||||
|
if (getAsBooleanFromENV('PLAYWRIGHT_SKIP_VALIDATE_HOST_REQUIREMENTS')) {
|
||||||
|
process.stderr.write('Skipping host requirements validation logic because `PLAYWRIGHT_SKIP_VALIDATE_HOST_REQUIREMENTS` env variable is set.\n');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (const executable of executables)
|
||||||
|
await this._validateHostRequirementsForExecutableIfNeeded(executable, sdkLanguage);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async _validateHostRequirementsForExecutableIfNeeded(executable: Executable, sdkLanguage: string) {
|
||||||
|
const kMaximumReValidationPeriod = 30 * 24 * 60 * 60 * 1000; // 30 days
|
||||||
|
// Executable does not require validation.
|
||||||
|
if (!executable.directory)
|
||||||
|
return;
|
||||||
|
const markerFile = path.join(executable.directory, 'DEPENDENCIES_VALIDATED');
|
||||||
|
// Executable is already validated.
|
||||||
|
if (await fs.promises.stat(markerFile).then(stat => (Date.now() - stat.mtime.getTime()) < kMaximumReValidationPeriod).catch(() => false))
|
||||||
|
return;
|
||||||
|
|
||||||
|
debugLogger.log('install', `validating host requirements for "${executable.name}"`);
|
||||||
|
try {
|
||||||
|
await executable._validateHostRequirements(sdkLanguage);
|
||||||
|
debugLogger.log('install', `validation passed for ${executable.name}`);
|
||||||
|
} catch (error) {
|
||||||
|
debugLogger.log('install', `validation failed for ${executable.name}`);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
|
||||||
|
await fs.promises.writeFile(markerFile, '').catch(() => {});
|
||||||
|
}
|
||||||
|
|
||||||
private _downloadURLs(descriptor: BrowsersJSONDescriptor): string[] {
|
private _downloadURLs(descriptor: BrowsersJSONDescriptor): string[] {
|
||||||
const paths = (DOWNLOAD_PATHS as any)[descriptor.name];
|
const paths = (DOWNLOAD_PATHS as any)[descriptor.name];
|
||||||
const downloadPathTemplate: string|undefined = paths[hostPlatform] || paths['<unknown>'];
|
const downloadPathTemplate: string|undefined = paths[hostPlatform] || paths['<unknown>'];
|
||||||
|
@ -1,8 +0,0 @@
|
|||||||
const playwright = require('playwright');
|
|
||||||
|
|
||||||
process.env.PLAYWRIGHT_SKIP_VALIDATE_HOST_REQUIREMENTS = 1;
|
|
||||||
|
|
||||||
(async () => {
|
|
||||||
const browser = await playwright.chromium.launch();
|
|
||||||
await browser.close();
|
|
||||||
})();
|
|
@ -15,17 +15,96 @@
|
|||||||
*/
|
*/
|
||||||
import { test, expect } from './npmTest';
|
import { test, expect } from './npmTest';
|
||||||
|
|
||||||
test('validate dependencies', async ({ exec }) => {
|
test.use({ isolateBrowsers: true });
|
||||||
await exec('npm i playwright');
|
|
||||||
await exec('npx playwright install chromium');
|
|
||||||
|
|
||||||
await test.step('default (on)', async () => {
|
test('should validate dependencies correctly if skipped during install', async ({ exec, writeFiles }) => {
|
||||||
const result1 = await exec('node validate-dependencies.js');
|
await exec('npm i playwright');
|
||||||
expect(result1).toContain(`PLAYWRIGHT_SKIP_VALIDATE_HOST_REQUIREMENTS`);
|
|
||||||
|
await writeFiles({
|
||||||
|
'test.js': `const { chromium } = require('playwright');
|
||||||
|
(async () => {
|
||||||
|
const browser = await chromium.launch();
|
||||||
|
const page = await browser.newPage();
|
||||||
|
await page.close();
|
||||||
|
await browser.close();
|
||||||
|
})();`,
|
||||||
});
|
});
|
||||||
|
|
||||||
await test.step('disabled (off)', async () => {
|
const result = await exec('npx playwright install chromium', {
|
||||||
|
env: {
|
||||||
|
PLAYWRIGHT_SKIP_VALIDATE_HOST_REQUIREMENTS: '1',
|
||||||
|
DEBUG: 'pw:install',
|
||||||
|
}
|
||||||
|
});
|
||||||
|
expect(result).toContain(`Skipping host requirements validation logic because`);
|
||||||
|
|
||||||
|
await test.step('should skip dependency validation for a custom executablePath', async () => {
|
||||||
const result2 = await exec('node validate-dependencies-skip-executable-path.js');
|
const result2 = await exec('node validate-dependencies-skip-executable-path.js');
|
||||||
expect(result2).not.toContain(`PLAYWRIGHT_SKIP_VALIDATE_HOST_REQUIREMENTS`);
|
expect(result2).not.toContain(`PLAYWRIGHT_SKIP_VALIDATE_HOST_REQUIREMENTS`);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
await test.step('should skip dependency validation on launch if env var is passed', async () => {
|
||||||
|
const result = await exec('node test.js', {
|
||||||
|
env: {
|
||||||
|
PLAYWRIGHT_SKIP_VALIDATE_HOST_REQUIREMENTS: '1',
|
||||||
|
}
|
||||||
|
});
|
||||||
|
expect(result).toContain(`Skipping host requirements validation logic because`);
|
||||||
|
});
|
||||||
|
|
||||||
|
await test.step('should validate dependencies (skipped during install)', async () => {
|
||||||
|
const result = await exec('node test.js', {
|
||||||
|
env: {
|
||||||
|
DEBUG: 'pw:install',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
expect(result).toContain(`validating host requirements for "chromium"`);
|
||||||
|
expect(result).not.toContain(`validating host requirements for "firefox"`);
|
||||||
|
expect(result).not.toContain(`validating host requirements for "webkit"`);
|
||||||
|
});
|
||||||
|
|
||||||
|
await test.step('should validate dependencies for a second launch (skipped during install)', async () => {
|
||||||
|
const result = await exec('node test.js', {
|
||||||
|
env: {
|
||||||
|
DEBUG: 'pw:install',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
expect(result).toContain(`validating host requirements for "chromium"`);
|
||||||
|
expect(result).not.toContain(`validating host requirements for "firefox"`);
|
||||||
|
expect(result).not.toContain(`validating host requirements for "webkit"`);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should not validate dependencies on launch if validated during install', async ({ exec, writeFiles }) => {
|
||||||
|
await exec('npm i playwright');
|
||||||
|
|
||||||
|
await writeFiles({
|
||||||
|
'test.js': `const { chromium } = require('playwright');
|
||||||
|
(async () => {
|
||||||
|
const browser = await chromium.launch();
|
||||||
|
const page = await browser.newPage();
|
||||||
|
await page.close();
|
||||||
|
await browser.close();
|
||||||
|
})();`,
|
||||||
|
});
|
||||||
|
|
||||||
|
const result = await exec('npx playwright install chromium', {
|
||||||
|
env: {
|
||||||
|
DEBUG: 'pw:install',
|
||||||
|
}
|
||||||
|
});
|
||||||
|
expect(result).toContain(`validating host requirements for "chromium"`);
|
||||||
|
expect(result).not.toContain(`validating host requirements for "firefox"`);
|
||||||
|
expect(result).not.toContain(`validating host requirements for "webkit"`);
|
||||||
|
|
||||||
|
await test.step('should not validate dependencies on launch if already validated', async () => {
|
||||||
|
const result = await exec('node test.js', {
|
||||||
|
env: {
|
||||||
|
DEBUG: 'pw:install',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
expect(result).not.toContain(`validating host requirements for "chromium"`);
|
||||||
|
expect(result).not.toContain(`validating host requirements for "firefox"`);
|
||||||
|
expect(result).not.toContain(`validating host requirements for "webkit"`);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
Loading…
x
Reference in New Issue
Block a user