Skip to content

Commit

Permalink
feat: support chrome-headless-shell (#10739)
Browse files Browse the repository at this point in the history
  • Loading branch information
mathiasbynens committed Aug 16, 2023
1 parent e12b558 commit 416843b
Show file tree
Hide file tree
Showing 10 changed files with 413 additions and 9 deletions.
13 changes: 7 additions & 6 deletions docs/browsers-api/browsers.browser.md
Expand Up @@ -14,9 +14,10 @@ export declare enum Browser

## Enumeration Members

| Member | Value | Description |
| ------------ | ------------------------------------- | ----------- |
| CHROME | <code>&quot;chrome&quot;</code> | |
| CHROMEDRIVER | <code>&quot;chromedriver&quot;</code> | |
| CHROMIUM | <code>&quot;chromium&quot;</code> | |
| FIREFOX | <code>&quot;firefox&quot;</code> | |
| Member | Value | Description |
| ------------------- | ---------------------------------------------- | ----------- |
| CHROME | <code>&quot;chrome&quot;</code> | |
| CHROMEDRIVER | <code>&quot;chromedriver&quot;</code> | |
| CHROMEHEADLESSSHELL | <code>&quot;chrome-headless-shell&quot;</code> | |
| CHROMIUM | <code>&quot;chromium&quot;</code> | |
| FIREFOX | <code>&quot;firefox&quot;</code> | |
12 changes: 12 additions & 0 deletions packages/browsers/src/CLI.ts
Expand Up @@ -152,6 +152,18 @@ export class CLI {
'$0 install chromedriver@115.0.5790',
'Install the latest available patch (115.0.5790.X) build for ChromeDriver.'
);
yargs.example(
'$0 install chrome-headless-shell',
'Install the latest available chrome-headless-shell build.'
);
yargs.example(
'$0 install chrome-headless-shell@beta',
'Install the latest available chrome-headless-shell build corresponding to the Beta channel.'
);
yargs.example(
'$0 install chrome-headless-shell@118',
'Install the latest available chrome-headless-shell 118 build.'
);
yargs.example(
'$0 install chromium@1083080',
'Install the revision 1083080 of the Chromium browser.'
Expand Down
32 changes: 32 additions & 0 deletions packages/browsers/src/browser-data/browser-data.ts
Expand Up @@ -14,6 +14,7 @@
* limitations under the License.
*/

import * as chromeHeadlessShell from './chrome-headless-shell.js';
import * as chrome from './chrome.js';
import * as chromedriver from './chromedriver.js';
import * as chromium from './chromium.js';
Expand All @@ -30,20 +31,23 @@ export {ProfileOptions};

export const downloadUrls = {
[Browser.CHROMEDRIVER]: chromedriver.resolveDownloadUrl,
[Browser.CHROMEHEADLESSSHELL]: chromeHeadlessShell.resolveDownloadUrl,
[Browser.CHROME]: chrome.resolveDownloadUrl,
[Browser.CHROMIUM]: chromium.resolveDownloadUrl,
[Browser.FIREFOX]: firefox.resolveDownloadUrl,
};

export const downloadPaths = {
[Browser.CHROMEDRIVER]: chromedriver.resolveDownloadPath,
[Browser.CHROMEHEADLESSSHELL]: chromeHeadlessShell.resolveDownloadPath,
[Browser.CHROME]: chrome.resolveDownloadPath,
[Browser.CHROMIUM]: chromium.resolveDownloadPath,
[Browser.FIREFOX]: firefox.resolveDownloadPath,
};

export const executablePathByBrowser = {
[Browser.CHROMEDRIVER]: chromedriver.relativeExecutablePath,
[Browser.CHROMEHEADLESSSHELL]: chromeHeadlessShell.relativeExecutablePath,
[Browser.CHROME]: chrome.relativeExecutablePath,
[Browser.CHROMIUM]: chromium.relativeExecutablePath,
[Browser.FIREFOX]: firefox.relativeExecutablePath,
Expand Down Expand Up @@ -111,6 +115,33 @@ export async function resolveBuildId(
}
return tag;
}
case Browser.CHROMEHEADLESSSHELL: {
switch (tag) {
case BrowserTag.LATEST:
case BrowserTag.CANARY:
return await chromeHeadlessShell.resolveBuildId(
ChromeReleaseChannel.CANARY
);
case BrowserTag.BETA:
return await chromeHeadlessShell.resolveBuildId(
ChromeReleaseChannel.BETA
);
case BrowserTag.DEV:
return await chromeHeadlessShell.resolveBuildId(
ChromeReleaseChannel.DEV
);
case BrowserTag.STABLE:
return await chromeHeadlessShell.resolveBuildId(
ChromeReleaseChannel.STABLE
);
default:
const result = await chromeHeadlessShell.resolveBuildId(tag);
if (result) {
return result;
}
}
return tag;
}
case Browser.CHROMIUM:
switch (tag as BrowserTag) {
case BrowserTag.LATEST:
Expand Down Expand Up @@ -154,6 +185,7 @@ export function resolveSystemExecutablePath(
): string {
switch (browser) {
case Browser.CHROMEDRIVER:
case Browser.CHROMEHEADLESSSHELL:
case Browser.FIREFOX:
case Browser.CHROMIUM:
throw new Error(
Expand Down
79 changes: 79 additions & 0 deletions packages/browsers/src/browser-data/chrome-headless-shell.ts
@@ -0,0 +1,79 @@
/**
* Copyright 2023 Google Inc. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import path from 'path';

import {BrowserPlatform} from './types.js';

function folder(platform: BrowserPlatform): string {
switch (platform) {
case BrowserPlatform.LINUX:
return 'linux64';
case BrowserPlatform.MAC_ARM:
return 'mac-arm64';
case BrowserPlatform.MAC:
return 'mac-x64';
case BrowserPlatform.WIN32:
return 'win32';
case BrowserPlatform.WIN64:
return 'win64';
}
}

export function resolveDownloadUrl(
platform: BrowserPlatform,
buildId: string,
baseUrl = 'https://edgedl.me.gvt1.com/edgedl/chrome/chrome-for-testing'
): string {
return `${baseUrl}/${resolveDownloadPath(platform, buildId).join('/')}`;
}

export function resolveDownloadPath(
platform: BrowserPlatform,
buildId: string
): string[] {
return [
buildId,
folder(platform),
`chrome-headless-shell-${folder(platform)}.zip`,
];
}

export function relativeExecutablePath(
platform: BrowserPlatform,
_buildId: string
): string {
switch (platform) {
case BrowserPlatform.MAC:
case BrowserPlatform.MAC_ARM:
return path.join(
'chrome-headless-shell-' + folder(platform),
'chrome-headless-shell'
);
case BrowserPlatform.LINUX:
return path.join(
'chrome-headless-shell-linux64',
'chrome-headless-shell'
);
case BrowserPlatform.WIN32:
case BrowserPlatform.WIN64:
return path.join(
'chrome-headless-shell-' + folder(platform),
'chrome-headless-shell.exe'
);
}
}

export {resolveBuildId} from './chrome.js';
1 change: 1 addition & 0 deletions packages/browsers/src/browser-data/types.ts
Expand Up @@ -24,6 +24,7 @@ import * as firefox from './firefox.js';
*/
export enum Browser {
CHROME = 'chrome',
CHROMEHEADLESSSHELL = 'chrome-headless-shell',
CHROMIUM = 'chromium',
FIREFOX = 'firefox',
CHROMEDRIVER = 'chromedriver',
Expand Down
@@ -0,0 +1,81 @@
/**
* Copyright 2023 Google Inc. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import assert from 'assert';
import path from 'path';

import {BrowserPlatform} from '../../../lib/cjs/browser-data/browser-data.js';
import {
resolveDownloadUrl,
relativeExecutablePath,
resolveBuildId,
} from '../../../lib/cjs/browser-data/chrome-headless-shell.js';

describe('chrome-headless-shell', () => {
it('should resolve download URLs', () => {
assert.strictEqual(
resolveDownloadUrl(BrowserPlatform.LINUX, '118.0.5950.0'),
'https://edgedl.me.gvt1.com/edgedl/chrome/chrome-for-testing/118.0.5950.0/linux64/chrome-headless-shell-linux64.zip'
);
assert.strictEqual(
resolveDownloadUrl(BrowserPlatform.MAC, '118.0.5950.0'),
'https://edgedl.me.gvt1.com/edgedl/chrome/chrome-for-testing/118.0.5950.0/mac-x64/chrome-headless-shell-mac-x64.zip'
);
assert.strictEqual(
resolveDownloadUrl(BrowserPlatform.MAC_ARM, '118.0.5950.0'),
'https://edgedl.me.gvt1.com/edgedl/chrome/chrome-for-testing/118.0.5950.0/mac-arm64/chrome-headless-shell-mac-arm64.zip'
);
assert.strictEqual(
resolveDownloadUrl(BrowserPlatform.WIN32, '118.0.5950.0'),
'https://edgedl.me.gvt1.com/edgedl/chrome/chrome-for-testing/118.0.5950.0/win32/chrome-headless-shell-win32.zip'
);
assert.strictEqual(
resolveDownloadUrl(BrowserPlatform.WIN64, '118.0.5950.0'),
'https://edgedl.me.gvt1.com/edgedl/chrome/chrome-for-testing/118.0.5950.0/win64/chrome-headless-shell-win64.zip'
);
});

it('should resolve milestones', async () => {
assert.strictEqual(await resolveBuildId('118'), '118.0.5950.0');
});

it('should resolve build prefix', async () => {
assert.strictEqual(await resolveBuildId('118.0.5950'), '118.0.5950.0');
});

it('should resolve executable paths', () => {
assert.strictEqual(
relativeExecutablePath(BrowserPlatform.LINUX, '12372323'),
path.join('chrome-headless-shell-linux64', 'chrome-headless-shell')
);
assert.strictEqual(
relativeExecutablePath(BrowserPlatform.MAC, '12372323'),
path.join('chrome-headless-shell-mac-x64/', 'chrome-headless-shell')
);
assert.strictEqual(
relativeExecutablePath(BrowserPlatform.MAC_ARM, '12372323'),
path.join('chrome-headless-shell-mac-arm64', 'chrome-headless-shell')
);
assert.strictEqual(
relativeExecutablePath(BrowserPlatform.WIN32, '12372323'),
path.join('chrome-headless-shell-win32', 'chrome-headless-shell.exe')
);
assert.strictEqual(
relativeExecutablePath(BrowserPlatform.WIN64, '12372323'),
path.join('chrome-headless-shell-win64', 'chrome-headless-shell.exe')
);
});
});
91 changes: 91 additions & 0 deletions packages/browsers/test/src/chrome-headless-shell/cli.spec.ts
@@ -0,0 +1,91 @@
/**
* Copyright 2023 Google Inc. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import assert from 'assert';
import fs from 'fs';
import os from 'os';
import path from 'path';

import {CLI} from '../../../lib/cjs/CLI.js';
import {
createMockedReadlineInterface,
setupTestServer,
getServerUrl,
} from '../utils.js';
import {testChromeHeadlessShellBuildId} from '../versions.js';

describe('chrome-headless-shell CLI', function () {
this.timeout(90000);

setupTestServer();

let tmpDir = '/tmp/puppeteer-browsers-test';

beforeEach(() => {
tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'puppeteer-browsers-test'));
});

afterEach(async () => {
await new CLI(tmpDir, createMockedReadlineInterface('yes')).run([
'npx',
'@puppeteer/browsers',
'clear',
`--path=${tmpDir}`,
`--base-url=${getServerUrl()}`,
]);
});

it('should download chrome-headless-shell binaries', async () => {
await new CLI(tmpDir).run([
'npx',
'@puppeteer/browsers',
'install',
`chrome-headless-shell@${testChromeHeadlessShellBuildId}`,
`--path=${tmpDir}`,
'--platform=linux',
`--base-url=${getServerUrl()}`,
]);
assert.ok(
fs.existsSync(
path.join(
tmpDir,
'chrome-headless-shell',
`linux-${testChromeHeadlessShellBuildId}`,
'chrome-headless-shell-linux64',
'chrome-headless-shell'
)
)
);

await new CLI(tmpDir, createMockedReadlineInterface('no')).run([
'npx',
'@puppeteer/browsers',
'clear',
`--path=${tmpDir}`,
]);
assert.ok(
fs.existsSync(
path.join(
tmpDir,
'chrome-headless-shell',
`linux-${testChromeHeadlessShellBuildId}`,
'chrome-headless-shell-linux64',
'chrome-headless-shell'
)
)
);
});
});

0 comments on commit 416843b

Please sign in to comment.