From 2c7caa62922af5c4a1269bb320412bb7ed7b17be Mon Sep 17 00:00:00 2001 From: Yury Semikhatsky Date: Sun, 6 Dec 2020 09:27:15 -0800 Subject: [PATCH] feat(api): support storage state (#89) --- .../playwright/tools/ApiGenerator.java | 44 ++++++++++++ .../com/microsoft/playwright/tools/Types.java | 3 + .../com/microsoft/playwright/Browser.java | 66 +++-------------- .../microsoft/playwright/BrowserContext.java | 43 ++++++++++- .../playwright/impl/BrowserContextImpl.java | 6 +- .../TestBrowserContextStorageState.java | 71 +++++++++++++++++++ 6 files changed, 171 insertions(+), 62 deletions(-) create mode 100644 playwright/src/test/java/com/microsoft/playwright/TestBrowserContextStorageState.java diff --git a/api-generator/src/main/java/com/microsoft/playwright/tools/ApiGenerator.java b/api-generator/src/main/java/com/microsoft/playwright/tools/ApiGenerator.java index a027e07c..526ce5b5 100644 --- a/api-generator/src/main/java/com/microsoft/playwright/tools/ApiGenerator.java +++ b/api-generator/src/main/java/com/microsoft/playwright/tools/ApiGenerator.java @@ -116,6 +116,9 @@ class TypeRef extends Element { if (jsonName.equals("Array") && "BrowserContext.addCookies.cookies".equals(jsonPath)) { isClass = true; } + if (jsonName.equals("Promise") && "BrowserContext.storageState".equals(jsonPath)) { + isClass = true; + } Types.Mapping mapping = TypeDefinition.types.findForPath(parentPath); if (mapping == null) { if (isEnum) { @@ -423,6 +426,7 @@ class Method extends Element { } private static Set skipJavadoc = new HashSet<>(asList( + "BrowserContext.waitForEvent.optionsOrPredicate", "Page.waitForEvent.optionsOrPredicate", "Page.frame.options", "WebSocket.waitForEvent.optionsOrPredicate" @@ -871,6 +875,46 @@ class Interface extends TypeDefinition { output.add(offset + " }"); output.add(offset + "}"); output.add(""); + output.add(offset + "class StorageState {"); + output.add(offset + " public List cookies;"); + output.add(offset + " public List origins;"); + output.add(""); + output.add(offset + " public static class OriginState {"); + output.add(offset + " public final String origin;"); + output.add(offset + " public List localStorage;"); + output.add(""); + output.add(offset + " public static class LocalStorageItem {"); + output.add(offset + " public String name;"); + output.add(offset + " public String value;"); + output.add(offset + " public LocalStorageItem(String name, String value) {"); + output.add(offset + " this.name = name;"); + output.add(offset + " this.value = value;"); + output.add(offset + " }"); + output.add(offset + " }"); + output.add(""); + output.add(offset + " public OriginState(String origin) {"); + output.add(offset + " this.origin = origin;"); + output.add(offset + " }"); + output.add(""); + output.add(offset + " public OriginState withLocalStorage(List localStorage) {"); + output.add(offset + " this.localStorage = localStorage;"); + output.add(offset + " return this;"); + output.add(offset + " }"); + output.add(offset + " }"); + output.add(""); + output.add(offset + " public StorageState() {"); + output.add(offset + " cookies = new ArrayList<>();"); + output.add(offset + " origins = new ArrayList<>();"); + output.add(offset + " }"); + output.add(""); + output.add(offset + " public List cookies() {"); + output.add(offset + " return this.cookies;"); + output.add(offset + " }"); + output.add(offset + " public List origins() {"); + output.add(offset + " return this.origins;"); + output.add(offset + " }"); + output.add(offset + "}"); + output.add(""); break; } case "Browser": { 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 85af4593..1ca16c5d 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 @@ -253,6 +253,7 @@ class Types { 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.storageState", "Promise", "StorageState", new Empty()); add("BrowserContext.waitForEvent.event", "string", "EventType", new Empty()); add("BrowserContext.waitForEvent.optionsOrPredicate", "Function|Object", "String"); add("BrowserContext.waitForEvent", "Promise", "Deferred>", new Empty()); @@ -297,6 +298,8 @@ class Types { add("BrowserContext.setGeolocation.geolocation", "null|Object", "Geolocation", new Empty()); add("Browser.newContext.options.geolocation", "Object", "Geolocation", new Empty()); + add("Browser.newContext.options.storageState", "Object", "BrowserContext.StorageState", new Empty()); + add("Browser.newPage.options.storageState", "Object", "BrowserContext.StorageState", new Empty()); add("Browser.newPage.options.geolocation", "Object", "Geolocation", new Empty()); add("BrowserType.launchPersistentContext.options.geolocation", "Object", "Geolocation", new Empty()); add("Download.saveAs.path", "string", "Path", new Empty()); diff --git a/playwright/src/main/java/com/microsoft/playwright/Browser.java b/playwright/src/main/java/com/microsoft/playwright/Browser.java index 33c8f0ac..4108303e 100644 --- a/playwright/src/main/java/com/microsoft/playwright/Browser.java +++ b/playwright/src/main/java/com/microsoft/playwright/Browser.java @@ -140,31 +140,6 @@ public interface Browser { return this; } } - public class StorageState { - /** - * Optional cookies to set for context - */ - public List cookies; - /** - * Optional localStorage to set for context - */ - public List origins; - - StorageState() { - } - public NewContextOptions done() { - return NewContextOptions.this; - } - - public StorageState withCookies(List cookies) { - this.cookies = cookies; - return this; - } - public StorageState withOrigins(List origins) { - this.origins = origins; - return this; - } - } /** * Whether to automatically download all the attachments. Defaults to {@code false} where all the downloads are canceled. */ @@ -249,7 +224,7 @@ public interface Browser { /** * Populates context with given storage state. This method can be used to initialize context with logged-in information obtained via browserContext.storageState(). */ - public StorageState storageState; + public BrowserContext.StorageState storageState; public NewContextOptions withAcceptDownloads(Boolean acceptDownloads) { this.acceptDownloads = acceptDownloads; @@ -335,9 +310,9 @@ public interface Browser { this.proxy = new Proxy(); return this.proxy; } - public StorageState setStorageState() { - this.storageState = new StorageState(); - return this.storageState; + public NewContextOptions withStorageState(BrowserContext.StorageState storageState) { + this.storageState = storageState; + return this; } } class NewPageOptions { @@ -432,31 +407,6 @@ public interface Browser { return this; } } - public class StorageState { - /** - * Optional cookies to set for context - */ - public List cookies; - /** - * Optional localStorage to set for context - */ - public List origins; - - StorageState() { - } - public NewPageOptions done() { - return NewPageOptions.this; - } - - public StorageState withCookies(List cookies) { - this.cookies = cookies; - return this; - } - public StorageState withOrigins(List origins) { - this.origins = origins; - return this; - } - } /** * Whether to automatically download all the attachments. Defaults to {@code false} where all the downloads are canceled. */ @@ -541,7 +491,7 @@ public interface Browser { /** * Populates context with given storage state. This method can be used to initialize context with logged-in information obtained via browserContext.storageState(). */ - public StorageState storageState; + public BrowserContext.StorageState storageState; public NewPageOptions withAcceptDownloads(Boolean acceptDownloads) { this.acceptDownloads = acceptDownloads; @@ -627,9 +577,9 @@ public interface Browser { this.proxy = new Proxy(); return this.proxy; } - public StorageState setStorageState() { - this.storageState = new StorageState(); - return this.storageState; + public NewPageOptions withStorageState(BrowserContext.StorageState storageState) { + this.storageState = storageState; + return this; } } /** diff --git a/playwright/src/main/java/com/microsoft/playwright/BrowserContext.java b/playwright/src/main/java/com/microsoft/playwright/BrowserContext.java index bcad7ea6..4addadf2 100644 --- a/playwright/src/main/java/com/microsoft/playwright/BrowserContext.java +++ b/playwright/src/main/java/com/microsoft/playwright/BrowserContext.java @@ -54,6 +54,46 @@ public interface BrowserContext { } } + class StorageState { + public List cookies; + public List origins; + + public static class OriginState { + public final String origin; + public List localStorage; + + public static class LocalStorageItem { + public String name; + public String value; + public LocalStorageItem(String name, String value) { + this.name = name; + this.value = value; + } + } + + public OriginState(String origin) { + this.origin = origin; + } + + public OriginState withLocalStorage(List localStorage) { + this.localStorage = localStorage; + return this; + } + } + + public StorageState() { + cookies = new ArrayList<>(); + origins = new ArrayList<>(); + } + + public List cookies() { + return this.cookies; + } + public List origins() { + return this.origins; + } + } + class WaitForEventOptions { public Integer timeout; public Predicate> predicate; @@ -381,7 +421,7 @@ public interface BrowserContext { /** * Returns storage state for this browser context, contains current cookies and local storage snapshot. */ - Object storageState(); + StorageState storageState(); default void unroute(String url) { unroute(url, null); } default void unroute(Pattern url) { unroute(url, null); } default void unroute(Predicate url) { unroute(url, null); } @@ -408,7 +448,6 @@ public interface BrowserContext { *

* * @param event Event name, same one would pass into {@code browserContext.on(event)}. - * @param optionsOrPredicate Either a predicate that receives an event or an options object. * @return Promise which resolves to the event data value. */ Deferred> waitForEvent(EventType event, WaitForEventOptions options); 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 cf2270b4..ebbe9b5f 100644 --- a/playwright/src/main/java/com/microsoft/playwright/impl/BrowserContextImpl.java +++ b/playwright/src/main/java/com/microsoft/playwright/impl/BrowserContextImpl.java @@ -17,6 +17,7 @@ package com.microsoft.playwright.impl; import com.google.gson.JsonArray; +import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.microsoft.playwright.*; @@ -241,8 +242,9 @@ class BrowserContextImpl extends ChannelOwner implements BrowserContext { } @Override - public Object storageState() { - return null; + public StorageState storageState() { + JsonElement json = sendMessage("storageState"); + return gson().fromJson(json, StorageState.class); } @Override diff --git a/playwright/src/test/java/com/microsoft/playwright/TestBrowserContextStorageState.java b/playwright/src/test/java/com/microsoft/playwright/TestBrowserContextStorageState.java new file mode 100644 index 00000000..62e3fe22 --- /dev/null +++ b/playwright/src/test/java/com/microsoft/playwright/TestBrowserContextStorageState.java @@ -0,0 +1,71 @@ +/* + * 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 java.util.Arrays; + +import static com.microsoft.playwright.Utils.assertJsonEquals; +import static com.microsoft.playwright.Utils.mapOf; +import static org.junit.jupiter.api.Assertions.assertEquals; + +public class TestBrowserContextStorageState extends TestBase { + + @Test + void shouldCaptureLocalStorage() { + page.route("**/*", route -> { + route.fulfill(new Route.FulfillResponse().withBody("")); + }); + page.navigate("https://www.example.com"); + page.evaluate("localStorage['name1'] = 'value1';"); + page.navigate("https://www.domain.com"); + page.evaluate("localStorage['name2'] = 'value2';"); + BrowserContext.StorageState storageState = context.storageState(); + + assertJsonEquals("[{\n" + + " origin: 'https://www.example.com',\n" + + " localStorage: [{\n" + + " name: 'name1',\n" + + " value: 'value1'\n" + + " }]\n" + + "}, {\n" + + " origin: 'https://www.domain.com',\n" + + " localStorage: [{\n" + + " name: 'name2',\n" + + " value: 'value2'\n" + + " }]\n" + + "}]", storageState.origins()); + } + + @Test + void shouldSetLocalStorage() { + BrowserContext.StorageState storageState = new BrowserContext.StorageState(); + storageState.origins.add(new BrowserContext.StorageState.OriginState("https://www.example.com") + .withLocalStorage(Arrays.asList( + new BrowserContext.StorageState.OriginState.LocalStorageItem("name1", "value1")))); + BrowserContext context = browser.newContext(new Browser.NewContextOptions().withStorageState(storageState)); + Page page = context.newPage(); + page.route("**/*", route -> { + route.fulfill(new Route.FulfillResponse().withBody("")); + }); + page.navigate("https://www.example.com"); + Object localStorage = page.evaluate("window.localStorage"); + assertEquals(mapOf("name1", "value1"), localStorage); + context.close(); + } +}