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 3e5e39ce..6406c5f3 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 @@ -262,6 +262,7 @@ class Event extends Element { // TODO: only whitelisted events are generated for now as the API may change. if (!"BrowserContext.page".equals(jsonPath) && !"Page.console".equals(jsonPath) && + !"Page.dialog".equals(jsonPath) && !"Page.popup".equals(jsonPath)) { return; } diff --git a/lib/src/main/java/com/microsoft/playwright/Page.java b/lib/src/main/java/com/microsoft/playwright/Page.java index 2ee041b0..fd47f381 100644 --- a/lib/src/main/java/com/microsoft/playwright/Page.java +++ b/lib/src/main/java/com/microsoft/playwright/Page.java @@ -749,6 +749,8 @@ public interface Page { } void addConsoleListener(Listener listener); void removeConsoleListener(Listener listener); + void addDialogListener(Listener listener); + void removeDialogListener(Listener listener); Deferred waitForPopup(); default void close() { close(null); diff --git a/lib/src/main/java/com/microsoft/playwright/impl/DialogImpl.java b/lib/src/main/java/com/microsoft/playwright/impl/DialogImpl.java index 11460720..83de4673 100644 --- a/lib/src/main/java/com/microsoft/playwright/impl/DialogImpl.java +++ b/lib/src/main/java/com/microsoft/playwright/impl/DialogImpl.java @@ -17,13 +17,15 @@ package com.microsoft.playwright.impl; import com.google.gson.JsonObject; +import com.microsoft.playwright.Dialog; -public class DialogImpl extends ChannelOwner { +public class DialogImpl extends ChannelOwner implements Dialog { private boolean handled; DialogImpl(ChannelOwner parent, String type, String guid, JsonObject initializer) { super(parent, type, guid, initializer); } + @Override public void accept(String promptText) { handled = true; JsonObject params = new JsonObject(); @@ -32,20 +34,24 @@ public class DialogImpl extends ChannelOwner { sendMessageNoWait("accept", params); } + @Override public void dismiss() { handled = true; sendMessageNoWait("dismiss", new JsonObject()); } + @Override public String defaultValue() { return initializer.get("defaultValue").getAsString(); } + @Override public String message() { return initializer.get("message").getAsString(); } -// public enum Type { Alert, BeforeUnload, Confirm, Prompt } + // public enum Type { Alert, BeforeUnload, Confirm, Prompt } + @Override public String type() { return initializer.get("type").getAsString(); } diff --git a/lib/src/main/java/com/microsoft/playwright/impl/FrameImpl.java b/lib/src/main/java/com/microsoft/playwright/impl/FrameImpl.java index 95cc97ea..72129f9a 100644 --- a/lib/src/main/java/com/microsoft/playwright/impl/FrameImpl.java +++ b/lib/src/main/java/com/microsoft/playwright/impl/FrameImpl.java @@ -49,10 +49,6 @@ public class FrameImpl extends ChannelOwner implements Frame { } } - public T evalTyped(String expression) { - return (T) evaluate(expression, null, false); - } - private Object evaluate(String expression, Object arg, boolean forceExpression) { JsonObject params = new JsonObject(); params.addProperty("expression", expression); diff --git a/lib/src/main/java/com/microsoft/playwright/impl/PageImpl.java b/lib/src/main/java/com/microsoft/playwright/impl/PageImpl.java index 5209d118..634ae4ca 100644 --- a/lib/src/main/java/com/microsoft/playwright/impl/PageImpl.java +++ b/lib/src/main/java/com/microsoft/playwright/impl/PageImpl.java @@ -35,8 +35,8 @@ public class PageImpl extends ChannelOwner implements Page { private final FrameImpl mainFrame; private final KeyboardImpl keyboard; private final MouseImpl mouse; - private final List dialogHandlers = new ArrayList<>(); private final List> consoleListeners = new ArrayList<>(); + private final List> dialogListeners = new ArrayList<>(); final Map bindings = new HashMap(); BrowserContextImpl ownedContext; @@ -59,6 +59,16 @@ public class PageImpl extends ChannelOwner implements Page { consoleListeners.remove(listener); } + @Override + public void addDialogListener(Listener listener) { + dialogListeners.add(listener); + } + + @Override + public void removeDialogListener(Listener listener) { + dialogListeners.remove(listener); + } + @Override public Deferred waitForPopup() { Supplier popupSupplier = waitForProtocolEvent("popup"); @@ -69,28 +79,17 @@ public class PageImpl extends ChannelOwner implements Page { }; } - public interface DialogHandler { - void handle(DialogImpl d); - } - - public void addDialogHandler(DialogHandler handler) { - dialogHandlers.add(handler); - } - - public void removeDialogHandler(DialogHandler handler) { - dialogHandlers.remove(handler); - } - protected void handleEvent(String event, JsonObject params) { if ("dialog".equals(event)) { String guid = params.getAsJsonObject("dialog").get("guid").getAsString(); DialogImpl dialog = connection.getExistingObject(guid); - for (DialogHandler handler: new ArrayList<>(dialogHandlers)) { - handler.handle(dialog); + for (Listener listener: new ArrayList<>(dialogListeners)) { + listener.handle(dialog); } // If no action taken dismiss dialog to not hang. - if (!dialog.isHandled()) + if (!dialog.isHandled()) { dialog.dismiss(); + } } else if ("console".equals(event)) { String guid = params.getAsJsonObject("message").get("guid").getAsString(); ConsoleMessageImpl message = connection.getExistingObject(guid); @@ -100,10 +99,6 @@ public class PageImpl extends ChannelOwner implements Page { } } - public T evalTyped(String expression) { - return mainFrame.evalTyped(expression); - } - @Override public void close(CloseOptions options) { JsonObject params = options == null ? new JsonObject() : new Gson().toJsonTree(options).getAsJsonObject(); @@ -410,6 +405,9 @@ public class PageImpl extends ChannelOwner implements Page { @Override public Object waitForEvent(String event, String optionsOrPredicate) { + // TODO: do we want to keep this method ? + Supplier popupSupplier = waitForProtocolEvent(event); + popupSupplier.get(); return null; } diff --git a/lib/src/test/java/com/microsoft/playwright/TestDialog.java b/lib/src/test/java/com/microsoft/playwright/TestDialog.java new file mode 100644 index 00000000..e8fc2082 --- /dev/null +++ b/lib/src/test/java/com/microsoft/playwright/TestDialog.java @@ -0,0 +1,126 @@ +/** + * 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.*; + +import java.io.IOException; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; + +public class TestDialog { + private static Server server; + private static Browser browser; + private BrowserContext context; + private Page page; + + @BeforeAll + static void launchBrowser() { + Playwright playwright = Playwright.create(); + BrowserType.LaunchOptions options = new BrowserType.LaunchOptions(); + browser = playwright.chromium().launch(options); + } + + @BeforeAll + static void startServer() throws IOException { + server = new Server(8907); + } + + @AfterAll + static void stopServer() throws IOException { + browser.close(); + server.stop(); + server = null; + } + + @BeforeEach + void setUp() { + context = browser.newContext(); + page = context.newPage(); + } + + @AfterEach + void tearDown() { + context.close(); + context = null; + page = null; + } + + @Test + void should_fire() { + page.addDialogListener(dialog -> { + assertEquals( "alert", dialog.type()); + assertEquals( "", dialog.defaultValue()); + assertEquals( "yo", dialog.message()); + dialog.accept(); + }); + page.evaluate("() => alert('yo')"); + } + + @Test + void should_allow_accepting_prompts() { + page.addDialogListener(dialog -> { + assertEquals("prompt", dialog.type()); + assertEquals("yes.", dialog.defaultValue()); + assertEquals("question?", dialog.message()); + dialog.accept("answer!"); + }); + Object result = page.evaluate("() => prompt('question?', 'yes.')"); + assertEquals("answer!", result); + } + + @Test + void should_dismiss_the_prompt() { + page.addDialogListener(dialog -> { + dialog.dismiss(); + }); + Object result = page.evaluate("() => prompt('question?')"); + assertNull(result); + } + + @Test + void should_accept_the_confirm_prompt() { + page.addDialogListener(dialog -> { + dialog.accept(); + }); + Object result = page.evaluate("() => confirm('boolean?')"); + assertEquals(true, result); + } + + @Test + void should_dismiss_the_confirm_prompt() { + page.addDialogListener(dialog -> { + dialog.dismiss(); + }); + Object result = page.evaluate("() => confirm('boolean?')"); + assertEquals(false, result); + } + + @Test + void should_be_able_to_close_context_with_open_alert() { +// test.fixme(browserName === "webkit" && platform === "darwin"); + BrowserContext context = browser.newContext(); + Page page = context.newPage(); +// const alertPromise = page.waitForEvent("dialog"); + page.evaluate("() => {\n" + + " setTimeout(() => alert('hello'), 0);\n" + + "}"); +// alertPromise; + context.close(); + } +}