chore: allow reading stderr of the browser process (#9813)
Co-authored-by: Nikolay Vitkov <34244704+Lightning00Blade@users.noreply.github.com>
This commit is contained in:
parent
2335770aee
commit
a17b7ffaf6
@ -17,6 +17,7 @@
|
|||||||
import childProcess from 'child_process';
|
import childProcess from 'child_process';
|
||||||
import os from 'os';
|
import os from 'os';
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
|
import readline from 'readline';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
Browser,
|
Browser,
|
||||||
@ -88,6 +89,9 @@ export function launch(opts: LaunchOptions): Process {
|
|||||||
return new Process(opts);
|
return new Process(opts);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const CDP_WEBSOCKET_ENDPOINT_REGEX =
|
||||||
|
/^DevTools listening on (ws:\/\/.*)$/;
|
||||||
|
|
||||||
class Process {
|
class Process {
|
||||||
#executablePath;
|
#executablePath;
|
||||||
#args: string[];
|
#args: string[];
|
||||||
@ -245,6 +249,66 @@ class Process {
|
|||||||
}
|
}
|
||||||
this.#clearListeners();
|
this.#clearListeners();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
waitForLineOutput(regex: RegExp, timeout?: number): Promise<string> {
|
||||||
|
if (!this.#browserProcess.stderr) {
|
||||||
|
throw new Error('`browserProcess` does not have stderr.');
|
||||||
|
}
|
||||||
|
const rl = readline.createInterface(this.#browserProcess.stderr);
|
||||||
|
let stderr = '';
|
||||||
|
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
rl.on('line', onLine);
|
||||||
|
rl.on('close', onClose);
|
||||||
|
this.#browserProcess.on('exit', onClose);
|
||||||
|
this.#browserProcess.on('error', onClose);
|
||||||
|
const timeoutId = timeout ? setTimeout(onTimeout, timeout) : 0;
|
||||||
|
|
||||||
|
const cleanup = (): void => {
|
||||||
|
if (timeoutId) {
|
||||||
|
clearTimeout(timeoutId);
|
||||||
|
}
|
||||||
|
rl.off('line', onLine);
|
||||||
|
rl.off('close', onClose);
|
||||||
|
this.#browserProcess.off('exit', onClose);
|
||||||
|
this.#browserProcess.off('error', onClose);
|
||||||
|
};
|
||||||
|
|
||||||
|
function onClose(error?: Error): void {
|
||||||
|
cleanup();
|
||||||
|
reject(
|
||||||
|
new Error(
|
||||||
|
[
|
||||||
|
`Failed to launch the browser process!${
|
||||||
|
error ? ' ' + error.message : ''
|
||||||
|
}`,
|
||||||
|
stderr,
|
||||||
|
].join('\n')
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function onTimeout(): void {
|
||||||
|
cleanup();
|
||||||
|
reject(
|
||||||
|
new Error(
|
||||||
|
`Timed out after ${timeout} ms while waiting for the WS endpoint URL to appear in stdout!`
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function onLine(line: string): void {
|
||||||
|
stderr += line + '\n';
|
||||||
|
const match = line.match(regex);
|
||||||
|
if (!match) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
cleanup();
|
||||||
|
// The RegExp matches, so this will obviously exist.
|
||||||
|
resolve(match[1]!);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const PROCESS_ERROR_EXPLANATION = `Puppeteer was unable to kill the process which ran the browser binary.
|
const PROCESS_ERROR_EXPLANATION = `Puppeteer was unable to kill the process which ran the browser binary.
|
||||||
|
@ -21,7 +21,11 @@ import path from 'path';
|
|||||||
|
|
||||||
import {Browser, BrowserPlatform} from '../../lib/cjs/browsers/browsers.js';
|
import {Browser, BrowserPlatform} from '../../lib/cjs/browsers/browsers.js';
|
||||||
import {fetch} from '../../lib/cjs/fetch.js';
|
import {fetch} from '../../lib/cjs/fetch.js';
|
||||||
import {computeExecutablePath, launch} from '../../lib/cjs/launcher.js';
|
import {
|
||||||
|
CDP_WEBSOCKET_ENDPOINT_REGEX,
|
||||||
|
computeExecutablePath,
|
||||||
|
launch,
|
||||||
|
} from '../../lib/cjs/launcher.js';
|
||||||
|
|
||||||
import {testChromeBuildId, testFirefoxBuildId} from './versions.js';
|
import {testChromeBuildId, testFirefoxBuildId} from './versions.js';
|
||||||
|
|
||||||
@ -91,6 +95,7 @@ describe('launcher', () => {
|
|||||||
const process = launch({
|
const process = launch({
|
||||||
executablePath,
|
executablePath,
|
||||||
args: [
|
args: [
|
||||||
|
'--headless=new',
|
||||||
'--use-mock-keychain',
|
'--use-mock-keychain',
|
||||||
'--disable-features=DialMediaRouteProvider',
|
'--disable-features=DialMediaRouteProvider',
|
||||||
`--user-data-dir=${path.join(tmpDir, 'profile')}`,
|
`--user-data-dir=${path.join(tmpDir, 'profile')}`,
|
||||||
@ -98,6 +103,27 @@ describe('launcher', () => {
|
|||||||
});
|
});
|
||||||
await process.close();
|
await process.close();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should allow parsing stderr output of the browser process', async () => {
|
||||||
|
const executablePath = computeExecutablePath({
|
||||||
|
cacheDir: tmpDir,
|
||||||
|
browser: Browser.CHROME,
|
||||||
|
buildId: testChromeBuildId,
|
||||||
|
});
|
||||||
|
const process = launch({
|
||||||
|
executablePath,
|
||||||
|
args: [
|
||||||
|
'--headless=new',
|
||||||
|
'--use-mock-keychain',
|
||||||
|
'--disable-features=DialMediaRouteProvider',
|
||||||
|
'--remote-debugging-port=9222',
|
||||||
|
`--user-data-dir=${path.join(tmpDir, 'profile')}`,
|
||||||
|
],
|
||||||
|
});
|
||||||
|
const url = await process.waitForLineOutput(CDP_WEBSOCKET_ENDPOINT_REGEX);
|
||||||
|
await process.close();
|
||||||
|
assert.ok(url.startsWith('ws://127.0.0.1:9222/devtools/browser'));
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('Firefox', function () {
|
describe('Firefox', function () {
|
||||||
|
Loading…
Reference in New Issue
Block a user