fix: kill browser if process doesnt exit for 30s after close (#5968)
This commit is contained in:
parent
779037a77e
commit
0943af2806
|
|
@ -26,7 +26,7 @@ import { launchProcess, Env, envArrayToObject } from './processLauncher';
|
||||||
import { PipeTransport } from './pipeTransport';
|
import { PipeTransport } from './pipeTransport';
|
||||||
import { Progress, ProgressController } from './progress';
|
import { Progress, ProgressController } from './progress';
|
||||||
import * as types from './types';
|
import * as types from './types';
|
||||||
import { TimeoutSettings } from '../utils/timeoutSettings';
|
import { DEFAULT_TIMEOUT, TimeoutSettings } from '../utils/timeoutSettings';
|
||||||
import { validateHostRequirements } from './validateDependencies';
|
import { validateHostRequirements } from './validateDependencies';
|
||||||
import { isDebugMode } from '../utils/utils';
|
import { isDebugMode } from '../utils/utils';
|
||||||
import { helper } from './helper';
|
import { helper } from './helper';
|
||||||
|
|
@ -219,13 +219,26 @@ export abstract class BrowserType extends SdkObject {
|
||||||
browserProcess.onclose(exitCode, signal);
|
browserProcess.onclose(exitCode, signal);
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
async function closeOrKill(timeout: number): Promise<void> {
|
||||||
|
let timer: NodeJS.Timer;
|
||||||
|
try {
|
||||||
|
await Promise.race([
|
||||||
|
gracefullyClose(),
|
||||||
|
new Promise((resolve, reject) => timer = setTimeout(reject, timeout)),
|
||||||
|
]);
|
||||||
|
} catch (ignored) {
|
||||||
|
await kill().catch(ignored => {}); // Make sure to await actual process exit.
|
||||||
|
} finally {
|
||||||
|
clearTimeout(timer!);
|
||||||
|
}
|
||||||
|
}
|
||||||
browserProcess = {
|
browserProcess = {
|
||||||
onclose: undefined,
|
onclose: undefined,
|
||||||
process: launchedProcess,
|
process: launchedProcess,
|
||||||
close: gracefullyClose,
|
close: () => closeOrKill((options as any).__testHookBrowserCloseTimeout || DEFAULT_TIMEOUT),
|
||||||
kill
|
kill
|
||||||
};
|
};
|
||||||
progress.cleanupWhenAborted(() => browserProcess && closeOrKill(browserProcess, progress.timeUntilDeadline()));
|
progress.cleanupWhenAborted(() => closeOrKill(progress.timeUntilDeadline()));
|
||||||
if (options.useWebSocket) {
|
if (options.useWebSocket) {
|
||||||
transport = await WebSocketTransport.connect(progress, await wsEndpoint!);
|
transport = await WebSocketTransport.connect(progress, await wsEndpoint!);
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -260,17 +273,3 @@ function validateLaunchOptions<Options extends types.LaunchOptions>(options: Opt
|
||||||
headless = false;
|
headless = false;
|
||||||
return { ...options, devtools, headless };
|
return { ...options, devtools, headless };
|
||||||
}
|
}
|
||||||
|
|
||||||
async function closeOrKill(browserProcess: BrowserProcess, timeout: number): Promise<void> {
|
|
||||||
let timer: NodeJS.Timer;
|
|
||||||
try {
|
|
||||||
await Promise.race([
|
|
||||||
browserProcess.close(),
|
|
||||||
new Promise((resolve, reject) => timer = setTimeout(reject, timeout)),
|
|
||||||
]);
|
|
||||||
} catch (ignored) {
|
|
||||||
await browserProcess.kill().catch(ignored => {}); // Make sure to await actual process exit.
|
|
||||||
} finally {
|
|
||||||
clearTimeout(timer!);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -27,3 +27,18 @@ it('should require top-level DeviceDescriptors', async ({playwright}) => {
|
||||||
expect(Devices['iPhone 6']).toBeTruthy();
|
expect(Devices['iPhone 6']).toBeTruthy();
|
||||||
expect(Devices['iPhone 6']).toEqual(playwright.devices['iPhone 6']);
|
expect(Devices['iPhone 6']).toEqual(playwright.devices['iPhone 6']);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should kill browser process on timeout after close', (test, { mode }) => {
|
||||||
|
test.skip(mode !== 'default', 'Test passes server hooks via options');
|
||||||
|
}, async ({browserType, browserOptions}) => {
|
||||||
|
const launchOptions = { ...browserOptions };
|
||||||
|
let stalled = false;
|
||||||
|
(launchOptions as any).__testHookGracefullyClose = () => {
|
||||||
|
stalled = true;
|
||||||
|
return new Promise(() => {});
|
||||||
|
};
|
||||||
|
(launchOptions as any).__testHookBrowserCloseTimeout = 1_000;
|
||||||
|
const browser = await browserType.launch(launchOptions);
|
||||||
|
await browser.close();
|
||||||
|
expect(stalled).toBeTruthy();
|
||||||
|
});
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue