From eaa501a6c889641e1b7a1bdf48e77d099e74d10a Mon Sep 17 00:00:00 2001 From: Yury Semikhatsky Date: Fri, 2 Feb 2024 17:43:37 -0800 Subject: [PATCH] feat: support device name in playwright fixtures Reference https://github.com/microsoft/playwright-java/issues/1369 Reference https://github.com/microsoft/playwright-java/issues/939 --- .../microsoft/playwright/impl/LocalUtils.java | 4 ++ .../playwright/impl/PlaywrightImpl.java | 5 +++ .../microsoft/playwright/junit/Options.java | 12 +++++- .../junit/impl/BrowserContextExtension.java | 22 ++++++++++- .../junit/impl/BrowserExtension.java | 34 ++++++++++++----- .../junit/impl/DeviceDescriptor.java | 34 +++++++++++++++++ .../TestPlaywrightDeviceOption.java | 37 +++++++++++++++++++ 7 files changed, 135 insertions(+), 13 deletions(-) create mode 100644 playwright/src/main/java/com/microsoft/playwright/junit/impl/DeviceDescriptor.java create mode 100644 playwright/src/test/java/com/microsoft/playwright/TestPlaywrightDeviceOption.java diff --git a/playwright/src/main/java/com/microsoft/playwright/impl/LocalUtils.java b/playwright/src/main/java/com/microsoft/playwright/impl/LocalUtils.java index 43ba176d3..376ab3142 100644 --- a/playwright/src/main/java/com/microsoft/playwright/impl/LocalUtils.java +++ b/playwright/src/main/java/com/microsoft/playwright/impl/LocalUtils.java @@ -29,6 +29,10 @@ class LocalUtils extends ChannelOwner { super(parent, type, guid, initializer); } + JsonArray deviceDescriptors() { + return initializer.getAsJsonArray("deviceDescriptors"); + } + void zip(Path zipFile, JsonArray entries, String stacksId, boolean appendMode, boolean includeSources) { JsonObject params = new JsonObject(); params.addProperty("zipFile", zipFile.toString()); diff --git a/playwright/src/main/java/com/microsoft/playwright/impl/PlaywrightImpl.java b/playwright/src/main/java/com/microsoft/playwright/impl/PlaywrightImpl.java index b730bd6fd..32963edbf 100644 --- a/playwright/src/main/java/com/microsoft/playwright/impl/PlaywrightImpl.java +++ b/playwright/src/main/java/com/microsoft/playwright/impl/PlaywrightImpl.java @@ -16,6 +16,7 @@ package com.microsoft.playwright.impl; +import com.google.gson.JsonArray; import com.google.gson.JsonObject; import com.microsoft.playwright.APIRequest; import com.microsoft.playwright.Playwright; @@ -89,6 +90,10 @@ void unregisterSelectors() { sharedSelectors.removeChannel(selectors); } + public JsonArray deviceDescriptors() { + return connection.localUtils.deviceDescriptors(); + } + @Override public BrowserTypeImpl chromium() { return chromium; diff --git a/playwright/src/main/java/com/microsoft/playwright/junit/Options.java b/playwright/src/main/java/com/microsoft/playwright/junit/Options.java index 4ccdd19ac..819e74ad0 100644 --- a/playwright/src/main/java/com/microsoft/playwright/junit/Options.java +++ b/playwright/src/main/java/com/microsoft/playwright/junit/Options.java @@ -14,7 +14,8 @@ public class Options { public ViewportSize viewportSize; public String channel; public Boolean headless; - public String browserName = "chromium"; + public String browserName; + public String device; public BrowserType.LaunchOptions launchOptions; public Browser.NewContextOptions contextOption; public APIRequest.NewContextOptions apiRequestOptions; @@ -83,6 +84,15 @@ public Options setBrowserName(String browserName) { return this; } + public String getDevice() { + return device; + } + + public Options setDevice(String device) { + this.device = device; + return this; + } + public String getChannel() { return channel; } diff --git a/playwright/src/main/java/com/microsoft/playwright/junit/impl/BrowserContextExtension.java b/playwright/src/main/java/com/microsoft/playwright/junit/impl/BrowserContextExtension.java index 5e32f628b..9ca50b5fa 100644 --- a/playwright/src/main/java/com/microsoft/playwright/junit/impl/BrowserContextExtension.java +++ b/playwright/src/main/java/com/microsoft/playwright/junit/impl/BrowserContextExtension.java @@ -2,8 +2,11 @@ import com.microsoft.playwright.Browser; import com.microsoft.playwright.BrowserContext; +import com.microsoft.playwright.Playwright; +import com.microsoft.playwright.PlaywrightException; import com.microsoft.playwright.impl.Utils; import com.microsoft.playwright.junit.Options; +import com.microsoft.playwright.options.ViewportSize; import org.junit.jupiter.api.extension.*; import static com.microsoft.playwright.junit.impl.ExtensionUtils.isClassHook; @@ -38,14 +41,15 @@ static BrowserContext getOrCreateBrowserContext(ExtensionContext extensionContex } Options options = OptionsExtension.getOptions(extensionContext); + Playwright playwright = PlaywrightExtension.getOrCreatePlaywright(extensionContext); Browser browser = BrowserExtension.getOrCreateBrowser(extensionContext); - Browser.NewContextOptions contextOptions = getContextOptions(options); + Browser.NewContextOptions contextOptions = getContextOptions(playwright, options); browserContext = browser.newContext(contextOptions); threadLocalBrowserContext.set(browserContext); return browserContext; } - private static Browser.NewContextOptions getContextOptions(Options options) { + private static Browser.NewContextOptions getContextOptions(Playwright playwright, Options options) { Browser.NewContextOptions contextOptions = Utils.clone(options.getContextOption()); if (contextOptions == null) { contextOptions = new Browser.NewContextOptions(); @@ -59,6 +63,20 @@ private static Browser.NewContextOptions getContextOptions(Options options) { contextOptions.setStorageStatePath(options.getStorageStatePath()); } + if (options.getDevice() != null) { + DeviceDescriptor deviceDescriptor = DeviceDescriptor.findByName(playwright, options.getDevice()); + if (deviceDescriptor == null) { + throw new PlaywrightException("Unknown device name: " + options.getDevice()); + } + contextOptions.userAgent = deviceDescriptor.userAgent; + if (deviceDescriptor.viewport != null) { + contextOptions.setViewportSize(deviceDescriptor.viewport.width, deviceDescriptor.viewport.height); + } + contextOptions.deviceScaleFactor = deviceDescriptor.deviceScaleFactor; + contextOptions.isMobile = deviceDescriptor.isMobile; + contextOptions.hasTouch = deviceDescriptor.hasTouch; + } + if (options.getViewportSize() != null) { contextOptions.setViewportSize(options.getViewportSize()); } diff --git a/playwright/src/main/java/com/microsoft/playwright/junit/impl/BrowserExtension.java b/playwright/src/main/java/com/microsoft/playwright/junit/impl/BrowserExtension.java index af0a32eb8..fb341f01b 100644 --- a/playwright/src/main/java/com/microsoft/playwright/junit/impl/BrowserExtension.java +++ b/playwright/src/main/java/com/microsoft/playwright/junit/impl/BrowserExtension.java @@ -1,9 +1,13 @@ package com.microsoft.playwright.junit.impl; +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; import com.microsoft.playwright.Browser; import com.microsoft.playwright.BrowserType; import com.microsoft.playwright.Playwright; import com.microsoft.playwright.PlaywrightException; +import com.microsoft.playwright.impl.PlaywrightImpl; import com.microsoft.playwright.impl.Utils; import com.microsoft.playwright.junit.Options; import org.junit.jupiter.api.extension.*; @@ -42,22 +46,32 @@ static Browser getOrCreateBrowser(ExtensionContext extensionContext) { Playwright playwright = PlaywrightExtension.getOrCreatePlaywright(extensionContext); BrowserType.LaunchOptions launchOptions = getLaunchOptions(options); - switch (options.getBrowserName()) { + BrowserType browserType = playwright.chromium(); + if (options.getBrowserName() != null) { + browserType = getBrowserTypeForName(playwright, options.getBrowserName()); + } else if (options.device != null) { + DeviceDescriptor deviceDescriptor = DeviceDescriptor.findByName(playwright, options.device); + if (deviceDescriptor != null && deviceDescriptor.defaultBrowserType != null) { + browserType = getBrowserTypeForName(playwright, deviceDescriptor.defaultBrowserType); + } + } + browser = browserType.launch(launchOptions); + + threadLocalBrowser.set(browser); + return browser; + } + + private static BrowserType getBrowserTypeForName(Playwright playwright, String name) { + switch (name) { case "webkit": - browser = playwright.webkit().launch(launchOptions); - break; + return playwright.webkit(); case "firefox": - browser = playwright.firefox().launch(launchOptions); - break; + return playwright.firefox(); case "chromium": - browser = playwright.chromium().launch(launchOptions); - break; + return playwright.chromium(); default: throw new PlaywrightException("Invalid browser name."); } - - threadLocalBrowser.set(browser); - return browser; } private static BrowserType.LaunchOptions getLaunchOptions(Options options) { diff --git a/playwright/src/main/java/com/microsoft/playwright/junit/impl/DeviceDescriptor.java b/playwright/src/main/java/com/microsoft/playwright/junit/impl/DeviceDescriptor.java new file mode 100644 index 000000000..3b59a7b87 --- /dev/null +++ b/playwright/src/main/java/com/microsoft/playwright/junit/impl/DeviceDescriptor.java @@ -0,0 +1,34 @@ +package com.microsoft.playwright.junit.impl; + +import com.google.gson.Gson; +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.microsoft.playwright.Playwright; +import com.microsoft.playwright.impl.PlaywrightImpl; +import com.microsoft.playwright.options.ViewportSize; + +class DeviceDescriptor { + public String userAgent; + public ViewportSize viewport; + public Double deviceScaleFactor; + public Boolean isMobile; + public Boolean hasTouch; + public String defaultBrowserType; + + static DeviceDescriptor findByName(Playwright playwright, String name) { + JsonArray devices = ((PlaywrightImpl) playwright).deviceDescriptors(); + JsonObject descriptor = null; + for (JsonElement item : devices) { + if (name.equals(item.getAsJsonObject().get("name").getAsString())) { + descriptor = item.getAsJsonObject().getAsJsonObject("descriptor"); + break; + } + } + if (descriptor == null) { + return null; + } + return new Gson().fromJson(descriptor, DeviceDescriptor.class); + } + +} diff --git a/playwright/src/test/java/com/microsoft/playwright/TestPlaywrightDeviceOption.java b/playwright/src/test/java/com/microsoft/playwright/TestPlaywrightDeviceOption.java new file mode 100644 index 000000000..793c2dd3f --- /dev/null +++ b/playwright/src/test/java/com/microsoft/playwright/TestPlaywrightDeviceOption.java @@ -0,0 +1,37 @@ +package com.microsoft.playwright; + +import com.microsoft.playwright.junit.Options; +import com.microsoft.playwright.junit.OptionsFactory; +import com.microsoft.playwright.junit.UsePlaywright; +import org.junit.jupiter.api.Test; + +import java.util.regex.Pattern; + +import static com.microsoft.playwright.ServerLifecycle.serverMap; +import static com.microsoft.playwright.assertions.PlaywrightAssertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertEquals; + +@FixtureTest +@UsePlaywright(TestPlaywrightDeviceOption.CustomOptions.class) +public class TestPlaywrightDeviceOption { + + public static class CustomOptions implements OptionsFactory { + @Override + public Options getOptions() { + return new Options().setDevice("iPhone 14"); + } + } + + private Server server() { + return serverMap.get(this.getClass()); + } + + @Test + public void testPredifinedDeviceParameters(Page page) { + page.navigate(server().EMPTY_PAGE); + assertEquals("webkit", page.context().browser().browserType().name()); + assertEquals(3, page.evaluate("window.devicePixelRatio")); + assertEquals(980, page.evaluate("window.innerWidth")); + assertEquals(1668, page.evaluate("window.innerHeight")); + } +}