fix: always use ENV executable path when present (#7985)

Some recent changes to allow arm64 environments (including M1 macs) to
launch a chromium installation successfully before arm-compatible builds
were downloadable prevented the usage of PUPPETEER_EXECUTABLE_PATH in
some environments. Currently, when the platform is not darwin and the
arch is arm64, an executable cannot be specified using the environment
variable.

Generally speaking, environment variables have highest precedence for
options such as this since they depend on system configuration.

These change:

1. allow the ENV variable to always be used when defined and not
   specified in LaunchOptions (and when not puppeteer-core)
2. Retain the existing behavior of assuming /usr/bin/chromium-browser on
   platforms like Ubuntu (exact if-conditions preserved to avoid any
   breaking changes)
3. Add some tests for this particular portion of the code.
This commit is contained in:
Josh Bielick 2022-02-11 08:07:31 -05:00 committed by GitHub
parent 7e2b47c974
commit 6d6ea9bf59
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 104 additions and 17 deletions

View File

@ -146,15 +146,9 @@ class ChromeLauncher implements ProductLauncher {
chromeExecutable = executablePathForChannel(channel);
} else if (!executablePath) {
// Use Intel x86 builds on Apple M1 until native macOS arm64
// Chromium builds are available.
if (os.platform() !== 'darwin' && os.arch() === 'arm64') {
chromeExecutable = '/usr/bin/chromium-browser';
} else {
const { missingText, executablePath } = resolveExecutablePath(this);
if (missingText) throw new Error(missingText);
chromeExecutable = executablePath;
}
const { missingText, executablePath } = resolveExecutablePath(this);
if (missingText) throw new Error(missingText);
chromeExecutable = executablePath;
}
if (!chromeExecutable) {
@ -799,9 +793,11 @@ function resolveExecutablePath(launcher: ChromeLauncher | FirefoxLauncher): {
executablePath: string;
missingText?: string;
} {
const { product, _isPuppeteerCore, _projectRoot, _preferredRevision } =
launcher;
let downloadPath: string | undefined;
// puppeteer-core doesn't take into account PUPPETEER_* env variables.
if (!launcher._isPuppeteerCore) {
if (!_isPuppeteerCore) {
const executablePath =
process.env.PUPPETEER_EXECUTABLE_PATH ||
process.env.npm_config_puppeteer_executable_path ||
@ -813,22 +809,31 @@ function resolveExecutablePath(launcher: ChromeLauncher | FirefoxLauncher): {
: undefined;
return { executablePath, missingText };
}
const ubuntuChromiumPath = '/usr/bin/chromium-browser';
if (
product === 'chrome' &&
os.platform() !== 'darwin' &&
os.arch() === 'arm64' &&
fs.existsSync(ubuntuChromiumPath)
) {
return { executablePath: ubuntuChromiumPath, missingText: undefined };
}
downloadPath =
process.env.PUPPETEER_DOWNLOAD_PATH ||
process.env.npm_config_puppeteer_download_path ||
process.env.npm_package_config_puppeteer_download_path;
}
if (!launcher._projectRoot) {
if (!_projectRoot) {
throw new Error(
'_projectRoot is undefined. Unable to create a BrowserFetcher.'
);
}
const browserFetcher = new BrowserFetcher(launcher._projectRoot, {
product: launcher.product,
const browserFetcher = new BrowserFetcher(_projectRoot, {
product: product,
path: downloadPath,
});
if (!launcher._isPuppeteerCore && launcher.product === 'chrome') {
if (!_isPuppeteerCore && product === 'chrome') {
const revision = process.env['PUPPETEER_CHROMIUM_REVISION'];
if (revision) {
const revisionInfo = browserFetcher.revisionInfo(revision);
@ -839,13 +844,13 @@ function resolveExecutablePath(launcher: ChromeLauncher | FirefoxLauncher): {
return { executablePath: revisionInfo.executablePath, missingText };
}
}
const revisionInfo = browserFetcher.revisionInfo(launcher._preferredRevision);
const revisionInfo = browserFetcher.revisionInfo(_preferredRevision);
const firefoxHelp = `Run \`PUPPETEER_PRODUCT=firefox npm install\` to download a supported Firefox browser binary.`;
const chromeHelp = `Run \`npm install\` to download the correct Chromium revision (${launcher._preferredRevision}).`;
const missingText = !revisionInfo.local
? `Could not find expected browser (${launcher.product}) locally. ${
launcher.product === 'chrome' ? chromeHelp : firefoxHelp
? `Could not find expected browser (${product}) locally. ${
product === 'chrome' ? chromeHelp : firefoxHelp
}`
: undefined;
return { executablePath: revisionInfo.executablePath, missingText };

View File

@ -733,6 +733,88 @@ describe('Launcher specs', function () {
const executablePath = puppeteer.executablePath('chrome');
expect(executablePath).toBeTruthy();
});
describe('when PUPPETEER_EXECUTABLE_PATH is set', () => {
const sandbox = sinon.createSandbox();
beforeEach(() => {
process.env.PUPPETEER_EXECUTABLE_PATH = '';
sandbox
.stub(process.env, 'PUPPETEER_EXECUTABLE_PATH')
.value('SOME_CUSTOM_EXECUTABLE');
});
afterEach(() => sandbox.restore());
it('its value is returned', async () => {
const { puppeteer } = getTestState();
const executablePath = puppeteer.executablePath();
expect(executablePath).toEqual('SOME_CUSTOM_EXECUTABLE');
});
});
describe('when the product is chrome, platform is not darwin, and arch is arm64', () => {
describe('and the executable exists', () => {
itChromeOnly('returns /usr/bin/chromium-browser', async () => {
const { puppeteer } = getTestState();
const osPlatformStub = sinon.stub(os, 'platform').returns('linux');
const osArchStub = sinon.stub(os, 'arch').returns('arm64');
const fsExistsStub = sinon.stub(fs, 'existsSync');
fsExistsStub.withArgs('/usr/bin/chromium-browser').returns(true);
const executablePath = puppeteer.executablePath();
expect(executablePath).toEqual('/usr/bin/chromium-browser');
osPlatformStub.restore();
osArchStub.restore();
fsExistsStub.restore();
});
describe('and PUPPETEER_EXECUTABLE_PATH is set', () => {
const sandbox = sinon.createSandbox();
beforeEach(() => {
process.env.PUPPETEER_EXECUTABLE_PATH = '';
sandbox
.stub(process.env, 'PUPPETEER_EXECUTABLE_PATH')
.value('SOME_CUSTOM_EXECUTABLE');
});
afterEach(() => sandbox.restore());
it('its value is returned', async () => {
const { puppeteer } = getTestState();
const executablePath = puppeteer.executablePath();
expect(executablePath).toEqual('SOME_CUSTOM_EXECUTABLE');
});
});
});
describe('and the executable does not exist', () => {
itChromeOnly(
'does not return /usr/bin/chromium-browser',
async () => {
const { puppeteer } = getTestState();
const osPlatformStub = sinon
.stub(os, 'platform')
.returns('linux');
const osArchStub = sinon.stub(os, 'arch').returns('arm64');
const fsExistsStub = sinon.stub(fs, 'existsSync');
fsExistsStub.withArgs('/usr/bin/chromium-browser').returns(false);
const executablePath = puppeteer.executablePath();
expect(executablePath).not.toEqual('/usr/bin/chromium-browser');
osPlatformStub.restore();
osArchStub.restore();
fsExistsStub.restore();
}
);
});
});
});
});