{report.projectNames.length === 1 && !!report.projectNames[0] &&
Project: {report.projectNames[0]}
}
diff --git a/packages/html-reporter/src/testResultView.tsx b/packages/html-reporter/src/testResultView.tsx
index 410677cb02..bdaec18d24 100644
--- a/packages/html-reporter/src/testResultView.tsx
+++ b/packages/html-reporter/src/testResultView.tsx
@@ -36,8 +36,9 @@ function groupImageDiffs(screenshots: Set
): ImageDiffWithAnchors
const snapshotNameToImageDiff = new Map();
for (const attachment of screenshots) {
const match = attachment.name.match(/^(.*)-(expected|actual|diff|previous)(\.[^.]+)?$/);
- if (!match)
+ if (!match) {
continue;
+ }
const [, name, category, extension = ''] = match;
const snapshotName = name + extension;
let imageDiff = snapshotNameToImageDiff.get(snapshotName);
@@ -46,14 +47,18 @@ function groupImageDiffs(screenshots: Set): ImageDiffWithAnchors
snapshotNameToImageDiff.set(snapshotName, imageDiff);
}
imageDiff.anchors.push(`attachment-${attachment.name}`);
- if (category === 'actual')
+ if (category === 'actual') {
imageDiff.actual = { attachment };
- if (category === 'expected')
+ }
+ if (category === 'expected') {
imageDiff.expected = { attachment, title: 'Expected' };
- if (category === 'previous')
+ }
+ if (category === 'previous') {
imageDiff.expected = { attachment, title: 'Previous' };
- if (category === 'diff')
+ }
+ if (category === 'diff') {
imageDiff.diff = { attachment };
+ }
}
for (const [name, diff] of snapshotNameToImageDiff) {
if (!diff.actual || !diff.expected) {
@@ -88,8 +93,9 @@ export const TestResultView: React.FC<{
return
{!!errors.length &&
{errors.map((error, index) => {
- if (error.type === 'screenshot')
+ if (error.type === 'screenshot') {
return ;
+ }
return ;
})}
}
@@ -177,15 +183,18 @@ const StepTreeItem: React.FC<{
const attachmentName = step.title.match(/^attach "(.*)"$/)?.[1];
return
{msToString(step.duration)}
- {attachmentName && { evt.stopPropagation(); }}>{icons.attachment()}}
+ {attachmentName && {
+ evt.stopPropagation();
+ }}>{icons.attachment()}}
{statusIcon(step.error || step.duration === -1 ? 'failed' : 'passed')}
{step.title}
{step.count > 1 && <> ✕ {step.count}>}
{step.location && — {step.location.file}:{step.location.line}}
} loadChildren={step.steps.length + (step.snippet ? 1 : 0) ? () => {
const children = step.steps.map((s, i) => );
- if (step.snippet)
+ if (step.snippet) {
children.unshift();
+ }
return children;
} : undefined} depth={depth}/>;
};
diff --git a/packages/html-reporter/src/treeItem.tsx b/packages/html-reporter/src/treeItem.tsx
index 926a398a05..7f06cf1fb7 100644
--- a/packages/html-reporter/src/treeItem.tsx
+++ b/packages/html-reporter/src/treeItem.tsx
@@ -30,7 +30,9 @@ export const TreeItem: React.FunctionComponent<{
}> = ({ title, loadChildren, onClick, expandByDefault, depth, selected, style }) => {
const [expanded, setExpanded] = React.useState(expandByDefault || false);
return
-
{ onClick?.(); setExpanded(!expanded); }} >
+ {
+ onClick?.(); setExpanded(!expanded);
+ }} >
{loadChildren && !!expanded && icons.downArrow()}
{loadChildren && !expanded && icons.rightArrow()}
{!loadChildren && {icons.rightArrow()}}
diff --git a/packages/html-reporter/src/utils.ts b/packages/html-reporter/src/utils.ts
index 65404b2fe7..60dc3c1be9 100644
--- a/packages/html-reporter/src/utils.ts
+++ b/packages/html-reporter/src/utils.ts
@@ -15,26 +15,32 @@
*/
export function msToString(ms: number): string {
- if (!isFinite(ms))
+ if (!isFinite(ms)) {
return '-';
+ }
- if (ms === 0)
+ if (ms === 0) {
return '0ms';
+ }
- if (ms < 1000)
+ if (ms < 1000) {
return ms.toFixed(0) + 'ms';
+ }
const seconds = ms / 1000;
- if (seconds < 60)
+ if (seconds < 60) {
return seconds.toFixed(1) + 's';
+ }
const minutes = seconds / 60;
- if (minutes < 60)
+ if (minutes < 60) {
return minutes.toFixed(1) + 'm';
+ }
const hours = minutes / 60;
- if (hours < 24)
+ if (hours < 24) {
return hours.toFixed(1) + 'h';
+ }
const days = hours / 24;
return days.toFixed(1) + 'd';
@@ -43,8 +49,9 @@ export function msToString(ms: number): string {
// hash string to integer in range [0, 6] for color index, to get same color for same tag
export function hashStringToInt(str: string) {
let hash = 0;
- for (let i = 0; i < str.length; i++)
+ for (let i = 0; i < str.length; i++) {
hash = str.charCodeAt(i) + ((hash << 8) - hash);
+ }
return Math.abs(hash % 6);
}
diff --git a/packages/playwright-core/src/androidServerImpl.ts b/packages/playwright-core/src/androidServerImpl.ts
index f0108e67c7..c45f4ca6bf 100644
--- a/packages/playwright-core/src/androidServerImpl.ts
+++ b/packages/playwright-core/src/androidServerImpl.ts
@@ -32,17 +32,20 @@ export class AndroidServerLauncherImpl {
omitDriverInstall: options.omitDriverInstall,
});
- if (devices.length === 0)
+ if (devices.length === 0) {
throw new Error('No devices found');
+ }
if (options.deviceSerialNumber) {
devices = devices.filter(d => d.serial === options.deviceSerialNumber);
- if (devices.length === 0)
+ if (devices.length === 0) {
throw new Error(`No device with serial number '${options.deviceSerialNumber}' was found`);
+ }
}
- if (devices.length > 1)
+ if (devices.length > 1) {
throw new Error(`More than one device found. Please specify deviceSerialNumber`);
+ }
const device = devices[0];
diff --git a/packages/playwright-core/src/browserServerImpl.ts b/packages/playwright-core/src/browserServerImpl.ts
index dfe960c5ea..73455aa5c0 100644
--- a/packages/playwright-core/src/browserServerImpl.ts
+++ b/packages/playwright-core/src/browserServerImpl.ts
@@ -80,7 +80,8 @@ export class BrowserServerLauncherImpl implements BrowserServerLauncher {
function toProtocolLogger(logger: Logger | undefined): ProtocolLogger | undefined {
return logger ? (direction: 'send' | 'receive', message: object) => {
- if (logger.isEnabled('protocol', 'verbose'))
+ if (logger.isEnabled('protocol', 'verbose')) {
logger.log('protocol', 'verbose', (direction === 'send' ? 'SEND ► ' : '◀ RECV ') + JSON.stringify(message), [], {});
+ }
} : undefined;
}
diff --git a/packages/playwright-core/src/cli/driver.ts b/packages/playwright-core/src/cli/driver.ts
index e48dc2a4d2..5448618562 100644
--- a/packages/playwright-core/src/cli/driver.ts
+++ b/packages/playwright-core/src/cli/driver.ts
@@ -41,8 +41,9 @@ export function runDriver() {
// Certain Language Binding JSON parsers (e.g. .NET) do not like strings with lone surrogates.
const isJavaScriptLanguageBinding = !process.env.PW_LANG_NAME || process.env.PW_LANG_NAME === 'javascript';
const replacer = !isJavaScriptLanguageBinding && (String.prototype as any).toWellFormed ? (key: string, value: any): any => {
- if (typeof value === 'string')
+ if (typeof value === 'string') {
return value.toWellFormed();
+ }
return value;
} : undefined;
dispatcherConnection.onmessage = message => transport.send(JSON.stringify(message, replacer));
@@ -85,8 +86,9 @@ export async function runServer(options: RunServerOptions) {
export async function launchBrowserServer(browserName: string, configFile?: string) {
let options: LaunchServerOptions = {};
- if (configFile)
+ if (configFile) {
options = JSON.parse(fs.readFileSync(configFile).toString());
+ }
const browserType = (playwright as any)[browserName] as BrowserType;
const server = await browserType.launchServer(options);
console.log(server.wsEndpoint());
diff --git a/packages/playwright-core/src/cli/program.ts b/packages/playwright-core/src/cli/program.ts
index 7ce1c4f928..2c0a4b519f 100644
--- a/packages/playwright-core/src/cli/program.ts
+++ b/packages/playwright-core/src/cli/program.ts
@@ -82,42 +82,50 @@ function suggestedBrowsersToInstall() {
function defaultBrowsersToInstall(options: { noShell?: boolean, onlyShell?: boolean }): Executable[] {
let executables = registry.defaultExecutables();
- if (options.noShell)
+ if (options.noShell) {
executables = executables.filter(e => e.name !== 'chromium-headless-shell');
- if (options.onlyShell)
+ }
+ if (options.onlyShell) {
executables = executables.filter(e => e.name !== 'chromium');
+ }
return executables;
}
function checkBrowsersToInstall(args: string[], options: { noShell?: boolean, onlyShell?: boolean }): Executable[] {
- if (options.noShell && options.onlyShell)
+ if (options.noShell && options.onlyShell) {
throw new Error(`Only one of --no-shell and --only-shell can be specified`);
+ }
const faultyArguments: string[] = [];
const executables: Executable[] = [];
const handleArgument = (arg: string) => {
const executable = registry.findExecutable(arg);
- if (!executable || executable.installType === 'none')
+ if (!executable || executable.installType === 'none') {
faultyArguments.push(arg);
- else
+ } else {
executables.push(executable);
- if (executable?.browserName === 'chromium')
+ }
+ if (executable?.browserName === 'chromium') {
executables.push(registry.findExecutable('ffmpeg')!);
+ }
};
for (const arg of args) {
if (arg === 'chromium') {
- if (!options.onlyShell)
+ if (!options.onlyShell) {
handleArgument('chromium');
- if (!options.noShell)
+ }
+ if (!options.noShell) {
handleArgument('chromium-headless-shell');
+ }
} else {
handleArgument(arg);
}
}
- if (faultyArguments.length)
+ if (faultyArguments.length) {
throw new Error(`Invalid installation targets: ${faultyArguments.map(name => `'${name}'`).join(', ')}. Expecting one of: ${suggestedBrowsersToInstall()}`);
+ }
return executables;
}
@@ -132,8 +140,9 @@ program
.option('--no-shell', 'do not install chromium headless shell')
.action(async function(args: string[], options: { withDeps?: boolean, force?: boolean, dryRun?: boolean, shell?: boolean, noShell?: boolean, onlyShell?: boolean }) {
// For '--no-shell' option, commander sets `shell: false` instead.
- if (options.shell === false)
+ if (options.shell === false) {
options.noShell = true;
+ }
if (isLikelyNpxGlobal()) {
console.error(wrapInASCIIBox([
`WARNING: It looks like you are running 'npx playwright install' without first`,
@@ -157,8 +166,9 @@ program
try {
const hasNoArguments = !args.length;
const executables = hasNoArguments ? defaultBrowsersToInstall(options) : checkBrowsersToInstall(args, options);
- if (options.withDeps)
+ if (options.withDeps) {
await registry.installDeps(executables, !!options.dryRun);
+ }
if (options.dryRun) {
for (const executable of executables) {
const version = executable.browserVersion ? `version ` + executable.browserVersion : '';
@@ -167,8 +177,9 @@ program
if (executable.downloadURLs?.length) {
const [url, ...fallbacks] = executable.downloadURLs;
console.log(` Download url: ${url}`);
- for (let i = 0; i < fallbacks.length; ++i)
+ for (let i = 0; i < fallbacks.length; ++i) {
console.log(` Download fallback ${i + 1}: ${fallbacks[i]}`);
+ }
}
console.log(``);
}
@@ -213,10 +224,11 @@ program
.option('--dry-run', 'Do not execute installation commands, only print them')
.action(async function(args: string[], options: { dryRun?: boolean }) {
try {
- if (!args.length)
+ if (!args.length) {
await registry.installDeps(defaultBrowsersToInstall({}), !!options.dryRun);
- else
+ } else {
await registry.installDeps(checkBrowsersToInstall(args, {}), !!options.dryRun);
+ }
} catch (e) {
console.log(`Failed to install browser dependencies\n${e}`);
gracefullyProcessExitDoNotHang(1);
@@ -313,12 +325,15 @@ program
.option('--stdin', 'Accept trace URLs over stdin to update the viewer')
.description('show trace viewer')
.action(function(traces, options) {
- if (options.browser === 'cr')
+ if (options.browser === 'cr') {
options.browser = 'chromium';
- if (options.browser === 'ff')
+ }
+ if (options.browser === 'ff') {
options.browser = 'firefox';
- if (options.browser === 'wk')
+ }
+ if (options.browser === 'wk') {
options.browser = 'webkit';
+ }
const openOptions: TraceViewerServerOptions = {
host: options.host,
@@ -326,10 +341,11 @@ program
isServer: !!options.stdin,
};
- if (options.port !== undefined || options.host !== undefined)
+ if (options.port !== undefined || options.host !== undefined) {
runTraceInBrowser(traces, openOptions).catch(logErrorAndExit);
- else
+ } else {
runTraceViewerApp(traces, options.browser, openOptions, true).catch(logErrorAndExit);
+ }
}).addHelpText('afterAll', `
Examples:
@@ -367,8 +383,9 @@ async function launchContext(options: Options, extraOptions: LaunchOptions): Pro
validateOptions(options);
const browserType = lookupBrowserType(options);
const launchOptions: LaunchOptions = extraOptions;
- if (options.channel)
+ if (options.channel) {
launchOptions.channel = options.channel as any;
+ }
launchOptions.handleSIGINT = false;
const contextOptions: BrowserContextOptions =
@@ -378,8 +395,9 @@ async function launchContext(options: Options, extraOptions: LaunchOptions): Pro
// In headful mode, use host device scale factor for things to look nice.
// In headless, keep things the way it works in Playwright by default.
// Assume high-dpi on MacOS. TODO: this is not perfect.
- if (!extraOptions.headless)
+ if (!extraOptions.headless) {
contextOptions.deviceScaleFactor = os.platform() === 'darwin' ? 2 : 1;
+ }
// Work around the WebKit GTK scrolling issue.
if (browserType.name() === 'webkit' && process.platform === 'linux') {
@@ -387,11 +405,13 @@ async function launchContext(options: Options, extraOptions: LaunchOptions): Pro
delete contextOptions.isMobile;
}
- if (contextOptions.isMobile && browserType.name() === 'firefox')
+ if (contextOptions.isMobile && browserType.name() === 'firefox') {
contextOptions.isMobile = undefined;
+ }
- if (options.blockServiceWorkers)
+ if (options.blockServiceWorkers) {
contextOptions.serviceWorkers = 'block';
+ }
// Proxy
@@ -399,8 +419,9 @@ async function launchContext(options: Options, extraOptions: LaunchOptions): Pro
launchOptions.proxy = {
server: options.proxyServer
};
- if (options.proxyBypass)
+ if (options.proxyBypass) {
launchOptions.proxy.bypass = options.proxyBypass;
+ }
}
const browser = await browserType.launch(launchOptions);
@@ -411,8 +432,9 @@ async function launchContext(options: Options, extraOptions: LaunchOptions): Pro
process.stdout.write(text);
process.stdout.write('\n-------------8<-------------\n');
const autoExitCondition = process.env.PWTEST_CLI_AUTO_EXIT_WHEN;
- if (autoExitCondition && text.includes(autoExitCondition))
+ if (autoExitCondition && text.includes(autoExitCondition)) {
closeBrowser();
+ }
};
// Make sure we exit abnormally when browser crashes.
const logs: string[] = [];
@@ -434,8 +456,9 @@ async function launchContext(options: Options, extraOptions: LaunchOptions): Pro
if (options.viewportSize) {
try {
const [width, height] = options.viewportSize.split(',').map(n => +n);
- if (isNaN(width) || isNaN(height))
+ if (isNaN(width) || isNaN(height)) {
throw new Error('bad values');
+ }
contextOptions.viewport = { width, height };
} catch (e) {
throw new Error('Invalid viewport size format: use "width,height", for example --viewport-size="800,600"');
@@ -459,38 +482,45 @@ async function launchContext(options: Options, extraOptions: LaunchOptions): Pro
// User agent
- if (options.userAgent)
+ if (options.userAgent) {
contextOptions.userAgent = options.userAgent;
+ }
// Lang
- if (options.lang)
+ if (options.lang) {
contextOptions.locale = options.lang;
+ }
// Color scheme
- if (options.colorScheme)
+ if (options.colorScheme) {
contextOptions.colorScheme = options.colorScheme as 'dark' | 'light';
+ }
// Timezone
- if (options.timezone)
+ if (options.timezone) {
contextOptions.timezoneId = options.timezone;
+ }
// Storage
- if (options.loadStorage)
+ if (options.loadStorage) {
contextOptions.storageState = options.loadStorage;
+ }
- if (options.ignoreHttpsErrors)
+ if (options.ignoreHttpsErrors) {
contextOptions.ignoreHTTPSErrors = true;
+ }
// HAR
if (options.saveHar) {
contextOptions.recordHar = { path: path.resolve(process.cwd(), options.saveHar), mode: 'minimal' };
- if (options.saveHarGlob)
+ if (options.saveHarGlob) {
contextOptions.recordHar.urlFilter = options.saveHarGlob;
+ }
contextOptions.serviceWorkers = 'block';
}
@@ -502,15 +532,19 @@ async function launchContext(options: Options, extraOptions: LaunchOptions): Pro
async function closeBrowser() {
// We can come here multiple times. For example, saving storage creates
// a temporary page and we call closeBrowser again when that page closes.
- if (closingBrowser)
+ if (closingBrowser) {
return;
+ }
closingBrowser = true;
- if (options.saveTrace)
+ if (options.saveTrace) {
await context.tracing.stop({ path: options.saveTrace });
- if (options.saveStorage)
+ }
+ if (options.saveStorage) {
await context.storageState({ path: options.saveStorage }).catch(e => null);
- if (options.saveHar)
+ }
+ if (options.saveHar) {
await context.close();
+ }
await browser.close();
}
@@ -518,8 +552,9 @@ async function launchContext(options: Options, extraOptions: LaunchOptions): Pro
page.on('dialog', () => {}); // Prevent dialogs from being automatically dismissed.
page.on('close', () => {
const hasPage = browser.contexts().some(context => context.pages().length > 0);
- if (hasPage)
+ if (hasPage) {
return;
+ }
// Avoid the error when the last page is closed because the browser has been closed.
closeBrowser().catch(() => {});
});
@@ -533,8 +568,9 @@ async function launchContext(options: Options, extraOptions: LaunchOptions): Pro
context.setDefaultTimeout(timeout);
context.setDefaultNavigationTimeout(timeout);
- if (options.saveTrace)
+ if (options.saveTrace) {
await context.tracing.start({ screenshots: true, snapshots: true });
+ }
// Omit options that we add automatically for presentation purpose.
delete launchOptions.headless;
@@ -547,10 +583,11 @@ async function launchContext(options: Options, extraOptions: LaunchOptions): Pro
async function openPage(context: BrowserContext, url: string | undefined): Promise {
const page = await context.newPage();
if (url) {
- if (fs.existsSync(url))
+ if (fs.existsSync(url)) {
url = 'file://' + path.resolve(url);
- else if (!url.startsWith('http') && !url.startsWith('file://') && !url.startsWith('about:') && !url.startsWith('data:'))
+ } 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)) {
// Tests with PWTEST_CLI_AUTO_EXIT_WHEN might close page too fast, resulting
@@ -623,8 +660,9 @@ async function screenshot(options: Options, captureOptions: CaptureOptions, url:
}
async function pdf(options: Options, captureOptions: CaptureOptions, url: string, path: string) {
- if (options.browser !== 'chromium')
+ if (options.browser !== 'chromium') {
throw new Error('PDF creation is only working with Chromium');
+ }
const { context } = await launchContext({ ...options, browser: 'chromium' }, { headless: true });
console.log('Navigating to ' + url);
const page = await openPage(context, url);
@@ -650,27 +688,31 @@ function lookupBrowserType(options: Options): BrowserType {
case 'wk': browserType = playwright.webkit; break;
case 'ff': browserType = playwright.firefox; break;
}
- if (browserType)
+ if (browserType) {
return browserType;
+ }
program.help();
}
function validateOptions(options: Options) {
if (options.device && !(options.device in playwright.devices)) {
const lines = [`Device descriptor not found: '${options.device}', available devices are:`];
- for (const name in playwright.devices)
+ for (const name in playwright.devices) {
lines.push(` "${name}"`);
+ }
throw new Error(lines.join('\n'));
}
- if (options.colorScheme && !['light', 'dark'].includes(options.colorScheme))
+ if (options.colorScheme && !['light', 'dark'].includes(options.colorScheme)) {
throw new Error('Invalid color scheme, should be one of "light", "dark"');
+ }
}
function logErrorAndExit(e: Error) {
- if (process.env.PWDEBUGIMPL)
+ if (process.env.PWDEBUGIMPL) {
console.error(e);
- else
+ } else {
console.error(e.name + ': ' + e.message);
+ }
gracefullyProcessExitDoNotHang(1);
}
@@ -680,8 +722,9 @@ function codegenId(): string {
function commandWithOpenOptions(command: string, description: string, options: any[][]): Command {
let result = program.command(command).description(description);
- for (const option of options)
+ for (const option of options) {
result = result.option(option[0], ...option.slice(1));
+ }
return result
.option('-b, --browser ', 'browser to use, one of cr, chromium, ff, firefox, wk, webkit', 'chromium')
.option('--block-service-workers', 'block service workers')
diff --git a/packages/playwright-core/src/cli/programWithTestStub.ts b/packages/playwright-core/src/cli/programWithTestStub.ts
index 1c11c14ec2..2ccd71b64a 100644
--- a/packages/playwright-core/src/cli/programWithTestStub.ts
+++ b/packages/playwright-core/src/cli/programWithTestStub.ts
@@ -29,8 +29,9 @@ function printPlaywrightTestError(command: string) {
} catch (e) {
}
}
- if (!packages.length)
+ if (!packages.length) {
packages.push('playwright');
+ }
const packageManager = getPackageManager();
if (packageManager === 'yarn') {
console.error(`Please install @playwright/test package before running "yarn playwright ${command}"`);
@@ -63,5 +64,6 @@ function addExternalPlaywrightTestCommands() {
}
}
-if (!process.env.PW_LANG_NAME)
+if (!process.env.PW_LANG_NAME) {
addExternalPlaywrightTestCommands();
+}
diff --git a/packages/playwright-core/src/client/android.ts b/packages/playwright-core/src/client/android.ts
index 07912bfbdd..3e9ea44341 100644
--- a/packages/playwright-core/src/client/android.ts
+++ b/packages/playwright-core/src/client/android.ts
@@ -58,8 +58,9 @@ export class Android extends ChannelOwner implements ap
}
async launchServer(options: types.LaunchServerOptions = {}): Promise {
- if (!this._serverLauncher)
+ if (!this._serverLauncher) {
throw new Error('Launching server is not supported');
+ }
return await this._serverLauncher.launchServer(options);
}
@@ -78,7 +79,7 @@ export class Android extends ChannelOwner implements ap
let device: AndroidDevice;
let closeError: string | undefined;
const onPipeClosed = () => {
- device?._didClose();
+ device._didClose();
connection.close(closeError);
};
pipe.on('closed', onPipeClosed);
@@ -143,8 +144,9 @@ export class AndroidDevice extends ChannelOwner i
private _onWebViewRemoved(socketName: string) {
const view = this._webViews.get(socketName);
this._webViews.delete(socketName);
- if (view)
+ if (view) {
view.emit(Events.AndroidWebView.Close);
+ }
}
setDefaultTimeout(timeout: number) {
@@ -166,15 +168,18 @@ export class AndroidDevice extends ChannelOwner i
async webView(selector: { pkg?: string; socketName?: string; }, options?: types.TimeoutOptions): Promise {
const predicate = (v: AndroidWebView) => {
- if (selector.pkg)
+ if (selector.pkg) {
return v.pkg() === selector.pkg;
- if (selector.socketName)
+ }
+ if (selector.socketName) {
return v._socketName() === selector.socketName;
+ }
return false;
};
const webView = [...this._webViews.values()].find(predicate);
- if (webView)
+ if (webView) {
return webView;
+ }
return await this.waitForEvent('webview', { ...options, predicate });
}
@@ -229,8 +234,9 @@ export class AndroidDevice extends ChannelOwner i
async screenshot(options: { path?: string } = {}): Promise {
const { binary } = await this._channel.screenshot();
- if (options.path)
+ if (options.path) {
await fs.promises.writeFile(options.path, binary);
+ }
return binary;
}
@@ -240,13 +246,15 @@ export class AndroidDevice extends ChannelOwner i
async close() {
try {
- if (this._shouldCloseConnectionOnClose)
+ if (this._shouldCloseConnectionOnClose) {
this._connection.close();
- else
+ } else {
await this._channel.close();
+ }
} catch (e) {
- if (isTargetClosedError(e))
+ if (isTargetClosedError(e)) {
return;
+ }
throw e;
}
}
@@ -286,8 +294,9 @@ export class AndroidDevice extends ChannelOwner i
const predicate = typeof optionsOrPredicate === 'function' ? optionsOrPredicate : optionsOrPredicate.predicate;
const waiter = Waiter.createForEvent(this, event);
waiter.rejectOnTimeout(timeout, `Timeout ${timeout}ms exceeded while waiting for event "${event}"`);
- if (event !== Events.AndroidDevice.Close)
+ if (event !== Events.AndroidDevice.Close) {
waiter.rejectOnEvent(this, Events.AndroidDevice.Close, () => new TargetClosedError());
+ }
const result = await waiter.waitForEvent(this, event, predicate as any);
waiter.dispose();
return result;
@@ -320,8 +329,9 @@ export class AndroidSocket extends ChannelOwner i
}
async function loadFile(file: string | Buffer): Promise {
- if (isString(file))
+ if (isString(file)) {
return await fs.promises.readFile(file);
+ }
return file;
}
@@ -375,10 +385,12 @@ function toSelectorChannel(selector: api.AndroidSelector): channels.AndroidSelec
} = selector;
const toRegex = (value: RegExp | string | undefined): string | undefined => {
- if (value === undefined)
+ if (value === undefined) {
return undefined;
- if (isRegExp(value))
+ }
+ if (isRegExp(value)) {
return value.source;
+ }
return '^' + value.replace(/[|\\{}()[\]^$+*?.]/g, '\\$&').replace(/-/g, '\\x2d') + '$';
};
@@ -427,8 +439,9 @@ export class AndroidWebView extends EventEmitter implements api.AndroidWebView {
}
async page(): Promise {
- if (!this._pagePromise)
+ if (!this._pagePromise) {
this._pagePromise = this._fetchPage();
+ }
return await this._pagePromise;
}
diff --git a/packages/playwright-core/src/client/artifact.ts b/packages/playwright-core/src/client/artifact.ts
index c3a53c0294..7f07d8e0f2 100644
--- a/packages/playwright-core/src/client/artifact.ts
+++ b/packages/playwright-core/src/client/artifact.ts
@@ -27,8 +27,9 @@ export class Artifact extends ChannelOwner {
}
async pathAfterFinished(): Promise {
- if (this._connection.isRemote())
+ if (this._connection.isRemote()) {
throw new Error(`Path is not available when connecting remotely. Use saveAs() to save a local copy.`);
+ }
return (await this._channel.pathAfterFinished()).value;
}
diff --git a/packages/playwright-core/src/client/browser.ts b/packages/playwright-core/src/client/browser.ts
index be47ddeb51..b5f4bd56f3 100644
--- a/packages/playwright-core/src/client/browser.ts
+++ b/packages/playwright-core/src/client/browser.ts
@@ -65,8 +65,9 @@ export class Browser extends ChannelOwner implements ap
return await this._wrapApiCall(async () => {
for (const context of this._contexts) {
await this._browserType._willCloseContext(context);
- for (const page of context.pages())
+ for (const page of context.pages()) {
page._onClose();
+ }
context._onClose();
}
return await this._innerNewContext(options, true);
@@ -138,14 +139,16 @@ export class Browser extends ChannelOwner implements ap
async close(options: { reason?: string } = {}): Promise {
this._closeReason = options.reason;
try {
- if (this._shouldCloseConnectionOnClose)
+ if (this._shouldCloseConnectionOnClose) {
this._connection.close();
- else
+ } else {
await this._channel.close(options);
+ }
await this._closedPromise;
} catch (e) {
- if (isTargetClosedError(e))
+ if (isTargetClosedError(e)) {
return;
+ }
throw e;
}
}
diff --git a/packages/playwright-core/src/client/browserContext.ts b/packages/playwright-core/src/client/browserContext.ts
index 5ff432ec60..28afee001e 100644
--- a/packages/playwright-core/src/client/browserContext.ts
+++ b/packages/playwright-core/src/client/browserContext.ts
@@ -79,8 +79,9 @@ export class BrowserContext extends ChannelOwner
constructor(parent: ChannelOwner, type: string, guid: string, initializer: channels.BrowserContextInitializer) {
super(parent, type, guid, initializer);
- if (parent instanceof Browser)
+ if (parent instanceof Browser) {
this._browser = parent;
+ }
this._browser?._contexts.add(this);
this._isChromium = this._browser?._name === 'chromium';
this.tracing = Tracing.from(initializer.tracing);
@@ -107,31 +108,35 @@ export class BrowserContext extends ChannelOwner
const consoleMessage = new ConsoleMessage(event);
this.emit(Events.BrowserContext.Console, consoleMessage);
const page = consoleMessage.page();
- if (page)
+ if (page) {
page.emit(Events.Page.Console, consoleMessage);
+ }
});
this._channel.on('pageError', ({ error, page }) => {
const pageObject = Page.from(page);
const parsedError = parseError(error);
this.emit(Events.BrowserContext.WebError, new WebError(pageObject, parsedError));
- if (pageObject)
+ if (pageObject) {
pageObject.emit(Events.Page.PageError, parsedError);
+ }
});
this._channel.on('dialog', ({ dialog }) => {
const dialogObject = Dialog.from(dialog);
let hasListeners = this.emit(Events.BrowserContext.Dialog, dialogObject);
const page = dialogObject.page();
- if (page)
+ if (page) {
hasListeners = page.emit(Events.Page.Dialog, dialogObject) || hasListeners;
+ }
if (!hasListeners) {
// Although we do similar handling on the server side, we still need this logic
// on the client side due to a possible race condition between two async calls:
// a) removing "dialog" listener subscription (client->server)
// b) actual "dialog" event (server->client)
- if (dialogObject.type() === 'beforeunload')
+ if (dialogObject.type() === 'beforeunload') {
dialog.accept({}).catch(() => {});
- else
+ } else {
dialog.dismiss().catch(() => {});
+ }
}
});
this._channel.on('request', ({ request, page }) => this._onRequest(network.Request.from(request), Page.fromNullable(page)));
@@ -152,36 +157,41 @@ export class BrowserContext extends ChannelOwner
_setOptions(contextOptions: channels.BrowserNewContextParams, browserOptions: LaunchOptions) {
this._options = contextOptions;
- if (this._options.recordHar)
+ if (this._options.recordHar) {
this._harRecorders.set('', { path: this._options.recordHar.path, content: this._options.recordHar.content });
+ }
this.tracing._tracesDir = browserOptions.tracesDir;
}
private _onPage(page: Page): void {
this._pages.add(page);
this.emit(Events.BrowserContext.Page, page);
- if (page._opener && !page._opener.isClosed())
+ if (page._opener && !page._opener.isClosed()) {
page._opener.emit(Events.Page.Popup, page);
+ }
}
private _onRequest(request: network.Request, page: Page | null) {
this.emit(Events.BrowserContext.Request, request);
- if (page)
+ if (page) {
page.emit(Events.Page.Request, request);
+ }
}
private _onResponse(response: network.Response, page: Page | null) {
this.emit(Events.BrowserContext.Response, response);
- if (page)
+ if (page) {
page.emit(Events.Page.Response, response);
+ }
}
private _onRequestFailed(request: network.Request, responseEndTiming: number, failureText: string | undefined, page: Page | null) {
request._failureText = failureText || null;
request._setResponseEndTiming(responseEndTiming);
this.emit(Events.BrowserContext.RequestFailed, request);
- if (page)
+ if (page) {
page.emit(Events.Page.RequestFailed, request);
+ }
}
private _onRequestFinished(params: channels.BrowserContextRequestFinishedEvent) {
@@ -191,10 +201,12 @@ export class BrowserContext extends ChannelOwner
const page = Page.fromNullable(params.page);
request._setResponseEndTiming(responseEndTiming);
this.emit(Events.BrowserContext.RequestFinished, request);
- if (page)
+ if (page) {
page.emit(Events.Page.RequestFinished, request);
- if (response)
+ }
+ if (response) {
response._finishedPromise.resolve(null);
+ }
}
async _onRoute(route: network.Route) {
@@ -203,20 +215,26 @@ export class BrowserContext extends ChannelOwner
const routeHandlers = this._routes.slice();
for (const routeHandler of routeHandlers) {
// If the page or the context was closed we stall all requests right away.
- if (page?._closeWasCalled || this._closeWasCalled)
+ if (page?._closeWasCalled || this._closeWasCalled) {
return;
- if (!routeHandler.matches(route.request().url()))
+ }
+ if (!routeHandler.matches(route.request().url())) {
continue;
+ }
const index = this._routes.indexOf(routeHandler);
- if (index === -1)
+ if (index === -1) {
continue;
- if (routeHandler.willExpire())
+ }
+ if (routeHandler.willExpire()) {
this._routes.splice(index, 1);
+ }
const handled = await routeHandler.handle(route);
- if (!this._routes.length)
+ if (!this._routes.length) {
this._wrapApiCall(() => this._updateInterceptionPatterns(), true).catch(() => {});
- if (handled)
+ }
+ if (handled) {
return;
+ }
}
// If the page is closed or unrouteAll() was called without waiting and interception disabled,
// the method will throw an error - silence it.
@@ -225,16 +243,18 @@ export class BrowserContext extends ChannelOwner
async _onWebSocketRoute(webSocketRoute: network.WebSocketRoute) {
const routeHandler = this._webSocketRoutes.find(route => route.matches(webSocketRoute.url()));
- if (routeHandler)
+ if (routeHandler) {
await routeHandler.handle(webSocketRoute);
- else
+ } else {
webSocketRoute.connectToServer();
+ }
}
async _onBinding(bindingCall: BindingCall) {
const func = this._bindings.get(bindingCall._initializer.name);
- if (!func)
+ if (!func) {
return;
+ }
await bindingCall.call(func);
}
@@ -261,16 +281,19 @@ export class BrowserContext extends ChannelOwner
}
async newPage(): Promise {
- if (this._ownerPage)
+ if (this._ownerPage) {
throw new Error('Please use browser.newContext()');
+ }
return Page.from((await this._channel.newPage()).page);
}
async cookies(urls?: string | string[]): Promise {
- if (!urls)
+ if (!urls) {
urls = [];
- if (urls && typeof urls === 'string')
+ }
+ if (urls && typeof urls === 'string') {
urls = [urls];
+ }
return (await this._channel.cookies({ urls: urls as string[] })).cookies;
}
@@ -380,10 +403,11 @@ export class BrowserContext extends ChannelOwner
const removed = [];
const remaining = [];
for (const route of this._routes) {
- if (urlMatchesEqual(route.url, url) && (!handler || route.handler === handler))
+ if (urlMatchesEqual(route.url, url) && (!handler || route.handler === handler)) {
removed.push(route);
- else
+ } else {
remaining.push(route);
+ }
}
await this._unrouteInternal(removed, remaining, 'default');
}
@@ -391,8 +415,9 @@ export class BrowserContext extends ChannelOwner
private async _unrouteInternal(removed: network.RouteHandler[], remaining: network.RouteHandler[], behavior?: 'wait'|'ignoreErrors'|'default'): Promise {
this._routes = remaining;
await this._updateInterceptionPatterns();
- if (!behavior || behavior === 'default')
+ if (!behavior || behavior === 'default') {
return;
+ }
const promises = removed.map(routeHandler => routeHandler.stop(behavior));
await Promise.all(promises);
}
@@ -417,8 +442,9 @@ export class BrowserContext extends ChannelOwner
const predicate = typeof optionsOrPredicate === 'function' ? optionsOrPredicate : optionsOrPredicate.predicate;
const waiter = Waiter.createForEvent(this, event);
waiter.rejectOnTimeout(timeout, `Timeout ${timeout}ms exceeded while waiting for event "${event}"`);
- if (event !== Events.BrowserContext.Close)
+ if (event !== Events.BrowserContext.Close) {
waiter.rejectOnEvent(this, Events.BrowserContext.Close, () => new TargetClosedError(this._effectiveCloseReason()));
+ }
const result = await waiter.waitForEvent(this, event, predicate as any);
waiter.dispose();
return result;
@@ -444,16 +470,18 @@ export class BrowserContext extends ChannelOwner
async newCDPSession(page: Page | Frame): Promise {
// channelOwner.ts's validation messages don't handle the pseudo-union type, so we're explicit here
- if (!(page instanceof Page) && !(page instanceof Frame))
+ if (!(page instanceof Page) && !(page instanceof Frame)) {
throw new Error('page: expected Page or Frame');
+ }
const result = await this._channel.newCDPSession(page instanceof Page ? { page: page._channel } : { frame: page._channel });
return CDPSession.from(result.session);
}
_onClose() {
- if (this._browser)
+ if (this._browser) {
this._browser._contexts.delete(this);
- this._browserType?._contexts?.delete(this);
+ }
+ this._browserType?._contexts.delete(this);
this._disposeHarRouters();
this.tracing._resetStackCounter();
this.emit(Events.BrowserContext.Close, this);
@@ -464,8 +492,9 @@ export class BrowserContext extends ChannelOwner
}
async close(options: { reason?: string } = {}): Promise {
- if (this._closeWasCalled)
+ if (this._closeWasCalled) {
return;
+ }
this._closeReason = options.reason;
this._closeWasCalled = true;
await this._wrapApiCall(async () => {
@@ -498,8 +527,9 @@ export class BrowserContext extends ChannelOwner
}
async function prepareStorageState(options: BrowserContextOptions): Promise {
- if (typeof options.storageState !== 'string')
+ if (typeof options.storageState !== 'string') {
return options.storageState;
+ }
try {
return JSON.parse(await fs.promises.readFile(options.storageState, 'utf8'));
} catch (e) {
@@ -509,8 +539,9 @@ async function prepareStorageState(options: BrowserContextOptions): Promise {
- if (options.videoSize && !options.videosPath)
+ if (options.videoSize && !options.videosPath) {
throw new Error(`"videoSize" option requires "videosPath" to be specified`);
- if (options.extraHTTPHeaders)
+ }
+ if (options.extraHTTPHeaders) {
network.validateHeaders(options.extraHTTPHeaders);
+ }
const contextParams: channels.BrowserNewContextParams = {
...options,
viewport: options.viewport === null ? undefined : options.viewport,
@@ -546,28 +579,34 @@ export async function prepareBrowserContextParams(options: BrowserContextOptions
size: options.videoSize
};
}
- if (contextParams.recordVideo && contextParams.recordVideo.dir)
+ if (contextParams.recordVideo && contextParams.recordVideo.dir) {
contextParams.recordVideo.dir = path.resolve(process.cwd(), contextParams.recordVideo.dir);
+ }
return contextParams;
}
function toAcceptDownloadsProtocol(acceptDownloads?: boolean) {
- if (acceptDownloads === undefined)
+ if (acceptDownloads === undefined) {
return undefined;
- if (acceptDownloads)
+ }
+ if (acceptDownloads) {
return 'accept';
+ }
return 'deny';
}
export async function toClientCertificatesProtocol(certs?: BrowserContextOptions['clientCertificates']): Promise {
- if (!certs)
+ if (!certs) {
return undefined;
+ }
const bufferizeContent = async (value?: Buffer, path?: string): Promise => {
- if (value)
+ if (value) {
return value;
- if (path)
+ }
+ if (path) {
return await fs.promises.readFile(path);
+ }
};
return await Promise.all(certs.map(async cert => ({
diff --git a/packages/playwright-core/src/client/browserType.ts b/packages/playwright-core/src/client/browserType.ts
index 06672cc64e..d4eb59ff5a 100644
--- a/packages/playwright-core/src/client/browserType.ts
+++ b/packages/playwright-core/src/client/browserType.ts
@@ -56,8 +56,9 @@ export class BrowserType extends ChannelOwner imple
}
executablePath(): string {
- if (!this._initializer.executablePath)
+ if (!this._initializer.executablePath) {
throw new Error('Browser is not supported on current platform');
+ }
return this._initializer.executablePath;
}
@@ -85,8 +86,9 @@ export class BrowserType extends ChannelOwner imple
}
async launchServer(options: LaunchServerOptions = {}): Promise {
- if (!this._serverLauncher)
+ if (!this._serverLauncher) {
throw new Error('Launching server is not supported');
+ }
options = { ...this._defaultLaunchOptions, ...options };
return await this._serverLauncher.launchServer(options);
}
@@ -115,8 +117,9 @@ export class BrowserType extends ChannelOwner imple
connect(options: api.ConnectOptions & { wsEndpoint: string }): Promise;
connect(wsEndpoint: string, options?: api.ConnectOptions): Promise;
async connect(optionsOrWsEndpoint: string | (api.ConnectOptions & { wsEndpoint: string }), options?: api.ConnectOptions): Promise{
- if (typeof optionsOrWsEndpoint === 'string')
+ if (typeof optionsOrWsEndpoint === 'string') {
return await this._connect({ ...options, wsEndpoint: optionsOrWsEndpoint });
+ }
assert(optionsOrWsEndpoint.wsEndpoint, 'options.wsEndpoint is required');
return await this._connect(optionsOrWsEndpoint);
}
@@ -134,8 +137,9 @@ export class BrowserType extends ChannelOwner imple
slowMo: params.slowMo,
timeout: params.timeout,
};
- if ((params as any).__testHookRedirectPortForwarding)
+ if ((params as any).__testHookRedirectPortForwarding) {
connectParams.socksProxyRedirectPortForTest = (params as any).__testHookRedirectPortForwarding;
+ }
const { pipe, headers: connectHeaders } = await localUtils._channel.connect(connectParams);
const closePipe = () => pipe.close().catch(() => {});
const connection = new Connection(localUtils, this._instrumentation);
@@ -146,9 +150,10 @@ export class BrowserType extends ChannelOwner imple
let closeError: string | undefined;
const onPipeClosed = (reason?: string) => {
// Emulate all pages, contexts and the browser closing upon disconnect.
- for (const context of browser?.contexts() || []) {
- for (const page of context.pages())
+ for (const context of browser.contexts() || []) {
+ for (const page of context.pages()) {
page._onClose();
+ }
context._onClose();
}
connection.close(reason || closeError);
@@ -158,7 +163,7 @@ export class BrowserType extends ChannelOwner imple
// here and promises did not have a chance to reject.
// The order of rejects vs closure is a part of the API contract and our test runner
// relies on it to attribute rejections to the right test.
- setTimeout(() => browser?._didClose(), 0);
+ setTimeout(() => browser._didClose(), 0);
};
pipe.on('closed', params => onPipeClosed(params.reason));
connection.onmessage = message => this._wrapApiCall(() => pipe.send({ message }).catch(() => onPipeClosed()), /* isInternal */ true);
@@ -174,8 +179,9 @@ export class BrowserType extends ChannelOwner imple
const result = await raceAgainstDeadline(async () => {
// For tests.
- if ((params as any).__testHookBeforeCreateBrowser)
+ if ((params as any).__testHookBeforeCreateBrowser) {
await (params as any).__testHookBeforeCreateBrowser();
+ }
const playwright = await connection!.initializePlaywright();
if (!playwright._initializer.preLaunchedBrowser) {
@@ -202,16 +208,18 @@ export class BrowserType extends ChannelOwner imple
async connectOverCDP(options: api.ConnectOverCDPOptions & { wsEndpoint?: string }): Promise;
async connectOverCDP(endpointURL: string, options?: api.ConnectOverCDPOptions): Promise;
async connectOverCDP(endpointURLOrOptions: (api.ConnectOverCDPOptions & { wsEndpoint?: string })|string, options?: api.ConnectOverCDPOptions) {
- if (typeof endpointURLOrOptions === 'string')
+ if (typeof endpointURLOrOptions === 'string') {
return await this._connectOverCDP(endpointURLOrOptions, options);
+ }
const endpointURL = 'endpointURL' in endpointURLOrOptions ? endpointURLOrOptions.endpointURL : endpointURLOrOptions.wsEndpoint;
assert(endpointURL, 'Cannot connect over CDP without wsEndpoint.');
return await this.connectOverCDP(endpointURL, endpointURLOrOptions);
}
async _connectOverCDP(endpointURL: string, params: api.ConnectOverCDPOptions = {}): Promise {
- if (this.name() !== 'chromium')
+ if (this.name() !== 'chromium') {
throw new Error('Connecting over CDP is only supported in Chromium.');
+ }
const headers = params.headers ? headersObjectToArray(params.headers) : undefined;
const result = await this._channel.connectOverCDP({
endpointURL,
@@ -221,8 +229,9 @@ export class BrowserType extends ChannelOwner imple
});
const browser = Browser.from(result.browser);
this._didLaunchBrowser(browser, {}, params.logger);
- if (result.defaultContext)
+ if (result.defaultContext) {
await this._didCreateContext(BrowserContext.from(result.defaultContext), {}, {}, params.logger);
+ }
return browser;
}
@@ -237,10 +246,12 @@ export class BrowserType extends ChannelOwner imple
context._browserType = this;
this._contexts.add(context);
context._setOptions(contextOptions, browserOptions);
- if (this._defaultContextTimeout !== undefined)
+ if (this._defaultContextTimeout !== undefined) {
context.setDefaultTimeout(this._defaultContextTimeout);
- if (this._defaultContextNavigationTimeout !== undefined)
+ }
+ if (this._defaultContextNavigationTimeout !== undefined) {
context.setDefaultNavigationTimeout(this._defaultContextNavigationTimeout);
+ }
await this._instrumentation.runAfterCreateBrowserContext(context);
}
diff --git a/packages/playwright-core/src/client/channelOwner.ts b/packages/playwright-core/src/client/channelOwner.ts
index a5d753507b..a0f5e127f0 100644
--- a/packages/playwright-core/src/client/channelOwner.ts
+++ b/packages/playwright-core/src/client/channelOwner.ts
@@ -80,37 +80,42 @@ export abstract class ChannelOwner(func: (apiZone: ApiZone) => Promise, isInternal?: boolean): Promise {
const logger = this._logger;
const apiZone = zones.zoneData('apiZone');
- if (apiZone)
+ if (apiZone) {
return await func(apiZone);
+ }
const stackTrace = captureLibraryStackTrace();
let apiName: string | undefined = stackTrace.apiName;
const frames: channels.StackFrame[] = stackTrace.frames;
- if (isInternal === undefined)
+ if (isInternal === undefined) {
isInternal = this._isInternalType;
- if (isInternal)
+ }
+ if (isInternal) {
apiName = undefined;
+ }
// Enclosing zone could have provided the apiName and wallTime.
const expectZone = zones.zoneData('expectZone');
const stepId = expectZone?.stepId;
- if (!isInternal && expectZone)
+ if (!isInternal && expectZone) {
apiName = expectZone.title;
+ }
// If we are coming from the expectZone, there is no need to generate a new
// step for the API call, since it will be generated by the expect itself.
@@ -203,13 +214,15 @@ export abstract class ChannelOwner\n' + e.stack : '';
- if (apiName && !apiName.includes(''))
+ if (apiName && !apiName.includes('')) {
e.message = apiName + ': ' + e.message;
+ }
const stackFrames = '\n' + stringifyStackFrames(stackTrace.frames).join('\n') + innerError;
- if (stackFrames.trim())
+ if (stackFrames.trim()) {
e.stack = e.message + stackFrames;
- else
+ } else {
e.stack = '';
+ }
csi?.onApiCallEnd(callCookie, e);
logApiCall(logger, `<= ${apiName} failed`, isInternal);
throw e;
@@ -233,16 +246,19 @@ export abstract class ChannelOwner {
- if (typeof prop !== 'string')
+ if (typeof prop !== 'string') {
return obj[prop];
- if (prop === 'addListener')
+ }
+ if (prop === 'addListener') {
return (listener: ClientInstrumentationListener) => listeners.push(listener);
- if (prop === 'removeListener')
+ }
+ if (prop === 'removeListener') {
return (listener: ClientInstrumentationListener) => listeners.splice(listeners.indexOf(listener), 1);
- if (prop === 'removeAllListeners')
+ }
+ if (prop === 'removeAllListeners') {
return () => listeners.splice(0, listeners.length);
+ }
if (prop.startsWith('run')) {
return async (...params: any[]) => {
- for (const listener of listeners)
+ for (const listener of listeners) {
await (listener as any)[prop]?.(...params);
+ }
};
}
if (prop.startsWith('on')) {
return (...params: any[]) => {
- for (const listener of listeners)
+ for (const listener of listeners) {
(listener as any)[prop]?.(...params);
+ }
};
}
return obj[prop];
diff --git a/packages/playwright-core/src/client/clock.ts b/packages/playwright-core/src/client/clock.ts
index 73eb538c26..338bf634ed 100644
--- a/packages/playwright-core/src/client/clock.ts
+++ b/packages/playwright-core/src/client/clock.ts
@@ -54,12 +54,15 @@ export class Clock implements api.Clock {
}
function parseTime(time: string | number | Date): { timeNumber?: number, timeString?: string } {
- if (typeof time === 'number')
+ if (typeof time === 'number') {
return { timeNumber: time };
- if (typeof time === 'string')
+ }
+ if (typeof time === 'string') {
return { timeString: time };
- if (!isFinite(time.getTime()))
+ }
+ if (!isFinite(time.getTime())) {
throw new Error(`Invalid date: ${time}`);
+ }
return { timeNumber: time.getTime() };
}
diff --git a/packages/playwright-core/src/client/connection.ts b/packages/playwright-core/src/client/connection.ts
index 75d1878da3..dba0cdd303 100644
--- a/packages/playwright-core/src/client/connection.ts
+++ b/packages/playwright-core/src/client/connection.ts
@@ -112,17 +112,20 @@ export class Connection extends EventEmitter {
}
setIsTracing(isTracing: boolean) {
- if (isTracing)
+ if (isTracing) {
this._tracingCount++;
- else
+ } else {
this._tracingCount--;
+ }
}
async sendMessageToServer(object: ChannelOwner, method: string, params: any, apiName: string | undefined, frames: channels.StackFrame[], stepId?: string): Promise {
- if (this._closedError)
+ if (this._closedError) {
throw this._closedError;
- if (object._wasCollected)
+ }
+ if (object._wasCollected) {
throw new Error('The object has been collected to prevent unbounded heap growth.');
+ }
const guid = object._guid;
const type = object._type;
@@ -134,8 +137,9 @@ export class Connection extends EventEmitter {
}
const location = frames[0] ? { file: frames[0].file, line: frames[0].line, column: frames[0].column } : undefined;
const metadata: channels.Metadata = { apiName, location, internal: !apiName, stepId };
- if (this._tracingCount && frames && type !== 'LocalUtils')
+ if (this._tracingCount && frames && type !== 'LocalUtils') {
this._localUtils?._channel.addStackToTracingNoReply({ callData: { stack: frames, id } }).catch(() => {});
+ }
// We need to exit zones before calling into the server, otherwise
// when we receive events from the server, we would be in an API zone.
zones.exitZones(() => this.onmessage({ ...message, metadata }));
@@ -143,16 +147,19 @@ export class Connection extends EventEmitter {
}
dispatch(message: object) {
- if (this._closedError)
+ if (this._closedError) {
return;
+ }
const { id, guid, method, params, result, error, log } = message as any;
if (id) {
- if (debugLogger.isEnabled('channel'))
+ if (debugLogger.isEnabled('channel')) {
debugLogger.log('channel', ';
const validator = findValidator(type, '', 'Initializer');
initializer = validator(initializer, '', { tChannelImpl: this._tChannelImplFromWire.bind(this), binary: this._rawBuffers ? 'buffer' : 'fromBase64' });
@@ -276,8 +291,9 @@ export class Connection extends EventEmitter {
break;
case 'LocalUtils':
result = new LocalUtils(parent, type, guid, initializer);
- if (!this._localUtils)
+ if (!this._localUtils) {
this._localUtils = result as LocalUtils;
+ }
break;
case 'Page':
result = new Page(parent, type, guid, initializer);
diff --git a/packages/playwright-core/src/client/electron.ts b/packages/playwright-core/src/client/electron.ts
index fe5b6e189e..7d73be023e 100644
--- a/packages/playwright-core/src/client/electron.ts
+++ b/packages/playwright-core/src/client/electron.ts
@@ -74,8 +74,9 @@ export class ElectronApplication extends ChannelOwner this._onPage(page));
this._channel.on('close', () => {
this.emit(Events.ElectronApplication.Close);
@@ -102,8 +103,9 @@ export class ElectronApplication extends ChannelOwner {
- if (this._windows.size)
+ if (this._windows.size) {
return this._windows.values().next().value!;
+ }
return await this.waitForEvent('window', options);
}
@@ -119,8 +121,9 @@ export class ElectronApplication extends ChannelOwner new TargetClosedError());
+ }
const result = await waiter.waitForEvent(this, event, predicate as any);
waiter.dispose();
return result;
diff --git a/packages/playwright-core/src/client/elementHandle.ts b/packages/playwright-core/src/client/elementHandle.ts
index 0a89d3091b..c731781ffb 100644
--- a/packages/playwright-core/src/client/elementHandle.ts
+++ b/packages/playwright-core/src/client/elementHandle.ts
@@ -147,8 +147,9 @@ export class ElementHandle extends JSHandle implements
async setInputFiles(files: string | FilePayload | string[] | FilePayload[], options: channels.ElementHandleSetInputFilesOptions = {}) {
const frame = await this.ownerFrame();
- if (!frame)
+ if (!frame) {
throw new Error('Cannot set input files to detached element');
+ }
const converted = await convertInputFiles(files, frame.page().context());
await this._elementChannel.setInputFiles({ ...converted, ...options });
}
@@ -174,10 +175,11 @@ export class ElementHandle extends JSHandle implements
}
async setChecked(checked: boolean, options?: channels.ElementHandleCheckOptions) {
- if (checked)
+ if (checked) {
await this.check(options);
- else
+ } else {
await this.uncheck(options);
+ }
}
async boundingBox(): Promise {
@@ -187,8 +189,9 @@ export class ElementHandle extends JSHandle implements
async screenshot(options: Omit & { path?: string, mask?: Locator[] } = {}): Promise {
const copy: channels.ElementHandleScreenshotOptions = { ...options, mask: undefined };
- if (!copy.type)
+ if (!copy.type) {
copy.type = determineScreenshotType(options);
+ }
if (options.mask) {
copy.mask = options.mask.map(locator => ({
frame: locator._frame._channel,
@@ -235,18 +238,24 @@ export class ElementHandle extends JSHandle implements
}
export function convertSelectOptionValues(values: string | api.ElementHandle | SelectOption | string[] | api.ElementHandle[] | SelectOption[] | null): { elements?: channels.ElementHandleChannel[], options?: SelectOption[] } {
- if (values === null)
+ if (values === null) {
return {};
- if (!Array.isArray(values))
+ }
+ if (!Array.isArray(values)) {
values = [values as any];
- if (!values.length)
+ }
+ if (!values.length) {
return {};
- for (let i = 0; i < values.length; i++)
+ }
+ for (let i = 0; i < values.length; i++) {
assert(values[i] !== null, `options[${i}]: expected object, got null`);
- if (values[0] instanceof ElementHandle)
+ }
+ if (values[0] instanceof ElementHandle) {
return { elements: (values as ElementHandle[]).map((v: ElementHandle) => v._elementChannel) };
- if (isString(values[0]))
+ }
+ if (isString(values[0])) {
return { options: (values as string[]).map(valueOrLabel => ({ valueOrLabel })) };
+ }
return { options: values as SelectOption[] };
}
@@ -262,16 +271,18 @@ async function resolvePathsAndDirectoryForInputFiles(items: string[]): Promise<[
for (const item of items) {
const stat = await fs.promises.stat(item as string);
if (stat.isDirectory()) {
- if (localDirectory)
+ if (localDirectory) {
throw new Error('Multiple directories are not supported');
+ }
localDirectory = path.resolve(item as string);
} else {
localPaths ??= [];
localPaths.push(path.resolve(item as string));
}
}
- if (localPaths?.length && localDirectory)
+ if (localPaths?.length && localDirectory) {
throw new Error('File paths must be all files or a single directory');
+ }
return [localPaths, localDirectory];
}
@@ -279,8 +290,9 @@ export async function convertInputFiles(files: string | FilePayload | string[] |
const items: (string | FilePayload)[] = Array.isArray(files) ? files.slice() : [files];
if (items.some(item => typeof item === 'string')) {
- if (!items.every(item => typeof item === 'string'))
+ if (!items.every(item => typeof item === 'string')) {
throw new Error('File paths cannot be mixed with buffers');
+ }
const [localPaths, localDirectory] = await resolvePathsAndDirectoryForInputFiles(items);
@@ -312,18 +324,20 @@ export async function convertInputFiles(files: string | FilePayload | string[] |
}
const payloads = items as FilePayload[];
- if (filePayloadExceedsSizeLimit(payloads))
+ if (filePayloadExceedsSizeLimit(payloads)) {
throw new Error('Cannot set buffer larger than 50Mb, please write it to a file and pass its path instead.');
+ }
return { payloads };
}
export function determineScreenshotType(options: { path?: string, type?: 'png' | 'jpeg' }): 'png' | 'jpeg' | undefined {
if (options.path) {
const mimeType = mime.getType(options.path);
- if (mimeType === 'image/png')
+ if (mimeType === 'image/png') {
return 'png';
- else if (mimeType === 'image/jpeg')
+ } else if (mimeType === 'image/jpeg') {
return 'jpeg';
+ }
throw new Error(`path: unsupported mime type "${mimeType}"`);
}
return options.type;
diff --git a/packages/playwright-core/src/client/errors.ts b/packages/playwright-core/src/client/errors.ts
index 51555202e5..fdcfc1e1ac 100644
--- a/packages/playwright-core/src/client/errors.ts
+++ b/packages/playwright-core/src/client/errors.ts
@@ -36,15 +36,17 @@ export function isTargetClosedError(error: Error) {
}
export function serializeError(e: any): SerializedError {
- if (isError(e))
+ if (isError(e)) {
return { error: { message: e.message, stack: e.stack, name: e.name } };
+ }
return { value: serializeValue(e, value => ({ fallThrough: value })) };
}
export function parseError(error: SerializedError): Error {
if (!error.error) {
- if (error.value === undefined)
+ if (error.value === undefined) {
throw new Error('Serialized error must have either an error or a value');
+ }
return parseSerializedValue(error.value, undefined);
}
if (error.error.name === 'TimeoutError') {
diff --git a/packages/playwright-core/src/client/eventEmitter.ts b/packages/playwright-core/src/client/eventEmitter.ts
index c0375a70dc..01d620225d 100644
--- a/packages/playwright-core/src/client/eventEmitter.ts
+++ b/packages/playwright-core/src/client/eventEmitter.ts
@@ -48,8 +48,9 @@ export class EventEmitter implements EventEmitterType {
}
setMaxListeners(n: number): this {
- if (typeof n !== 'number' || n < 0 || Number.isNaN(n))
+ if (typeof n !== 'number' || n < 0 || Number.isNaN(n)) {
throw new RangeError('The value of "n" is out of range. It must be a non-negative number. Received ' + n + '.');
+ }
this._maxListeners = n;
return this;
}
@@ -60,28 +61,32 @@ export class EventEmitter implements EventEmitterType {
emit(type: EventType, ...args: any[]): boolean {
const events = this._events;
- if (events === undefined)
+ if (events === undefined) {
return false;
+ }
- const handler = events?.[type];
- if (handler === undefined)
+ const handler = events[type];
+ if (handler === undefined) {
return false;
+ }
if (typeof handler === 'function') {
this._callHandler(type, handler, args);
} else {
const len = handler.length;
const listeners = handler.slice();
- for (let i = 0; i < len; ++i)
+ for (let i = 0; i < len; ++i) {
this._callHandler(type, listeners[i], args);
+ }
}
return true;
}
private _callHandler(type: EventType, handler: Listener, args: any[]): void {
const promise = Reflect.apply(handler, this, args);
- if (!(promise instanceof Promise))
+ if (!(promise instanceof Promise)) {
return;
+ }
let set = this._pendingHandlers.get(type);
if (!set) {
set = new Set();
@@ -89,10 +94,11 @@ export class EventEmitter implements EventEmitterType {
}
set.add(promise);
promise.catch(e => {
- if (this._rejectionHandler)
+ if (this._rejectionHandler) {
this._rejectionHandler(e);
- else
+ } else {
throw e;
+ }
}).finally(() => set.delete(promise));
}
@@ -183,20 +189,23 @@ export class EventEmitter implements EventEmitterType {
checkListener(listener);
const events = this._events;
- if (events === undefined)
+ if (events === undefined) {
return this;
+ }
const list = events[type];
- if (list === undefined)
+ if (list === undefined) {
return this;
+ }
if (list === listener || (list as any).listener === listener) {
if (--this._eventsCount === 0) {
this._events = Object.create(null);
} else {
delete events[type];
- if (events.removeListener)
+ if (events.removeListener) {
this.emit('removeListener', type, (list as any).listener ?? listener);
+ }
}
} else if (typeof list !== 'function') {
let position = -1;
@@ -210,19 +219,23 @@ export class EventEmitter implements EventEmitterType {
}
}
- if (position < 0)
+ if (position < 0) {
return this;
+ }
- if (position === 0)
+ if (position === 0) {
list.shift();
- else
+ } else {
list.splice(position, 1);
+ }
- if (list.length === 1)
+ if (list.length === 1) {
events[type] = list[0];
+ }
- if (events.removeListener !== undefined)
+ if (events.removeListener !== undefined) {
this.emit('removeListener', type, originalListener || listener);
+ }
}
return this;
@@ -237,21 +250,24 @@ export class EventEmitter implements EventEmitterType {
removeAllListeners(type: EventType | undefined, options: { behavior?: 'wait'|'ignoreErrors'|'default' }): Promise;
removeAllListeners(type?: string, options?: { behavior?: 'wait'|'ignoreErrors'|'default' }): this | Promise {
this._removeAllListeners(type);
- if (!options)
+ if (!options) {
return this;
+ }
if (options.behavior === 'wait') {
const errors: Error[] = [];
this._rejectionHandler = error => errors.push(error);
// eslint-disable-next-line internal-playwright/await-promise-in-class-returns
return this._waitFor(type).then(() => {
- if (errors.length)
+ if (errors.length) {
throw errors[0];
+ }
});
}
- if (options.behavior === 'ignoreErrors')
+ if (options.behavior === 'ignoreErrors') {
this._rejectionHandler = () => {};
+ }
// eslint-disable-next-line internal-playwright/await-promise-in-class-returns
return Promise.resolve();
@@ -259,8 +275,9 @@ export class EventEmitter implements EventEmitterType {
private _removeAllListeners(type?: string) {
const events = this._events;
- if (!events)
+ if (!events) {
return;
+ }
// not listening for removeListener, no need to emit
if (!events.removeListener) {
@@ -268,10 +285,11 @@ export class EventEmitter implements EventEmitterType {
this._events = Object.create(null);
this._eventsCount = 0;
} else if (events[type] !== undefined) {
- if (--this._eventsCount === 0)
+ if (--this._eventsCount === 0) {
this._events = Object.create(null);
- else
+ } else {
delete events[type];
+ }
}
return;
}
@@ -282,8 +300,9 @@ export class EventEmitter implements EventEmitterType {
let key;
for (let i = 0; i < keys.length; ++i) {
key = keys[i];
- if (key === 'removeListener')
+ if (key === 'removeListener') {
continue;
+ }
this._removeAllListeners(key);
}
this._removeAllListeners('removeListener');
@@ -298,8 +317,9 @@ export class EventEmitter implements EventEmitterType {
this.removeListener(type, listeners);
} else if (listeners !== undefined) {
// LIFO order
- for (let i = listeners.length - 1; i >= 0; i--)
+ for (let i = listeners.length - 1; i >= 0; i--) {
this.removeListener(type, listeners[i]);
+ }
}
}
@@ -315,10 +335,12 @@ export class EventEmitter implements EventEmitterType {
const events = this._events;
if (events !== undefined) {
const listener = events[type];
- if (typeof listener === 'function')
+ if (typeof listener === 'function') {
return 1;
- if (listener !== undefined)
+ }
+ if (listener !== undefined) {
return listener.length;
+ }
}
return 0;
}
@@ -333,8 +355,9 @@ export class EventEmitter implements EventEmitterType {
promises = [...(this._pendingHandlers.get(type) || [])];
} else {
promises = [];
- for (const [, pending] of this._pendingHandlers)
+ for (const [, pending] of this._pendingHandlers) {
promises.push(...pending);
+ }
}
await Promise.all(promises);
}
@@ -342,23 +365,27 @@ export class EventEmitter implements EventEmitterType {
private _listeners(target: EventEmitter, type: EventType, unwrap: boolean): Listener[] {
const events = target._events;
- if (events === undefined)
+ if (events === undefined) {
return [];
+ }
const listener = events[type];
- if (listener === undefined)
+ if (listener === undefined) {
return [];
+ }
- if (typeof listener === 'function')
+ if (typeof listener === 'function') {
return unwrap ? [unwrapListener(listener)] : [listener];
+ }
return unwrap ? unwrapListeners(listener) : listener.slice();
}
}
function checkListener(listener: any) {
- if (typeof listener !== 'function')
+ if (typeof listener !== 'function') {
throw new TypeError('The "listener" argument must be of type Function. Received type ' + typeof listener);
+ }
}
class OnceWrapper {
@@ -377,8 +404,9 @@ class OnceWrapper {
}
private _handle(...args: any[]) {
- if (this._fired)
+ if (this._fired) {
return;
+ }
this._fired = true;
this._eventEmitter.removeListener(this._eventType, this.wrapperFunction);
return this._listener.apply(this._eventEmitter, args);
diff --git a/packages/playwright-core/src/client/fetch.ts b/packages/playwright-core/src/client/fetch.ts
index 58928532ac..d508b6fd3a 100644
--- a/packages/playwright-core/src/client/fetch.ts
+++ b/packages/playwright-core/src/client/fetch.ts
@@ -110,8 +110,9 @@ export class APIRequestContext extends ChannelOwner {
return await this._wrapApiCall(async () => {
- if (this._closeReason)
+ if (this._closeReason) {
throw new TargetClosedError(this._closeReason);
+ }
assert(options.request || typeof options.url === 'string', 'First argument must be either URL string or Request');
assert((options.data === undefined ? 0 : 1) + (options.form === undefined ? 0 : 1) + (options.multipart === undefined ? 0 : 1) <= 1, `Only one of 'data', 'form' or 'multipart' can be specified`);
assert(options.maxRedirects === undefined || options.maxRedirects >= 0, `'maxRedirects' must be greater than or equal to '0'`);
@@ -177,10 +179,11 @@ export class APIRequestContext extends ChannelOwner {
if (isFilePayload(value)) {
const payload = value as FilePayload;
- if (!Buffer.isBuffer(payload.buffer))
+ if (!Buffer.isBuffer(payload.buffer)) {
throw new Error(`Unexpected buffer type of 'data.${name}'`);
+ }
return { name, file: filePayloadToJson(payload) };
} else if (value instanceof fs.ReadStream) {
return { name, file: await readStreamToJson(value as fs.ReadStream) };
@@ -284,16 +292,18 @@ async function toFormField(name: string, value: string|number|boolean|fs.ReadStr
}
function isJsonParsable(value: any) {
- if (typeof value !== 'string')
+ if (typeof value !== 'string') {
return false;
+ }
try {
JSON.parse(value);
return true;
} catch (e) {
- if (e instanceof SyntaxError)
+ if (e instanceof SyntaxError) {
return false;
- else
+ } else {
throw e;
+ }
}
}
@@ -335,12 +345,14 @@ export class APIResponse implements api.APIResponse {
async body(): Promise {
try {
const result = await this._request._channel.fetchResponseBody({ fetchUid: this._fetchUid() });
- if (result.binary === undefined)
+ if (result.binary === undefined) {
throw new Error('Response has been disposed');
+ }
return result.binary;
} catch (e) {
- if (isTargetClosedError(e))
+ if (isTargetClosedError(e)) {
throw new Error('Response has been disposed');
+ }
throw e;
}
}
@@ -403,21 +415,25 @@ async function readStreamToJson(stream: fs.ReadStream): Promise implements api.Fr
this._eventEmitter = new EventEmitter();
this._eventEmitter.setMaxListeners(0);
this._parentFrame = Frame.fromNullable(initializer.parentFrame);
- if (this._parentFrame)
+ if (this._parentFrame) {
this._parentFrame._childFrames.add(this);
+ }
this._name = initializer.name;
this._url = initializer.url;
this._loadStates = new Set(initializer.loadStates);
@@ -76,19 +77,23 @@ export class Frame extends ChannelOwner implements api.Fr
this._loadStates.add(event.add);
this._eventEmitter.emit('loadstate', event.add);
}
- if (event.remove)
+ if (event.remove) {
this._loadStates.delete(event.remove);
- if (!this._parentFrame && event.add === 'load' && this._page)
+ }
+ if (!this._parentFrame && event.add === 'load' && this._page) {
this._page.emit(Events.Page.Load, this._page);
- if (!this._parentFrame && event.add === 'domcontentloaded' && this._page)
+ }
+ if (!this._parentFrame && event.add === 'domcontentloaded' && this._page) {
this._page.emit(Events.Page.DOMContentLoaded, this._page);
+ }
});
this._channel.on('navigated', event => {
this._url = event.url;
this._name = event.name;
this._eventEmitter.emit('navigated', event);
- if (!event.error && this._page)
+ if (!event.error && this._page) {
this._page.emit(Events.Page.FrameNavigated, this);
+ }
});
}
@@ -103,8 +108,9 @@ export class Frame extends ChannelOwner implements api.Fr
private _setupNavigationWaiter(options: { timeout?: number }): Waiter {
const waiter = new Waiter(this._page!, '');
- if (this._page!.isClosed())
+ if (this._page!.isClosed()) {
waiter.rejectImmediately(this._page!._closeErrorWithReason());
+ }
waiter.rejectOnEvent(this._page!, Events.Page.Close, () => this._page!._closeErrorWithReason());
waiter.rejectOnEvent(this._page!, Events.Page.Crash, new Error('Navigation failed because page crashed!'));
waiter.rejectOnEvent(this._page!, Events.Page.FrameDetached, new Error('Navigating frame was detached!'), frame => frame === this);
@@ -123,8 +129,9 @@ export class Frame extends ChannelOwner implements api.Fr
const navigatedEvent = await waiter.waitForEvent(this._eventEmitter, 'navigated', event => {
// Any failed navigation results in a rejection.
- if (event.error)
+ if (event.error) {
return true;
+ }
waiter.log(` navigated to "${event.url}"`);
return urlMatches(this._page?.context()._options.baseURL, event.url, options.url);
});
@@ -165,8 +172,9 @@ export class Frame extends ChannelOwner implements api.Fr
}
async waitForURL(url: URLMatch, options: { waitUntil?: LifecycleEvent, timeout?: number } = {}): Promise {
- if (urlMatches(this._page?.context()._options.baseURL, this.url(), url))
+ if (urlMatches(this._page?.context()._options.baseURL, this.url(), url)) {
return await this.waitForLoadState(options.waitUntil, options);
+ }
await this.waitForNavigation({ url, ...options });
}
@@ -201,10 +209,12 @@ export class Frame extends ChannelOwner implements api.Fr
waitForSelector(selector: string, options: channels.FrameWaitForSelectorOptions & { state: 'attached' | 'visible' }): Promise>;
waitForSelector(selector: string, options?: channels.FrameWaitForSelectorOptions): Promise | null>;
async waitForSelector(selector: string, options: channels.FrameWaitForSelectorOptions = {}): Promise | null> {
- if ((options as any).visibility)
+ if ((options as any).visibility) {
throw new Error('options.visibility is not supported, did you mean options.state?');
- if ((options as any).waitFor && (options as any).waitFor !== 'visible')
+ }
+ if ((options as any).waitFor && (options as any).waitFor !== 'visible') {
throw new Error('options.waitFor is not supported, did you mean options.state?');
+ }
const result = await this._channel.waitForSelector({ selector, ...options });
return ElementHandle.fromNullable(result.element) as ElementHandle | null;
}
@@ -421,10 +431,11 @@ export class Frame extends ChannelOwner implements api.Fr
}
async setChecked(selector: string, checked: boolean, options?: channels.FrameCheckOptions) {
- if (checked)
+ if (checked) {
await this.check(selector, options);
- else
+ } else {
await this.uncheck(selector, options);
+ }
}
async waitForTimeout(timeout: number) {
@@ -432,8 +443,9 @@ export class Frame extends ChannelOwner implements api.Fr
}
async waitForFunction(pageFunction: structs.PageFunction, arg?: Arg, options: WaitForFunctionOptions = {}): Promise> {
- if (typeof options.polling === 'string')
+ if (typeof options.polling === 'string') {
assert(options.polling === 'raf', 'Unknown polling option: ' + options.polling);
+ }
const result = await this._channel.waitForFunction({
...options,
pollingInterval: options.polling === 'raf' ? undefined : options.polling,
@@ -450,9 +462,11 @@ export class Frame extends ChannelOwner implements api.Fr
}
export function verifyLoadState(name: string, waitUntil: LifecycleEvent): LifecycleEvent {
- if (waitUntil as unknown === 'networkidle0')
+ if (waitUntil as unknown === 'networkidle0') {
waitUntil = 'networkidle';
- if (!kLifecycleEvents.has(waitUntil))
+ }
+ if (!kLifecycleEvents.has(waitUntil)) {
throw new Error(`${name}: expected one of (load|domcontentloaded|networkidle|commit)`);
+ }
return waitUntil;
}
diff --git a/packages/playwright-core/src/client/harRouter.ts b/packages/playwright-core/src/client/harRouter.ts
index 5e617d7ce9..17320ffd78 100644
--- a/packages/playwright-core/src/client/harRouter.ts
+++ b/packages/playwright-core/src/client/harRouter.ts
@@ -31,8 +31,9 @@ export class HarRouter {
static async create(localUtils: LocalUtils, file: string, notFoundAction: HarNotFoundAction, options: { urlMatch?: URLMatch }): Promise {
const { harId, error } = await localUtils._channel.harOpen({ file });
- if (error)
+ if (error) {
throw new Error(error);
+ }
return new HarRouter(localUtils, harId!, notFoundAction, options);
}
@@ -67,8 +68,9 @@ export class HarRouter {
// TODO: it'd be better to abort such requests, but then we likely need to respect the timing,
// because the request might have been stalled for a long time until the very end of the
// test when HAR was recorded but we'd abort it immediately.
- if (response.status === -1)
+ if (response.status === -1) {
return;
+ }
await route.fulfill({
status: response.status,
headers: Object.fromEntries(response.headers!.map(h => [h.name, h.value])),
@@ -77,8 +79,9 @@ export class HarRouter {
return;
}
- if (response.action === 'error')
+ if (response.action === 'error') {
debugLogger.log('api', 'HAR: ' + response.message!);
+ }
// Report the error, but fall through to the default handler.
if (this._notFoundAction === 'abort') {
diff --git a/packages/playwright-core/src/client/jsHandle.ts b/packages/playwright-core/src/client/jsHandle.ts
index 8577400f3d..3561b28e8e 100644
--- a/packages/playwright-core/src/client/jsHandle.ts
+++ b/packages/playwright-core/src/client/jsHandle.ts
@@ -51,8 +51,9 @@ export class JSHandle extends ChannelOwner im
async getProperties(): Promise