diff --git a/playwright/src/main/java/com/microsoft/playwright/impl/BrowserContextImpl.java b/playwright/src/main/java/com/microsoft/playwright/impl/BrowserContextImpl.java index ee4dd4fc..d7f14118 100644 --- a/playwright/src/main/java/com/microsoft/playwright/impl/BrowserContextImpl.java +++ b/playwright/src/main/java/com/microsoft/playwright/impl/BrowserContextImpl.java @@ -277,6 +277,39 @@ class BrowserContextImpl extends ChannelOwner implements BrowserContext { unroute(new UrlMatcher(url), handler); } + private class WaitableContextClose implements Waitable, Listener { + private String errorMessage; + + WaitableContextClose() { + addListener(EventType.CLOSE, this); + } + + @Override + public void handle(Event event) { + if (EventType.CLOSE == event.type()) { + errorMessage = "Context closed"; + } else { + return; + } + dispose(); + } + + @Override + public boolean isDone() { + return errorMessage != null; + } + + @Override + public R get() { + throw new PlaywrightException(errorMessage); + } + + @Override + public void dispose() { + removeListener(EventType.CLOSE, this); + } + } + @Override public Deferred> waitForEvent(EventType event, WaitForEventOptions options) { if (options == null) { @@ -284,6 +317,7 @@ class BrowserContextImpl extends ChannelOwner implements BrowserContext { } List>> waitables = new ArrayList<>(); waitables.add(new WaitableEvent<>(listeners, event, options.predicate)); + waitables.add(new WaitableContextClose<>()); waitables.add(timeoutSettings.createWaitable(options.timeout)); return toDeferred(new WaitableRace<>(waitables)); } diff --git a/playwright/src/main/java/com/microsoft/playwright/impl/PageImpl.java b/playwright/src/main/java/com/microsoft/playwright/impl/PageImpl.java index 1f43352a..569c6493 100644 --- a/playwright/src/main/java/com/microsoft/playwright/impl/PageImpl.java +++ b/playwright/src/main/java/com/microsoft/playwright/impl/PageImpl.java @@ -56,6 +56,9 @@ public class PageImpl extends ChannelOwner implements Page { mainFrame = connection.getExistingObject(initializer.getAsJsonObject("mainFrame").get("guid").getAsString()); mainFrame.page = this; isClosed = initializer.get("isClosed").getAsBoolean(); + if (initializer.has("viewportSize")) { + viewport = gson().fromJson(initializer.get("viewportSize"), Viewport.class); + } keyboard = new KeyboardImpl(this); mouse = new MouseImpl(this); touchscreen = new TouchscreenImpl(this); diff --git a/playwright/src/test/java/com/microsoft/playwright/TestBrowserContextBasic.java b/playwright/src/test/java/com/microsoft/playwright/TestBrowserContextBasic.java index a0aa451c..a278cf8e 100644 --- a/playwright/src/test/java/com/microsoft/playwright/TestBrowserContextBasic.java +++ b/playwright/src/test/java/com/microsoft/playwright/TestBrowserContextBasic.java @@ -16,15 +16,163 @@ package com.microsoft.playwright; +import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; import java.io.OutputStreamWriter; +import java.util.List; import static com.microsoft.playwright.BrowserContext.EventType.PAGE; -import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.junit.jupiter.api.Assertions.assertTrue; +import static com.microsoft.playwright.Page.EventType.POPUP; +import static org.junit.jupiter.api.Assertions.*; public class TestBrowserContextBasic extends TestBase { + @Test + void shouldCreateNewContext() { + assertEquals(1, browser.contexts().size()); + BrowserContext context = browser.newContext(); + assertEquals(2, browser.contexts().size()); + assertTrue(browser.contexts().indexOf(context) != -1); + assertEquals(context.browser(), browser); + context.close(); + assertEquals(1, browser.contexts().size()); + assertEquals(context.browser(), browser); + } + + @Test + void windowOpenShouldUseParentTabContext() { + BrowserContext context = browser.newContext(); + Page page = context.newPage(); + page.navigate(server.EMPTY_PAGE); + Deferred> popupEvent = page.waitForEvent(POPUP); + page.evaluate("url => window.open(url)", server.EMPTY_PAGE); + Page popup = (Page) popupEvent.get().data(); + assertEquals(context, popup.context()); + context.close(); + } + + @Test + void shouldIsolateLocalStorageAndCookies() { + // Create two incognito contexts. + BrowserContext context1 = browser.newContext(); + BrowserContext context2 = browser.newContext(); + assertEquals(0, context1.pages().size()); + assertEquals(0, context2.pages().size()); + + // Create a page in first incognito context. + Page page1 = context1.newPage(); + page1.navigate(server.EMPTY_PAGE); + page1.evaluate("() => {\n" + + " localStorage.setItem('name', 'page1');\n" + + " document.cookie = 'name=page1';\n" + + "}"); + + assertEquals(1, context1.pages().size()); + assertEquals(0, context2.pages().size()); + + // Create a page in second incognito context. + Page page2 = context2.newPage(); + page2.navigate(server.EMPTY_PAGE); + page2.evaluate("() => {\n" + + " localStorage.setItem('name', 'page2');\n" + + " document.cookie = 'name=page2';\n" + + "}"); + + assertEquals(1, context1.pages().size()); + assertEquals(1, context2.pages().size()); + assertEquals(page1, context1.pages().get(0)); + assertEquals(page2, context2.pages().get(0)); + + // Make sure pages don"t share localstorage or cookies. + assertEquals("page1", page1.evaluate("() => localStorage.getItem('name')")); + assertEquals("name=page1", page1.evaluate("() => document.cookie")); + assertEquals("page2", page2.evaluate("() => localStorage.getItem('name')")); + assertEquals("name=page2", page2.evaluate("() => document.cookie")); + + // Cleanup contexts. + context1.close(); + context2.close(); + + assertEquals(1, browser.contexts().size()); + } + + static void verifyViewport(Page page, int width, int height) { + assertEquals(width, page.viewportSize().width()); + assertEquals(height, page.viewportSize().height()); + assertEquals(width, page.evaluate("window.innerWidth")); + assertEquals(height, page.evaluate("window.innerHeight")); + } + + @Test + void shouldPropagateDefaultViewportToThePage() { + BrowserContext context = browser.newContext(new Browser.NewContextOptions().withViewport(456, 789)); + Page page = context.newPage(); + verifyViewport(page, 456, 789); + context.close(); + } + + void shouldMakeACopyOfDefaultViewport() { + // Doesn't make sense in Java. + } + + @Test + void shouldRespectDeviceScaleFactor() { + BrowserContext context = browser.newContext(new Browser.NewContextOptions().withDeviceScaleFactor(3)); + Page page = context.newPage(); + assertEquals(3, page.evaluate("window.devicePixelRatio")); + context.close(); + } + + + @Test + @Disabled("TODO: supported null viewport option") + void shouldNotAllowDeviceScaleFactorWithNullViewport() { + try { + browser.newContext(new Browser.NewContextOptions().withDeviceScaleFactor(1)); + fail("did not throw"); + } catch (PlaywrightException e) { + assertTrue(e.getMessage().contains("\"deviceScaleFactor\" option is not supported with null \"viewport\"")); + } + } + + @Test + @Disabled("TODO: supported null viewport option") + void shouldNotAllowIsMobileWithNullViewport() { + try { + browser.newContext(new Browser.NewContextOptions().withIsMobile(true)); + fail("did not throw"); + } catch (PlaywrightException e) { + assertTrue(e.getMessage().contains("\"isMobile\" option is not supported with null \"viewport\"")); + } + } + + @Test + void closeShouldWorkForEmptyContext() { + BrowserContext context = browser.newContext(); + context.close(); + } + + @Test + void closeShouldAbortWaitForEvent() { + BrowserContext context = browser.newContext(); + Deferred> pageEvent = context.waitForEvent(PAGE); + context.close(); + try { + pageEvent.get(); + fail("did not throw"); + } catch (PlaywrightException e) { + assertTrue(e.getMessage().contains("Context closed")); + } + } + + @Test + void closeShouldBeCallableTwice() { + BrowserContext context = browser.newContext(); + context.close(); + context.close(); + context.close(); + } + @Test void shouldNotReportFramelessPagesOnError() { BrowserContext context = browser.newContext(); @@ -46,4 +194,88 @@ public class TestBrowserContextBasic extends TestBase { assertNotNull(popup[0].mainFrame()); } } + + @Test + void shouldReturnAllOfThePages() { + BrowserContext context = browser.newContext(); + Page page = context.newPage(); + Page second = context.newPage(); + List allPages = context.pages(); + assertEquals(2, allPages.size()); + assertTrue(allPages.contains(page)); + assertTrue(allPages.contains(second)); + context.close(); + } + + @Test + void shouldCloseAllBelongingPagesOnceClosingContext() { + BrowserContext context = browser.newContext(); + context.newPage(); + assertEquals(1, context.pages().size()); + context.close(); + assertEquals(0, context.pages().size()); + } + + @Test + void shouldDisableJavascript() { + { + BrowserContext context = browser.newContext(new Browser.NewContextOptions().withJavaScriptEnabled(false)); + Page page = context.newPage(); + page.navigate("data:text/html, "); + try { + page.evaluate("something"); + fail("did not throw"); + } catch (PlaywrightException e) { + if (isWebKit()) + assertTrue(e.getMessage().contains("Can\'t find variable: something")); + else + assertTrue(e.getMessage().contains("something is not defined")); + } + context.close(); + } + + { + BrowserContext context = browser.newContext(); + Page page = context.newPage(); + page.navigate("data:text/html, "); + assertEquals("forbidden", page.evaluate("something")); + context.close(); + } + } + + @Test + void shouldBeAbleToNavigateAfterDisablingJavascript() { + BrowserContext context = browser.newContext(new Browser.NewContextOptions().withJavaScriptEnabled(false)); + Page page = context.newPage(); + page.navigate(server.EMPTY_PAGE); + context.close(); + } + + @Test + void shouldWorkWithOfflineOption() { + BrowserContext context = browser.newContext(new Browser.NewContextOptions().withOffline(true)); + Page page = context.newPage(); + try { + page.navigate(server.EMPTY_PAGE); + fail("did not throw"); + } catch (PlaywrightException e) { + } + + context.setOffline(false); + Response response = page.navigate(server.EMPTY_PAGE); + assertEquals(200, response.status()); + context.close(); + } + + @Test + void shouldEmulateNavigatorOnLine() { + BrowserContext context = browser.newContext(); + Page page = context.newPage(); + assertEquals(true, page.evaluate("() => window.navigator.onLine")); + context.setOffline(true); + assertEquals(false, page.evaluate("() => window.navigator.onLine")); + context.setOffline(false); + assertEquals(true, page.evaluate("() => window.navigator.onLine")); + context.close(); + } }