chore: do not use process in client (#34816)
This commit is contained in:
parent
3606a434fe
commit
f70f92d5cd
|
@ -177,7 +177,7 @@ const noBooleanCompareRules = {
|
||||||
'@typescript-eslint/no-unnecessary-boolean-literal-compare': 2,
|
'@typescript-eslint/no-unnecessary-boolean-literal-compare': 2,
|
||||||
};
|
};
|
||||||
|
|
||||||
const noRestrictedGlobalsRules = {
|
const noWebGlobalsRules = {
|
||||||
'no-restricted-globals': [
|
'no-restricted-globals': [
|
||||||
'error',
|
'error',
|
||||||
{ 'name': 'window' },
|
{ 'name': 'window' },
|
||||||
|
@ -186,6 +186,13 @@ const noRestrictedGlobalsRules = {
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const noNodeGlobalsRules = {
|
||||||
|
'no-restricted-globals': [
|
||||||
|
'error',
|
||||||
|
{ 'name': 'process' },
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
const importOrderRules = {
|
const importOrderRules = {
|
||||||
'import/order': [2, {
|
'import/order': [2, {
|
||||||
'groups': ['builtin', 'external', 'internal', ['parent', 'sibling'], 'index', 'type'],
|
'groups': ['builtin', 'external', 'internal', ['parent', 'sibling'], 'index', 'type'],
|
||||||
|
@ -249,7 +256,19 @@ export default [{
|
||||||
files: ['packages/playwright-core/src/server/injected/**/*.ts'],
|
files: ['packages/playwright-core/src/server/injected/**/*.ts'],
|
||||||
languageOptions: languageOptionsWithTsConfig,
|
languageOptions: languageOptionsWithTsConfig,
|
||||||
rules: {
|
rules: {
|
||||||
...noRestrictedGlobalsRules,
|
...noWebGlobalsRules,
|
||||||
|
...noFloatingPromisesRules,
|
||||||
|
...noBooleanCompareRules,
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
files: [
|
||||||
|
'packages/playwright-core/src/client/**/*.ts',
|
||||||
|
'packages/playwright-core/src/protocol/**/*.ts',
|
||||||
|
'packages/playwright-core/src/utils/**/*.ts',
|
||||||
|
],
|
||||||
|
languageOptions: languageOptionsWithTsConfig,
|
||||||
|
rules: {
|
||||||
|
...noNodeGlobalsRules,
|
||||||
...noFloatingPromisesRules,
|
...noFloatingPromisesRules,
|
||||||
...noBooleanCompareRules,
|
...noBooleanCompareRules,
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,9 +23,9 @@ import * as path from 'path';
|
||||||
import * as playwright from '../..';
|
import * as playwright from '../..';
|
||||||
import { launchBrowserServer, printApiJson, runDriver, runServer } from './driver';
|
import { launchBrowserServer, printApiJson, runDriver, runServer } from './driver';
|
||||||
import { registry, writeDockerVersion } from '../server';
|
import { registry, writeDockerVersion } from '../server';
|
||||||
import { gracefullyProcessExitDoNotHang } from '../utils';
|
import { gracefullyProcessExitDoNotHang, isLikelyNpxGlobal } from '../utils';
|
||||||
import { runTraceInBrowser, runTraceViewerApp } from '../server/trace/viewer/traceViewer';
|
import { runTraceInBrowser, runTraceViewerApp } from '../server/trace/viewer/traceViewer';
|
||||||
import { assert, getPackageManagerExecCommand, isLikelyNpxGlobal } from '../utils';
|
import { assert, getPackageManagerExecCommand } from '../utils';
|
||||||
import { wrapInASCIIBox } from '../server/utils/ascii';
|
import { wrapInASCIIBox } from '../server/utils/ascii';
|
||||||
import { dotenv, program } from '../utilsBundle';
|
import { dotenv, program } from '../utilsBundle';
|
||||||
|
|
||||||
|
|
|
@ -51,7 +51,9 @@ export class Android extends ChannelOwner<channels.AndroidChannel> implements ap
|
||||||
|
|
||||||
setDefaultTimeout(timeout: number) {
|
setDefaultTimeout(timeout: number) {
|
||||||
this._timeoutSettings.setDefaultTimeout(timeout);
|
this._timeoutSettings.setDefaultTimeout(timeout);
|
||||||
this._channel.setDefaultTimeoutNoReply({ timeout });
|
this._wrapApiCall(async () => {
|
||||||
|
await this._channel.setDefaultTimeoutNoReply({ timeout });
|
||||||
|
}, true).catch(() => {});
|
||||||
}
|
}
|
||||||
|
|
||||||
async devices(options: { port?: number } = {}): Promise<AndroidDevice[]> {
|
async devices(options: { port?: number } = {}): Promise<AndroidDevice[]> {
|
||||||
|
@ -133,7 +135,9 @@ export class AndroidDevice extends ChannelOwner<channels.AndroidDeviceChannel> i
|
||||||
|
|
||||||
setDefaultTimeout(timeout: number) {
|
setDefaultTimeout(timeout: number) {
|
||||||
this._timeoutSettings.setDefaultTimeout(timeout);
|
this._timeoutSettings.setDefaultTimeout(timeout);
|
||||||
this._channel.setDefaultTimeoutNoReply({ timeout });
|
this._wrapApiCall(async () => {
|
||||||
|
await this._channel.setDefaultTimeoutNoReply({ timeout });
|
||||||
|
}, true).catch(() => {});
|
||||||
}
|
}
|
||||||
|
|
||||||
serial(): string {
|
serial(): string {
|
||||||
|
|
|
@ -246,15 +246,15 @@ export class BrowserContext extends ChannelOwner<channels.BrowserContextChannel>
|
||||||
setDefaultNavigationTimeout(timeout: number | undefined) {
|
setDefaultNavigationTimeout(timeout: number | undefined) {
|
||||||
this._timeoutSettings.setDefaultNavigationTimeout(timeout);
|
this._timeoutSettings.setDefaultNavigationTimeout(timeout);
|
||||||
this._wrapApiCall(async () => {
|
this._wrapApiCall(async () => {
|
||||||
this._channel.setDefaultNavigationTimeoutNoReply({ timeout }).catch(() => {});
|
await this._channel.setDefaultNavigationTimeoutNoReply({ timeout });
|
||||||
}, true);
|
}, true).catch(() => {});
|
||||||
}
|
}
|
||||||
|
|
||||||
setDefaultTimeout(timeout: number | undefined) {
|
setDefaultTimeout(timeout: number | undefined) {
|
||||||
this._timeoutSettings.setDefaultTimeout(timeout);
|
this._timeoutSettings.setDefaultTimeout(timeout);
|
||||||
this._wrapApiCall(async () => {
|
this._wrapApiCall(async () => {
|
||||||
this._channel.setDefaultTimeoutNoReply({ timeout }).catch(() => {});
|
await this._channel.setDefaultTimeoutNoReply({ timeout });
|
||||||
}, true);
|
}, true).catch(() => {});
|
||||||
}
|
}
|
||||||
|
|
||||||
browser(): Browser | null {
|
browser(): Browser | null {
|
||||||
|
@ -559,7 +559,7 @@ export async function prepareBrowserContextParams(platform: Platform, options: B
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
if (contextParams.recordVideo && contextParams.recordVideo.dir)
|
if (contextParams.recordVideo && contextParams.recordVideo.dir)
|
||||||
contextParams.recordVideo.dir = platform.path().resolve(process.cwd(), contextParams.recordVideo.dir);
|
contextParams.recordVideo.dir = platform.path().resolve(contextParams.recordVideo.dir);
|
||||||
return contextParams;
|
return contextParams;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -199,7 +199,7 @@ export abstract class ChannelOwner<T extends channels.Channel = channels.Channel
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
const innerError = ((process.env.PWDEBUGIMPL || this._platform.isUnderTest()) && e.stack) ? '\n<inner error>\n' + e.stack : '';
|
const innerError = ((this._platform.showInternalStackFrames() || this._platform.isUnderTest()) && e.stack) ? '\n<inner error>\n' + e.stack : '';
|
||||||
if (apiZone.apiName && !apiZone.apiName.includes('<anonymous>'))
|
if (apiZone.apiName && !apiZone.apiName.includes('<anonymous>'))
|
||||||
e.message = apiZone.apiName + ': ' + e.message;
|
e.message = apiZone.apiName + ': ' + e.message;
|
||||||
const stackFrames = '\n' + stringifyStackFrames(stackTrace.frames).join('\n') + innerError;
|
const stackFrames = '\n' + stringifyStackFrames(stackTrace.frames).join('\n') + innerError;
|
||||||
|
|
|
@ -28,7 +28,7 @@ export function captureLibraryStackTrace(platform: Platform): { frames: StackFra
|
||||||
isPlaywrightLibrary: boolean;
|
isPlaywrightLibrary: boolean;
|
||||||
};
|
};
|
||||||
let parsedFrames = stack.map(line => {
|
let parsedFrames = stack.map(line => {
|
||||||
const frame = parseStackFrame(line, platform.pathSeparator);
|
const frame = parseStackFrame(line, platform.pathSeparator, platform.showInternalStackFrames());
|
||||||
if (!frame || !frame.file)
|
if (!frame || !frame.file)
|
||||||
return null;
|
return null;
|
||||||
const isPlaywrightLibrary = !!platform.coreDir && frame.file.startsWith(platform.coreDir);
|
const isPlaywrightLibrary = !!platform.coreDir && frame.file.startsWith(platform.coreDir);
|
||||||
|
@ -62,10 +62,8 @@ export function captureLibraryStackTrace(platform: Platform): { frames: StackFra
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is for the inspector so that it did not include the test runner stack frames.
|
// 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();
|
const filterPrefixes = platform.boxedStackPrefixes();
|
||||||
parsedFrames = parsedFrames.filter(f => {
|
parsedFrames = parsedFrames.filter(f => {
|
||||||
if (process.env.PWDEBUGIMPL)
|
|
||||||
return true;
|
|
||||||
if (filterPrefixes.some(prefix => f.frame.file.startsWith(prefix)))
|
if (filterPrefixes.some(prefix => f.frame.file.startsWith(prefix)))
|
||||||
return false;
|
return false;
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -54,7 +54,7 @@ export class Electron extends ChannelOwner<channels.ElectronChannel> implements
|
||||||
async launch(options: ElectronOptions = {}): Promise<ElectronApplication> {
|
async launch(options: ElectronOptions = {}): Promise<ElectronApplication> {
|
||||||
const params: channels.ElectronLaunchParams = {
|
const params: channels.ElectronLaunchParams = {
|
||||||
...await prepareBrowserContextParams(this._platform, options),
|
...await prepareBrowserContextParams(this._platform, options),
|
||||||
env: envObjectToArray(options.env ? options.env : process.env),
|
env: envObjectToArray(options.env ? options.env : this._platform.env),
|
||||||
tracesDir: options.tracesDir,
|
tracesDir: options.tracesDir,
|
||||||
};
|
};
|
||||||
const app = ElectronApplication.from((await this._channel.launch(params)).electronApplication);
|
const app = ElectronApplication.from((await this._channel.launch(params)).electronApplication);
|
||||||
|
|
|
@ -277,15 +277,15 @@ export class Page extends ChannelOwner<channels.PageChannel> implements api.Page
|
||||||
setDefaultNavigationTimeout(timeout: number) {
|
setDefaultNavigationTimeout(timeout: number) {
|
||||||
this._timeoutSettings.setDefaultNavigationTimeout(timeout);
|
this._timeoutSettings.setDefaultNavigationTimeout(timeout);
|
||||||
this._wrapApiCall(async () => {
|
this._wrapApiCall(async () => {
|
||||||
this._channel.setDefaultNavigationTimeoutNoReply({ timeout }).catch(() => {});
|
await this._channel.setDefaultNavigationTimeoutNoReply({ timeout });
|
||||||
}, true);
|
}, true).catch(() => {});
|
||||||
}
|
}
|
||||||
|
|
||||||
setDefaultTimeout(timeout: number) {
|
setDefaultTimeout(timeout: number) {
|
||||||
this._timeoutSettings.setDefaultTimeout(timeout);
|
this._timeoutSettings.setDefaultTimeout(timeout);
|
||||||
this._wrapApiCall(async () => {
|
this._wrapApiCall(async () => {
|
||||||
this._channel.setDefaultTimeoutNoReply({ timeout }).catch(() => {});
|
await this._channel.setDefaultTimeoutNoReply({ timeout });
|
||||||
}, true);
|
}, true).catch(() => {});
|
||||||
}
|
}
|
||||||
|
|
||||||
private _forceVideo(): Video {
|
private _forceVideo(): Video {
|
||||||
|
|
|
@ -45,6 +45,7 @@ export type Platform = {
|
||||||
coreDir?: string;
|
coreDir?: string;
|
||||||
createGuid: () => string;
|
createGuid: () => string;
|
||||||
defaultMaxListeners: () => number;
|
defaultMaxListeners: () => number;
|
||||||
|
env: Record<string, string | undefined>;
|
||||||
fs: () => typeof fs;
|
fs: () => typeof fs;
|
||||||
inspectCustom: symbol | undefined;
|
inspectCustom: symbol | undefined;
|
||||||
isDebugMode: () => boolean;
|
isDebugMode: () => boolean;
|
||||||
|
@ -54,6 +55,7 @@ export type Platform = {
|
||||||
log: (name: 'api' | 'channel', message: string | Error | object) => void;
|
log: (name: 'api' | 'channel', message: string | Error | object) => void;
|
||||||
path: () => typeof path;
|
path: () => typeof path;
|
||||||
pathSeparator: string;
|
pathSeparator: string;
|
||||||
|
showInternalStackFrames: () => boolean,
|
||||||
streamFile: (path: string, writable: Writable) => Promise<void>,
|
streamFile: (path: string, writable: Writable) => Promise<void>,
|
||||||
streamReadable: (channel: channels.StreamChannel) => Readable,
|
streamReadable: (channel: channels.StreamChannel) => Readable,
|
||||||
streamWritable: (channel: channels.WritableStreamChannel) => Writable,
|
streamWritable: (channel: channels.WritableStreamChannel) => Writable,
|
||||||
|
@ -77,6 +79,8 @@ export const emptyPlatform: Platform = {
|
||||||
|
|
||||||
defaultMaxListeners: () => 10,
|
defaultMaxListeners: () => 10,
|
||||||
|
|
||||||
|
env: {},
|
||||||
|
|
||||||
fs: () => {
|
fs: () => {
|
||||||
throw new Error('Not implemented');
|
throw new Error('Not implemented');
|
||||||
},
|
},
|
||||||
|
@ -101,6 +105,8 @@ export const emptyPlatform: Platform = {
|
||||||
|
|
||||||
pathSeparator: '/',
|
pathSeparator: '/',
|
||||||
|
|
||||||
|
showInternalStackFrames: () => false,
|
||||||
|
|
||||||
streamFile(path: string, writable: Writable): Promise<void> {
|
streamFile(path: string, writable: Writable): Promise<void> {
|
||||||
throw new Error('Streams are not available');
|
throw new Error('Streams are not available');
|
||||||
},
|
},
|
||||||
|
|
|
@ -96,8 +96,8 @@ export class Waiter {
|
||||||
log(s: string) {
|
log(s: string) {
|
||||||
this._logs.push(s);
|
this._logs.push(s);
|
||||||
this._channelOwner._wrapApiCall(async () => {
|
this._channelOwner._wrapApiCall(async () => {
|
||||||
await this._channelOwner._channel.waitForEventInfo({ info: { waitId: this._waitId, phase: 'log', message: s } }).catch(() => {});
|
await this._channelOwner._channel.waitForEventInfo({ info: { waitId: this._waitId, phase: 'log', message: s } });
|
||||||
}, true);
|
}, true).catch(() => {});
|
||||||
}
|
}
|
||||||
|
|
||||||
private _rejectOn(promise: Promise<any>, dispose?: () => void) {
|
private _rejectOn(promise: Promise<any>, dispose?: () => void) {
|
||||||
|
|
|
@ -39,7 +39,7 @@ export async function connectOverWebSocket(parentConnection: Connection, params:
|
||||||
connection!.dispatch(message);
|
connection!.dispatch(message);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
closeError = String(e);
|
closeError = String(e);
|
||||||
transport.close();
|
transport.close().catch(() => {});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return connection;
|
return connection;
|
||||||
|
@ -70,7 +70,7 @@ class JsonPipeTransport implements Transport {
|
||||||
}
|
}
|
||||||
|
|
||||||
async send(message: object) {
|
async send(message: object) {
|
||||||
this._owner._wrapApiCall(async () => {
|
await this._owner._wrapApiCall(async () => {
|
||||||
await this._pipe!.send({ message });
|
await this._pipe!.send({ message });
|
||||||
}, /* isInternal */ true);
|
}, /* isInternal */ true);
|
||||||
}
|
}
|
||||||
|
|
|
@ -47,3 +47,7 @@ export function getPackageManagerExecCommand() {
|
||||||
return 'pnpm exec';
|
return 'pnpm exec';
|
||||||
return 'npx';
|
return 'npx';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function isLikelyNpxGlobal() {
|
||||||
|
return process.argv.length >= 2 && process.argv[1].includes('_npx');
|
||||||
|
}
|
||||||
|
|
|
@ -61,10 +61,16 @@ export function setBoxedStackPrefixes(prefixes: string[]) {
|
||||||
boxedStackPrefixes = prefixes;
|
boxedStackPrefixes = prefixes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const coreDir = path.dirname(require.resolve('../../../package.json'));
|
||||||
|
|
||||||
export const nodePlatform: Platform = {
|
export const nodePlatform: Platform = {
|
||||||
name: 'node',
|
name: 'node',
|
||||||
|
|
||||||
boxedStackPrefixes: () => boxedStackPrefixes,
|
boxedStackPrefixes: () => {
|
||||||
|
if (process.env.PWDEBUGIMPL)
|
||||||
|
return [];
|
||||||
|
return [coreDir, ...boxedStackPrefixes];
|
||||||
|
},
|
||||||
|
|
||||||
calculateSha1: (text: string) => {
|
calculateSha1: (text: string) => {
|
||||||
const sha1 = crypto.createHash('sha1');
|
const sha1 = crypto.createHash('sha1');
|
||||||
|
@ -74,13 +80,15 @@ export const nodePlatform: Platform = {
|
||||||
|
|
||||||
colors,
|
colors,
|
||||||
|
|
||||||
coreDir: path.dirname(require.resolve('../../../package.json')),
|
coreDir,
|
||||||
|
|
||||||
createGuid: () => crypto.randomBytes(16).toString('hex'),
|
createGuid: () => crypto.randomBytes(16).toString('hex'),
|
||||||
|
|
||||||
defaultMaxListeners: () => EventEmitter.defaultMaxListeners,
|
defaultMaxListeners: () => EventEmitter.defaultMaxListeners,
|
||||||
fs: () => fs,
|
fs: () => fs,
|
||||||
|
|
||||||
|
env: process.env,
|
||||||
|
|
||||||
inspectCustom: util.inspect.custom,
|
inspectCustom: util.inspect.custom,
|
||||||
|
|
||||||
isDebugMode: () => !!debugMode(),
|
isDebugMode: () => !!debugMode(),
|
||||||
|
@ -101,6 +109,8 @@ export const nodePlatform: Platform = {
|
||||||
|
|
||||||
pathSeparator: path.sep,
|
pathSeparator: path.sep,
|
||||||
|
|
||||||
|
showInternalStackFrames: () => !!process.env.PWDEBUGIMPL,
|
||||||
|
|
||||||
async streamFile(path: string, stream: Writable): Promise<void> {
|
async streamFile(path: string, stream: Writable): Promise<void> {
|
||||||
await pipelineAsync(fs.createReadStream(path), stream);
|
await pipelineAsync(fs.createReadStream(path), stream);
|
||||||
},
|
},
|
||||||
|
|
|
@ -27,5 +27,3 @@ export function isObject(obj: any): obj is NonNullable<object> {
|
||||||
export function isError(obj: any): obj is Error {
|
export function isError(obj: any): obj is Error {
|
||||||
return obj instanceof Error || (obj && Object.getPrototypeOf(obj)?.name === 'Error');
|
return obj instanceof Error || (obj && Object.getPrototypeOf(obj)?.name === 'Error');
|
||||||
}
|
}
|
||||||
|
|
||||||
export const isLikelyNpxGlobal = () => process.argv.length >= 2 && process.argv[1].includes('_npx');
|
|
||||||
|
|
|
@ -37,7 +37,7 @@ export function captureRawStack(): RawStack {
|
||||||
return stack.split('\n');
|
return stack.split('\n');
|
||||||
}
|
}
|
||||||
|
|
||||||
export function parseStackFrame(text: string, pathSeparator: string): StackFrame | null {
|
export function parseStackFrame(text: string, pathSeparator: string, showInternalStackFrames: boolean): StackFrame | null {
|
||||||
const match = text && text.match(re);
|
const match = text && text.match(re);
|
||||||
if (!match)
|
if (!match)
|
||||||
return null;
|
return null;
|
||||||
|
@ -46,7 +46,7 @@ export function parseStackFrame(text: string, pathSeparator: string): StackFrame
|
||||||
let file = match[7];
|
let file = match[7];
|
||||||
if (!file)
|
if (!file)
|
||||||
return null;
|
return null;
|
||||||
if (!process.env.PWDEBUGIMPL && (file.startsWith('internal') || file.startsWith('node:')))
|
if (!showInternalStackFrames && (file.startsWith('internal') || file.startsWith('node:')))
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
const line = match[8];
|
const line = match[8];
|
||||||
|
|
|
@ -522,7 +522,7 @@ export function prepareErrorStack(stack: string): {
|
||||||
const stackLines = lines.slice(firstStackLine);
|
const stackLines = lines.slice(firstStackLine);
|
||||||
let location: Location | undefined;
|
let location: Location | undefined;
|
||||||
for (const line of stackLines) {
|
for (const line of stackLines) {
|
||||||
const frame = parseStackFrame(line, path.sep);
|
const frame = parseStackFrame(line, path.sep, !!process.env.PWDEBUGIMPL);
|
||||||
if (!frame || !frame.file)
|
if (!frame || !frame.file)
|
||||||
continue;
|
continue;
|
||||||
if (belongsToNodeModules(frame.file))
|
if (belongsToNodeModules(frame.file))
|
||||||
|
|
|
@ -55,7 +55,7 @@ export function filterStackFile(file: string) {
|
||||||
export function filteredStackTrace(rawStack: RawStack): StackFrame[] {
|
export function filteredStackTrace(rawStack: RawStack): StackFrame[] {
|
||||||
const frames: StackFrame[] = [];
|
const frames: StackFrame[] = [];
|
||||||
for (const line of rawStack) {
|
for (const line of rawStack) {
|
||||||
const frame = parseStackFrame(line, path.sep);
|
const frame = parseStackFrame(line, path.sep, !!process.env.PWDEBUGIMPL);
|
||||||
if (!frame || !frame.file)
|
if (!frame || !frame.file)
|
||||||
continue;
|
continue;
|
||||||
if (!filterStackFile(frame.file))
|
if (!filterStackFile(frame.file))
|
||||||
|
|
Loading…
Reference in New Issue