diff --git a/src/cli/cli.ts b/src/cli/cli.ts index 7a5d86edcf..d3bde5a029 100755 --- a/src/cli/cli.ts +++ b/src/cli/cli.ts @@ -348,7 +348,7 @@ async function openPage(context: BrowserContext, url: string | undefined): Promi if (url) { if (fs.existsSync(url)) url = 'file://' + path.resolve(url); - else if (!url.startsWith('http') && !url.startsWith('file://') && !url.startsWith('about:')) + else if (!url.startsWith('http') && !url.startsWith('file://') && !url.startsWith('about:') && !url.startsWith('data:')) url = 'http://' + url; await page.goto(url); } diff --git a/src/server/supplements/recorder/java.ts b/src/server/supplements/recorder/java.ts index 8c8b83bac7..f32f7a7fea 100644 --- a/src/server/supplements/recorder/java.ts +++ b/src/server/supplements/recorder/java.ts @@ -18,7 +18,7 @@ import type { BrowserContextOptions } from '../../../..'; import { LanguageGenerator, LanguageGeneratorOptions, toSignalMap } from './language'; import { ActionInContext } from './codeGenerator'; import { Action, actionTitle } from './recorderActions'; -import { toModifiers } from './utils'; +import { MouseClickOptions, toModifiers } from './utils'; import deviceDescriptors from '../../deviceDescriptors'; import { JavaScriptFormatter } from './javascript'; @@ -54,7 +54,7 @@ export class JavaLanguageGenerator implements LanguageGenerator { });`); } - const actionCall = this._generateActionCall(action); + const actionCall = this._generateActionCall(action, actionInContext.isMainFrame); let code = `${subject}.${actionCall};`; if (signals.popup) { @@ -84,7 +84,7 @@ export class JavaLanguageGenerator implements LanguageGenerator { return formatter.format(); } - private _generateActionCall(action: Action): string { + private _generateActionCall(action: Action, isPage: boolean): string { switch (action.name) { case 'openPage': throw Error('Not reached'); @@ -94,7 +94,16 @@ export class JavaLanguageGenerator implements LanguageGenerator { let method = 'click'; if (action.clickCount === 2) method = 'dblclick'; - return `${method}(${quote(action.selector)})`; + const modifiers = toModifiers(action.modifiers); + const options: MouseClickOptions = {}; + if (action.button !== 'left') + options.button = action.button; + if (modifiers.length) + options.modifiers = modifiers; + if (action.clickCount > 2) + options.clickCount = action.clickCount; + const optionsText = formatClickOptions(options, isPage); + return `${method}(${quote(action.selector)}${optionsText ? ', ' : ''}${optionsText})`; } case 'check': return `check(${quote(action.selector)})`; @@ -121,6 +130,7 @@ export class JavaLanguageGenerator implements LanguageGenerator { formatter.add(` import com.microsoft.playwright.*; import com.microsoft.playwright.options.*; + import java.util.*; public class Example { public static void main(String[] args) { @@ -131,9 +141,8 @@ export class JavaLanguageGenerator implements LanguageGenerator { } generateFooter(saveStorage: string | undefined): string { - const storageStateLine = saveStorage ? `\n context.storageState(new BrowserContext.StorageStateOptions().setPath(${quote(saveStorage)}));` : ''; - return `\n // ---------------------${storageStateLine} - } + const storageStateLine = saveStorage ? `\n context.storageState(new BrowserContext.StorageStateOptions().setPath(${quote(saveStorage)}));\n` : ''; + return `${storageStateLine} } } }`; } @@ -176,29 +185,46 @@ function formatContextOptions(contextOptions: BrowserContextOptions, deviceName: const device = deviceName ? deviceDescriptors[deviceName] : {}; const options: BrowserContextOptions = { ...device, ...contextOptions }; lines.push('new Browser.NewContextOptions()'); + if (options.acceptDownloads) + lines.push(` .setAcceptDownloads(true)`); + if (options.bypassCSP) + lines.push(` .setBypassCSP(true)`); if (options.colorScheme) lines.push(` .setColorScheme(ColorScheme.${options.colorScheme.toUpperCase()})`); + if (options.deviceScaleFactor) + lines.push(` .setDeviceScaleFactor(${options.deviceScaleFactor})`); if (options.geolocation) lines.push(` .setGeolocation(${options.geolocation.latitude}, ${options.geolocation.longitude})`); + if (options.hasTouch) + lines.push(` .setHasTouch(${options.hasTouch})`); + if (options.isMobile) + lines.push(` .setIsMobile(${options.isMobile})`); if (options.locale) lines.push(` .setLocale("${options.locale}")`); if (options.proxy) lines.push(` .setProxy(new Proxy("${options.proxy.server}"))`); + if (options.storageState) + lines.push(` .setStorageStatePath(Paths.get(${quote(options.storageState as string)}))`); if (options.timezoneId) lines.push(` .setTimezoneId("${options.timezoneId}")`); if (options.userAgent) lines.push(` .setUserAgent("${options.userAgent}")`); if (options.viewport) lines.push(` .setViewportSize(${options.viewport.width}, ${options.viewport.height})`); - if (options.deviceScaleFactor) - lines.push(` .setDeviceScaleFactor(${options.deviceScaleFactor})`); - if (options.isMobile) - lines.push(` .setIsMobile(${options.isMobile})`); - if (options.hasTouch) - lines.push(` .setHasTouch(${options.hasTouch})`); - if (options.storageState) - lines.push(` .setStorageStatePath(Paths.get(${quote(options.storageState as string)}))`); + return lines.join('\n'); +} +function formatClickOptions(options: MouseClickOptions, isPage: boolean) { + const lines = []; + if (options.button) + lines.push(` .setButton(MouseButton.${options.button.toUpperCase()})`); + if (options.modifiers) + lines.push(` .setModifiers(Arrays.asList(${options.modifiers.map(m => `KeyboardModifier.${m.toUpperCase()}`).join(', ')}))`); + if (options.clickCount) + lines.push(` .setClickCount(${options.clickCount})`); + if (!lines.length) + return ''; + lines.unshift(`new ${isPage ? 'Page' : 'Frame'}.ClickOptions()`); return lines.join('\n'); } diff --git a/tests/inspector/cli-codegen-1.spec.ts b/tests/inspector/cli-codegen-1.spec.ts index 44004b0bea..1fb4aabd35 100644 --- a/tests/inspector/cli-codegen-1.spec.ts +++ b/tests/inspector/cli-codegen-1.spec.ts @@ -647,9 +647,9 @@ test.describe('cli codegen', () => { expect(sources.get('').text).toContain(` await page.click("text=Click me", button="middle")`); - // TODO: fix this for java - // expect(sources.get('').text).toContain(` - // page.click("text=Click me", foo);`); + expect(sources.get('').text).toContain(` + page.click("text=Click me", new Page.ClickOptions() + .setButton(MouseButton.MIDDLE));`); expect(sources.get('').text).toContain(` await page.ClickAsync("text=Click me", new PageClickOptions diff --git a/tests/inspector/cli-codegen-2.spec.ts b/tests/inspector/cli-codegen-2.spec.ts index f3c14ede06..6650e69068 100644 --- a/tests/inspector/cli-codegen-2.spec.ts +++ b/tests/inspector/cli-codegen-2.spec.ts @@ -261,9 +261,9 @@ test.describe('cli codegen', () => { page.click('text=Download') ]);`); - // TODO: fix generated options in java. expect(sources.get('').text).toContain(` - BrowserContext context = browser.newContext(new Browser.NewContextOptions());`); + BrowserContext context = browser.newContext(new Browser.NewContextOptions() + .setAcceptDownloads(true));`); expect(sources.get('').text).toContain(` // Click text=Download Download download = page.waitForDownload(() -> { diff --git a/tests/inspector/cli-codegen-java.spec.ts b/tests/inspector/cli-codegen-java.spec.ts index 42fb9a06f9..3bf75a75db 100644 --- a/tests/inspector/cli-codegen-java.spec.ts +++ b/tests/inspector/cli-codegen-java.spec.ts @@ -27,6 +27,7 @@ test('should print the correct imports and context options', async ({ runCLI, ch const cli = runCLI(['--target=java', emptyHTML]); const expectedResult = `import com.microsoft.playwright.*; import com.microsoft.playwright.options.*; +import java.util.*; public class Example { public static void main(String[] args) { @@ -50,13 +51,13 @@ test('should print the correct context options when using a device', async ({ br test.skip(browserName !== 'chromium'); const cli = runCLI(['--device=Pixel 2', '--target=java', emptyHTML]); - await cli.waitFor(`setHasTouch(true));`); + await cli.waitFor(`.setViewportSize(411, 731));`); const expectedResult = `BrowserContext context = browser.newContext(new Browser.NewContextOptions() - .setUserAgent("Mozilla/5.0 (Linux; Android 8.0; Pixel 2 Build/OPD3.170816.012) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/XXXX Mobile Safari/537.36") - .setViewportSize(411, 731) .setDeviceScaleFactor(2.625) + .setHasTouch(true) .setIsMobile(true) - .setHasTouch(true));`; + .setUserAgent("Mozilla/5.0 (Linux; Android 8.0; Pixel 2 Build/OPD3.170816.012) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/XXXX Mobile Safari/537.36") + .setViewportSize(411, 731));`; expect(cli.text().replace(/(.*Chrome\/)(.*?)( .*)/m, '$1XXXX$3')).toContain(expectedResult); }); @@ -66,11 +67,11 @@ test('should print the correct context options when using a device and additiona const cli = runCLI(['--color-scheme=light', '--device=iPhone 11', '--target=java', emptyHTML]); const expectedResult = `BrowserContext context = browser.newContext(new Browser.NewContextOptions() .setColorScheme(ColorScheme.LIGHT) - .setUserAgent("Mozilla/5.0 (iPhone; CPU iPhone OS 12_2 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0 Mobile/15E148 Safari/604.1") - .setViewportSize(414, 715) .setDeviceScaleFactor(2) + .setHasTouch(true) .setIsMobile(true) - .setHasTouch(true));`; + .setUserAgent("Mozilla/5.0 (iPhone; CPU iPhone OS 12_2 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0 Mobile/15E148 Safari/604.1") + .setViewportSize(414, 715));`; await cli.waitFor(expectedResult); expect(cli.text()).toContain(expectedResult); }); @@ -85,7 +86,6 @@ test('should print load/save storage_state', async ({ runCLI, browserName }, tes await cli.waitFor(expectedResult1); const expectedResult2 = ` - // --------------------- context.storageState(new BrowserContext.StorageStateOptions().setPath("${saveFileName}"))`; await cli.waitFor(expectedResult2); });