chore: introduce @puppeteer/browsers with a fetch method implementation (#9647)
Co-authored-by: Nikolay Vitkov <34244704+Lightning00Blade@users.noreply.github.com>
This commit is contained in:
parent
6ada628f39
commit
b50e43bc17
38
.github/workflows/ci.yml
vendored
38
.github/workflows/ci.yml
vendored
@ -84,6 +84,9 @@ jobs:
|
|||||||
ng-schematics:
|
ng-schematics:
|
||||||
- '.github/workflows/ci.yml'
|
- '.github/workflows/ci.yml'
|
||||||
- 'packages/ng-schematics/**'
|
- 'packages/ng-schematics/**'
|
||||||
|
browsers:
|
||||||
|
- '.github/workflows/ci.yml'
|
||||||
|
- 'packages/browsers/**'
|
||||||
|
|
||||||
deploy-docs:
|
deploy-docs:
|
||||||
needs: check-changes
|
needs: check-changes
|
||||||
@ -368,3 +371,38 @@ jobs:
|
|||||||
run: npm ci --ignore-scripts
|
run: npm ci --ignore-scripts
|
||||||
- name: Run tests
|
- name: Run tests
|
||||||
run: npm run test --workspace @puppeteer/ng-schematics
|
run: npm run test --workspace @puppeteer/ng-schematics
|
||||||
|
|
||||||
|
browsers-tests:
|
||||||
|
name: Browsers tests on ${{ matrix.os }}
|
||||||
|
runs-on: ${{ matrix.os }}
|
||||||
|
needs: check-changes
|
||||||
|
if: ${{ contains(fromJSON(needs.check-changes.outputs.changes), 'browsers') }}
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
os:
|
||||||
|
- ubuntu-latest
|
||||||
|
- windows-latest
|
||||||
|
- macos-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
- name: Set up Node.js
|
||||||
|
uses: actions/setup-node@v3.5.1
|
||||||
|
with:
|
||||||
|
cache: npm
|
||||||
|
node-version: latest
|
||||||
|
- name: Install dependencies
|
||||||
|
run: npm ci --ignore-scripts
|
||||||
|
- name: Run tests
|
||||||
|
run: npm run test --workspace @puppeteer/browsers
|
||||||
|
|
||||||
|
browsers-tests-required:
|
||||||
|
name: '[Required] Test the browsers packages'
|
||||||
|
needs: [check-changes, browsers-tests]
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
if: ${{ always() }}
|
||||||
|
steps:
|
||||||
|
- if: ${{ needs.browsers-tests.result != 'success' && contains(fromJSON(needs.check-changes.outputs.changes), 'browsers') }}
|
||||||
|
run: 'exit 1'
|
||||||
|
- run: 'exit 0'
|
||||||
|
57
package-lock.json
generated
57
package-lock.json
generated
@ -1385,6 +1385,10 @@
|
|||||||
"resolved": "test",
|
"resolved": "test",
|
||||||
"link": true
|
"link": true
|
||||||
},
|
},
|
||||||
|
"node_modules/@puppeteer/browsers": {
|
||||||
|
"resolved": "packages/browsers",
|
||||||
|
"link": true
|
||||||
|
},
|
||||||
"node_modules/@puppeteer/ng-schematics": {
|
"node_modules/@puppeteer/ng-schematics": {
|
||||||
"resolved": "packages/ng-schematics",
|
"resolved": "packages/ng-schematics",
|
||||||
"link": true
|
"link": true
|
||||||
@ -8678,6 +8682,39 @@
|
|||||||
"url": "https://github.com/sponsors/colinhacks"
|
"url": "https://github.com/sponsors/colinhacks"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"packages/browsers": {
|
||||||
|
"name": "@puppeteer/browsers",
|
||||||
|
"version": "0.0.1",
|
||||||
|
"license": "Apache-2.0",
|
||||||
|
"dependencies": {
|
||||||
|
"debug": "4.3.4",
|
||||||
|
"extract-zip": "2.0.1",
|
||||||
|
"https-proxy-agent": "5.0.1",
|
||||||
|
"proxy-from-env": "1.1.0",
|
||||||
|
"tar-fs": "2.1.1",
|
||||||
|
"unbzip2-stream": "1.4.3"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@types/node": "^14.15.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=14.1.0"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"typescript": ">= 4.7.4"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"typescript": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"packages/browsers/node_modules/@types/node": {
|
||||||
|
"version": "14.18.36",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/node/-/node-14.18.36.tgz",
|
||||||
|
"integrity": "sha512-FXKWbsJ6a1hIrRxv+FoukuHnGTgEzKYGi7kilfMae96AL9UNkPFNWJEEYWzdRI9ooIkbr4AKldyuSTLql06vLQ==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"packages/ng-schematics": {
|
"packages/ng-schematics": {
|
||||||
"name": "@puppeteer/ng-schematics",
|
"name": "@puppeteer/ng-schematics",
|
||||||
"version": "0.1.0",
|
"version": "0.1.0",
|
||||||
@ -10040,6 +10077,26 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"@puppeteer/browsers": {
|
||||||
|
"version": "file:packages/browsers",
|
||||||
|
"requires": {
|
||||||
|
"@types/node": "^14.15.0",
|
||||||
|
"debug": "4.3.4",
|
||||||
|
"extract-zip": "2.0.1",
|
||||||
|
"https-proxy-agent": "5.0.1",
|
||||||
|
"proxy-from-env": "1.1.0",
|
||||||
|
"tar-fs": "2.1.1",
|
||||||
|
"unbzip2-stream": "1.4.3"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@types/node": {
|
||||||
|
"version": "14.18.36",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/node/-/node-14.18.36.tgz",
|
||||||
|
"integrity": "sha512-FXKWbsJ6a1hIrRxv+FoukuHnGTgEzKYGi7kilfMae96AL9UNkPFNWJEEYWzdRI9ooIkbr4AKldyuSTLql06vLQ==",
|
||||||
|
"dev": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"@puppeteer/ng-schematics": {
|
"@puppeteer/ng-schematics": {
|
||||||
"version": "file:packages/ng-schematics",
|
"version": "file:packages/ng-schematics",
|
||||||
"requires": {
|
"requires": {
|
||||||
|
6
packages/browsers/.mocharc.cjs
Normal file
6
packages/browsers/.mocharc.cjs
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
module.exports = {
|
||||||
|
logLevel: 'debug',
|
||||||
|
spec: 'test/build/**/*.spec.js',
|
||||||
|
exit: !!process.env.CI,
|
||||||
|
reporter: 'spec',
|
||||||
|
};
|
3
packages/browsers/README.md
Normal file
3
packages/browsers/README.md
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
# @puppeteer/browsers
|
||||||
|
|
||||||
|
TODO
|
81
packages/browsers/package.json
Normal file
81
packages/browsers/package.json
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
{
|
||||||
|
"name": "@puppeteer/browsers",
|
||||||
|
"version": "0.0.1",
|
||||||
|
"description": "Download and launch browsers",
|
||||||
|
"scripts": {
|
||||||
|
"build": "wireit",
|
||||||
|
"build:test": "wireit",
|
||||||
|
"clean": "tsc --build --clean && rimraf lib",
|
||||||
|
"test": "wireit"
|
||||||
|
},
|
||||||
|
"wireit": {
|
||||||
|
"build": {
|
||||||
|
"command": "tsc -b",
|
||||||
|
"files": [
|
||||||
|
"src/**/*.ts",
|
||||||
|
"tsconfig.json"
|
||||||
|
],
|
||||||
|
"output": [
|
||||||
|
"lib/**"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"build:test": {
|
||||||
|
"command": "tsc -b test/src/tsconfig.json",
|
||||||
|
"files": [
|
||||||
|
"test/**/*.ts",
|
||||||
|
"test/src/tsconfig.json"
|
||||||
|
],
|
||||||
|
"output": [
|
||||||
|
"test/build/**"
|
||||||
|
],
|
||||||
|
"dependencies": [
|
||||||
|
"build"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"test": {
|
||||||
|
"command": "mocha",
|
||||||
|
"files": [
|
||||||
|
".mocharc.cjs"
|
||||||
|
],
|
||||||
|
"dependencies": [
|
||||||
|
"build:test"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"keywords": [
|
||||||
|
"puppeteer",
|
||||||
|
"browsers"
|
||||||
|
],
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/puppeteer/puppeteer/tree/main/packages/browsers"
|
||||||
|
},
|
||||||
|
"author": "The Chromium Authors",
|
||||||
|
"license": "Apache-2.0",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=14.1.0"
|
||||||
|
},
|
||||||
|
"files": [
|
||||||
|
"lib",
|
||||||
|
"!*.tsbuildinfo"
|
||||||
|
],
|
||||||
|
"dependencies": {
|
||||||
|
"debug": "4.3.4",
|
||||||
|
"extract-zip": "2.0.1",
|
||||||
|
"https-proxy-agent": "5.0.1",
|
||||||
|
"proxy-from-env": "1.1.0",
|
||||||
|
"tar-fs": "2.1.1",
|
||||||
|
"unbzip2-stream": "1.4.3"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@types/node": "^14.15.0"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"typescript": ">= 4.7.4"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"typescript": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
26
packages/browsers/src/browsers/browsers.ts
Normal file
26
packages/browsers/src/browsers/browsers.ts
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
/**
|
||||||
|
* 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 * as chrome from './chrome.js';
|
||||||
|
import * as firefox from './firefox.js';
|
||||||
|
import {Browser, BrowserPlatform} from './types.js';
|
||||||
|
|
||||||
|
export const downloadUrls = {
|
||||||
|
[Browser.CHROME]: chrome.resolveDownloadUrl,
|
||||||
|
[Browser.FIREFOX]: firefox.resolveDownloadUrl,
|
||||||
|
};
|
||||||
|
|
||||||
|
export {Browser, BrowserPlatform};
|
57
packages/browsers/src/browsers/chrome.ts
Normal file
57
packages/browsers/src/browsers/chrome.ts
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
/**
|
||||||
|
* 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 {BrowserPlatform} from './types.js';
|
||||||
|
|
||||||
|
function archive(platform: BrowserPlatform, revision: string): string {
|
||||||
|
switch (platform) {
|
||||||
|
case BrowserPlatform.LINUX:
|
||||||
|
return 'chrome-linux';
|
||||||
|
case BrowserPlatform.MAC_ARM:
|
||||||
|
case BrowserPlatform.MAC:
|
||||||
|
return 'chrome-mac';
|
||||||
|
case BrowserPlatform.WIN32:
|
||||||
|
case BrowserPlatform.WIN64:
|
||||||
|
// Windows archive name changed at r591479.
|
||||||
|
return parseInt(revision, 10) > 591479 ? 'chrome-win' : 'chrome-win32';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function folder(platform: BrowserPlatform): string {
|
||||||
|
switch (platform) {
|
||||||
|
case BrowserPlatform.LINUX:
|
||||||
|
return 'Linux_x64';
|
||||||
|
case BrowserPlatform.MAC_ARM:
|
||||||
|
return 'Mac_Arm';
|
||||||
|
case BrowserPlatform.MAC:
|
||||||
|
return 'Mac';
|
||||||
|
case BrowserPlatform.WIN32:
|
||||||
|
return 'Win';
|
||||||
|
case BrowserPlatform.WIN64:
|
||||||
|
return 'Win_x64';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function resolveDownloadUrl(
|
||||||
|
platform: BrowserPlatform,
|
||||||
|
revision: string,
|
||||||
|
baseUrl = 'https://storage.googleapis.com/chromium-browser-snapshots'
|
||||||
|
): string {
|
||||||
|
return `${baseUrl}/${folder(platform)}/${revision}/${archive(
|
||||||
|
platform,
|
||||||
|
revision
|
||||||
|
)}.zip`;
|
||||||
|
}
|
39
packages/browsers/src/browsers/firefox.ts
Normal file
39
packages/browsers/src/browsers/firefox.ts
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
/**
|
||||||
|
* 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 {BrowserPlatform} from './types.js';
|
||||||
|
|
||||||
|
function archive(platform: BrowserPlatform, revision: string): string {
|
||||||
|
switch (platform) {
|
||||||
|
case BrowserPlatform.LINUX:
|
||||||
|
return `firefox-${revision}.en-US.${platform}-x86_64.tar.bz2`;
|
||||||
|
case BrowserPlatform.MAC_ARM:
|
||||||
|
case BrowserPlatform.MAC:
|
||||||
|
return `firefox-${revision}.en-US.mac.dmg`;
|
||||||
|
case BrowserPlatform.WIN32:
|
||||||
|
return `firefox-${revision}.en-US.${platform}.zip`;
|
||||||
|
case BrowserPlatform.WIN64:
|
||||||
|
return `firefox-${revision}.en-US.${platform}.zip`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function resolveDownloadUrl(
|
||||||
|
platform: BrowserPlatform,
|
||||||
|
revision: string,
|
||||||
|
baseUrl = 'https://archive.mozilla.org/pub/firefox/nightly/latest-mozilla-central'
|
||||||
|
): string {
|
||||||
|
return `${baseUrl}/${archive(platform, revision)}`;
|
||||||
|
}
|
43
packages/browsers/src/browsers/types.ts
Normal file
43
packages/browsers/src/browsers/types.ts
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
/**
|
||||||
|
* 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 * as chrome from './chrome.js';
|
||||||
|
import * as firefox from './firefox.js';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Supported browsers.
|
||||||
|
*/
|
||||||
|
export enum Browser {
|
||||||
|
CHROME = 'chrome',
|
||||||
|
FIREFOX = 'firefox',
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Platform names used to identify a OS platfrom x architecture combination in the way
|
||||||
|
* that is relevant for the browser download.
|
||||||
|
*/
|
||||||
|
export enum BrowserPlatform {
|
||||||
|
LINUX = 'linux',
|
||||||
|
MAC = 'mac',
|
||||||
|
MAC_ARM = 'mac_arm',
|
||||||
|
WIN32 = 'win32',
|
||||||
|
WIN64 = 'win64',
|
||||||
|
}
|
||||||
|
|
||||||
|
export const downloadUrls = {
|
||||||
|
[Browser.CHROME]: chrome.resolveDownloadUrl,
|
||||||
|
[Browser.FIREFOX]: firefox.resolveDownloadUrl,
|
||||||
|
};
|
19
packages/browsers/src/debug.ts
Normal file
19
packages/browsers/src/debug.ts
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
/**
|
||||||
|
* 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 debug from 'debug';
|
||||||
|
|
||||||
|
export {debug};
|
171
packages/browsers/src/fetch.ts
Normal file
171
packages/browsers/src/fetch.ts
Normal file
@ -0,0 +1,171 @@
|
|||||||
|
/**
|
||||||
|
* Copyright 2017 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 {existsSync} from 'fs';
|
||||||
|
import {mkdir, unlink} from 'fs/promises';
|
||||||
|
import os from 'os';
|
||||||
|
import path from 'path';
|
||||||
|
|
||||||
|
import {debug} from './debug.js';
|
||||||
|
import {Browser, BrowserPlatform, downloadUrls} from './browsers/browsers.js';
|
||||||
|
import {downloadFile, headHttpRequest} from './httpUtil.js';
|
||||||
|
import assert from 'assert';
|
||||||
|
import {unpackArchive} from './fileUtil.js';
|
||||||
|
|
||||||
|
const debugFetch = debug('puppeteer:browsers:fetcher');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @public
|
||||||
|
*/
|
||||||
|
export interface Options {
|
||||||
|
/**
|
||||||
|
* Determines the path to download browsers to.
|
||||||
|
*/
|
||||||
|
outputDir: string;
|
||||||
|
/**
|
||||||
|
* Determines which platform the browser will be suited for.
|
||||||
|
*
|
||||||
|
* @defaultValue Auto-detected.
|
||||||
|
*/
|
||||||
|
platform?: BrowserPlatform;
|
||||||
|
/**
|
||||||
|
* Determines which browser to fetch.
|
||||||
|
*/
|
||||||
|
browser: Browser;
|
||||||
|
/**
|
||||||
|
* Determines which revision to dowloand. Revision should uniquely identify
|
||||||
|
* binaries and they are used for caching.
|
||||||
|
*/
|
||||||
|
revision: string;
|
||||||
|
/**
|
||||||
|
* Provides information about the progress of the download.
|
||||||
|
*/
|
||||||
|
progressCallback?: (downloadedBytes: number, totalBytes: number) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type InstalledBrowser = {
|
||||||
|
path: string;
|
||||||
|
browser: Browser;
|
||||||
|
revision: string;
|
||||||
|
platform: BrowserPlatform;
|
||||||
|
};
|
||||||
|
|
||||||
|
export async function fetch(options: Options): Promise<InstalledBrowser> {
|
||||||
|
options.platform ??= detectPlatform();
|
||||||
|
if (!options.platform) {
|
||||||
|
throw new Error(
|
||||||
|
`Cannot download a binary for the provided platform: ${os.platform()} (${os.arch()})`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
const url = getDownloadUrl(
|
||||||
|
options.browser,
|
||||||
|
options.platform,
|
||||||
|
options.revision
|
||||||
|
);
|
||||||
|
const fileName = url.toString().split('/').pop();
|
||||||
|
assert(fileName, `A malformed download URL was found: ${url}.`);
|
||||||
|
const archivePath = path.join(options.outputDir, fileName);
|
||||||
|
const outputPath = path.resolve(
|
||||||
|
options.outputDir,
|
||||||
|
`${options.platform}-${options.revision}`
|
||||||
|
);
|
||||||
|
if (existsSync(outputPath)) {
|
||||||
|
return {
|
||||||
|
path: outputPath,
|
||||||
|
browser: options.browser,
|
||||||
|
platform: options.platform,
|
||||||
|
revision: options.revision,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
if (!existsSync(options.outputDir)) {
|
||||||
|
await mkdir(options.outputDir, {recursive: true});
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
debugFetch(`Downloading binary from ${url}`);
|
||||||
|
await downloadFile(url, archivePath, options.progressCallback);
|
||||||
|
debugFetch(`Installing ${archivePath} to ${outputPath}`);
|
||||||
|
await unpackArchive(archivePath, outputPath);
|
||||||
|
} finally {
|
||||||
|
if (existsSync(archivePath)) {
|
||||||
|
await unlink(archivePath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
path: outputPath,
|
||||||
|
browser: options.browser,
|
||||||
|
platform: options.platform,
|
||||||
|
revision: options.revision,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function canFetch(options: Options): Promise<boolean> {
|
||||||
|
options.platform ??= detectPlatform();
|
||||||
|
if (!options.platform) {
|
||||||
|
throw new Error(
|
||||||
|
`Cannot download a binary for the provided platform: ${os.platform()} (${os.arch()})`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return await headHttpRequest(
|
||||||
|
getDownloadUrl(options.browser, options.platform, options.revision)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Windows 11 is identified by the version 10.0.22000 or greater
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
function isWindows11(version: string): boolean {
|
||||||
|
const parts = version.split('.');
|
||||||
|
if (parts.length > 2) {
|
||||||
|
const major = parseInt(parts[0] as string, 10);
|
||||||
|
const minor = parseInt(parts[1] as string, 10);
|
||||||
|
const patch = parseInt(parts[2] as string, 10);
|
||||||
|
return (
|
||||||
|
major > 10 ||
|
||||||
|
(major === 10 && minor > 0) ||
|
||||||
|
(major === 10 && minor === 0 && patch >= 22000)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
function detectPlatform(): BrowserPlatform | undefined {
|
||||||
|
const platform = os.platform();
|
||||||
|
switch (platform) {
|
||||||
|
case 'darwin':
|
||||||
|
return os.arch() === 'arm64'
|
||||||
|
? BrowserPlatform.MAC_ARM
|
||||||
|
: BrowserPlatform.MAC;
|
||||||
|
case 'linux':
|
||||||
|
return BrowserPlatform.LINUX;
|
||||||
|
case 'win32':
|
||||||
|
return os.arch() === 'x64' ||
|
||||||
|
// Windows 11 for ARM supports x64 emulation
|
||||||
|
(os.arch() === 'arm64' && isWindows11(os.release()))
|
||||||
|
? BrowserPlatform.WIN64
|
||||||
|
: BrowserPlatform.WIN32;
|
||||||
|
default:
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function getDownloadUrl(
|
||||||
|
browser: Browser,
|
||||||
|
platform: BrowserPlatform,
|
||||||
|
revision: string
|
||||||
|
): URL {
|
||||||
|
return new URL(downloadUrls[browser](platform, revision));
|
||||||
|
}
|
88
packages/browsers/src/fileUtil.ts
Normal file
88
packages/browsers/src/fileUtil.ts
Normal file
@ -0,0 +1,88 @@
|
|||||||
|
/**
|
||||||
|
* 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 * as path from 'path';
|
||||||
|
import {exec as execChildProcess} from 'child_process';
|
||||||
|
import extractZip from 'extract-zip';
|
||||||
|
import {createReadStream} from 'fs';
|
||||||
|
import {mkdir, readdir} from 'fs/promises';
|
||||||
|
import tar from 'tar-fs';
|
||||||
|
import bzip from 'unbzip2-stream';
|
||||||
|
import {promisify} from 'util';
|
||||||
|
|
||||||
|
const exec = promisify(execChildProcess);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
export async function unpackArchive(
|
||||||
|
archivePath: string,
|
||||||
|
folderPath: string
|
||||||
|
): Promise<void> {
|
||||||
|
if (archivePath.endsWith('.zip')) {
|
||||||
|
await extractZip(archivePath, {dir: folderPath});
|
||||||
|
} else if (archivePath.endsWith('.tar.bz2')) {
|
||||||
|
await extractTar(archivePath, folderPath);
|
||||||
|
} else if (archivePath.endsWith('.dmg')) {
|
||||||
|
await mkdir(folderPath);
|
||||||
|
await installDMG(archivePath, folderPath);
|
||||||
|
} else {
|
||||||
|
throw new Error(`Unsupported archive format: ${archivePath}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
function extractTar(tarPath: string, folderPath: string): Promise<void> {
|
||||||
|
return new Promise((fulfill, reject) => {
|
||||||
|
const tarStream = tar.extract(folderPath);
|
||||||
|
tarStream.on('error', reject);
|
||||||
|
tarStream.on('finish', fulfill);
|
||||||
|
const readStream = createReadStream(tarPath);
|
||||||
|
readStream.pipe(bzip()).pipe(tarStream);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
async function installDMG(dmgPath: string, folderPath: string): Promise<void> {
|
||||||
|
const {stdout} = await exec(
|
||||||
|
`hdiutil attach -nobrowse -noautoopen "${dmgPath}"`
|
||||||
|
);
|
||||||
|
|
||||||
|
const volumes = stdout.match(/\/Volumes\/(.*)/m);
|
||||||
|
if (!volumes) {
|
||||||
|
throw new Error(`Could not find volume path in ${stdout}`);
|
||||||
|
}
|
||||||
|
const mountPath = volumes[0]!;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const fileNames = await readdir(mountPath);
|
||||||
|
const appName = fileNames.find(item => {
|
||||||
|
return typeof item === 'string' && item.endsWith('.app');
|
||||||
|
});
|
||||||
|
if (!appName) {
|
||||||
|
throw new Error(`Cannot find app in ${mountPath}`);
|
||||||
|
}
|
||||||
|
const mountedPath = path.join(mountPath!, appName);
|
||||||
|
|
||||||
|
await exec(`cp -R "${mountedPath}" "${folderPath}"`);
|
||||||
|
} finally {
|
||||||
|
await exec(`hdiutil detach "${mountPath}" -quiet`);
|
||||||
|
}
|
||||||
|
}
|
136
packages/browsers/src/httpUtil.ts
Normal file
136
packages/browsers/src/httpUtil.ts
Normal file
@ -0,0 +1,136 @@
|
|||||||
|
/**
|
||||||
|
* 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 * as http from 'http';
|
||||||
|
import * as https from 'https';
|
||||||
|
import {URL} from 'url';
|
||||||
|
import createHttpsProxyAgent from 'https-proxy-agent';
|
||||||
|
import {getProxyForUrl} from 'proxy-from-env';
|
||||||
|
import {createWriteStream} from 'fs';
|
||||||
|
|
||||||
|
export function headHttpRequest(url: URL): Promise<boolean> {
|
||||||
|
return new Promise(resolve => {
|
||||||
|
const request = httpRequest(
|
||||||
|
url,
|
||||||
|
'HEAD',
|
||||||
|
response => {
|
||||||
|
resolve(response.statusCode === 200);
|
||||||
|
},
|
||||||
|
false
|
||||||
|
);
|
||||||
|
request.on('error', () => {
|
||||||
|
resolve(false);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export function httpRequest(
|
||||||
|
url: URL,
|
||||||
|
method: string,
|
||||||
|
response: (x: http.IncomingMessage) => void,
|
||||||
|
keepAlive = true
|
||||||
|
): http.ClientRequest {
|
||||||
|
const options: http.RequestOptions = {
|
||||||
|
protocol: url.protocol,
|
||||||
|
hostname: url.hostname,
|
||||||
|
port: url.port,
|
||||||
|
path: url.pathname,
|
||||||
|
headers: keepAlive ? {Connection: 'keep-alive'} : undefined,
|
||||||
|
};
|
||||||
|
|
||||||
|
const proxyURL = getProxyForUrl(url.toString());
|
||||||
|
if (proxyURL) {
|
||||||
|
const proxy = new URL(proxyURL);
|
||||||
|
if (proxy.protocol === 'http:') {
|
||||||
|
options.path = url.href;
|
||||||
|
options.hostname = proxy.hostname;
|
||||||
|
options.protocol = proxy.protocol;
|
||||||
|
} else {
|
||||||
|
options.agent = createHttpsProxyAgent({
|
||||||
|
host: proxy.host,
|
||||||
|
path: proxy.pathname,
|
||||||
|
port: proxy.port,
|
||||||
|
secureProxy: proxy.protocol === 'https:',
|
||||||
|
headers: options.headers,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const requestCallback = (res: http.IncomingMessage): void => {
|
||||||
|
if (
|
||||||
|
res.statusCode &&
|
||||||
|
res.statusCode >= 300 &&
|
||||||
|
res.statusCode < 400 &&
|
||||||
|
res.headers.location
|
||||||
|
) {
|
||||||
|
httpRequest(new URL(res.headers.location), method, response);
|
||||||
|
} else {
|
||||||
|
response(res);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const request =
|
||||||
|
options.protocol === 'https:'
|
||||||
|
? https.request(options, requestCallback)
|
||||||
|
: http.request(options, requestCallback);
|
||||||
|
request.end();
|
||||||
|
return request;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
export function downloadFile(
|
||||||
|
url: URL,
|
||||||
|
destinationPath: string,
|
||||||
|
progressCallback?: (downloadedBytes: number, totalBytes: number) => void
|
||||||
|
): Promise<void> {
|
||||||
|
return new Promise<void>((resolve, reject) => {
|
||||||
|
let downloadedBytes = 0;
|
||||||
|
let totalBytes = 0;
|
||||||
|
|
||||||
|
function onData(chunk: string): void {
|
||||||
|
downloadedBytes += chunk.length;
|
||||||
|
progressCallback!(downloadedBytes, totalBytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
const request = httpRequest(url, 'GET', response => {
|
||||||
|
if (response.statusCode !== 200) {
|
||||||
|
const error = new Error(
|
||||||
|
`Download failed: server returned code ${response.statusCode}. URL: ${url}`
|
||||||
|
);
|
||||||
|
// consume response data to free up memory
|
||||||
|
response.resume();
|
||||||
|
reject(error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const file = createWriteStream(destinationPath);
|
||||||
|
file.on('finish', () => {
|
||||||
|
return resolve();
|
||||||
|
});
|
||||||
|
file.on('error', error => {
|
||||||
|
return reject(error);
|
||||||
|
});
|
||||||
|
response.pipe(file);
|
||||||
|
totalBytes = parseInt(response.headers['content-length']!, 10);
|
||||||
|
if (progressCallback) {
|
||||||
|
response.on('data', onData);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
request.on('error', error => {
|
||||||
|
return reject(error);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
7
packages/browsers/src/tsconfig.cjs.json
Normal file
7
packages/browsers/src/tsconfig.cjs.json
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"extends": "../../../tsconfig.base.json",
|
||||||
|
"compilerOptions": {
|
||||||
|
"module": "CommonJS",
|
||||||
|
"outDir": "../lib/cjs"
|
||||||
|
}
|
||||||
|
}
|
6
packages/browsers/src/tsconfig.esm.json
Normal file
6
packages/browsers/src/tsconfig.esm.json
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"extends": "../../../tsconfig.base.json",
|
||||||
|
"compilerOptions": {
|
||||||
|
"outDir": "../lib/esm"
|
||||||
|
}
|
||||||
|
}
|
44
packages/browsers/test/src/chrome-data.spec.ts
Normal file
44
packages/browsers/test/src/chrome-data.spec.ts
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
/**
|
||||||
|
* 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 {resolveDownloadUrl} from '../../lib/cjs/browsers/chrome.js';
|
||||||
|
import {BrowserPlatform} from '../../lib/cjs/browsers/browsers.js';
|
||||||
|
import assert from 'assert';
|
||||||
|
|
||||||
|
describe('Chrome', () => {
|
||||||
|
it('should resolve download URLs', () => {
|
||||||
|
assert.strictEqual(
|
||||||
|
resolveDownloadUrl(BrowserPlatform.LINUX, '1083080'),
|
||||||
|
'https://storage.googleapis.com/chromium-browser-snapshots/Linux_x64/1083080/chrome-linux.zip'
|
||||||
|
);
|
||||||
|
assert.strictEqual(
|
||||||
|
resolveDownloadUrl(BrowserPlatform.MAC, '1083080'),
|
||||||
|
'https://storage.googleapis.com/chromium-browser-snapshots/Mac/1083080/chrome-mac.zip'
|
||||||
|
);
|
||||||
|
assert.strictEqual(
|
||||||
|
resolveDownloadUrl(BrowserPlatform.MAC_ARM, '1083080'),
|
||||||
|
'https://storage.googleapis.com/chromium-browser-snapshots/Mac_Arm/1083080/chrome-mac.zip'
|
||||||
|
);
|
||||||
|
assert.strictEqual(
|
||||||
|
resolveDownloadUrl(BrowserPlatform.WIN32, '1083080'),
|
||||||
|
'https://storage.googleapis.com/chromium-browser-snapshots/Win/1083080/chrome-win.zip'
|
||||||
|
);
|
||||||
|
assert.strictEqual(
|
||||||
|
resolveDownloadUrl(BrowserPlatform.WIN64, '1083080'),
|
||||||
|
'https://storage.googleapis.com/chromium-browser-snapshots/Win_x64/1083080/chrome-win.zip'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
129
packages/browsers/test/src/fetch.spec.ts
Normal file
129
packages/browsers/test/src/fetch.spec.ts
Normal file
@ -0,0 +1,129 @@
|
|||||||
|
/**
|
||||||
|
* 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 {fetch, canFetch} from '../../lib/cjs/fetch.js';
|
||||||
|
import {Browser, BrowserPlatform} from '../../lib/cjs/browsers/browsers.js';
|
||||||
|
|
||||||
|
import fs from 'fs';
|
||||||
|
import path from 'path';
|
||||||
|
import os from 'os';
|
||||||
|
import assert from 'assert';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests in this spec use real download URLs and unpack live browser archives
|
||||||
|
* so it requires the network access.
|
||||||
|
*/
|
||||||
|
describe('fetch', () => {
|
||||||
|
let tmpDir = '/tmp/puppeteer-browsers-test';
|
||||||
|
const testChromeRevision = '1083080';
|
||||||
|
const testFirefoxRevision = '111.0a1';
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'puppeteer-browsers-test'));
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
fs.rmSync(tmpDir, {recursive: true});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should check if a revision can be downloaded', async () => {
|
||||||
|
assert.ok(
|
||||||
|
await canFetch({
|
||||||
|
outputDir: tmpDir,
|
||||||
|
browser: Browser.CHROME,
|
||||||
|
platform: BrowserPlatform.LINUX,
|
||||||
|
revision: testChromeRevision,
|
||||||
|
})
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should report if a revision is not downloadable', async () => {
|
||||||
|
assert.strictEqual(
|
||||||
|
await canFetch({
|
||||||
|
outputDir: tmpDir,
|
||||||
|
browser: Browser.CHROME,
|
||||||
|
platform: BrowserPlatform.LINUX,
|
||||||
|
revision: 'unknown',
|
||||||
|
}),
|
||||||
|
false
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should download a revision that is a zip archive', async function () {
|
||||||
|
this.timeout(60000);
|
||||||
|
const expectedOutputPath = path.join(
|
||||||
|
tmpDir,
|
||||||
|
`${BrowserPlatform.LINUX}-${testChromeRevision}`
|
||||||
|
);
|
||||||
|
assert.strictEqual(fs.existsSync(expectedOutputPath), false);
|
||||||
|
let browser = await fetch({
|
||||||
|
outputDir: tmpDir,
|
||||||
|
browser: Browser.CHROME,
|
||||||
|
platform: BrowserPlatform.LINUX,
|
||||||
|
revision: testChromeRevision,
|
||||||
|
});
|
||||||
|
assert.strictEqual(browser.path, expectedOutputPath);
|
||||||
|
assert.ok(fs.existsSync(expectedOutputPath));
|
||||||
|
// Second iteration should be no-op.
|
||||||
|
browser = await fetch({
|
||||||
|
outputDir: tmpDir,
|
||||||
|
browser: Browser.CHROME,
|
||||||
|
platform: BrowserPlatform.LINUX,
|
||||||
|
revision: testChromeRevision,
|
||||||
|
});
|
||||||
|
assert.strictEqual(browser.path, expectedOutputPath);
|
||||||
|
assert.ok(fs.existsSync(expectedOutputPath));
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should download a revision that is a bzip2 archive', async function () {
|
||||||
|
this.timeout(60000);
|
||||||
|
const expectedOutputPath = path.join(
|
||||||
|
tmpDir,
|
||||||
|
`${BrowserPlatform.LINUX}-${testFirefoxRevision}`
|
||||||
|
);
|
||||||
|
assert.strictEqual(fs.existsSync(expectedOutputPath), false);
|
||||||
|
const browser = await fetch({
|
||||||
|
outputDir: tmpDir,
|
||||||
|
browser: Browser.FIREFOX,
|
||||||
|
platform: BrowserPlatform.LINUX,
|
||||||
|
revision: testFirefoxRevision,
|
||||||
|
});
|
||||||
|
assert.strictEqual(browser.path, expectedOutputPath);
|
||||||
|
assert.ok(fs.existsSync(expectedOutputPath));
|
||||||
|
});
|
||||||
|
|
||||||
|
// Fetch relies on the `hdiutil` utility on MacOS.
|
||||||
|
// The utility is not available on other platforms.
|
||||||
|
(os.platform() === 'darwin' ? it : it.skip)(
|
||||||
|
'should download a revision that is a dmg archive',
|
||||||
|
async function () {
|
||||||
|
this.timeout(60000);
|
||||||
|
const expectedOutputPath = path.join(
|
||||||
|
tmpDir,
|
||||||
|
`${BrowserPlatform.MAC}-${testFirefoxRevision}`
|
||||||
|
);
|
||||||
|
assert.strictEqual(fs.existsSync(expectedOutputPath), false);
|
||||||
|
const browser = await fetch({
|
||||||
|
outputDir: tmpDir,
|
||||||
|
browser: Browser.FIREFOX,
|
||||||
|
platform: BrowserPlatform.MAC,
|
||||||
|
revision: testFirefoxRevision,
|
||||||
|
});
|
||||||
|
assert.strictEqual(browser.path, expectedOutputPath);
|
||||||
|
assert.ok(fs.existsSync(expectedOutputPath));
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
44
packages/browsers/test/src/firefox-data.spec.ts
Normal file
44
packages/browsers/test/src/firefox-data.spec.ts
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
/**
|
||||||
|
* 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 {resolveDownloadUrl} from '../../lib/cjs/browsers/firefox.js';
|
||||||
|
import {BrowserPlatform} from '../../lib/cjs/browsers/browsers.js';
|
||||||
|
import assert from 'assert';
|
||||||
|
|
||||||
|
describe('Firefox', () => {
|
||||||
|
it('should resolve download URLs', () => {
|
||||||
|
assert.strictEqual(
|
||||||
|
resolveDownloadUrl(BrowserPlatform.LINUX, '111.0a1'),
|
||||||
|
'https://archive.mozilla.org/pub/firefox/nightly/latest-mozilla-central/firefox-111.0a1.en-US.linux-x86_64.tar.bz2'
|
||||||
|
);
|
||||||
|
assert.strictEqual(
|
||||||
|
resolveDownloadUrl(BrowserPlatform.MAC, '111.0a1'),
|
||||||
|
'https://archive.mozilla.org/pub/firefox/nightly/latest-mozilla-central/firefox-111.0a1.en-US.mac.dmg'
|
||||||
|
);
|
||||||
|
assert.strictEqual(
|
||||||
|
resolveDownloadUrl(BrowserPlatform.MAC_ARM, '111.0a1'),
|
||||||
|
'https://archive.mozilla.org/pub/firefox/nightly/latest-mozilla-central/firefox-111.0a1.en-US.mac.dmg'
|
||||||
|
);
|
||||||
|
assert.strictEqual(
|
||||||
|
resolveDownloadUrl(BrowserPlatform.WIN32, '111.0a1'),
|
||||||
|
'https://archive.mozilla.org/pub/firefox/nightly/latest-mozilla-central/firefox-111.0a1.en-US.win32.zip'
|
||||||
|
);
|
||||||
|
assert.strictEqual(
|
||||||
|
resolveDownloadUrl(BrowserPlatform.WIN64, '111.0a1'),
|
||||||
|
'https://archive.mozilla.org/pub/firefox/nightly/latest-mozilla-central/firefox-111.0a1.en-US.win64.zip'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
8
packages/browsers/test/src/tsconfig.json
Normal file
8
packages/browsers/test/src/tsconfig.json
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"extends": "../../../../tsconfig.base.json",
|
||||||
|
"compilerOptions": {
|
||||||
|
"module": "CommonJS",
|
||||||
|
"outDir": "../build"
|
||||||
|
},
|
||||||
|
"references": [{"path": "../../tsconfig.json"}]
|
||||||
|
}
|
8
packages/browsers/tsconfig.json
Normal file
8
packages/browsers/tsconfig.json
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"extends": "../../tsconfig.base.json",
|
||||||
|
"files": [],
|
||||||
|
"references": [
|
||||||
|
{"path": "src/tsconfig.esm.json"},
|
||||||
|
{"path": "src/tsconfig.cjs.json"}
|
||||||
|
]
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user