Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions eslint.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -296,6 +296,11 @@ const reactFiles = [
`packages/web/src/**/*.tsx`,
];

const noProcessExitSyntax = {
selector: "CallExpression[callee.name='processExit']",
message: "Please use gracefullyProcessExitDoNotHang function to exit the process.",
};

function reactPackageSection(packageName) {
return {
files: [
Expand Down Expand Up @@ -348,6 +353,10 @@ export default [
{ object: "process", property: "stdout" },
{ object: "process", property: "stderr" },
],
"no-restricted-syntax": [
"error",
noProcessExitSyntax,
],
},
},
{
Expand Down Expand Up @@ -424,6 +433,7 @@ export default [
],
"no-restricted-syntax": [
"error",
noProcessExitSyntax,
{
selector: "TSAsExpression > TSAnyKeyword",
message: "Avoid 'as any' — risk of accidentally casting to client interfaces. Use a precise type or add an eslint-disable with justification.",
Expand Down
1 change: 1 addition & 0 deletions packages/playwright-chromium/cli.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
* limitations under the License.
*/

require('playwright-core/lib/bootstrap');
const { program } = require('playwright-core/lib/utilsBundle');
const { libCli } = require('playwright-core/lib/coreBundle');
libCli.decorateProgram(program);
Expand Down
1 change: 1 addition & 0 deletions packages/playwright-core/cli.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
require('./lib/bootstrap');
const { libCli, libCliTestStub } = require('./lib/coreBundle');
const { program } = require('./lib/utilsBundle');
libCli.decorateProgram(program);
Expand Down
3 changes: 3 additions & 0 deletions packages/playwright-core/src/DEPS.list
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,9 @@ node_modules/stoppable
node_modules/ws
node_modules/yaml

[bootstrap.ts]
"strict"

[package.ts]
"strict"

Expand Down
41 changes: 41 additions & 0 deletions packages/playwright-core/src/bootstrap.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,47 @@ if (major < minimumMajorNodeVersion) {
process.exit(1);
}

let stopProfiling = (callback: () => void) => callback();

if (process.env.PW_PROFILE_DIR) {
const fs: typeof import('fs') = require('fs');
const path: typeof import('path') = require('path');
const { Session }: typeof import('inspector') = require('inspector');

const profileDir = path.resolve(process.env.PW_PROFILE_DIR);
const script = process.argv[1] ? path.basename(process.argv[1], path.extname(process.argv[1])) : 'node';
const command = /^[a-z][\w-]*$/i.test(process.argv[2] ?? '') ? process.argv[2] : undefined;
const profileName = [script, command, process.pid].filter(Boolean).join('-');

const session = new Session();
session.connect();
session.post('Profiler.enable');
session.post('Profiler.start');

stopProfiling = callback => {
stopProfiling = callback => callback();
session.post('Profiler.stop', (error, result) => {
try {
if (!error) {
fs.mkdirSync(profileDir, { recursive: true });
fs.writeFileSync(path.join(profileDir, profileName + '.cpuprofile'), JSON.stringify(result.profile));
}
} finally {
callback();
}
});
};
process.on('beforeExit', () => stopProfiling(() => {}));
}

export function processExit(code?: number): never {
stopProfiling(() => {
// eslint-disable-next-line no-restricted-properties
process.exit(code);
});
return undefined as never;
}

if (process.env.PW_INSTRUMENT_MODULES) {
const Module = require('module');
const originalLoad = Module._load;
Expand Down
1 change: 0 additions & 1 deletion packages/playwright-core/src/cli/DEPS.list
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
../tools/cli-client/program.ts
../tools/mcp/program.ts
../tools/trace/traceCli.ts
../bootstrap.ts
node_modules/commander
node_modules/debug
node_modules/dotenv
1 change: 0 additions & 1 deletion packages/playwright-core/src/cli/program.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@

/* eslint-disable no-console */

import '../bootstrap';
import { program } from 'commander';
import { gracefullyProcessExitDoNotHang } from '@utils/processLauncher';
import { getPackageManagerExecCommand } from '@utils/env';
Expand Down
6 changes: 0 additions & 6 deletions packages/playwright-core/src/remote/playwrightConnection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@
* limitations under the License.
*/

import { startProfiling, stopProfiling } from '@utils/profiler';
import { debugLogger } from '@utils/debugLogger';
import { monotonicTime } from '@isomorphic/time';
import { Semaphore } from '@isomorphic/semaphore';
Expand All @@ -39,13 +38,11 @@ export class PlaywrightConnection {
private _id: string;
private _onDisconnectPromise: Promise<void> | undefined;
private _root: DispatcherScope;
private _profileName: string;

constructor(semaphore: Semaphore, transport: ServerTransport, controller: boolean, playwright: Playwright, initialize: () => Promise<PlaywrightInitializeResult>, id: string) {
this._transport = transport;
this._semaphore = semaphore;
this._id = id;
this._profileName = new Date().toISOString();

const lock = this._semaphore.acquire();

Expand Down Expand Up @@ -89,8 +86,6 @@ export class PlaywrightConnection {
}

this._root = new RootDispatcher(this._dispatcherConnection, async (scope, params) => {
await startProfiling();

const options = await initialize();
if (options.preLaunchedBrowser) {
const browser = options.preLaunchedBrowser;
Expand Down Expand Up @@ -130,7 +125,6 @@ export class PlaywrightConnection {
debugLogger.log('server', `[${this._id}] starting cleanup`);
for (const cleanup of this._cleanups)
await cleanup().catch(() => {});
await stopProfiling(this._profileName);
this._semaphore.release();
debugLogger.log('server', `[${this._id}] finished cleanup`);
}
Expand Down
1 change: 1 addition & 0 deletions packages/playwright-core/src/server/registry/DEPS.list
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
[*]
@utils/**
@isomorphic/**
../../bootstrap.ts
../../package.ts
../utils.ts
../userAgent.ts
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import { getAsBooleanFromENV } from '@utils/env';
import { httpRequest } from '@utils/network';
import { removeFolders } from '@utils/fileUtils';
import { extractZip } from '@utils/third_party/extractZip';
import { processExit } from '../../bootstrap';

export type DownloadParams = {
title: string;
Expand Down Expand Up @@ -133,17 +134,17 @@ export function runOopDownloadBrowserMain() {
if (method === 'download') {
try {
await main(params);
// eslint-disable-next-line no-restricted-properties
process.exit(0);
// eslint-disable-next-line no-restricted-syntax
processExit(0);
} catch (e) {
// eslint-disable-next-line no-console
console.error(e);
// eslint-disable-next-line no-restricted-properties
process.exit(1);
// eslint-disable-next-line no-restricted-syntax
processExit(1);
}
}
});

// eslint-disable-next-line no-restricted-properties
process.on('disconnect', () => { process.exit(0); });
// eslint-disable-next-line no-restricted-syntax
process.on('disconnect', () => { processExit(0); });
}
7 changes: 7 additions & 0 deletions packages/playwright-core/src/tools/cli-client/DEPS.list
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
[cli.ts]
"strict"
../../bootstrap.ts
./program.ts

[program.ts]
"strict"
../../bootstrap.ts
../../package.ts
../../serverRegistry.ts
./channelSessions.ts
Expand All @@ -10,6 +16,7 @@

[output.ts]
"strict"
../../bootstrap.ts
../utils/extension.ts
./channelSessions.ts

Expand Down
5 changes: 3 additions & 2 deletions packages/playwright-core/src/tools/cli-client/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,12 @@
* limitations under the License.
*/

import { processExit } from '../../bootstrap';
import { program } from './program';

program().catch(e => {
/* eslint-disable no-console */
console.error(e.message);
/* eslint-disable no-restricted-properties */
process.exit(1);
// eslint-disable-next-line no-restricted-syntax
processExit(1);
});
50 changes: 33 additions & 17 deletions packages/playwright-core/src/tools/cli-client/output.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,11 @@
*/

/* eslint-disable no-console */
/* eslint-disable no-restricted-properties */

import path from 'path';

import { playwrightExtensionInstallUrl } from '../utils/extension';
import { processExit } from '../../bootstrap';

import type { ChannelSession } from './channelSessions';
import type { BrowserDescriptor } from '../../serverRegistry';
Expand Down Expand Up @@ -88,48 +88,56 @@ export class TextOutput implements Output {
errorUnknownCommand(name: string | undefined, globalHelp: string): never {
console.error(`Unknown command: ${name}\n`);
console.log(globalHelp);
return process.exit(1);
// eslint-disable-next-line no-restricted-syntax
return processExit(1);
}

errorUnknownOption(opts: string[], commandHelp: string): never {
console.error(`Unknown option${opts.length > 1 ? 's' : ''}: ${opts.map(f => `--${f}`).join(', ')}`);
console.log('');
console.log(commandHelp);
return process.exit(1);
// eslint-disable-next-line no-restricted-syntax
return processExit(1);
}

errorTooManyArguments(expected: number, received: number, commandHelp: string): never {
console.error(`error: too many arguments: expected ${expected}, received ${received}`);
console.log('');
console.log(commandHelp);
return process.exit(1);
// eslint-disable-next-line no-restricted-syntax
return processExit(1);
}

errorAttachConflict(): never {
console.error(`Error: only one of [name], --cdp, --endpoint, or --extension can be specified`);
return process.exit(1);
// eslint-disable-next-line no-restricted-syntax
return processExit(1);
}

errorDetachNotAttached(session: string): never {
console.error(`Error: session '${session}' was not attached; use \`playwright-cli${session !== 'default' ? ` -s=${session}` : ''} close\` to stop it.`);
return process.exit(1);
// eslint-disable-next-line no-restricted-syntax
return processExit(1);
}

errorBrowserNotOpenForTool(session: string): never {
console.log(`The browser '${session}' is not open, please run open first`);
console.log('');
console.log(` playwright-cli${session !== 'default' ? ` -s=${session}` : ''} open [params]`);
return process.exit(1);
// eslint-disable-next-line no-restricted-syntax
return processExit(1);
}

errorAttachNoTarget(): never {
console.error(`Error: no target specified for attach command; use one of [name], --cdp, --endpoint, or --extension to specify the target to attach to.`);
return process.exit(1);
// eslint-disable-next-line no-restricted-syntax
return processExit(1);
}

errorInstallGlobalRequiresSkills(): never {
console.error(`Error: --global requires --skills`);
return process.exit(1);
// eslint-disable-next-line no-restricted-syntax
return processExit(1);
}

list({ all, browsers, servers, channelSessions }: ListData): void {
Expand Down Expand Up @@ -280,42 +288,50 @@ export class JsonOutput implements Output {

errorUnknownCommand(name: string | undefined, _globalHelp: string): never {
this._emit({ isError: true, error: `Unknown command: ${name}` });
return process.exit(1);
// eslint-disable-next-line no-restricted-syntax
return processExit(1);
}

errorUnknownOption(opts: string[], _commandHelp: string): never {
this._emit({ isError: true, error: `Unknown option${opts.length > 1 ? 's' : ''}: ${opts.map(f => `--${f}`).join(', ')}` });
return process.exit(1);
// eslint-disable-next-line no-restricted-syntax
return processExit(1);
}

errorTooManyArguments(expected: number, received: number, _commandHelp: string): never {
this._emit({ isError: true, error: `error: too many arguments: expected ${expected}, received ${received}` });
return process.exit(1);
// eslint-disable-next-line no-restricted-syntax
return processExit(1);
}

errorAttachConflict(): never {
this._emit({ isError: true, error: `only one of [name], --cdp, --endpoint, or --extension can be specified` });
return process.exit(1);
// eslint-disable-next-line no-restricted-syntax
return processExit(1);
}

errorDetachNotAttached(session: string): never {
this._emit({ isError: true, error: `session '${session}' was not attached; use close to stop it.` });
return process.exit(1);
// eslint-disable-next-line no-restricted-syntax
return processExit(1);
}

errorBrowserNotOpenForTool(session: string): never {
this._emit({ isError: true, error: `The browser '${session}' is not open, please run open first` });
return process.exit(1);
// eslint-disable-next-line no-restricted-syntax
return processExit(1);
}

errorAttachNoTarget(): never {
this._emit({ isError: true, error: `no target specified for attach command; use one of [name], --cdp, --endpoint, or --extension to specify the target to attach to.` });
return process.exit(1);
// eslint-disable-next-line no-restricted-syntax
return processExit(1);
}

errorInstallGlobalRequiresSkills(): never {
this._emit({ isError: true, error: `--global requires --skills` });
return process.exit(1);
// eslint-disable-next-line no-restricted-syntax
return processExit(1);
}

list({ all, browsers, servers, channelSessions }: ListData): void {
Expand Down
Loading
Loading