Skip to content
Closed
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
@@ -0,0 +1,59 @@
package com.microsoft.playwright.junit;

import com.microsoft.playwright.APIRequest;
import com.microsoft.playwright.Browser;
import com.microsoft.playwright.BrowserType;

import java.nio.file.Path;
import java.util.HashMap;
import java.util.Map;

public class Config {
private BrowserType.LaunchOptions launchOptions = new BrowserType.LaunchOptions();
private Browser.NewContextOptions contextOption = new Browser.NewContextOptions();
private APIRequest.NewContextOptions apiRequestOptions = new APIRequest.NewContextOptions();
private Map<String, Object> clientValues = new HashMap<>();

private String browserName = "chromium";

public String browserName() {
return browserName;
}

public void setBrowserName(String browserName) {
this.browserName = browserName;
}

public void setHeadless(boolean headless) {
launchOptions.setHeadless(headless);
}

public void setBaseURL(String url) {
contextOption.setBaseURL(url);
}

public void setStorageStatePath(Path path) {
contextOption.setStorageStatePath(path);
Copy link
Contributor

@uchagani uchagani Oct 8, 2023

Choose a reason for hiding this comment

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

@yury-s which context options do we want the user to be able to set directly vs via providing ContextOptions? Do we want to have parity with the nodejs version.

Also in the node version you can specify certain options directly and also inside of certain objects like launchOptions and contextOptions. Do we want to do this also? If so, which one takes precedent if both are provided and conflict with each other?

Copy link
Member Author

Choose a reason for hiding this comment

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

which context options do we want the user to be able to set directly vs via providing ContextOptions? Do we want to have parity with the nodejs version.

There is no consensus at the moment. It's nice to have a shortcut for the most common ones like headless, viewport and baseURL but we are not sure if we need them for all properties.

Also in the node version you can specify certain options directly and also inside of certain objects like launchOptions and contextOptions. Do we want to do this also? If so, which one takes precedent if both are provided and conflict with each other?

In Node.js all properties can be set directly but some of them have shortcuts too. We want some shortcuts, in Node.js it is programmed so that short form overrides long one. We can do the same in java, I don't think there was a strong reason for that order over the other, we just want the order to be deterministic.

}

public BrowserType.LaunchOptions launchOptions() {
return launchOptions;
}

public Browser.NewContextOptions contextOptions() {
return contextOption;
}

public APIRequest.NewContextOptions apiRequestOptions() {
return apiRequestOptions;
}

public <T> void setClientValue(String name, T value) {
Copy link
Contributor

Choose a reason for hiding this comment

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

is this for setting PlaywrightOptions?

Copy link
Member Author

Choose a reason for hiding this comment

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

The idea here was to have a storage for the clients to pass some options to their tests. I.e. make the Config available in the tests (e.g. as a method parameter similar to Browser etc) and if the client needs to pass some custom properties they could achieve that by using these client property map.

Copy link
Contributor

Choose a reason for hiding this comment

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

We can make the whole Config object available to the test so I'm not sure if we need this but if you want it I can add it.

Copy link
Member Author

@yury-s yury-s Oct 11, 2023

Choose a reason for hiding this comment

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

Let's omit these two methods for now. Even if we expose Config object it won't have a getter setter for myCustomProperty and this is essentially a custom hash map on the config.

clientValues.put(name, value);
}

public <T> T getClientValue(String name) {
return (T) clientValues.get(name);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package com.microsoft.playwright.junit;

public interface ConfigFactory {
Config newConfig();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package com.microsoft.playwright.junit;

public class DefaultConfigFactory implements ConfigFactory {
@Override
public Config newConfig() {
return new Config();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,6 @@
Class<? extends BrowserFactory> browserFactory() default DefaultBrowserFactory.class;

Class<? extends BrowserContextFactory> browserContextFactory() default DefaultBrowserContextFactory.class;

Class<? extends ConfigFactory> configFactory() default DefaultConfigFactory.class;
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,16 @@
import com.microsoft.playwright.Browser;
import com.microsoft.playwright.BrowserContext;
import com.microsoft.playwright.PlaywrightException;
import com.microsoft.playwright.Tracing;
import com.microsoft.playwright.junit.BrowserContextFactory;
import com.microsoft.playwright.junit.Config;
import com.microsoft.playwright.junit.UsePlaywright;
import org.junit.jupiter.api.extension.*;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;

import static com.microsoft.playwright.junit.impl.ExtensionUtils.*;

public class BrowserContextExtension implements ParameterResolver, AfterEachCallback, AfterAllCallback {
Expand All @@ -20,7 +26,7 @@ public class BrowserContextExtension implements ParameterResolver, AfterEachCall

@Override
public void afterEach(ExtensionContext extensionContext) {
cleanupBrowserContext();
cleanupBrowserContext(extensionContext);
}

@Override
Expand Down Expand Up @@ -49,8 +55,16 @@ static BrowserContext getOrCreateBrowserContext(ExtensionContext extensionContex
}

Browser browser = BrowserExtension.getOrCreateBrowser(extensionContext);
BrowserContextFactory browserContextFactory = getBrowserContextFactoryInstance(extensionContext);
browserContext = browserContextFactory.newBrowserContext(browser);

Config config = ConfigExtension.getConfig(extensionContext);
if (config == null) {
BrowserContextFactory browserContextFactory = getBrowserContextFactoryInstance(extensionContext);
browserContext = browserContextFactory.newBrowserContext(browser);
} else {
Browser.NewContextOptions options = config.contextOptions();
browserContext = browser.newContext(options);
}

threadLocalBrowserContext.set(browserContext);
return browserContext;
}
Expand All @@ -71,7 +85,7 @@ private static BrowserContextFactory getBrowserContextFactoryInstance(ExtensionC
}
}

private void cleanupBrowserContext() {
private void cleanupBrowserContext(ExtensionContext extensionContext) {
try {
BrowserContext browserContext = threadLocalBrowserContext.get();
if (browserContext != null) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
package com.microsoft.playwright.junit.impl;

import com.microsoft.playwright.Browser;
import com.microsoft.playwright.BrowserType;
import com.microsoft.playwright.Playwright;
import com.microsoft.playwright.PlaywrightException;
import com.microsoft.playwright.junit.BrowserFactory;
import com.microsoft.playwright.junit.UsePlaywright;
import com.microsoft.playwright.junit.*;
import org.junit.jupiter.api.extension.*;

import static com.microsoft.playwright.junit.impl.ExtensionUtils.getUsePlaywrightAnnotation;
Expand Down Expand Up @@ -54,11 +54,32 @@ static Browser getOrCreateBrowser(ExtensionContext extensionContext) {

Playwright playwright = PlaywrightExtension.getOrCreatePlaywright(extensionContext);
BrowserFactory browserFactory = getBrowserFactoryInstance(extensionContext);
browser = browserFactory.newBrowser(playwright);

Config config = ConfigExtension.getConfig(extensionContext);
if (config == null) {
browser = browserFactory.newBrowser(playwright);
} else {
browser = newBrowser(playwright, config);
}
threadLocalBrowser.set(browser);
return browser;
}

private static Browser newBrowser(Playwright playwright, Config config) {
BrowserType.LaunchOptions launchOptions = config.launchOptions();
switch (config.browserName()) {
case "webkit":
return playwright.webkit().launch(launchOptions);
case "firefox":
return playwright.firefox().launch(launchOptions);
case "chromium":
return playwright.chromium().launch(launchOptions);
default:
throw new PlaywrightException("Invalid value set for browserName. Must be one of: chromium, firefox, webkit");
}
}


private static BrowserFactory getBrowserFactoryInstance(ExtensionContext extensionContext) {
if (threadLocalBrowserFactory.get() != null) {
return threadLocalBrowserFactory.get();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package com.microsoft.playwright.junit.impl;

import com.microsoft.playwright.*;
import com.microsoft.playwright.junit.*;
import org.junit.jupiter.api.extension.*;

import java.nio.file.FileSystems;
import java.nio.file.Path;

import static com.microsoft.playwright.junit.impl.ExtensionUtils.getUsePlaywrightAnnotation;

public class ConfigExtension implements AfterAllCallback {
private static final ThreadLocal<Config> threadLocalConfig = new ThreadLocal<>();

@Override
public void afterAll(ExtensionContext extensionContext) {
threadLocalConfig.remove();
}

static Config getConfig(ExtensionContext extensionContext) {
Config config = threadLocalConfig.get();
if (config != null) {
return config;
}
UsePlaywright usePlaywrightAnnotation = getUsePlaywrightAnnotation(extensionContext);
if (!DefaultConfigFactory.class.equals(usePlaywrightAnnotation.configFactory())) {
try {
ConfigFactory configFactory = usePlaywrightAnnotation.configFactory().newInstance();
config = configFactory.newConfig();
threadLocalConfig.set(config);
} catch (InstantiationException | IllegalAccessException e) {
throw new PlaywrightException("Failed to create config", e);
}
}
return config;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import com.microsoft.playwright.Playwright;
import com.microsoft.playwright.PlaywrightException;
import com.microsoft.playwright.junit.Config;
import com.microsoft.playwright.junit.PlaywrightFactory;
import com.microsoft.playwright.junit.UsePlaywright;
import org.junit.jupiter.api.extension.*;
Expand Down Expand Up @@ -43,8 +44,13 @@ static Playwright getOrCreatePlaywright(ExtensionContext extensionContext) {
return playwright;
}

PlaywrightFactory playwrightFactory = getPlaywrightFactoryInstance(extensionContext);
playwright = playwrightFactory.newPlaywright();
Config config = ConfigExtension.getConfig(extensionContext);
if (config == null) {
PlaywrightFactory playwrightFactory = getPlaywrightFactoryInstance(extensionContext);
playwright = playwrightFactory.newPlaywright();
} else {
playwright = Playwright.create();
}
threadLocalPlaywright.set(playwright);
return playwright;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package com.microsoft.playwright;

import com.microsoft.playwright.junit.Config;
import com.microsoft.playwright.junit.ConfigFactory;
import com.microsoft.playwright.junit.UsePlaywright;
import org.junit.jupiter.api.*;

import java.nio.file.Paths;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;


@UsePlaywright(configFactory = TestFixturesWithCustomConfig.CustomConfigFactory.class)
public class TestFixturesWithCustomConfig {
public static class CustomConfigFactory implements ConfigFactory {
@Override
public Config newConfig() {
Config config = new Config();
config.setBrowserName("webkit");
config.contextOptions().setViewportSize(1280, 960);
return config;
}
}

@Test
void recordTraceInWebKit(Page page) {
page.navigate("https://playwright.dev");
}
}