chore: implement launch command (#9692)
Co-authored-by: Nikolay Vitkov <34244704+Lightning00Blade@users.noreply.github.com>
This commit is contained in:
parent
b146287380
commit
5e81c5b7ee
@ -20,8 +20,9 @@ import {hideBin} from 'yargs/helpers';
|
|||||||
|
|
||||||
import {Browser, BrowserPlatform} from './browsers/types.js';
|
import {Browser, BrowserPlatform} from './browsers/types.js';
|
||||||
import {fetch} from './fetch.js';
|
import {fetch} from './fetch.js';
|
||||||
|
import {computeExecutablePath, launch} from './launcher.js';
|
||||||
|
|
||||||
type Arguments = {
|
type InstallArgs = {
|
||||||
browser: {
|
browser: {
|
||||||
name: Browser;
|
name: Browser;
|
||||||
revision: string;
|
revision: string;
|
||||||
@ -30,6 +31,16 @@ type Arguments = {
|
|||||||
platform?: BrowserPlatform;
|
platform?: BrowserPlatform;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
type LaunchArgs = {
|
||||||
|
browser: {
|
||||||
|
name: Browser;
|
||||||
|
revision: string;
|
||||||
|
};
|
||||||
|
path?: string;
|
||||||
|
platform?: BrowserPlatform;
|
||||||
|
detached: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
export class CLI {
|
export class CLI {
|
||||||
#cachePath;
|
#cachePath;
|
||||||
|
|
||||||
@ -40,13 +51,13 @@ export class CLI {
|
|||||||
async run(argv: string[]): Promise<void> {
|
async run(argv: string[]): Promise<void> {
|
||||||
await yargs(hideBin(argv))
|
await yargs(hideBin(argv))
|
||||||
.command(
|
.command(
|
||||||
'$0 install <browser>',
|
'install <browser>',
|
||||||
'run files',
|
'Download and install the specified browser',
|
||||||
yargs => {
|
yargs => {
|
||||||
yargs.positional('browser', {
|
yargs.positional('browser', {
|
||||||
description: 'The browser version',
|
description: 'The browser version',
|
||||||
type: 'string',
|
type: 'string',
|
||||||
coerce: (opt): Arguments['browser'] => {
|
coerce: (opt): InstallArgs['browser'] => {
|
||||||
return {
|
return {
|
||||||
name: this.#parseBrowser(opt),
|
name: this.#parseBrowser(opt),
|
||||||
revision: this.#parseRevision(opt),
|
revision: this.#parseRevision(opt),
|
||||||
@ -55,7 +66,7 @@ export class CLI {
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
async argv => {
|
async argv => {
|
||||||
const args = argv as unknown as Arguments;
|
const args = argv as unknown as InstallArgs;
|
||||||
await fetch({
|
await fetch({
|
||||||
browser: args.browser.name,
|
browser: args.browser.name,
|
||||||
revision: args.browser.revision,
|
revision: args.browser.revision,
|
||||||
@ -79,6 +90,51 @@ export class CLI {
|
|||||||
choices: Object.values(BrowserPlatform),
|
choices: Object.values(BrowserPlatform),
|
||||||
defaultDescription: 'Auto-detected by default.',
|
defaultDescription: 'Auto-detected by default.',
|
||||||
})
|
})
|
||||||
|
.command(
|
||||||
|
'launch <browser>',
|
||||||
|
'Launch the specified browser',
|
||||||
|
yargs => {
|
||||||
|
yargs.positional('browser', {
|
||||||
|
description: 'The browser version',
|
||||||
|
type: 'string',
|
||||||
|
coerce: (opt): LaunchArgs['browser'] => {
|
||||||
|
return {
|
||||||
|
name: this.#parseBrowser(opt),
|
||||||
|
revision: this.#parseRevision(opt),
|
||||||
|
};
|
||||||
|
},
|
||||||
|
});
|
||||||
|
},
|
||||||
|
async argv => {
|
||||||
|
const args = argv as unknown as LaunchArgs;
|
||||||
|
const executablePath = computeExecutablePath({
|
||||||
|
browser: args.browser.name,
|
||||||
|
revision: args.browser.revision,
|
||||||
|
cacheDir: args.path ?? this.#cachePath,
|
||||||
|
platform: args.platform,
|
||||||
|
});
|
||||||
|
launch({
|
||||||
|
executablePath,
|
||||||
|
detached: args.detached,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
)
|
||||||
|
.option('path', {
|
||||||
|
type: 'string',
|
||||||
|
desc: 'Path where the browsers will be downloaded to and installed from',
|
||||||
|
default: process.cwd(),
|
||||||
|
})
|
||||||
|
.option('detached', {
|
||||||
|
type: 'boolean',
|
||||||
|
desc: 'Whether to detach the child process.',
|
||||||
|
default: false,
|
||||||
|
})
|
||||||
|
.option('platform', {
|
||||||
|
type: 'string',
|
||||||
|
desc: 'Platform that the binary needs to be compatible with.',
|
||||||
|
choices: Object.values(BrowserPlatform),
|
||||||
|
defaultDescription: 'Auto-detected by default.',
|
||||||
|
})
|
||||||
.parse();
|
.parse();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -65,11 +65,17 @@ export function relativeExecutablePath(
|
|||||||
switch (platform) {
|
switch (platform) {
|
||||||
case BrowserPlatform.MAC:
|
case BrowserPlatform.MAC:
|
||||||
case BrowserPlatform.MAC_ARM:
|
case BrowserPlatform.MAC_ARM:
|
||||||
return path.join('Chromium.app', 'Contents', 'MacOS', 'Chromium');
|
return path.join(
|
||||||
|
'chrome-mac',
|
||||||
|
'Chromium.app',
|
||||||
|
'Contents',
|
||||||
|
'MacOS',
|
||||||
|
'Chromium'
|
||||||
|
);
|
||||||
case BrowserPlatform.LINUX:
|
case BrowserPlatform.LINUX:
|
||||||
return 'chrome';
|
return path.join('chrome-linux', 'chrome');
|
||||||
case BrowserPlatform.WIN32:
|
case BrowserPlatform.WIN32:
|
||||||
case BrowserPlatform.WIN64:
|
case BrowserPlatform.WIN64:
|
||||||
return 'chrome.exe';
|
return path.join('chrome-win', 'chrome.exe');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -14,6 +14,7 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import childProcess from 'child_process';
|
||||||
import os from 'os';
|
import os from 'os';
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
|
|
||||||
@ -23,8 +24,11 @@ import {
|
|||||||
executablePathByBrowser,
|
executablePathByBrowser,
|
||||||
} from './browsers/browsers.js';
|
} from './browsers/browsers.js';
|
||||||
import {CacheStructure} from './CacheStructure.js';
|
import {CacheStructure} from './CacheStructure.js';
|
||||||
|
import {debug} from './debug.js';
|
||||||
import {detectBrowserPlatform} from './detectPlatform.js';
|
import {detectBrowserPlatform} from './detectPlatform.js';
|
||||||
|
|
||||||
|
const debugLaunch = debug('puppeteer:browsers:launcher');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @public
|
* @public
|
||||||
*/
|
*/
|
||||||
@ -67,3 +71,225 @@ export function computeExecutablePath(options: Options): string {
|
|||||||
executablePathByBrowser[options.browser](options.platform, options.revision)
|
executablePathByBrowser[options.browser](options.platform, options.revision)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type LaunchOptions = {
|
||||||
|
executablePath: string;
|
||||||
|
pipe?: boolean;
|
||||||
|
dumpio?: boolean;
|
||||||
|
args?: string[];
|
||||||
|
env?: Record<string, string>;
|
||||||
|
handleSIGINT?: boolean;
|
||||||
|
handleSIGTERM?: boolean;
|
||||||
|
handleSIGHUP?: boolean;
|
||||||
|
detached?: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
|
export function launch(opts: LaunchOptions): Process {
|
||||||
|
return new Process(opts);
|
||||||
|
}
|
||||||
|
|
||||||
|
class Process {
|
||||||
|
#executablePath;
|
||||||
|
#args: string[];
|
||||||
|
#browserProcess: childProcess.ChildProcess;
|
||||||
|
#exited = false;
|
||||||
|
#browserProcessExiting: Promise<void>;
|
||||||
|
|
||||||
|
constructor(opts: LaunchOptions) {
|
||||||
|
this.#executablePath = opts.executablePath;
|
||||||
|
this.#args = opts.args ?? [];
|
||||||
|
|
||||||
|
opts.pipe ??= false;
|
||||||
|
opts.dumpio ??= false;
|
||||||
|
opts.handleSIGINT ??= true;
|
||||||
|
opts.handleSIGTERM ??= true;
|
||||||
|
opts.handleSIGHUP ??= true;
|
||||||
|
opts.detached ??= true;
|
||||||
|
|
||||||
|
const stdio = this.#configureStdio({
|
||||||
|
pipe: opts.pipe,
|
||||||
|
dumpio: opts.dumpio,
|
||||||
|
});
|
||||||
|
|
||||||
|
debugLaunch(`Launching ${this.#executablePath} ${this.#args.join(' ')}`);
|
||||||
|
|
||||||
|
this.#browserProcess = childProcess.spawn(
|
||||||
|
this.#executablePath,
|
||||||
|
this.#args,
|
||||||
|
{
|
||||||
|
// On non-windows platforms, `detached: true` makes child process a
|
||||||
|
// leader of a new process group, making it possible to kill child
|
||||||
|
// process tree with `.kill(-pid)` command. @see
|
||||||
|
// https://nodejs.org/api/child_process.html#child_process_options_detached
|
||||||
|
detached: opts.detached,
|
||||||
|
env: opts.env,
|
||||||
|
stdio,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
if (opts.dumpio) {
|
||||||
|
this.#browserProcess.stderr?.pipe(process.stderr);
|
||||||
|
this.#browserProcess.stdout?.pipe(process.stdout);
|
||||||
|
}
|
||||||
|
process.on('exit', this.#onDriverProcessExit);
|
||||||
|
if (opts.handleSIGINT) {
|
||||||
|
process.on('SIGINT', this.#onDriverProcessSignal);
|
||||||
|
}
|
||||||
|
if (opts.handleSIGTERM) {
|
||||||
|
process.on('SIGTERM', this.#onDriverProcessSignal);
|
||||||
|
}
|
||||||
|
if (opts.handleSIGHUP) {
|
||||||
|
process.on('SIGHUP', this.#onDriverProcessSignal);
|
||||||
|
}
|
||||||
|
this.#browserProcessExiting = new Promise(resolve => {
|
||||||
|
this.#browserProcess.once('exit', () => {
|
||||||
|
this.#exited = true;
|
||||||
|
this.#clearListeners();
|
||||||
|
resolve();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#configureStdio(opts: {
|
||||||
|
pipe: boolean;
|
||||||
|
dumpio: boolean;
|
||||||
|
}): Array<'ignore' | 'pipe'> {
|
||||||
|
if (opts.pipe) {
|
||||||
|
if (opts.dumpio) {
|
||||||
|
return ['ignore', 'pipe', 'pipe', 'pipe', 'pipe'];
|
||||||
|
} else {
|
||||||
|
return ['ignore', 'ignore', 'ignore', 'pipe', 'pipe'];
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (opts.dumpio) {
|
||||||
|
return ['pipe', 'pipe', 'pipe'];
|
||||||
|
} else {
|
||||||
|
return ['pipe', 'ignore', 'pipe'];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#clearListeners(): void {
|
||||||
|
process.off('exit', this.#onDriverProcessExit);
|
||||||
|
process.off('SIGINT', this.#onDriverProcessSignal);
|
||||||
|
process.off('SIGTERM', this.#onDriverProcessSignal);
|
||||||
|
process.off('SIGHUP', this.#onDriverProcessSignal);
|
||||||
|
}
|
||||||
|
|
||||||
|
#onDriverProcessExit = (_code: number) => {
|
||||||
|
this.kill();
|
||||||
|
};
|
||||||
|
|
||||||
|
#onDriverProcessSignal = (signal: string): void => {
|
||||||
|
switch (signal) {
|
||||||
|
case 'SIGINT':
|
||||||
|
this.kill();
|
||||||
|
process.exit(130);
|
||||||
|
case 'SIGTERM':
|
||||||
|
case 'SIGUP':
|
||||||
|
this.kill();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
close(): Promise<void> {
|
||||||
|
if (this.#exited) {
|
||||||
|
return Promise.resolve();
|
||||||
|
}
|
||||||
|
this.kill();
|
||||||
|
return this.#browserProcessExiting;
|
||||||
|
}
|
||||||
|
|
||||||
|
kill(): void {
|
||||||
|
// If the process failed to launch (for example if the browser executable path
|
||||||
|
// is invalid), then the process does not get a pid assigned. A call to
|
||||||
|
// `proc.kill` would error, as the `pid` to-be-killed can not be found.
|
||||||
|
if (
|
||||||
|
this.#browserProcess &&
|
||||||
|
this.#browserProcess.pid &&
|
||||||
|
pidExists(this.#browserProcess.pid)
|
||||||
|
) {
|
||||||
|
try {
|
||||||
|
if (process.platform === 'win32') {
|
||||||
|
childProcess.exec(
|
||||||
|
`taskkill /pid ${this.#browserProcess.pid} /T /F`,
|
||||||
|
error => {
|
||||||
|
if (error) {
|
||||||
|
// taskkill can fail to kill the process e.g. due to missing permissions.
|
||||||
|
// Let's kill the process via Node API. This delays killing of all child
|
||||||
|
// processes of `this.proc` until the main Node.js process dies.
|
||||||
|
this.#browserProcess.kill();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
// on linux the process group can be killed with the group id prefixed with
|
||||||
|
// a minus sign. The process group id is the group leader's pid.
|
||||||
|
const processGroupId = -this.#browserProcess.pid;
|
||||||
|
|
||||||
|
try {
|
||||||
|
process.kill(processGroupId, 'SIGKILL');
|
||||||
|
} catch (error) {
|
||||||
|
// Killing the process group can fail due e.g. to missing permissions.
|
||||||
|
// Let's kill the process via Node API. This delays killing of all child
|
||||||
|
// processes of `this.proc` until the main Node.js process dies.
|
||||||
|
this.#browserProcess.kill('SIGKILL');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
throw new Error(
|
||||||
|
`${PROCESS_ERROR_EXPLANATION}\nError cause: ${
|
||||||
|
isErrorLike(error) ? error.stack : error
|
||||||
|
}`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.#clearListeners();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const PROCESS_ERROR_EXPLANATION = `Puppeteer was unable to kill the process which ran the browser binary.
|
||||||
|
This means that, on future Puppeteer launches, Puppeteer might not be able to launch the browser.
|
||||||
|
Please check your open processes and ensure that the browser processes that Puppeteer launched have been killed.
|
||||||
|
If you think this is a bug, please report it on the Puppeteer issue tracker.`;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
function pidExists(pid: number): boolean {
|
||||||
|
try {
|
||||||
|
return process.kill(pid, 0);
|
||||||
|
} catch (error) {
|
||||||
|
if (isErrnoException(error)) {
|
||||||
|
if (error.code && error.code === 'ESRCH') {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
export interface ErrorLike extends Error {
|
||||||
|
name: string;
|
||||||
|
message: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
export function isErrorLike(obj: unknown): obj is ErrorLike {
|
||||||
|
return (
|
||||||
|
typeof obj === 'object' && obj !== null && 'name' in obj && 'message' in obj
|
||||||
|
);
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
export function isErrnoException(obj: unknown): obj is NodeJS.ErrnoException {
|
||||||
|
return (
|
||||||
|
isErrorLike(obj) &&
|
||||||
|
('errno' in obj || 'code' in obj || 'path' in obj || 'syscall' in obj)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
@ -50,23 +50,23 @@ describe('Chrome', () => {
|
|||||||
it('should resolve executable paths', () => {
|
it('should resolve executable paths', () => {
|
||||||
assert.strictEqual(
|
assert.strictEqual(
|
||||||
relativeExecutablePath(BrowserPlatform.LINUX, '12372323'),
|
relativeExecutablePath(BrowserPlatform.LINUX, '12372323'),
|
||||||
path.join('chrome')
|
path.join('chrome-linux', 'chrome')
|
||||||
);
|
);
|
||||||
assert.strictEqual(
|
assert.strictEqual(
|
||||||
relativeExecutablePath(BrowserPlatform.MAC, '12372323'),
|
relativeExecutablePath(BrowserPlatform.MAC, '12372323'),
|
||||||
path.join('Chromium.app', 'Contents', 'MacOS', 'Chromium')
|
path.join('chrome-mac', 'Chromium.app', 'Contents', 'MacOS', 'Chromium')
|
||||||
);
|
);
|
||||||
assert.strictEqual(
|
assert.strictEqual(
|
||||||
relativeExecutablePath(BrowserPlatform.MAC_ARM, '12372323'),
|
relativeExecutablePath(BrowserPlatform.MAC_ARM, '12372323'),
|
||||||
path.join('Chromium.app', 'Contents', 'MacOS', 'Chromium')
|
path.join('chrome-mac', 'Chromium.app', 'Contents', 'MacOS', 'Chromium')
|
||||||
);
|
);
|
||||||
assert.strictEqual(
|
assert.strictEqual(
|
||||||
relativeExecutablePath(BrowserPlatform.WIN32, '12372323'),
|
relativeExecutablePath(BrowserPlatform.WIN32, '12372323'),
|
||||||
path.join('chrome.exe')
|
path.join('chrome-win', 'chrome.exe')
|
||||||
);
|
);
|
||||||
assert.strictEqual(
|
assert.strictEqual(
|
||||||
relativeExecutablePath(BrowserPlatform.WIN64, '12372323'),
|
relativeExecutablePath(BrowserPlatform.WIN64, '12372323'),
|
||||||
path.join('chrome.exe')
|
path.join('chrome-win', 'chrome.exe')
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -46,7 +46,14 @@ describe('CLI', function () {
|
|||||||
'--platform=linux',
|
'--platform=linux',
|
||||||
]);
|
]);
|
||||||
assert.ok(
|
assert.ok(
|
||||||
fs.existsSync(path.join(tmpDir, 'chrome', `linux-${testChromeRevision}`))
|
fs.existsSync(
|
||||||
|
path.join(
|
||||||
|
tmpDir,
|
||||||
|
'chrome',
|
||||||
|
`linux-${testChromeRevision}`,
|
||||||
|
'chrome-linux'
|
||||||
|
)
|
||||||
|
)
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -61,7 +68,7 @@ describe('CLI', function () {
|
|||||||
]);
|
]);
|
||||||
assert.ok(
|
assert.ok(
|
||||||
fs.existsSync(
|
fs.existsSync(
|
||||||
path.join(tmpDir, 'firefox', `linux-${testFirefoxRevision}`)
|
path.join(tmpDir, 'firefox', `linux-${testFirefoxRevision}`, 'firefox')
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
@ -15,10 +15,13 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import assert from 'assert';
|
import assert from 'assert';
|
||||||
|
import fs from 'fs';
|
||||||
|
import os from 'os';
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
|
|
||||||
import {Browser, BrowserPlatform} from '../../lib/cjs/browsers/browsers.js';
|
import {Browser, BrowserPlatform} from '../../lib/cjs/browsers/browsers.js';
|
||||||
import {computeExecutablePath} from '../../lib/cjs/launcher.js';
|
import {fetch} from '../../lib/cjs/fetch.js';
|
||||||
|
import {computeExecutablePath, launch} from '../../lib/cjs/launcher.js';
|
||||||
|
|
||||||
describe('launcher', () => {
|
describe('launcher', () => {
|
||||||
it('should compute executable path for Chrome', () => {
|
it('should compute executable path for Chrome', () => {
|
||||||
@ -29,9 +32,10 @@ describe('launcher', () => {
|
|||||||
revision: '123',
|
revision: '123',
|
||||||
cacheDir: 'cache',
|
cacheDir: 'cache',
|
||||||
}),
|
}),
|
||||||
path.join('cache', 'chrome', 'linux-123', 'chrome')
|
path.join('cache', 'chrome', 'linux-123', 'chrome-linux', 'chrome')
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should compute executable path for Firefox', () => {
|
it('should compute executable path for Firefox', () => {
|
||||||
assert.strictEqual(
|
assert.strictEqual(
|
||||||
computeExecutablePath({
|
computeExecutablePath({
|
||||||
@ -43,4 +47,78 @@ describe('launcher', () => {
|
|||||||
path.join('cache', 'firefox', 'linux-123', 'firefox', 'firefox')
|
path.join('cache', 'firefox', 'linux-123', 'firefox', 'firefox')
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('Chrome', function () {
|
||||||
|
this.timeout(60000);
|
||||||
|
|
||||||
|
let tmpDir = '/tmp/puppeteer-browsers-test';
|
||||||
|
const testChromeRevision = '1083080';
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
tmpDir = fs.mkdtempSync(
|
||||||
|
path.join(os.tmpdir(), 'puppeteer-browsers-test')
|
||||||
|
);
|
||||||
|
await fetch({
|
||||||
|
cacheDir: tmpDir,
|
||||||
|
browser: Browser.CHROME,
|
||||||
|
revision: testChromeRevision,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
fs.rmSync(tmpDir, {recursive: true});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should launch a Chrome browser', async () => {
|
||||||
|
const executablePath = computeExecutablePath({
|
||||||
|
cacheDir: tmpDir,
|
||||||
|
browser: Browser.CHROME,
|
||||||
|
revision: testChromeRevision,
|
||||||
|
});
|
||||||
|
const process = launch({
|
||||||
|
executablePath,
|
||||||
|
args: [
|
||||||
|
'--use-mock-keychain',
|
||||||
|
'--disable-features=DialMediaRouteProvider',
|
||||||
|
`--user-data-dir=${path.join(tmpDir, 'profile')}`,
|
||||||
|
],
|
||||||
|
});
|
||||||
|
await process.close();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('Firefox', function () {
|
||||||
|
this.timeout(60000);
|
||||||
|
|
||||||
|
let tmpDir = '/tmp/puppeteer-browsers-test';
|
||||||
|
const testFirefoxRevision = '111.0a1';
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
tmpDir = fs.mkdtempSync(
|
||||||
|
path.join(os.tmpdir(), 'puppeteer-browsers-test')
|
||||||
|
);
|
||||||
|
await fetch({
|
||||||
|
cacheDir: tmpDir,
|
||||||
|
browser: Browser.FIREFOX,
|
||||||
|
revision: testFirefoxRevision,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
fs.rmSync(tmpDir, {recursive: true});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should launch a Firefox browser', async () => {
|
||||||
|
const executablePath = computeExecutablePath({
|
||||||
|
cacheDir: tmpDir,
|
||||||
|
browser: Browser.FIREFOX,
|
||||||
|
revision: testFirefoxRevision,
|
||||||
|
});
|
||||||
|
const process = launch({
|
||||||
|
executablePath,
|
||||||
|
args: [`--user-data-dir=${path.join(tmpDir, 'profile')}`],
|
||||||
|
});
|
||||||
|
await process.close();
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
Loading…
Reference in New Issue
Block a user