1
0
mirror of synced 2026-08-06 07:26:55 +00:00

feat: context.*cookies (#42)

This commit is contained in:
Yury Semikhatsky
2020-10-26 14:41:04 -07:00
committed by GitHub
parent 8d8756084e
commit e4a1753444
7 changed files with 438 additions and 21 deletions
@@ -77,9 +77,13 @@ class TypeRef extends Element {
void createCustomType() {
boolean isEnum = jsonName.contains("|\"");
boolean isClass = jsonName.replace("null|", "").equals("Object");
boolean isClass = jsonName.replace("null|", "").equals("Object")
|| jsonName.equals("Promise<Array<Object>>");
// Use path to the corresponding method, param of field as the key.
String parentPath = parent.jsonPath;
if (jsonName.equals("Array<Object>") && "BrowserContext.addCookies.cookies".equals(jsonPath)) {
isClass = true;
}
Types.Mapping mapping = TypeDefinition.types.findForPath(parentPath);
if (mapping == null) {
if (isEnum) {
@@ -266,6 +270,14 @@ class Method extends Element {
"void unroute(Pattern url, BiConsumer<Route, Request> handler);",
"void unroute(Predicate<String> url, BiConsumer<Route, Request> handler);",
});
customSignature.put("BrowserContext.cookies", new String[]{
"default List<Cookie> cookies() { return cookies((List<String>) null); }",
"default List<Cookie> cookies(String url) { return cookies(Arrays.asList(url)); }",
"List<Cookie> cookies(List<String> urls);",
});
customSignature.put("BrowserContext.addCookies", new String[]{
"void addCookies(List<AddCookie> cookies);"
});
customSignature.put("FileChooser.setFiles", new String[]{
"default void setFiles(File file) { setFiles(file, null); }",
"default void setFiles(File file, SetFilesOptions options) { setFiles(new File[]{ file }, options); }",
@@ -706,6 +718,8 @@ class Interface extends TypeDefinition {
break;
}
case "BrowserContext": {
output.add(offset + "enum SameSite { STRICT, LAX, NONE }");
output.add("");
output.add(offset + "class HTTPCredentials {");
output.add(offset + " private final String username;");
output.add(offset + " private final String password;");
@@ -208,7 +208,12 @@ class Types {
add("Page.goto.options", "Object", "NavigateOptions");
add("Frame.goto.options", "Object", "NavigateOptions");
add("BrowserContext.cookies.urls", "string|Array<string>", "String");
// The method has custom signatures
add("BrowserContext.cookies", "Promise<Array<Object>>", "Cookie");
add("BrowserContext.cookies.sameSite", "\"Lax\"|\"None\"|\"Strict\"", "SameSite", new Empty());
add("BrowserContext.cookies.expires", "number", "long");
add("BrowserContext.addCookies.cookies", "Array<Object>", "AddCookie");
add("BrowserContext.addCookies.cookies.sameSite", "\"Lax\"|\"None\"|\"Strict\"", "SameSite", 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());
@@ -22,6 +22,8 @@ import java.util.function.Predicate;
import java.util.regex.Pattern;
public interface BrowserContext {
enum SameSite { STRICT, LAX, NONE }
class HTTPCredentials {
private final String username;
private final String password;
@@ -59,6 +61,89 @@ public interface BrowserContext {
void addListener(EventType type, Listener<EventType> listener);
void removeListener(EventType type, Listener<EventType> listener);
class AddCookie {
public String name;
public String value;
public String url;
public String domain;
public String path;
public Integer expires;
public Boolean httpOnly;
public Boolean secure;
public SameSite sameSite;
public AddCookie withName(String name) {
this.name = name;
return this;
}
public AddCookie withValue(String value) {
this.value = value;
return this;
}
public AddCookie withUrl(String url) {
this.url = url;
return this;
}
public AddCookie withDomain(String domain) {
this.domain = domain;
return this;
}
public AddCookie withPath(String path) {
this.path = path;
return this;
}
public AddCookie withExpires(Integer expires) {
this.expires = expires;
return this;
}
public AddCookie withHttpOnly(Boolean httpOnly) {
this.httpOnly = httpOnly;
return this;
}
public AddCookie withSecure(Boolean secure) {
this.secure = secure;
return this;
}
public AddCookie withSameSite(SameSite sameSite) {
this.sameSite = sameSite;
return this;
}
}
class Cookie {
private String name;
private String value;
private String domain;
private String path;
private long expires;
private boolean httpOnly;
private boolean secure;
private SameSite sameSite;
public String name() {
return this.name;
}
public String value() {
return this.value;
}
public String domain() {
return this.domain;
}
public String path() {
return this.path;
}
public long expires() {
return this.expires;
}
public boolean httpOnly() {
return this.httpOnly;
}
public boolean secure() {
return this.secure;
}
public SameSite sameSite() {
return this.sameSite;
}
}
class ExposeBindingOptions {
public Boolean handle;
@@ -94,7 +179,7 @@ public interface BrowserContext {
}
}
void close();
void addCookies(List<Object> cookies);
void addCookies(List<AddCookie> cookies);
default void addInitScript(String script) {
addInitScript(script, null);
}
@@ -102,10 +187,9 @@ public interface BrowserContext {
Browser browser();
void clearCookies();
void clearPermissions();
default List<Object> cookies() {
return cookies(null);
}
List<Object> cookies(String urls);
default List<Cookie> cookies() { return cookies((List<String>) null); }
default List<Cookie> cookies(String url) { return cookies(Arrays.asList(url)); }
List<Cookie> cookies(List<String> urls);
default void exposeBinding(String name, Page.Binding playwrightBinding) {
exposeBinding(name, playwrightBinding, null);
}
@@ -40,6 +40,40 @@ public interface ChromiumCoverage {
return this;
}
}
class ChromiumCoverageStopCSSCoverage {
private String url;
private String text;
private List<Object> ranges;
public String url() {
return this.url;
}
public String text() {
return this.text;
}
public List<Object> ranges() {
return this.ranges;
}
}
class ChromiumCoverageStopJSCoverage {
private String url;
private String scriptId;
private String source;
private List<Object> functions;
public String url() {
return this.url;
}
public String scriptId() {
return this.scriptId;
}
public String source() {
return this.source;
}
public List<Object> functions() {
return this.functions;
}
}
default void startCSSCoverage() {
startCSSCoverage(null);
}
@@ -48,7 +82,7 @@ public interface ChromiumCoverage {
startJSCoverage(null);
}
void startJSCoverage(StartJSCoverageOptions options);
List<Object> stopCSSCoverage();
List<Object> stopJSCoverage();
ChromiumCoverageStopCSSCoverage stopCSSCoverage();
ChromiumCoverageStopJSCoverage stopJSCoverage();
}
@@ -16,15 +16,15 @@
package com.microsoft.playwright.impl;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.*;
import com.google.gson.reflect.TypeToken;
import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonToken;
import com.google.gson.stream.JsonWriter;
import com.microsoft.playwright.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.io.IOException;
import java.util.*;
import java.util.function.BiConsumer;
import java.util.function.Predicate;
import java.util.regex.Pattern;
@@ -67,8 +67,10 @@ class BrowserContextImpl extends ChannelOwner implements BrowserContext {
}
@Override
public void addCookies(List<Object> cookies) {
public void addCookies(List<AddCookie> cookies) {
JsonObject params = new JsonObject();
params.add("cookies", new Gson().toJsonTree(cookies));
sendMessage("addCookies", params);
}
@Override
@@ -89,17 +91,52 @@ class BrowserContextImpl extends ChannelOwner implements BrowserContext {
@Override
public void clearCookies() {
sendMessage("clearCookies");
}
@Override
public void clearPermissions() {
sendMessage("clearPermissions");
}
private static class SameSiteAdapter extends TypeAdapter<SameSite> {
@Override
public void write(JsonWriter out, SameSite value) throws IOException {
String stringValue;
switch (value) {
case STRICT:
stringValue = "Strict";
break;
case LAX:
stringValue = "Lax";
break;
case NONE:
stringValue = "None";
break;
default:
throw new PlaywrightException("Unexpected value: " + value);
}
out.value(stringValue);
}
@Override
public SameSite read(JsonReader in) throws IOException {
String value = in.nextString();
return SameSite.valueOf(value.toUpperCase());
}
}
@Override
public List<Object> cookies(String urls) {
return null;
public List<Cookie> cookies(List<String> urls) {
JsonObject params = new JsonObject();
if (urls == null) {
urls = Collections.emptyList();
}
params.add("urls", new Gson().toJsonTree(urls));
JsonObject json = sendMessage("cookies", params).getAsJsonObject();
Gson gson = new GsonBuilder().registerTypeAdapter(SameSite.class, new SameSiteAdapter().nullSafe()).create();
Cookie[] cookies = gson.fromJson(json.getAsJsonArray("cookies"), Cookie[].class);
return Arrays.asList(cookies);
}
@Override
@@ -0,0 +1,58 @@
/*
* 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 org.junit.jupiter.api.Test;
import static java.util.Arrays.asList;
import static java.util.Collections.emptyList;
import static org.junit.jupiter.api.Assertions.assertEquals;
public class TestBrowserContextClearCookies extends TestBase {
@Test
void shouldClearCookies() {
page.navigate(server.EMPTY_PAGE);
context.addCookies(asList(
new BrowserContext.AddCookie().withUrl(server.EMPTY_PAGE).withName("cookie1").withValue("1")));
assertEquals("cookie1=1", page.evaluate("document.cookie"));
context.clearCookies();
assertEquals(emptyList(), context.cookies());
page.reload();
assertEquals("", page.evaluate("document.cookie"));
}
@Test
void shouldIsolateCookiesWhenClearing() {
BrowserContext anotherContext = browser.newContext();
context.addCookies(asList(
new BrowserContext.AddCookie().withUrl(server.EMPTY_PAGE).withName("page1cookie").withValue("page1value")));
anotherContext.addCookies(asList(
new BrowserContext.AddCookie().withUrl(server.EMPTY_PAGE).withName("page2cookie").withValue("page2value")));
assertEquals(1, (context.cookies()).size());
assertEquals(1, (anotherContext.cookies()).size());
context.clearCookies();
assertEquals(0, (context.cookies()).size());
assertEquals(1, (anotherContext.cookies()).size());
anotherContext.clearCookies();
assertEquals(0, (context.cookies()).size());
assertEquals(0, (anotherContext.cookies()).size());
anotherContext.close();
}
}
@@ -0,0 +1,185 @@
/*
* 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.util.Comparator;
import java.util.List;
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);
Object documentCookie = page.evaluate("() => {\n" +
" document.cookie = 'username=John Doe';\n" +
" return document.cookie;\n" +
"}");
assertEquals("username=John Doe", documentCookie);
List<BrowserContext.Cookie> cookies = context.cookies();
assertJsonEquals("[{\n" +
" name: 'username',\n" +
" value: 'John Doe',\n" +
" domain: 'localhost',\n" +
" path: '/',\n" +
" expires: -1,\n" +
" httpOnly: false,\n" +
" secure: false,\n" +
" sameSite: 'NONE'\n" +
" }]", cookies);
}
@Test
void shouldGetANonSessionCookie() {
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);
int timestamp = (Integer) page.evaluate("+(new Date('1/1/2038'))/1000");
BrowserContext.Cookie cookie = context.cookies().get(0);
assertEquals("username", cookie.name());
assertEquals("John Doe", cookie.value());
assertEquals("localhost", cookie.domain());
assertEquals("/", cookie.path());
assertEquals(timestamp, cookie.expires());
assertEquals(false, cookie.httpOnly());
assertEquals(false, cookie.secure());
assertEquals(BrowserContext.SameSite.NONE, cookie.sameSite());
}
@Test
void shouldProperlyReportHttpOnlyCookie() {
server.setRoute("/empty.html", exchange -> {
exchange.getResponseHeaders().add("Set-Cookie", "name=value;HttpOnly; Path=/");
exchange.sendResponseHeaders(200, 0);
exchange.getResponseBody().close();
});
page.navigate(server.EMPTY_PAGE);
List<BrowserContext.Cookie> cookies = context.cookies();
assertEquals(1, cookies.size());
assertTrue(cookies.get(0).httpOnly());
}
@Test
void shouldProperlyReportStrictSameSiteCookie() {
// TODO: test.fail(browserName === "webkit" && platform === "win32");
server.setRoute("/empty.html", exchange -> {
exchange.getResponseHeaders().add("Set-Cookie", "name=value;SameSite=Strict");
exchange.sendResponseHeaders(200, 0);
exchange.getResponseBody().close();
});
page.navigate(server.EMPTY_PAGE);
List<BrowserContext.Cookie> cookies = context.cookies();
assertEquals(1, cookies.size());
assertEquals(BrowserContext.SameSite.STRICT, cookies.get(0).sameSite());
}
@Test
void shouldProperlyReportLaxSameSiteCookie() {
// TODO: test.fail(browserName === "webkit" && platform === "win32");
server.setRoute("/empty.html", exchange -> {
exchange.getResponseHeaders().add("Set-Cookie", "name=value;SameSite=Lax");
exchange.sendResponseHeaders(200, 0);
exchange.getResponseBody().close();
});
page.navigate(server.EMPTY_PAGE);
List<BrowserContext.Cookie> cookies = context.cookies();
assertEquals(1, cookies.size());
assertEquals(BrowserContext.SameSite.LAX, cookies.get(0).sameSite());
}
@Test
void shouldGetMultipleCookies() {
page.navigate(server.EMPTY_PAGE);
Object documentCookie = page.evaluate("() => {\n" +
" document.cookie = 'username=John Doe';\n" +
" document.cookie = 'password=1234';\n" +
" return document.cookie.split('; ').sort().join('; ');\n" +
"}");
List<BrowserContext.Cookie> cookies = context.cookies();
cookies.sort(Comparator.comparing(BrowserContext.Cookie::name));
assertEquals("password=1234; username=John Doe", documentCookie);
assertJsonEquals("[\n" +
" {\n" +
" name: 'password',\n" +
" value: '1234',\n" +
" domain: 'localhost',\n" +
" path: '/',\n" +
" expires: -1,\n" +
" httpOnly: false,\n" +
" secure: false,\n" +
" sameSite: 'NONE'\n" +
" },\n" +
" {\n" +
" name: 'username',\n" +
" value: 'John Doe',\n" +
" domain: 'localhost',\n" +
" path: '/',\n" +
" expires: -1,\n" +
" httpOnly: false,\n" +
" secure: false,\n" +
" sameSite: 'NONE'\n" +
" }\n" +
"]", cookies);
}
@Test
void shouldGetCookiesFromMultipleUrls() {
context.addCookies(asList(
new BrowserContext.AddCookie().withUrl("https://foo.com").withName("doggo").withValue("woofs"),
new BrowserContext.AddCookie().withUrl("https://bar.com").withName("catto").withValue("purrs"),
new BrowserContext.AddCookie().withUrl("https://baz.com").withName("birdo").withValue("tweets")));
List<BrowserContext.Cookie> cookies = context.cookies(asList("https://foo.com", "https://baz.com"));
cookies.sort(Comparator.comparing(BrowserContext.Cookie::name));
assertJsonEquals("[{\n" +
" name: 'birdo',\n" +
" value: 'tweets',\n" +
" domain: 'baz.com',\n" +
" path: '/',\n" +
" expires: -1,\n" +
" httpOnly: false,\n" +
" secure: true,\n" +
" sameSite: 'NONE'\n" +
"}, {\n" +
" name: 'doggo',\n" +
" value: 'woofs',\n" +
" domain: 'foo.com',\n" +
" path: '/',\n" +
" expires: -1,\n" +
" httpOnly: false,\n" +
" secure: true,\n" +
" sameSite: 'NONE'\n" +
"}]", cookies);
}
}