mirror of
https://github.com/microsoft/playwright.git
synced 2025-06-26 21:40:17 +00:00
fix: throw pretty error if opening userDataDir twice (#36007)
This commit is contained in:
parent
9d40340099
commit
bc92cb44fe
@ -21,6 +21,7 @@ import { BrowserReadyState, BrowserType, kNoXServerRunningError } from '../brows
|
|||||||
import { BidiBrowser } from './bidiBrowser';
|
import { BidiBrowser } from './bidiBrowser';
|
||||||
import { kBrowserCloseMessageId } from './bidiConnection';
|
import { kBrowserCloseMessageId } from './bidiConnection';
|
||||||
import { chromiumSwitches } from '../chromium/chromiumSwitches';
|
import { chromiumSwitches } from '../chromium/chromiumSwitches';
|
||||||
|
import { RecentLogsCollector } from '../utils/debugLogger';
|
||||||
|
|
||||||
import type { BrowserOptions } from '../browser';
|
import type { BrowserOptions } from '../browser';
|
||||||
import type { SdkObject } from '../instrumentation';
|
import type { SdkObject } from '../instrumentation';
|
||||||
@ -35,13 +36,23 @@ export class BidiChromium extends BrowserType {
|
|||||||
super(parent, 'bidi');
|
super(parent, 'bidi');
|
||||||
}
|
}
|
||||||
|
|
||||||
override async connectToTransport(transport: ConnectionTransport, options: BrowserOptions): Promise<BidiBrowser> {
|
override async connectToTransport(transport: ConnectionTransport, options: BrowserOptions, browserLogsCollector: RecentLogsCollector): Promise<BidiBrowser> {
|
||||||
// Chrome doesn't support Bidi, we create Bidi over CDP which is used by Chrome driver.
|
// Chrome doesn't support Bidi, we create Bidi over CDP which is used by Chrome driver.
|
||||||
// bidiOverCdp depends on chromium-bidi which we only have in devDependencies, so
|
// bidiOverCdp depends on chromium-bidi which we only have in devDependencies, so
|
||||||
// we load bidiOverCdp dynamically.
|
// we load bidiOverCdp dynamically.
|
||||||
const bidiTransport = await require('./bidiOverCdp').connectBidiOverCdp(transport);
|
const bidiTransport = await require('./bidiOverCdp').connectBidiOverCdp(transport);
|
||||||
(transport as any)[kBidiOverCdpWrapper] = bidiTransport;
|
(transport as any)[kBidiOverCdpWrapper] = bidiTransport;
|
||||||
return BidiBrowser.connect(this.attribution.playwright, bidiTransport, options);
|
try {
|
||||||
|
return BidiBrowser.connect(this.attribution.playwright, bidiTransport, options);
|
||||||
|
} catch (e) {
|
||||||
|
if (browserLogsCollector.recentLogs().some(log => log.includes('Failed to create a ProcessSingleton for your profile directory.'))) {
|
||||||
|
throw new Error(
|
||||||
|
'Failed to create a ProcessSingleton for your profile directory. ' +
|
||||||
|
'This usually means that the profile is already in use by another instance of Chromium.'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override doRewriteStartupLog(error: ProtocolError): ProtocolError {
|
override doRewriteStartupLog(error: ProtocolError): ProtocolError {
|
||||||
@ -155,6 +166,10 @@ export class BidiChromium extends BrowserType {
|
|||||||
|
|
||||||
class ChromiumReadyState extends BrowserReadyState {
|
class ChromiumReadyState extends BrowserReadyState {
|
||||||
override onBrowserOutput(message: string): void {
|
override onBrowserOutput(message: string): void {
|
||||||
|
if (message.includes('Failed to create a ProcessSingleton for your profile directory.')) {
|
||||||
|
this._wsEndpoint.reject(new Error('Failed to create a ProcessSingleton for your profile directory. ' +
|
||||||
|
'This usually means that the profile is already in use by another instance of Chromium.'));
|
||||||
|
}
|
||||||
const match = message.match(/DevTools listening on (.*)/);
|
const match = message.match(/DevTools listening on (.*)/);
|
||||||
if (match)
|
if (match)
|
||||||
this._wsEndpoint.resolve(match[1]);
|
this._wsEndpoint.resolve(match[1]);
|
||||||
|
@ -157,7 +157,7 @@ export abstract class BrowserType extends SdkObject {
|
|||||||
if (persistent)
|
if (persistent)
|
||||||
validateBrowserContextOptions(persistent, browserOptions);
|
validateBrowserContextOptions(persistent, browserOptions);
|
||||||
copyTestHooks(options, browserOptions);
|
copyTestHooks(options, browserOptions);
|
||||||
const browser = await this.connectToTransport(transport, browserOptions);
|
const browser = await this.connectToTransport(transport, browserOptions, browserLogsCollector);
|
||||||
(browser as any)._userDataDirForTest = userDataDir;
|
(browser as any)._userDataDirForTest = userDataDir;
|
||||||
// We assume no control when using custom arguments, and do not prepare the default context in that case.
|
// We assume no control when using custom arguments, and do not prepare the default context in that case.
|
||||||
if (persistent && !options.ignoreAllDefaultArgs)
|
if (persistent && !options.ignoreAllDefaultArgs)
|
||||||
@ -342,7 +342,7 @@ export abstract class BrowserType extends SdkObject {
|
|||||||
}
|
}
|
||||||
|
|
||||||
abstract defaultArgs(options: types.LaunchOptions, isPersistent: boolean, userDataDir: string): string[];
|
abstract defaultArgs(options: types.LaunchOptions, isPersistent: boolean, userDataDir: string): string[];
|
||||||
abstract connectToTransport(transport: ConnectionTransport, options: BrowserOptions): Promise<Browser>;
|
abstract connectToTransport(transport: ConnectionTransport, options: BrowserOptions, browserLogsCollector: RecentLogsCollector): Promise<Browser>;
|
||||||
abstract amendEnvironment(env: Env, userDataDir: string, executable: string, browserArguments: string[]): Env;
|
abstract amendEnvironment(env: Env, userDataDir: string, executable: string, browserArguments: string[]): Env;
|
||||||
abstract doRewriteStartupLog(error: ProtocolError): ProtocolError;
|
abstract doRewriteStartupLog(error: ProtocolError): ProtocolError;
|
||||||
abstract attemptToGracefullyCloseBrowser(transport: ConnectionTransport): void;
|
abstract attemptToGracefullyCloseBrowser(transport: ConnectionTransport): void;
|
||||||
|
@ -126,13 +126,23 @@ export class Chromium extends BrowserType {
|
|||||||
return directory ? new CRDevTools(path.join(directory, 'devtools-preferences.json')) : undefined;
|
return directory ? new CRDevTools(path.join(directory, 'devtools-preferences.json')) : undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
override async connectToTransport(transport: ConnectionTransport, options: BrowserOptions): Promise<CRBrowser> {
|
override async connectToTransport(transport: ConnectionTransport, options: BrowserOptions, browserLogsCollector: RecentLogsCollector): Promise<CRBrowser> {
|
||||||
let devtools = this._devtools;
|
let devtools = this._devtools;
|
||||||
if ((options as any).__testHookForDevTools) {
|
if ((options as any).__testHookForDevTools) {
|
||||||
devtools = this._createDevTools();
|
devtools = this._createDevTools();
|
||||||
await (options as any).__testHookForDevTools(devtools);
|
await (options as any).__testHookForDevTools(devtools);
|
||||||
}
|
}
|
||||||
return CRBrowser.connect(this.attribution.playwright, transport, options, devtools);
|
try {
|
||||||
|
return await CRBrowser.connect(this.attribution.playwright, transport, options, devtools);
|
||||||
|
} catch (e) {
|
||||||
|
if (browserLogsCollector.recentLogs().some(log => log.includes('Failed to create a ProcessSingleton for your profile directory.'))) {
|
||||||
|
throw new Error(
|
||||||
|
'Failed to create a ProcessSingleton for your profile directory. ' +
|
||||||
|
'This usually means that the profile is already in use by another instance of Chromium.'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override doRewriteStartupLog(error: ProtocolError): ProtocolError {
|
override doRewriteStartupLog(error: ProtocolError): ProtocolError {
|
||||||
@ -358,6 +368,10 @@ export class Chromium extends BrowserType {
|
|||||||
|
|
||||||
class ChromiumReadyState extends BrowserReadyState {
|
class ChromiumReadyState extends BrowserReadyState {
|
||||||
override onBrowserOutput(message: string): void {
|
override onBrowserOutput(message: string): void {
|
||||||
|
if (message.includes('Failed to create a ProcessSingleton for your profile directory.')) {
|
||||||
|
this._wsEndpoint.reject(new Error('Failed to create a ProcessSingleton for your profile directory. ' +
|
||||||
|
'This usually means that the profile is already in use by another instance of Chromium.'));
|
||||||
|
}
|
||||||
const match = message.match(/DevTools listening on (.*)/);
|
const match = message.match(/DevTools listening on (.*)/);
|
||||||
if (match)
|
if (match)
|
||||||
this._wsEndpoint.resolve(match[1]);
|
this._wsEndpoint.resolve(match[1]);
|
||||||
|
@ -630,3 +630,33 @@ test.describe('PW_EXPERIMENTAL_SERVICE_WORKER_NETWORK_EVENTS=1', () => {
|
|||||||
expect(req.headers['x-custom-header']).toBe('custom!');
|
expect(req.headers['x-custom-header']).toBe('custom!');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('should throw when connecting twice to an already running persistent context (--remote-debugging-port)', async ({ browserType, createUserDataDir, platform, isHeadlessShell }) => {
|
||||||
|
test.skip(isHeadlessShell, 'Headless shell does not create a ProcessSingleton');
|
||||||
|
test.fixme(platform === 'win32', 'Windows does not print something to the console when the profile is already in use by another instance of Chromium.');
|
||||||
|
const userDataDir = await createUserDataDir();
|
||||||
|
const browser = await browserType.launchPersistentContext(userDataDir, {
|
||||||
|
cdpPort: 9222,
|
||||||
|
} as any);
|
||||||
|
try {
|
||||||
|
const error = await browserType.launchPersistentContext(userDataDir, {
|
||||||
|
cdpPort: 9223,
|
||||||
|
} as any).catch(e => e);
|
||||||
|
expect(error.message).toContain('This usually means that the profile is already in use by another instance of Chromium.');
|
||||||
|
} finally {
|
||||||
|
await browser.close();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should throw when connecting twice to an already running persistent context (--remote-debugging-pipe)', async ({ browserType, createUserDataDir, platform, isHeadlessShell }) => {
|
||||||
|
test.skip(isHeadlessShell, 'Headless shell does not create a ProcessSingleton');
|
||||||
|
test.fixme(platform === 'win32', 'Windows does not print something to the console when the profile is already in use by another instance of Chromium.');
|
||||||
|
const userDataDir = await createUserDataDir();
|
||||||
|
const browser = await browserType.launchPersistentContext(userDataDir);
|
||||||
|
try {
|
||||||
|
const error = await browserType.launchPersistentContext(userDataDir).catch(e => e);
|
||||||
|
expect(error.message).toContain('This usually means that the profile is already in use by another instance of Chromium.');
|
||||||
|
} finally {
|
||||||
|
await browser.close();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
Loading…
x
Reference in New Issue
Block a user