/** * Copyright (c) Microsoft Corporation. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ import type { BrowserContextOptions } from '../../../..'; import { LanguageGenerator, LanguageGeneratorOptions, toSignalMap } from './language'; import { ActionInContext } from './codeGenerator'; import { Action, actionTitle } from './recorderActions'; import { toModifiers } from './utils'; import deviceDescriptors = require('../../deviceDescriptors'); import { JavaScriptFormatter } from './javascript'; export class JavaLanguageGenerator implements LanguageGenerator { id = 'java'; fileName = ''; highlighter = 'java'; generateAction(actionInContext: ActionInContext): string { const { action, pageAlias } = actionInContext; const formatter = new JavaScriptFormatter(6); formatter.newLine(); formatter.add('// ' + actionTitle(action)); if (action.name === 'openPage') { formatter.add(`Page ${pageAlias} = context.newPage();`); if (action.url && action.url !== 'about:blank' && action.url !== 'chrome://newtab/') formatter.add(`${pageAlias}.navigate("${action.url}");`); return formatter.format(); } const subject = actionInContext.isMainFrame ? pageAlias : (actionInContext.frameName ? `${pageAlias}.frame(${quote(actionInContext.frameName)})` : `${pageAlias}.frameByUrl(${quote(actionInContext.frameUrl)})`); const signals = toSignalMap(action); if (signals.dialog) { formatter.add(` ${pageAlias}.onceDialog(dialog -> { System.out.println(String.format("Dialog message: %s", dialog.message())); dialog.dismiss(); });`); } const actionCall = this._generateActionCall(action); let code = `${subject}.${actionCall};`; if (signals.popup) { code = `Page ${signals.popup.popupAlias} = ${pageAlias}.waitForPopup(() -> { ${code} });`; } if (signals.download) { code = `Download download = ${pageAlias}.waitForDownload(() -> { ${code} });`; } if (signals.waitForNavigation) { code = ` // ${pageAlias}.waitForNavigation(new Page.WaitForNavigationOptions().withUrl(${quote(signals.waitForNavigation.url)}), () -> ${pageAlias}.waitForNavigation(() -> { ${code} });`; } formatter.add(code); if (signals.assertNavigation) formatter.add(`// assert ${pageAlias}.url().equals(${quote(signals.assertNavigation.url)});`); return formatter.format(); } private _generateActionCall(action: Action): string { switch (action.name) { case 'openPage': throw Error('Not reached'); case 'closePage': return 'close()'; case 'click': { let method = 'click'; if (action.clickCount === 2) method = 'dblclick'; return `${method}(${quote(action.selector)})`; } case 'check': return `check(${quote(action.selector)})`; case 'uncheck': return `uncheck(${quote(action.selector)})`; case 'fill': return `fill(${quote(action.selector)}, ${quote(action.text)})`; case 'setInputFiles': return `setInputFiles(${quote(action.selector)}, ${formatPath(action.files.length === 1 ? action.files[0] : action.files)})`; case 'press': { const modifiers = toModifiers(action.modifiers); const shortcut = [...modifiers, action.key].join('+'); return `press(${quote(action.selector)}, ${quote(shortcut)})`; } case 'navigate': return `navigate(${quote(action.url)})`; case 'select': return `selectOption(${quote(action.selector)}, ${formatSelectOption(action.options.length > 1 ? action.options : action.options[0])})`; } } generateHeader(options: LanguageGeneratorOptions): string { const formatter = new JavaScriptFormatter(); formatter.add(` import com.microsoft.playwright.*; import com.microsoft.playwright.options.*; public class Example { public static void main(String[] args) { try (Playwright playwright = Playwright.create()) { Browser browser = playwright.${options.browserName}().launch(${formatLaunchOptions(options.launchOptions)}); BrowserContext context = browser.newContext(${formatContextOptions(options.contextOptions, options.deviceName)});`); return formatter.format(); } generateFooter(saveStorage: string | undefined): string { const storageStateLine = saveStorage ? `\n context.storageState(new BrowserContext.StorageStateOptions().withPath(${quote(saveStorage)}));` : ''; return `\n // ---------------------${storageStateLine} } } }`; } } function formatPath(files: string | string[]): string { if (Array.isArray(files)) { if (files.length === 0) return 'new Path[0]'; return `new Path[] {${files.map(s => 'Paths.get(' + quote(s) + ')').join(', ')}}`; } return `Paths.get(${quote(files)})`; } function formatSelectOption(options: string | string[]): string { if (Array.isArray(options)) { if (options.length === 0) return 'new String[0]'; return `new String[] {${options.map(s => quote(s)).join(', ')}}`; } return quote(options); } function formatLaunchOptions(options: any): string { const lines = []; if (!Object.keys(options).length) return ''; lines.push('new BrowserType.LaunchOptions()'); if (typeof options.headless === 'boolean') lines.push(` .withHeadless(false)`); return lines.join('\n'); } function formatContextOptions(contextOptions: BrowserContextOptions, deviceName: string | undefined): string { const lines = []; if (!Object.keys(contextOptions).length && !deviceName) return ''; const device = deviceName ? deviceDescriptors[deviceName] : {}; const options: BrowserContextOptions = { ...device, ...contextOptions }; lines.push('new Browser.NewContextOptions()'); if (options.colorScheme) lines.push(` .withColorScheme(ColorScheme.${options.colorScheme.toUpperCase()})`); if (options.geolocation) lines.push(` .withGeolocation(${options.geolocation.latitude}, ${options.geolocation.longitude})`); if (options.locale) lines.push(` .withLocale("${options.locale}")`); if (options.proxy) lines.push(` .withProxy(new Proxy("${options.proxy.server}"))`); if (options.timezoneId) lines.push(` .withTimezoneId("${options.timezoneId}")`); if (options.userAgent) lines.push(` .withUserAgent("${options.userAgent}")`); if (options.viewport) lines.push(` .withViewportSize(${options.viewport.width}, ${options.viewport.height})`); if (options.deviceScaleFactor) lines.push(` .withDeviceScaleFactor(${options.deviceScaleFactor})`); if (options.isMobile) lines.push(` .withIsMobile(${options.isMobile})`); if (options.hasTouch) lines.push(` .withHasTouch(${options.hasTouch})`); if (options.storageState) lines.push(` .withStorageStatePath(Paths.get(${quote(options.storageState as string)}))`); return lines.join('\n'); } function quote(text: string, char: string = '\"') { if (char === '\'') return char + text.replace(/[']/g, '\\\'') + char; if (char === '"') return char + text.replace(/["]/g, '\\"') + char; if (char === '`') return char + text.replace(/[`]/g, '\\`') + char; throw new Error('Invalid escape char'); }