diff --git a/src/node/Launcher.ts b/src/node/Launcher.ts index 4c87f0dbd43e9..e80c1690a6271 100644 --- a/src/node/Launcher.ts +++ b/src/node/Launcher.ts @@ -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 }; diff --git a/test/launcher.spec.ts b/test/launcher.spec.ts index 1570870337ddd..7fa0744562cd6 100644 --- a/test/launcher.spec.ts +++ b/test/launcher.spec.ts @@ -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(); + } + ); + }); + }); }); });