mirror of
https://github.com/microsoft/playwright-java.git
synced 2025-09-08 21:01:00 +00:00
feat: implement remaining frame methods (#49)
This commit is contained in:
parent
efa1a11c0f
commit
ec49645c16
@ -165,7 +165,7 @@ class ElementHandleImpl extends JSHandleImpl implements ElementHandle {
|
||||
JsonObject params = new JsonObject();
|
||||
params.addProperty("type", type);
|
||||
params.add("eventInit", new Gson().toJsonTree(serializeArgument(eventInit)));
|
||||
sendMessage("dispatchEvent", params).getAsJsonObject();
|
||||
sendMessage("dispatchEvent", params);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -38,7 +38,7 @@ public class FrameImpl extends ChannelOwner implements Frame {
|
||||
FrameImpl parentFrame;
|
||||
Set<FrameImpl> childFrames = new LinkedHashSet<>();
|
||||
private final Set<LoadState> loadStates = new HashSet<>();
|
||||
enum InternalEventType { NAVIGATED, LOADSTATE };
|
||||
enum InternalEventType { NAVIGATED, LOADSTATE }
|
||||
private final ListenerCollection<InternalEventType> internalListeners = new ListenerCollection<>();
|
||||
PageImpl page;
|
||||
boolean isDetached;
|
||||
@ -66,20 +66,6 @@ public class FrameImpl extends ChannelOwner implements Frame {
|
||||
}
|
||||
}
|
||||
|
||||
private Object evaluate(String expression, Object arg, boolean forceExpression) {
|
||||
JsonObject params = new JsonObject();
|
||||
params.addProperty("expression", expression);
|
||||
params.addProperty("world", "main");
|
||||
if (!isFunctionBody(expression)) {
|
||||
forceExpression = true;
|
||||
}
|
||||
params.addProperty("isFunction", !forceExpression);
|
||||
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 ElementHandle querySelector(String selector) {
|
||||
JsonObject params = new JsonObject();
|
||||
@ -140,7 +126,7 @@ public class FrameImpl extends ChannelOwner implements Frame {
|
||||
JsonObject params = new Gson().toJsonTree(options).getAsJsonObject();
|
||||
if (options.path != null) {
|
||||
params.remove("path");
|
||||
byte[] encoded = new byte[0];
|
||||
byte[] encoded;
|
||||
try {
|
||||
encoded = Files.readAllBytes(options.path.toPath());
|
||||
} catch (IOException e) {
|
||||
@ -162,7 +148,7 @@ public class FrameImpl extends ChannelOwner implements Frame {
|
||||
JsonObject params = new Gson().toJsonTree(options).getAsJsonObject();
|
||||
if (options.path != null) {
|
||||
params.remove("path");
|
||||
byte[] encoded = new byte[0];
|
||||
byte[] encoded;
|
||||
try {
|
||||
encoded = Files.readAllBytes(options.path.toPath());
|
||||
} catch (IOException e) {
|
||||
@ -240,12 +226,26 @@ public class FrameImpl extends ChannelOwner implements Frame {
|
||||
|
||||
@Override
|
||||
public void dispatchEvent(String selector, String type, Object eventInit, DispatchEventOptions options) {
|
||||
|
||||
if (options == null) {
|
||||
options = new DispatchEventOptions();
|
||||
}
|
||||
JsonObject params = new Gson().toJsonTree(options).getAsJsonObject();
|
||||
params.addProperty("selector", selector);
|
||||
params.addProperty("type", type);
|
||||
params.add("eventInit", new Gson().toJsonTree(serializeArgument(eventInit)));
|
||||
sendMessage("dispatchEvent", params);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object evaluate(String pageFunction, Object arg) {
|
||||
return evaluate(pageFunction, arg, false);
|
||||
public Object evaluate(String expression, Object arg) {
|
||||
JsonObject params = new JsonObject();
|
||||
params.addProperty("expression", expression);
|
||||
params.addProperty("world", "main");
|
||||
params.addProperty("isFunction", isFunctionBody(expression));
|
||||
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
|
||||
@ -282,15 +282,25 @@ public class FrameImpl extends ChannelOwner implements Frame {
|
||||
|
||||
@Override
|
||||
public ElementHandle frameElement() {
|
||||
return null;
|
||||
JsonObject json = sendMessage("frameElement").getAsJsonObject();
|
||||
return connection.getExistingObject(json.getAsJsonObject("element").get("guid").getAsString());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getAttribute(String selector, String name, GetAttributeOptions options) {
|
||||
if (options == null) {
|
||||
options = new GetAttributeOptions();
|
||||
}
|
||||
JsonObject params = new Gson().toJsonTree(options).getAsJsonObject();
|
||||
params.addProperty("selector", selector);
|
||||
params.addProperty("name", name);
|
||||
JsonObject json = sendMessage("getAttribute", params).getAsJsonObject();
|
||||
if (json.has("value")) {
|
||||
return json.get("value").getAsString();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public ResponseImpl navigate(String url, NavigateOptions options) {
|
||||
if (options == null) {
|
||||
@ -312,17 +322,34 @@ public class FrameImpl extends ChannelOwner implements Frame {
|
||||
|
||||
@Override
|
||||
public void hover(String selector, HoverOptions options) {
|
||||
|
||||
if (options == null) {
|
||||
options = new HoverOptions();
|
||||
}
|
||||
JsonObject params = new Gson().toJsonTree(options).getAsJsonObject();
|
||||
params.addProperty("selector", selector);
|
||||
sendMessage("hover", params);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String innerHTML(String selector, InnerHTMLOptions options) {
|
||||
return null;
|
||||
if (options == null) {
|
||||
options = new InnerHTMLOptions();
|
||||
}
|
||||
JsonObject params = new Gson().toJsonTree(options).getAsJsonObject();
|
||||
params.addProperty("selector", selector);
|
||||
JsonObject json = sendMessage("innerHTML", params).getAsJsonObject();
|
||||
return json.get("value").getAsString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String innerText(String selector, InnerTextOptions options) {
|
||||
return null;
|
||||
if (options == null) {
|
||||
options = new InnerTextOptions();
|
||||
}
|
||||
JsonObject params = new Gson().toJsonTree(options).getAsJsonObject();
|
||||
params.addProperty("selector", selector);
|
||||
JsonObject json = sendMessage("innerText", params).getAsJsonObject();
|
||||
return json.get("value").getAsString();
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -445,7 +472,13 @@ public class FrameImpl extends ChannelOwner implements Frame {
|
||||
|
||||
@Override
|
||||
public void type(String selector, String text, TypeOptions options) {
|
||||
|
||||
if (options == null) {
|
||||
options = new TypeOptions();
|
||||
}
|
||||
JsonObject params = new Gson().toJsonTree(options).getAsJsonObject();
|
||||
params.addProperty("selector", selector);
|
||||
params.addProperty("text", text);
|
||||
sendMessage("type", params);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -642,7 +675,7 @@ public class FrameImpl extends ChannelOwner implements Frame {
|
||||
|
||||
@Override
|
||||
public Deferred<Void> waitForTimeout(int timeout) {
|
||||
return toDeferred(new WaitableTimeout(timeout) {
|
||||
return toDeferred(new WaitableTimeout<Void>(timeout) {
|
||||
@Override
|
||||
public Void get() {
|
||||
// Override to not throw.
|
||||
|
@ -0,0 +1,155 @@
|
||||
/*
|
||||
* 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 com.microsoft.playwright.Utils.mapOf;
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
public class TestDispatchEvent extends TestBase {
|
||||
|
||||
@Test
|
||||
void shouldDispatchClickEvent() {
|
||||
page.navigate(server.PREFIX + "/input/button.html");
|
||||
page.dispatchEvent("button", "click");
|
||||
assertEquals("Clicked", page.evaluate("() => window['result']"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldDispatchClickEventProperties() {
|
||||
page.navigate(server.PREFIX + "/input/button.html");
|
||||
page.dispatchEvent("button", "click");
|
||||
assertNotNull(page.evaluate("bubbles"));
|
||||
assertNotNull(page.evaluate("cancelable"));
|
||||
assertNotNull(page.evaluate("composed"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldDispatchClickSvg() {
|
||||
page.setContent("<svg height='100' width='100'>\n" +
|
||||
" <circle onclick='javascript:window.__CLICKED=42' cx='50' cy='50' r='40' stroke='black' stroke-width='3' fill='red' />\n" +
|
||||
"</svg>");
|
||||
page.dispatchEvent("circle", "click");
|
||||
assertEquals(42, page.evaluate("() => window['__CLICKED']"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldDispatchClickOnASpanWithAnInlineElementInside() {
|
||||
page.setContent("<style>\n" +
|
||||
"span::before {\n" +
|
||||
" content: 'q';\n" +
|
||||
"}\n" +
|
||||
"</style>\n" +
|
||||
"<span onclick='javascript:window.CLICKED=42'></span>");
|
||||
page.dispatchEvent("span", "click");
|
||||
assertEquals(42, page.evaluate("() => window['CLICKED']"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldDispatchClickAfterNavigation() {
|
||||
page.navigate(server.PREFIX + "/input/button.html");
|
||||
page.dispatchEvent("button", "click");
|
||||
page.navigate(server.PREFIX + "/input/button.html");
|
||||
page.dispatchEvent("button", "click");
|
||||
assertEquals("Clicked", page.evaluate("() => window['result']"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldDispatchClickAfterACrossOriginNavigation() {
|
||||
page.navigate(server.PREFIX + "/input/button.html");
|
||||
page.dispatchEvent("button", "click");
|
||||
page.navigate(server.CROSS_PROCESS_PREFIX + "/input/button.html");
|
||||
page.dispatchEvent("button", "click");
|
||||
assertEquals("Clicked", page.evaluate("() => window['result']"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldNotFailWhenElementIsBlockedOnHover() {
|
||||
page.setContent("<style>\n" +
|
||||
" container { display: block; position: relative; width: 200px; height: 50px; }\n" +
|
||||
" div, button { position: absolute; left: 0; top: 0; bottom: 0; right: 0; }\n" +
|
||||
" div { pointer-events: none; }\n" +
|
||||
" container:hover div { pointer-events: auto; background: red; }\n" +
|
||||
"</style>\n" +
|
||||
"<container>\n" +
|
||||
" <button onclick='window.clicked=true'>Click me</button>\n" +
|
||||
" <div></div>\n" +
|
||||
"</container>");
|
||||
page.dispatchEvent("button", "click");
|
||||
assertNotNull(page.evaluate("() => window['clicked']"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldDispatchClickWhenNodeIsAddedInShadowDom() {
|
||||
page.navigate(server.EMPTY_PAGE);
|
||||
page.evaluate("() => {\n" +
|
||||
" const div = document.createElement('div');\n" +
|
||||
" div.attachShadow({mode: 'open'});\n" +
|
||||
" document.body.appendChild(div);\n" +
|
||||
"}");
|
||||
page.evaluate("() => new Promise(f => setTimeout(f, 100))");
|
||||
page.evaluate("() => {\n" +
|
||||
" const span = document.createElement('span');\n" +
|
||||
" span.textContent = 'Hello from shadow';\n" +
|
||||
" span.addEventListener('click', () => window['clicked'] = true);\n" +
|
||||
" document.querySelector('div').shadowRoot.appendChild(span);\n" +
|
||||
"}");
|
||||
// TODO: do it asynchronously before evals?
|
||||
page.dispatchEvent("span", "click");
|
||||
assertEquals(true, page.evaluate("() => window['clicked']"));
|
||||
}
|
||||
|
||||
// @Test
|
||||
void shouldBeAtomic() {
|
||||
// TODO: playwright.selectors.register
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldDispatchDragDropEvents() {
|
||||
page.navigate(server.PREFIX + "/drag-n-drop.html");
|
||||
JSHandle dataTransfer = page.evaluateHandle("() => new DataTransfer()");
|
||||
page.dispatchEvent("#source", "dragstart", mapOf("dataTransfer", dataTransfer));
|
||||
page.dispatchEvent("#target", "drop", mapOf("dataTransfer", dataTransfer));
|
||||
ElementHandle source = page.querySelector("#source");
|
||||
ElementHandle target = page.querySelector("#target");
|
||||
assertEquals(true, page.evaluate("({source, target}) => {\n" +
|
||||
" return source.parentElement === target;\n" +
|
||||
"}", mapOf("source", source,"target", target)));
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldDispatchDragDropEventsOnHandle() {
|
||||
page.navigate(server.PREFIX + "/drag-n-drop.html");
|
||||
JSHandle dataTransfer = page.evaluateHandle("() => new DataTransfer()");
|
||||
ElementHandle source = page.querySelector("#source");
|
||||
source.dispatchEvent("dragstart", mapOf("dataTransfer", dataTransfer));
|
||||
ElementHandle target = page.querySelector("#target");
|
||||
target.dispatchEvent("drop", mapOf("dataTransfer", dataTransfer));
|
||||
assertEquals(true, page.evaluate("({source, target}) => {\n" +
|
||||
" return source.parentElement === target;\n" +
|
||||
"}", mapOf("source", source,"target", target)));
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldDispatchClickEventOnHandle() {
|
||||
page.navigate(server.PREFIX + "/input/button.html");
|
||||
ElementHandle button = page.querySelector("button");
|
||||
button.dispatchEvent("click");
|
||||
assertEquals("Clicked", page.evaluate("() => window['result']"));
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user