From e8942215091df0a3c862fffba1799ce4d058fc63 Mon Sep 17 00:00:00 2001 From: Yury Semikhatsky Date: Mon, 26 Oct 2020 16:22:04 -0700 Subject: [PATCH] test: convert more cookie tests (#43) --- .../com/microsoft/playwright/tools/Types.java | 1 + .../microsoft/playwright/BrowserContext.java | 4 +- .../TestBrowserContextAddCookies.java | 372 ++++++++++++++++++ .../playwright/TestBrowserContextCookies.java | 9 +- .../java/com/microsoft/playwright/Utils.java | 11 + 5 files changed, 387 insertions(+), 10 deletions(-) create mode 100644 playwright/src/test/java/com/microsoft/playwright/TestBrowserContextAddCookies.java diff --git a/api-generator/src/main/java/com/microsoft/playwright/tools/Types.java b/api-generator/src/main/java/com/microsoft/playwright/tools/Types.java index 0f0073fb..e5e6f338 100644 --- a/api-generator/src/main/java/com/microsoft/playwright/tools/Types.java +++ b/api-generator/src/main/java/com/microsoft/playwright/tools/Types.java @@ -214,6 +214,7 @@ class Types { add("BrowserContext.cookies.expires", "number", "long"); add("BrowserContext.addCookies.cookies", "Array", "AddCookie"); add("BrowserContext.addCookies.cookies.sameSite", "\"Lax\"|\"None\"|\"Strict\"", "SameSite", new Empty()); + add("BrowserContext.addCookies.cookies.expires", "number", "Long", new Empty()); add("BrowserContext.route.url", "string|RegExp|function(URL):boolean", "String"); add("BrowserContext.unroute.url", "string|RegExp|function(URL):boolean", "String"); add("BrowserContext.waitForEvent.event", "string", "EventType", new Empty()); diff --git a/playwright/src/main/java/com/microsoft/playwright/BrowserContext.java b/playwright/src/main/java/com/microsoft/playwright/BrowserContext.java index 2e89d657..f8776569 100644 --- a/playwright/src/main/java/com/microsoft/playwright/BrowserContext.java +++ b/playwright/src/main/java/com/microsoft/playwright/BrowserContext.java @@ -67,7 +67,7 @@ public interface BrowserContext { public String url; public String domain; public String path; - public Integer expires; + public Long expires; public Boolean httpOnly; public Boolean secure; public SameSite sameSite; @@ -92,7 +92,7 @@ public interface BrowserContext { this.path = path; return this; } - public AddCookie withExpires(Integer expires) { + public AddCookie withExpires(Long expires) { this.expires = expires; return this; } diff --git a/playwright/src/test/java/com/microsoft/playwright/TestBrowserContextAddCookies.java b/playwright/src/test/java/com/microsoft/playwright/TestBrowserContextAddCookies.java new file mode 100644 index 00000000..88b1c316 --- /dev/null +++ b/playwright/src/test/java/com/microsoft/playwright/TestBrowserContextAddCookies.java @@ -0,0 +1,372 @@ +/* + * 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; + +import com.google.gson.Gson; +import com.google.gson.JsonElement; +import com.google.gson.JsonParser; +import org.junit.jupiter.api.Test; + +import java.time.Instant; +import java.util.List; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Future; + +import static com.microsoft.playwright.Utils.assertJsonEquals; +import static java.util.Arrays.asList; +import static java.util.Collections.emptyList; +import static java.util.Collections.singletonList; +import static org.junit.jupiter.api.Assertions.*; + +public class TestBrowserContextAddCookies extends TestBase { + @Test + void shouldWork() { + page.navigate(server.EMPTY_PAGE); + context.addCookies(asList( + new BrowserContext.AddCookie().withUrl(server.EMPTY_PAGE).withName("password").withValue("123456"))); + assertEquals("password=123456", page.evaluate("document.cookie")); + } + + @Test + void shouldRoundtripCookie() { + page.navigate(server.EMPTY_PAGE); + // @see https://en.wikipedia.org/wiki/Year_2038_problem + Object documentCookie = page.evaluate("() => {\n" + + " const date = new Date('1/1/2038');\n" + + " document.cookie = `username=John Doe;expires=${date.toUTCString()}`;\n" + + " return document.cookie;\n" + + "}"); + assertEquals("username=John Doe", documentCookie); + List cookies = context.cookies(); + context.clearCookies(); + assertEquals(emptyList(), context.cookies()); + context.addCookies(asList(new BrowserContext.AddCookie() + .withName(cookies.get(0).name()) + .withValue(cookies.get(0).value()) + .withDomain(cookies.get(0).domain()) + .withPath(cookies.get(0).path()) + .withExpires(cookies.get(0).expires()) + )); + assertJsonEquals(new Gson().toJson(cookies), context.cookies()); + } + + @Test + void shouldSendCookieHeader() throws ExecutionException, InterruptedException { + Future request = server.waitForRequest("/empty.html"); + context.addCookies(asList( + new BrowserContext.AddCookie().withUrl(server.EMPTY_PAGE).withName("cookie").withValue("value"))); + Page page = context.newPage(); + page.navigate(server.EMPTY_PAGE); + List cookies = request.get().headers.get("cookie"); + assertEquals(singletonList("cookie=value"), cookies); + } + + @Test + void shouldIsolateCookiesInBrowserContexts() { + BrowserContext anotherContext = browser.newContext(); + context.addCookies(asList( + new BrowserContext.AddCookie().withUrl(server.EMPTY_PAGE).withName("isolatecookie").withValue("page1value"))); + anotherContext.addCookies(asList( + new BrowserContext.AddCookie().withUrl(server.EMPTY_PAGE).withName("isolatecookie").withValue("page2value"))); + List cookies1 = context.cookies(); + List cookies2 = anotherContext.cookies(); + assertEquals(1, cookies1.size()); + assertEquals(1, cookies2.size()); + assertEquals("isolatecookie", cookies1.get(0).name()); + assertEquals("page1value", cookies1.get(0).value()); + assertEquals("isolatecookie", cookies2.get(0).name()); + assertEquals("page2value", cookies2.get(0).value()); + anotherContext.close(); + } + + @Test + void shouldIsolateSessionCookies() { + server.setRoute("/setcookie.html", exchange -> { + exchange.getResponseHeaders().add("Set-Cookie", "session=value"); + exchange.sendResponseHeaders(200, 0); + exchange.getResponseBody().close(); + }); + { + Page page = context.newPage(); + page.navigate(server.PREFIX + "/setcookie.html"); + } + { + Page page = context.newPage(); + page.navigate(server.EMPTY_PAGE); + List cookies = context.cookies(); + assertEquals(1, cookies.size()); + assertEquals("value", cookies.get(0).value()); + } + { + BrowserContext context2 = browser.newContext(); + Page page = context2.newPage(); + page.navigate(server.EMPTY_PAGE); + List cookies = context2.cookies(); + assertEquals(0, cookies.size()); + context2.close(); + } + } + + @Test + void shouldIsolatePersistentCookies() { + server.setRoute("/setcookie.html", exchange -> { + exchange.getResponseHeaders().add("Set-Cookie", "persistent=persistent-value; max-age=3600"); + exchange.sendResponseHeaders(200, 0); + exchange.getResponseBody().close(); + }); + Page page = context.newPage(); + page.navigate(server.PREFIX + "/setcookie.html"); + + BrowserContext context1 = context; + BrowserContext context2 = browser.newContext(); + Page page1 = context1.newPage(); + Page page2 = context2.newPage(); + page1.navigate(server.EMPTY_PAGE); + page2.navigate(server.EMPTY_PAGE); + List cookies1 = context1.cookies(); + List cookies2 = context2.cookies(); + assertEquals(1, cookies1.size()); + assertEquals("persistent", cookies1.get(0).name()); + assertEquals("persistent-value", cookies1.get(0).value()); + assertEquals(0, cookies2.size()); + context2.close(); + } + + @Test + void shouldIsolateSendCookieHeader() throws ExecutionException, InterruptedException { + context.addCookies(asList( + new BrowserContext.AddCookie().withUrl(server.EMPTY_PAGE).withName("sendcookie").withValue("value"))); + { + Page page = context.newPage(); + Future request = server.waitForRequest("/empty.html"); + page.navigate(server.EMPTY_PAGE); + List cookies = request.get().headers.get("cookie"); + assertEquals(asList("sendcookie=value"), cookies); + } + { + BrowserContext context = browser.newContext(); + Page page = context.newPage(); + Future request = server.waitForRequest("/empty.html"); + page.navigate(server.EMPTY_PAGE); + List cookies = request.get().headers.get("cookie"); + assertNull(cookies); + context.close(); + } + } + @Test + void shouldIsolateCookiesBetweenLaunches() { +// test.slow(); +// TODO: const browser1 = browserType.launch(browserOptions); + Browser browser1 = browserType.launch(); + BrowserContext context1 = browser1.newContext(); + context1.addCookies(asList(new BrowserContext.AddCookie() + .withUrl(server.EMPTY_PAGE) + .withName("cookie-in-context-1") + .withValue("value") + .withExpires(Instant.now().getEpochSecond() + + 10000))); + browser1.close(); + +// const browser2 = browserType.launch(browserOptions); + Browser browser2 = browserType.launch(); + BrowserContext context2 = browser2.newContext(); + List cookies = context2.cookies(); + assertEquals(0, cookies.size()); + browser2.close(); + } + + @Test + void shouldSetMultipleCookies() { + page.navigate(server.EMPTY_PAGE); + context.addCookies(asList( + new BrowserContext.AddCookie().withUrl(server.EMPTY_PAGE).withName("multiple-1").withValue("123456"), + new BrowserContext.AddCookie().withUrl(server.EMPTY_PAGE).withName("multiple-2").withValue("bar") + )); + assertEquals(asList("multiple-1=123456", "multiple-2=bar"), page.evaluate("() => {\n" + + " const cookies = document.cookie.split(';');\n" + + " return cookies.map(cookie => cookie.trim()).sort();\n" + + "}")); + } + + @Test + void shouldHaveExpiresSetTo1ForSessionCookies() { + context.addCookies(asList( + new BrowserContext.AddCookie().withUrl(server.EMPTY_PAGE).withName("expires").withValue("123456"))); + List cookies = context.cookies(); + assertEquals(-1, cookies.get(0).expires()); + } + + @Test + void shouldSetCookieWithReasonableDefaults() { + context.addCookies(asList( + new BrowserContext.AddCookie().withUrl(server.EMPTY_PAGE).withName("defaults").withValue("123456"))); + List cookies = context.cookies(); + assertJsonEquals("[{\n" + + " name: 'defaults',\n" + + " value: '123456',\n" + + " domain: 'localhost',\n" + + " path: '/',\n" + + " expires: -1,\n" + + " httpOnly: false,\n" + + " secure: false,\n" + + " sameSite: 'NONE'\n" + + "}]", cookies); + } + + @Test + void shouldSetACookieWithAPath() { + page.navigate(server.PREFIX + "/grid.html"); + context.addCookies(asList(new BrowserContext.AddCookie() + .withDomain("localhost") + .withPath("/grid.html") + .withName("gridcookie") + .withValue("GRID"))); + List cookies = context.cookies(); + assertJsonEquals("[{\n" + + " name: 'gridcookie',\n" + + " value: 'GRID',\n" + + " domain: 'localhost',\n" + + " path: '/grid.html',\n" + + " expires: -1,\n" + + " httpOnly: false,\n" + + " secure: false,\n" + + " sameSite: 'NONE'\n" + + "}]", cookies); + assertEquals("gridcookie=GRID", page.evaluate("document.cookie")); + page.navigate(server.EMPTY_PAGE); + assertEquals("", page.evaluate("document.cookie")); + page.navigate(server.PREFIX + "/grid.html"); + assertEquals("gridcookie=GRID", page.evaluate("document.cookie")); + } + + @Test + void shouldNotSetACookieWithBlankPageURL() { + try { + context.addCookies(asList( + new BrowserContext.AddCookie().withUrl(server.EMPTY_PAGE).withName("example-cookie").withValue("best"), + new BrowserContext.AddCookie().withUrl("about:blank").withName("example-cookie-blank").withValue("best") + )); + fail("did not throw"); + } catch (PlaywrightException e) { + assertTrue(e.getMessage().contains("Blank page can not have cookie \"example-cookie-blank\"")); + } + } + + @Test + void shouldNotSetACookieOnADataURLPage() { + try { + context.addCookies(asList( + new BrowserContext.AddCookie().withUrl("data:,Hello%2C%20World!").withName("example-cookie").withValue("best") + )); + fail("did not throw"); + } catch (PlaywrightException e) { + assertTrue(e.getMessage().contains("Data URL page can not have cookie \"example-cookie\"")); + } + } + + @Test + void shouldDefaultToSettingSecureCookieForHTTPSWebsites() { + page.navigate(server.EMPTY_PAGE); + String SECURE_URL = "https://example.com"; + context.addCookies(asList( + new BrowserContext.AddCookie().withUrl(SECURE_URL).withName("foo").withValue("bar") + )); + List cookies = context.cookies(SECURE_URL); + assertEquals(1, cookies.size()); + assertTrue(cookies.get(0).secure()); + } + + @Test + void shouldBeAbleToSetUnsecureCookieForHTTPWebsite() { + page.navigate(server.EMPTY_PAGE); + String HTTP_URL = "http://example.com"; + context.addCookies(asList( + new BrowserContext.AddCookie().withUrl(HTTP_URL).withName("foo").withValue("bar") + )); + List cookies = context.cookies(HTTP_URL); + assertEquals(1, cookies.size()); + assertFalse(cookies.get(0).secure()); + } + + @Test + void shouldSetACookieOnADifferentDomain() { + page.navigate(server.EMPTY_PAGE); + context.addCookies(asList( + new BrowserContext.AddCookie().withUrl("https://www.example.com").withName("example-cookie").withValue("best") + )); + assertEquals("", page.evaluate("document.cookie")); + assertJsonEquals("[{\n" + + " name: 'example-cookie',\n" + + " value: 'best',\n" + + " domain: 'www.example.com',\n" + + " path: '/',\n" + + " expires: -1,\n" + + " httpOnly: false,\n" + + " secure: true,\n" + + " sameSite: 'NONE'\n" + + "}]", context.cookies("https://www.example.com")); + } + + @Test + void shouldSetCookiesForAFrame() { + page.navigate(server.EMPTY_PAGE); + context.addCookies(asList( + new BrowserContext.AddCookie().withUrl(server.PREFIX).withName("frame-cookie").withValue("value") + )); + page.evaluate("src => {\n" + + " let fulfill;\n" + + " const promise = new Promise(x => fulfill = x);\n" + + " const iframe = document.createElement('iframe');\n" + + " document.body.appendChild(iframe);\n" + + " iframe.onload = fulfill;\n" + + " iframe.src = src;\n" + + " return promise;\n" + + "}", server.PREFIX + "/grid.html"); + assertEquals("frame-cookie=value", page.frames().get(1).evaluate("document.cookie")); + } + + @Test + void shouldNotBlockThirdPartyCookies() { + page.navigate(server.EMPTY_PAGE); + page.evaluate("src => {\n" + + " let fulfill;\n" + + " const promise = new Promise(x => fulfill = x);\n" + + " const iframe = document.createElement('iframe');\n" + + " document.body.appendChild(iframe);\n" + + " iframe.onload = fulfill;\n" + + " iframe.src = src;\n" + + " return promise;\n" + + "}", server.CROSS_PROCESS_PREFIX + "/grid.html"); + page.frames().get(1).evaluate("document.cookie = 'username=John Doe'"); + page.waitForTimeout(2000); + boolean allowsThirdParty = isChromium || isFirefox; + List cookies = context.cookies(server.CROSS_PROCESS_PREFIX + "/grid.html"); + if (allowsThirdParty) { + assertJsonEquals("[{\n" + + " 'domain': '127.0.0.1',\n" + + " 'expires': -1,\n" + + " 'httpOnly': false,\n" + + " 'name': 'username',\n" + + " 'path': '/',\n" + + " 'sameSite': 'NONE',\n" + + " 'secure': false,\n" + + " 'value': 'John Doe'\n" + + "}]", cookies); + } else { + assertEquals(0, cookies.size()); + } + } +} diff --git a/playwright/src/test/java/com/microsoft/playwright/TestBrowserContextCookies.java b/playwright/src/test/java/com/microsoft/playwright/TestBrowserContextCookies.java index 0993ecd8..2aad72e9 100644 --- a/playwright/src/test/java/com/microsoft/playwright/TestBrowserContextCookies.java +++ b/playwright/src/test/java/com/microsoft/playwright/TestBrowserContextCookies.java @@ -16,24 +16,17 @@ package com.microsoft.playwright; -import com.google.gson.Gson; -import com.google.gson.JsonElement; -import com.google.gson.JsonParser; import org.junit.jupiter.api.Test; import java.util.Comparator; import java.util.List; +import static com.microsoft.playwright.Utils.assertJsonEquals; import static java.util.Arrays.asList; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertTrue; public class TestBrowserContextCookies extends TestBase { - private static void assertJsonEquals(String expected, Object actual) { - JsonElement actualJson = JsonParser.parseString(new Gson().toJson(actual)); - assertEquals(JsonParser.parseString(expected), actualJson); - } - @Test void shouldGetACookie() { page.navigate(server.EMPTY_PAGE); diff --git a/playwright/src/test/java/com/microsoft/playwright/Utils.java b/playwright/src/test/java/com/microsoft/playwright/Utils.java index 9a6c2120..a1cdf217 100644 --- a/playwright/src/test/java/com/microsoft/playwright/Utils.java +++ b/playwright/src/test/java/com/microsoft/playwright/Utils.java @@ -16,10 +16,21 @@ package com.microsoft.playwright; +import com.google.gson.Gson; +import com.google.gson.JsonElement; +import com.google.gson.JsonParser; + import java.util.HashMap; import java.util.Map; +import static org.junit.jupiter.api.Assertions.assertEquals; + class Utils { + static void assertJsonEquals(String expected, Object actual) { + JsonElement actualJson = JsonParser.parseString(new Gson().toJson(actual)); + assertEquals(JsonParser.parseString(expected), actualJson); + } + @SuppressWarnings("unchecked") static Map mapOf(Object... entries) { Map result = new HashMap();