Skip to content

Commit

Permalink
chrome: remove state from isomorphic utils (#34795)
Browse files Browse the repository at this point in the history
  • Loading branch information
pavelfeldman authored Feb 14, 2025
1 parent be95a08 commit 8b28e63
Show file tree
Hide file tree
Showing 87 changed files with 560 additions and 467 deletions.
15 changes: 10 additions & 5 deletions packages/playwright-core/src/DEPS.list
Original file line number Diff line number Diff line change
@@ -1,22 +1,27 @@
[browserServerImpl.ts]
**
remote/
server/
server/utils
utils/isomorphic/
utilsBundle.ts

[androidServerImpl.ts]
**
remote/
server/
server/utils
utils/isomorphic/
utilsBundle.ts

[inProcessFactory.ts]
**

[inprocess.ts]
common/
utils/
server/utils

[outofprocess.ts]
client/
common/
protocol/
utils/
utils/isomorphic
server/utils
common/
12 changes: 10 additions & 2 deletions packages/playwright-core/src/browserServerImpl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@
* limitations under the License.
*/

import { envObjectToArray } from './client/clientHelper';
import { SocksProxy } from './server/utils/socksProxy';
import { PlaywrightServer } from './remote/playwrightServer';
import { helper } from './server/helper';
Expand All @@ -25,7 +24,7 @@ import { rewriteErrorMessage } from './utils/isomorphic/stackTrace';
import { ws } from './utilsBundle';

import type { BrowserServer, BrowserServerLauncher } from './client/browserType';
import type { LaunchServerOptions, Logger } from './client/types';
import type { LaunchServerOptions, Logger, Env } from './client/types';
import type { ProtocolLogger } from './server/types';
import type { WebSocketEventEmitter } from './utilsBundle';

Expand Down Expand Up @@ -85,3 +84,12 @@ function toProtocolLogger(logger: Logger | undefined): ProtocolLogger | undefine
logger.log('protocol', 'verbose', (direction === 'send' ? 'SEND ► ' : '◀ RECV ') + JSON.stringify(message), [], {});
} : undefined;
}

function envObjectToArray(env: Env): { name: string, value: string }[] {
const result: { name: string, value: string }[] = [];
for (const name in env) {
if (!Object.is(env[name], undefined))
result.push({ name, value: String(env[name]) });
}
return result;
}
2 changes: 0 additions & 2 deletions packages/playwright-core/src/cli/DEPS.list
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
[*]
../../
../client
../common
../debug/injected
../generated/
../server/
Expand Down
3 changes: 1 addition & 2 deletions packages/playwright-core/src/cli/program.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ import * as path from 'path';

import * as playwright from '../..';
import { launchBrowserServer, printApiJson, runDriver, runServer } from './driver';
import { isTargetClosedError } from '../client/errors';
import { registry, writeDockerVersion } from '../server';
import { gracefullyProcessExitDoNotHang } from '../utils';
import { runTraceInBrowser, runTraceViewerApp } from '../server/trace/viewer/traceViewer';
Expand Down Expand Up @@ -553,7 +552,7 @@ async function openPage(context: BrowserContext, url: string | undefined): Promi
else if (!url.startsWith('http') && !url.startsWith('file://') && !url.startsWith('about:') && !url.startsWith('data:'))
url = 'http://' + url;
await page.goto(url).catch(error => {
if (process.env.PWTEST_CLI_AUTO_EXIT_WHEN && isTargetClosedError(error)) {
if (process.env.PWTEST_CLI_AUTO_EXIT_WHEN) {
// Tests with PWTEST_CLI_AUTO_EXIT_WHEN might close page too fast, resulting
// in a stray navigation aborted error. We should ignore it.
} else {
Expand Down
1 change: 0 additions & 1 deletion packages/playwright-core/src/client/DEPS.list
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
[*]
../common/
../protocol/
../utils/isomorphic
8 changes: 4 additions & 4 deletions packages/playwright-core/src/client/android.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import { ChannelOwner } from './channelOwner';
import { TargetClosedError, isTargetClosedError } from './errors';
import { Events } from './events';
import { Waiter } from './waiter';
import { TimeoutSettings } from '../utils/isomorphic/timeoutSettings';
import { TimeoutSettings } from './timeoutSettings';
import { isRegExp, isString } from '../utils/isomorphic/rtti';
import { monotonicTime } from '../utils/isomorphic/time';
import { raceAgainstDeadline } from '../utils/isomorphic/timeoutRunner';
Expand All @@ -30,7 +30,7 @@ import type { Page } from './page';
import type * as types from './types';
import type * as api from '../../types/types';
import type { AndroidServerLauncherImpl } from '../androidServerImpl';
import type { Platform } from '../common/platform';
import type { Platform } from './platform';
import type * as channels from '@protocol/channels';

type Direction = 'down' | 'up' | 'left' | 'right';
Expand All @@ -46,7 +46,7 @@ export class Android extends ChannelOwner<channels.AndroidChannel> implements ap

constructor(parent: ChannelOwner, type: string, guid: string, initializer: channels.AndroidInitializer) {
super(parent, type, guid, initializer);
this._timeoutSettings = new TimeoutSettings();
this._timeoutSettings = new TimeoutSettings(this._platform);
}

setDefaultTimeout(timeout: number) {
Expand Down Expand Up @@ -112,7 +112,7 @@ export class AndroidDevice extends ChannelOwner<channels.AndroidDeviceChannel> i
constructor(parent: ChannelOwner, type: string, guid: string, initializer: channels.AndroidDeviceInitializer) {
super(parent, type, guid, initializer);
this.input = new AndroidInput(this);
this._timeoutSettings = new TimeoutSettings((parent as Android)._timeoutSettings);
this._timeoutSettings = new TimeoutSettings(this._platform, (parent as Android)._timeoutSettings);
this._channel.on('webViewAdded', ({ webView }) => this._onWebViewAdded(webView));
this._channel.on('webViewRemoved', ({ socketName }) => this._onWebViewRemoved(socketName));
this._channel.on('close', () => this._didClose());
Expand Down
7 changes: 4 additions & 3 deletions packages/playwright-core/src/client/browserContext.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ import { Tracing } from './tracing';
import { Waiter } from './waiter';
import { WebError } from './webError';
import { Worker } from './worker';
import { TimeoutSettings } from '../utils/isomorphic/timeoutSettings';
import { TimeoutSettings } from './timeoutSettings';
import { mkdirIfNeeded } from './fileUtils';
import { headersObjectToArray } from '../utils/isomorphic/headers';
import { urlMatchesEqual } from '../utils/isomorphic/urlMatch';
Expand All @@ -46,7 +46,7 @@ import type { BrowserContextOptions, Headers, LaunchOptions, StorageState, WaitF
import type * as structs from '../../types/structs';
import type * as api from '../../types/types';
import type { URLMatch } from '../utils/isomorphic/urlMatch';
import type { Platform } from '../common/platform';
import type { Platform } from './platform';
import type * as channels from '@protocol/channels';

export class BrowserContext extends ChannelOwner<channels.BrowserContextChannel> implements api.BrowserContext {
Expand All @@ -56,7 +56,7 @@ export class BrowserContext extends ChannelOwner<channels.BrowserContextChannel>
readonly _browser: Browser | null = null;
_browserType: BrowserType | undefined;
readonly _bindings = new Map<string, (source: structs.BindingSource, ...args: any[]) => any>();
_timeoutSettings = new TimeoutSettings();
_timeoutSettings: TimeoutSettings;
_ownerPage: Page | undefined;
private _closedPromise: Promise<void>;
_options: channels.BrowserNewContextParams = { };
Expand All @@ -83,6 +83,7 @@ export class BrowserContext extends ChannelOwner<channels.BrowserContextChannel>

constructor(parent: ChannelOwner, type: string, guid: string, initializer: channels.BrowserContextInitializer) {
super(parent, type, guid, initializer);
this._timeoutSettings = new TimeoutSettings(this._platform);
if (parent instanceof Browser)
this._browser = parent;
this._browser?._contexts.add(this);
Expand Down
2 changes: 1 addition & 1 deletion packages/playwright-core/src/client/browserType.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import { BrowserContext, prepareBrowserContextParams } from './browserContext';
import { ChannelOwner } from './channelOwner';
import { envObjectToArray } from './clientHelper';
import { Events } from './events';
import { assert } from '../utils/isomorphic/debug';
import { assert } from '../utils/isomorphic/assert';
import { headersObjectToArray } from '../utils/isomorphic/headers';
import { monotonicTime } from '../utils/isomorphic/time';
import { raceAgainstDeadline } from '../utils/isomorphic/timeoutRunner';
Expand Down
10 changes: 5 additions & 5 deletions packages/playwright-core/src/client/channelOwner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,14 @@

import { EventEmitter } from './eventEmitter';
import { ValidationError, maybeFindValidator } from '../protocol/validator';
import { isUnderTest } from '../utils/isomorphic/debug';
import { captureLibraryStackTrace, stringifyStackFrames } from '../utils/isomorphic/stackTrace';
import { captureLibraryStackTrace } from './clientStackTrace';
import { stringifyStackFrames } from '../utils/isomorphic/stackTrace';

import type { ClientInstrumentation } from './clientInstrumentation';
import type { Connection } from './connection';
import type { Logger } from './types';
import type { ValidatorContext } from '../protocol/validator';
import type { Platform } from '../common/platform';
import type { Platform } from './platform';
import type * as channels from '@protocol/channels';

type Listener = (...args: any[]) => void;
Expand Down Expand Up @@ -181,7 +181,7 @@ export abstract class ChannelOwner<T extends channels.Channel = channels.Channel

if (isInternal === undefined)
isInternal = this._isInternalType;
const stackTrace = captureLibraryStackTrace(this._platform.pathSeparator);
const stackTrace = captureLibraryStackTrace(this._platform);
const apiZone: ApiZone = { apiName: stackTrace.apiName, frames: stackTrace.frames, isInternal, reported: false, userData: undefined, stepId: undefined };

try {
Expand All @@ -192,7 +192,7 @@ export abstract class ChannelOwner<T extends channels.Channel = channels.Channel
}
return result;
} catch (e) {
const innerError = ((process.env.PWDEBUGIMPL || isUnderTest()) && e.stack) ? '\n<inner error>\n' + e.stack : '';
const innerError = ((process.env.PWDEBUGIMPL || this._platform.isUnderTest()) && e.stack) ? '\n<inner error>\n' + e.stack : '';
if (apiZone.apiName && !apiZone.apiName.includes('<anonymous>'))
e.message = apiZone.apiName + ': ' + e.message;
const stackFrames = '\n' + stringifyStackFrames(stackTrace.frames).join('\n') + innerError;
Expand Down
29 changes: 29 additions & 0 deletions packages/playwright-core/src/client/clientBundle.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/**
* Copyright (c) Microsoft Corporation.
*
* 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 { Connection } from './connection';
import { setPlatformForSelectors } from './selectors';
import { setPlatformForEventEmitter } from './eventEmitter';
import { setIsUnderTestForValidator } from '../protocol/validatorPrimitives';

import type { Platform } from './platform';

export function createConnectionFactory(platform: Platform): () => Connection {
setPlatformForSelectors(platform);
setPlatformForEventEmitter(platform);
setIsUnderTestForValidator(() => platform.isUnderTest());
return () => new Connection(platform);
}
2 changes: 1 addition & 1 deletion packages/playwright-core/src/client/clientHelper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
import { isString } from '../utils/isomorphic/rtti';

import type * as types from './types';
import type { Platform } from '../common/platform';
import type { Platform } from './platform';

export function envObjectToArray(env: types.Env): { name: string, value: string }[] {
const result: { name: string, value: string }[] = [];
Expand Down
78 changes: 78 additions & 0 deletions packages/playwright-core/src/client/clientStackTrace.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
/**
* Copyright (c) Microsoft Corporation.
*
* 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 { captureRawStack, parseStackFrame } from '../utils/isomorphic/stackTrace';

import type { Platform } from './platform';
import type { StackFrame } from '@isomorphic/stackTrace';

export function captureLibraryStackTrace(platform: Platform): { frames: StackFrame[], apiName: string } {
const stack = captureRawStack();

type ParsedFrame = {
frame: StackFrame;
frameText: string;
isPlaywrightLibrary: boolean;
};
let parsedFrames = stack.map(line => {
const frame = parseStackFrame(line, platform.pathSeparator);
if (!frame || !frame.file)
return null;
const isPlaywrightLibrary = !!platform.coreDir && frame.file.startsWith(platform.coreDir);
const parsed: ParsedFrame = {
frame,
frameText: line,
isPlaywrightLibrary
};
return parsed;
}).filter(Boolean) as ParsedFrame[];

let apiName = '';

// Deepest transition between non-client code calling into client
// code is the api entry.
for (let i = 0; i < parsedFrames.length - 1; i++) {
const parsedFrame = parsedFrames[i];
if (parsedFrame.isPlaywrightLibrary && !parsedFrames[i + 1].isPlaywrightLibrary) {
apiName = apiName || normalizeAPIName(parsedFrame.frame.function);
break;
}
}

function normalizeAPIName(name?: string): string {
if (!name)
return '';
const match = name.match(/(API|JS|CDP|[A-Z])(.*)/);
if (!match)
return name;
return match[1].toLowerCase() + match[2];
}

// This is for the inspector so that it did not include the test runner stack frames.
const filterPrefixes = platform.coreDir ? [platform.coreDir, ...platform.boxedStackPrefixes()] : platform.boxedStackPrefixes();
parsedFrames = parsedFrames.filter(f => {
if (process.env.PWDEBUGIMPL)
return true;
if (filterPrefixes.some(prefix => f.frame.file.startsWith(prefix)))
return false;
return true;
});

return {
frames: parsedFrames.map(p => p.frame),
apiName
};
}
16 changes: 12 additions & 4 deletions packages/playwright-core/src/client/connection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@
* limitations under the License.
*/


import { EventEmitter } from './eventEmitter';
import { Android, AndroidDevice, AndroidSocket } from './android';
import { Artifact } from './artifact';
Expand Down Expand Up @@ -42,12 +41,12 @@ import { Tracing } from './tracing';
import { Worker } from './worker';
import { WritableStream } from './writableStream';
import { ValidationError, findValidator } from '../protocol/validator';
import { formatCallLog, rewriteErrorMessage } from '../utils/isomorphic/stackTrace';
import { rewriteErrorMessage } from '../utils/isomorphic/stackTrace';

import type { ClientInstrumentation } from './clientInstrumentation';
import type { HeadersArray } from './types';
import type { ValidatorContext } from '../protocol/validator';
import type { Platform } from '../common/platform';
import type { Platform } from './platform';
import type * as channels from '@protocol/channels';

class Root extends ChannelOwner<channels.RootChannel> {
Expand Down Expand Up @@ -83,7 +82,7 @@ export class Connection extends EventEmitter {
// Used from @playwright/test fixtures -> TODO remove?
readonly headers: HeadersArray;

constructor(localUtils: LocalUtils | undefined, platform: Platform, instrumentation: ClientInstrumentation | undefined, headers: HeadersArray) {
constructor(platform: Platform, localUtils?: LocalUtils, instrumentation?: ClientInstrumentation, headers: HeadersArray = []) {
super();
this._instrumentation = instrumentation || createInstrumentation();
this._localUtils = localUtils;
Expand Down Expand Up @@ -333,3 +332,12 @@ export class Connection extends EventEmitter {
return result;
}
}

function formatCallLog(platform: Platform, log: string[] | undefined): string {
if (!log || !log.some(l => !!l))
return '';
return `
Call log:
${platform.colors.dim(log.join('\n'))}
`;
}
2 changes: 1 addition & 1 deletion packages/playwright-core/src/client/consoleMessage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import { JSHandle } from './jsHandle';
import { Page } from './page';

import type * as api from '../../types/types';
import type { Platform } from '../common/platform';
import type { Platform } from './platform';
import type * as channels from '@protocol/channels';

type ConsoleMessageLocation = channels.BrowserContextConsoleEvent['location'];
Expand Down
Loading

0 comments on commit 8b28e63

Please sign in to comment.