From be8b400b2b31a859e97384a1fb8f1812d5a03ec5 Mon Sep 17 00:00:00 2001 From: Yury Semikhatsky Date: Mon, 12 Oct 2020 23:07:22 -0700 Subject: [PATCH] test: querySelector{All} (#8) --- .../playwright/impl/ElementHandleImpl.java | 27 ++- .../microsoft/playwright/impl/FrameImpl.java | 2 + .../playwright/impl/JSHandleImpl.java | 23 +- .../playwright/TestQuerySelector.java | 213 ++++++++++++++++++ 4 files changed, 260 insertions(+), 5 deletions(-) create mode 100644 playwright/src/test/java/com/microsoft/playwright/TestQuerySelector.java diff --git a/playwright/src/main/java/com/microsoft/playwright/impl/ElementHandleImpl.java b/playwright/src/main/java/com/microsoft/playwright/impl/ElementHandleImpl.java index 1621af6d..8a2354b4 100644 --- a/playwright/src/main/java/com/microsoft/playwright/impl/ElementHandleImpl.java +++ b/playwright/src/main/java/com/microsoft/playwright/impl/ElementHandleImpl.java @@ -17,12 +17,14 @@ package com.microsoft.playwright.impl; import com.google.gson.Gson; +import com.google.gson.JsonArray; import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.microsoft.playwright.ElementHandle; import com.microsoft.playwright.Frame; import com.microsoft.playwright.JSHandle; +import java.util.ArrayList; import java.util.List; import static com.microsoft.playwright.impl.Serialization.toProtocol; @@ -51,7 +53,18 @@ public class ElementHandleImpl extends JSHandleImpl implements ElementHandle { @Override public List querySelectorAll(String selector) { - return null; + JsonObject params = new JsonObject(); + params.addProperty("selector", selector); + JsonElement json = sendMessage("querySelectorAll", params); + JsonArray elements = json.getAsJsonObject().getAsJsonArray("elements"); + if (elements == null) { + return null; + } + List handles = new ArrayList<>(); + for (JsonElement item : elements) { + handles.add(connection.getExistingObject(item.getAsJsonObject().get("guid").getAsString())); + } + return handles; } @Override @@ -71,7 +84,11 @@ public class ElementHandleImpl extends JSHandleImpl implements ElementHandle { @Override public void check(CheckOptions options) { - + if (options == null) { + options = new CheckOptions(); + } + JsonObject params = new Gson().toJsonTree(options).getAsJsonObject(); + sendMessage("check", params); } @Override @@ -199,7 +216,11 @@ public class ElementHandleImpl extends JSHandleImpl implements ElementHandle { @Override public void uncheck(UncheckOptions options) { - + if (options == null) { + options = new UncheckOptions(); + } + JsonObject params = new Gson().toJsonTree(options).getAsJsonObject(); + sendMessage("uncheck", params); } @Override diff --git a/playwright/src/main/java/com/microsoft/playwright/impl/FrameImpl.java b/playwright/src/main/java/com/microsoft/playwright/impl/FrameImpl.java index 8611fedc..4f699f30 100644 --- a/playwright/src/main/java/com/microsoft/playwright/impl/FrameImpl.java +++ b/playwright/src/main/java/com/microsoft/playwright/impl/FrameImpl.java @@ -99,6 +99,7 @@ public class FrameImpl extends ChannelOwner implements Frame { params.addProperty("selector", selector); JsonElement json = sendMessage("querySelectorAll", params); JsonArray elements = json.getAsJsonObject().getAsJsonArray("elements"); + System.out.println(new Gson().toJson(elements)); if (elements == null) { return null; } @@ -384,6 +385,7 @@ public class FrameImpl extends ChannelOwner implements Frame { params.addProperty("html", html); params.remove("waitUntil"); params.addProperty("waitUntil", toProtocol(options.waitUntil)); +// System.out.println(new Gson().toJson(params)); sendMessage("setContent", params); } diff --git a/playwright/src/main/java/com/microsoft/playwright/impl/JSHandleImpl.java b/playwright/src/main/java/com/microsoft/playwright/impl/JSHandleImpl.java index 2c1f0644..e0555db8 100644 --- a/playwright/src/main/java/com/microsoft/playwright/impl/JSHandleImpl.java +++ b/playwright/src/main/java/com/microsoft/playwright/impl/JSHandleImpl.java @@ -16,12 +16,18 @@ package com.microsoft.playwright.impl; +import com.google.gson.Gson; +import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.microsoft.playwright.ElementHandle; import com.microsoft.playwright.JSHandle; import java.util.Map; +import static com.microsoft.playwright.impl.Serialization.deserialize; +import static com.microsoft.playwright.impl.Serialization.serializeArgument; +import static com.microsoft.playwright.impl.Utils.isFunctionBody; + public class JSHandleImpl extends ChannelOwner implements JSHandle { public JSHandleImpl(ChannelOwner parent, String type, String guid, JsonObject initializer) { super(parent, type, guid, initializer); @@ -34,12 +40,25 @@ public class JSHandleImpl extends ChannelOwner implements JSHandle { @Override public Object evaluate(String pageFunction, Object arg) { - return null; + JsonObject params = new JsonObject(); + params.addProperty("expression", pageFunction); + params.addProperty("world", "main"); + params.addProperty("isFunction", isFunctionBody(pageFunction)); + params.add("arg", new Gson().toJsonTree(serializeArgument(arg))); + JsonElement json = sendMessage("evaluateExpression", params); + SerializedValue value = new Gson().fromJson(json.getAsJsonObject().get("value"), SerializedValue.class); + return deserialize(value); } @Override public JSHandle evaluateHandle(String pageFunction, Object arg) { - return null; + JsonObject params = new JsonObject(); + params.addProperty("expression", pageFunction); + params.addProperty("world", "main"); + params.addProperty("isFunction", isFunctionBody(pageFunction)); + params.add("arg", new Gson().toJsonTree(serializeArgument(arg))); + JsonElement json = sendMessage("evaluateExpressionHandle", params); + return connection.getExistingObject(json.getAsJsonObject().getAsJsonObject("handle").get("guid").getAsString()); } @Override diff --git a/playwright/src/test/java/com/microsoft/playwright/TestQuerySelector.java b/playwright/src/test/java/com/microsoft/playwright/TestQuerySelector.java new file mode 100644 index 00000000..62632d9b --- /dev/null +++ b/playwright/src/test/java/com/microsoft/playwright/TestQuerySelector.java @@ -0,0 +1,213 @@ +/** + * 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 javax.swing.text.Element; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +import static com.microsoft.playwright.Keyboard.Modifier.SHIFT; +import static com.microsoft.playwright.Mouse.Button.RIGHT; +import static com.microsoft.playwright.Page.EventType.CONSOLE; +import static org.junit.jupiter.api.Assertions.*; + +public class TestQuerySelector { + private static Playwright playwright; + private static Server server; + private static Browser browser; + private static boolean isChromium; + private static boolean isWebKit; + private static boolean headful; + private BrowserContext context; + private Page page; + + @BeforeAll + static void launchBrowser() { + playwright = Playwright.create(); + BrowserType.LaunchOptions options = new BrowserType.LaunchOptions(); + browser = playwright.chromium().launch(options); + isChromium = true; + isWebKit = false; + headful = false; + } + + @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() { + server.reset(); + context = browser.newContext(); + page = context.newPage(); + } + + @AfterEach + void tearDown() { + context.close(); + context = null; + page = null; + } + + + @Test + void shouldThrowForNonStringSelector() { + try { + page.querySelector(null); + fail("did not throw"); + } catch (RuntimeException e) { + System.out.println(e.getMessage()); + assertTrue(e.getMessage().contains("selector: expected string, got undefined")); + } + } + + @Test + void shouldQueryExistingElementWithCssSelector() { + page.setContent("
test
"); + ElementHandle element = page.querySelector("css=section"); + assertNotNull(element); + } + + @Test + void shouldQueryExistingElementWithTextSelector() { + page.setContent("
test
"); + ElementHandle element = page.querySelector("text='test'"); + assertNotNull(element); + } + + @Test + void shouldQueryExistingElementWithXpathSelector() { + page.setContent("
test
"); + ElementHandle element = page.querySelector("xpath=/html/body/section"); + assertNotNull(element); + } + + @Test + void shouldReturnNullForNonExistingElement() { + ElementHandle element = page.querySelector("non-existing-element"); + assertNull(element); + } + + @Test + void shouldAutoDetectXpathSelector() { + page.setContent("
test
"); + ElementHandle element = page.querySelector("//html/body/section"); + assertNotNull(element); + } + + @Test + void shouldAutoDetectXpathSelectorWithStartingParenthesis() { + page.setContent("
test
"); + ElementHandle element = page.querySelector("(//section)[1]"); + assertNotNull(element); + } + + @Test + void shouldAutoDetectXpathSelectorStartingWith() { + page.setContent("
test
"); + ElementHandle span = page.querySelector("'test' >> ../span"); + assertEquals("SPAN", span.evaluate("e => e.nodeName")); + ElementHandle div = page.querySelector("'test' >> .."); + assertEquals("DIV", div.evaluate("e => e.nodeName")); + } + + @Test + void shouldAutoDetectTextSelector() { + page.setContent("
test
"); + ElementHandle element = page.querySelector("'test'"); + assertNotNull(element); + } + + @Test + void shouldAutoDetectCssSelector() { + page.setContent("
test
"); + ElementHandle element = page.querySelector("section"); + assertNotNull(element); + } + + @Test + void shouldSupportSyntax() { + page.setContent("
test
"); + ElementHandle element = page.querySelector("css=section >> css=div"); + assertNotNull(element); + } + + @Test + void shouldQueryExistingElements() { + page.setContent("
A

B
"); + List elements = page.querySelectorAll("div"); + assertEquals(2, elements.size()); + List results = new ArrayList<>(); + for (ElementHandle element : elements) { + results.add(page.evaluate("e => e.textContent", element)); + } + assertEquals(Arrays.asList("A", "B"), results); + } + + @Test + void shouldReturnEmptyArrayIfNothingIsFound() { + page.navigate(server.EMPTY_PAGE); + List elements = page.querySelectorAll("div"); + assertEquals(0, elements.size()); + } + + @Test + void xpathShouldQueryExistingElement() { + page.setContent("
test
"); + List elements = page.querySelectorAll("xpath=/html/body/section"); + assertNotNull(elements.get(0)); + assertEquals(1, elements.size()); + } + + @Test + void xpathShouldReturnEmptyArrayForNonExistingElement() { + List elements = page.querySelectorAll("//html/body/non-existing-element"); + assertEquals(Collections.emptyList(), elements); + } + + @Test + void xpathShouldReturnMultipleElements() { + page.setContent("
"); + List elements = page.querySelectorAll("xpath=/html/body/div"); + assertEquals(2, elements.size()); + } + +// @Test +// void querySelectorAllShouldWorkWithBogusArrayFrom() { +// page.setContent("
hello
"); +// JSHandle div1 = page.evaluateHandle("() => {\n" + +// " Array.from = () => [];\n" + +// " return document.querySelector('div');\n" + +// "}"); +// List elements = page.querySelectorAll("div"); +// assertEquals(2, elements.size()); +// // Check that element handle is functional and belongs to the main world. +// assertEquals(true, elements.get(0).evaluate("(div, div1) => div === div1", div1)); +// } +}