Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: support device name in playwright fixtures #1472

Merged
merged 1 commit into from
Feb 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -89,6 +90,10 @@ void unregisterSelectors() {
sharedSelectors.removeChannel(selectors);
}

public JsonArray deviceDescriptors() {
return connection.localUtils.deviceDescriptors();
}

@Override
public BrowserTypeImpl chromium() {
return chromium;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 deviceName;
public BrowserType.LaunchOptions launchOptions;
public Browser.NewContextOptions contextOption;
public APIRequest.NewContextOptions apiRequestOptions;
Expand Down Expand Up @@ -83,6 +84,15 @@ public Options setBrowserName(String browserName) {
return this;
}

public String getDeviceName() {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's unfortunate that we cannot read back the actual values here, only the device name. However, that's better than nothing.

return deviceName;
}

public Options setDeviceName(String deviceName) {
this.deviceName = deviceName;
return this;
}

public String getChannel() {
return channel;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

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 org.junit.jupiter.api.extension.*;
Expand Down Expand Up @@ -38,14 +40,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();
Expand All @@ -59,6 +62,20 @@ private static Browser.NewContextOptions getContextOptions(Options options) {
contextOptions.setStorageStatePath(options.getStorageStatePath());
}

if (options.getDeviceName() != null) {
DeviceDescriptor deviceDescriptor = DeviceDescriptor.findByName(playwright, options.getDeviceName());
if (deviceDescriptor == null) {
throw new PlaywrightException("Unknown device name: " + options.getDeviceName());
}
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());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,22 +42,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.deviceName != null) {
DeviceDescriptor deviceDescriptor = DeviceDescriptor.findByName(playwright, options.deviceName);
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) {
Expand Down
Original file line number Diff line number Diff line change
@@ -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();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@yury-s this is returning null for me and so a null pointer exception is being thrown.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

image

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, that's odd. Is options in options.deviceName null or where does it come from?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe PlaywrightImpl.deviceDescriptors() is returning null so the for loop throws a null pointer exception:

image

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, do you have a test where this is happening? This should never happen if playwright is initialized.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, I assume it is just the new test. It passes on the bots and locally. Could it be that you have some stale driver? We changed the way device descriptors pushed to the client some time ago. Try downloading current driver and see if it still fails.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just running ./scripts/download_driver_for_all_platforms.sh -f and rebuilding should be sufficient

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it was failing on main for me too but you figured it out. downloaded the current driver and it's all good. apologies for that. i'll make running that command part of my workflow.

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);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
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 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().setDeviceName("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"));
}
}
Loading