Skip to content
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 @@ -17,7 +17,6 @@
package com.microsoft.playwright.impl.junit;

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

Expand Down Expand Up @@ -59,7 +58,7 @@ public static BrowserContext getOrCreateBrowserContext(ExtensionContext extensio
Playwright playwright = PlaywrightExtension.getOrCreatePlaywright(extensionContext);
setTestIdAttribute(playwright, options);
Browser browser = BrowserExtension.getOrCreateBrowser(extensionContext);
Browser.NewContextOptions contextOptions = getContextOptions(playwright, options);
Browser.NewContextOptions contextOptions = BrowserContextOptionsExtension.getContextOptions(playwright, options);
browserContext = browser.newContext(contextOptions);
if (options.defaultTimeout != null) {
browserContext.setDefaultTimeout(options.defaultTimeout);
Expand Down Expand Up @@ -154,35 +153,4 @@ private void closeBrowserContext() {
private static boolean shouldRecordTrace(Options options) {
return options.trace.equals(Options.Trace.ON) || options.trace.equals(Options.Trace.RETAIN_ON_FAILURE);
}

private static Browser.NewContextOptions getContextOptions(Playwright playwright, Options options) {
Browser.NewContextOptions contextOptions = Utils.clone(options.contextOptions);
if (contextOptions == null) {
contextOptions = new Browser.NewContextOptions();
}

if (options.baseUrl != null) {
contextOptions.setBaseURL(options.baseUrl);
}

if (options.deviceName != null) {
DeviceDescriptor deviceDescriptor = DeviceDescriptor.findByName(playwright, options.deviceName);
if (deviceDescriptor == null) {
throw new PlaywrightException("Unknown device name: " + options.deviceName);
}
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.ignoreHTTPSErrors != null) {
contextOptions.setIgnoreHTTPSErrors(options.ignoreHTTPSErrors);
}

return contextOptions;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
/*
* 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.
*/

package com.microsoft.playwright.impl.junit;

import com.microsoft.playwright.Browser;
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.*;

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

public class BrowserContextOptionsExtension implements ParameterResolver {
@Override
public boolean supportsParameter(ParameterContext parameterContext, ExtensionContext extensionContext) throws ParameterResolutionException {
return isParameterSupported(parameterContext, extensionContext, Browser.NewContextOptions.class);
}

@Override
public Object resolveParameter(ParameterContext parameterContext, ExtensionContext extensionContext) throws ParameterResolutionException {
Options options = OptionsExtension.getOptions(extensionContext);
Playwright playwright = PlaywrightExtension.getOrCreatePlaywright(extensionContext);
return getContextOptions(playwright, options);
}

// Returns a new instance every time, so that callers can modify it without affecting other tests.
static Browser.NewContextOptions getContextOptions(Playwright playwright, Options options) {
Browser.NewContextOptions contextOptions = Utils.clone(options.contextOptions);
if (contextOptions == null) {
contextOptions = new Browser.NewContextOptions();
}

if (options.baseUrl != null) {
contextOptions.setBaseURL(options.baseUrl);
}

if (options.deviceName != null) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Assert browser type.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Done in decf3d4: setting both deviceName and a browserName that differs from the device's defaultBrowserType now throws. With only deviceName set, the browser is already taken from the device.

DeviceDescriptor deviceDescriptor = DeviceDescriptor.findByName(playwright, options.deviceName);
if (deviceDescriptor == null) {
throw new PlaywrightException("Unknown device name: " + options.deviceName);
}
if (options.browserName != null && deviceDescriptor.defaultBrowserType != null &&
!options.browserName.equals(deviceDescriptor.defaultBrowserType)) {
throw new PlaywrightException("Device \"" + options.deviceName + "\" requires \"" + deviceDescriptor.defaultBrowserType +
"\" browser, but browserName is \"" + options.browserName + "\"");
}
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.ignoreHTTPSErrors != null) {
contextOptions.setIgnoreHTTPSErrors(options.ignoreHTTPSErrors);
}

return contextOptions;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -36,10 +36,22 @@
* <li> {@link com.microsoft.playwright.Browser Browser browser}</li>
* <li> {@link com.microsoft.playwright.APIRequestContext APIRequestContext request}</li>
* <li> {@link com.microsoft.playwright.Playwright Playwright playwright}</li>
* <li> {@link com.microsoft.playwright.Browser.NewContextOptions Browser.NewContextOptions contextOptions}</li>
* </ul>
* {@code Page} and {@code BrowserContext} are created before each test and closed
* after the test has finished. {@code Browser} and {@code Playwright} are reused
* between tests for better efficiency.
* between tests for better efficiency. {@code Browser.NewContextOptions} is a new instance
* every time it is requested, configured from the {@link OptionsFactory} the same way as for
* the {@code BrowserContext} fixture. Unlike {@code Page} and {@code BrowserContext}, it can also
* be used in {@code @BeforeAll} and {@code @AfterAll} methods to create a context manually:
* <pre>{@code
* @BeforeAll
* static void beforeAll(Browser browser, Browser.NewContextOptions contextOptions) {
* BrowserContext context = browser.newContext(contextOptions);
* // ...
* context.close();
* }
* }</pre>
*
* <p> An example of using {@code @UsePlaywright} annotation:
* <pre>{@code
Expand Down Expand Up @@ -73,7 +85,7 @@
* <a href="https://playwright.dev/java/docs/junit">JUnit guide</a>.
*/
@ExtendWith({OptionsExtension.class, PlaywrightExtension.class, BrowserExtension.class, BrowserContextExtension.class,
PageExtension.class, APIRequestContextExtension.class})
PageExtension.class, APIRequestContextExtension.class, BrowserContextOptionsExtension.class})
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Inherited
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/*
* 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.
*/

package com.microsoft.playwright.impl.junit;

import com.microsoft.playwright.Browser;
import com.microsoft.playwright.Playwright;
import com.microsoft.playwright.PlaywrightException;
import com.microsoft.playwright.junit.Options;
import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.*;

public class TestBrowserContextOptionsExtension {
@Test
void shouldThrowWhenBrowserNameDoesNotMatchDevice() {
try (Playwright playwright = Playwright.create()) {
Options options = new Options().setDeviceName("iPhone 14").setBrowserName("chromium");
PlaywrightException e = assertThrows(PlaywrightException.class,
() -> BrowserContextOptionsExtension.getContextOptions(playwright, options));
assertEquals("Device \"iPhone 14\" requires \"webkit\" browser, but browserName is \"chromium\"", e.getMessage());
}
}

@Test
void shouldAllowBrowserNameMatchingDevice() {
try (Playwright playwright = Playwright.create()) {
Options options = new Options().setDeviceName("iPhone 14").setBrowserName("webkit");
Browser.NewContextOptions contextOptions = BrowserContextOptionsExtension.getContextOptions(playwright, options);
assertTrue(contextOptions.isMobile);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
/*
* 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.
*/

package com.microsoft.playwright.junit;

import com.microsoft.playwright.Browser;
import com.microsoft.playwright.BrowserContext;
import com.microsoft.playwright.Page;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.*;

@FixtureTest
@UsePlaywright(TestFixtureNewContextOptions.CustomOptions.class)
public class TestFixtureNewContextOptions {
// Only checked as an option value, never navigated to.
private static final String BASE_URL = "http://localhost:1234/base/";
private static Browser.NewContextOptions contextOptionsFromBeforeAll;

public static class CustomOptions implements OptionsFactory {
@Override
public Options getOptions() {
return new Options()
.setBaseUrl(BASE_URL)
.setDeviceName("iPhone 14")
.setIgnoreHTTPSErrors(true)
.setContextOptions(new Browser.NewContextOptions().setLocale("de-DE"));
}
}

private static void assertConfiguredFromOptionsFactory(Browser.NewContextOptions contextOptions) {
assertNotNull(contextOptions);
assertEquals(BASE_URL, contextOptions.baseURL);
assertEquals(true, contextOptions.ignoreHTTPSErrors);
assertEquals("de-DE", contextOptions.locale);
assertEquals(390, contextOptions.viewportSize.get().width);
assertEquals(664, contextOptions.viewportSize.get().height);
assertEquals(true, contextOptions.isMobile);
assertEquals(true, contextOptions.hasTouch);
assertTrue(contextOptions.userAgent.contains("iPhone"), contextOptions.userAgent);
}

@BeforeAll
static void beforeAll(Browser browser, Browser.NewContextOptions contextOptions) {
assertConfiguredFromOptionsFactory(contextOptions);
contextOptionsFromBeforeAll = contextOptions;

BrowserContext context = browser.newContext(contextOptions);
Page page = context.newPage();
assertEquals(390, page.viewportSize().width);
assertEquals(664, page.viewportSize().height);
assertEquals("de-DE", page.evaluate("() => navigator.language"));
assertTrue(((String) page.evaluate("() => navigator.userAgent")).contains("iPhone"));
context.close();

// Modifying the options must not affect other tests.
contextOptions.setBaseURL("http://localhost:1234/modified/").setLocale("fr-FR");
}

@AfterAll
static void afterAll(Browser.NewContextOptions contextOptions) {
assertConfiguredFromOptionsFactory(contextOptions);
}

@Test
void shouldBeConfiguredFromOptionsFactory(Browser.NewContextOptions contextOptions) {
assertConfiguredFromOptionsFactory(contextOptions);
}

@Test
void shouldReturnNewInstanceEveryTime(Browser.NewContextOptions contextOptions1, Browser.NewContextOptions contextOptions2) {
assertNotSame(contextOptionsFromBeforeAll, contextOptions1);
assertNotSame(contextOptions1, contextOptions2);
contextOptions1.setBaseURL("http://localhost:1234/modified/").setLocale("fr-FR");
assertConfiguredFromOptionsFactory(contextOptions2);
}

@Test
void shouldNotAffectBrowserContextFixture(Page page) {
assertEquals(390, page.viewportSize().width);
assertEquals("de-DE", page.evaluate("() => navigator.language"));
}
}
Loading