From e31ea3cbe95ff41015fe72293f99e6a802521f08 Mon Sep 17 00:00:00 2001 From: Yury Semikhatsky Date: Wed, 3 Feb 2021 12:58:38 -0800 Subject: [PATCH] fix: change Accessibility.snapshot type to String (#251) --- .../microsoft/playwright/Accessibility.java | 4 +- .../playwright/AccessibilityNode.java | 51 ---- .../java/com/microsoft/playwright/Dialog.java | 5 + .../playwright/impl/AccessibilityImpl.java | 9 +- .../impl/AccessibilityNodeImpl.java | 258 ------------------ .../playwright/TestAccessibility.java | 199 ++++---------- scripts/CLI_VERSION | 2 +- .../com/microsoft/playwright/tools/Types.java | 1 - 8 files changed, 72 insertions(+), 457 deletions(-) delete mode 100644 playwright/src/main/java/com/microsoft/playwright/AccessibilityNode.java delete mode 100644 playwright/src/main/java/com/microsoft/playwright/impl/AccessibilityNodeImpl.java diff --git a/playwright/src/main/java/com/microsoft/playwright/Accessibility.java b/playwright/src/main/java/com/microsoft/playwright/Accessibility.java index 42488966..684c2b62 100644 --- a/playwright/src/main/java/com/microsoft/playwright/Accessibility.java +++ b/playwright/src/main/java/com/microsoft/playwright/Accessibility.java @@ -53,7 +53,7 @@ public interface Accessibility { return this; } } - default AccessibilityNode snapshot() { + default String snapshot() { return snapshot(null); } /** @@ -63,6 +63,6 @@ public interface Accessibility { *

NOTE: The Chromium accessibility tree contains nodes that go unused on most platforms and by most screen readers. * Playwright will discard them as well for an easier to process tree, unless {@code interestingOnly} is set to {@code false}. */ - AccessibilityNode snapshot(SnapshotOptions options); + String snapshot(SnapshotOptions options); } diff --git a/playwright/src/main/java/com/microsoft/playwright/AccessibilityNode.java b/playwright/src/main/java/com/microsoft/playwright/AccessibilityNode.java deleted file mode 100644 index bc24dd27..00000000 --- a/playwright/src/main/java/com/microsoft/playwright/AccessibilityNode.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * 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 java.util.List; - -public interface AccessibilityNode { - String role(); - String name(); - String valueString(); - Double valueNumber(); - String description(); - String keyshortcuts(); - String roledescription(); - String valuetext(); - Boolean disabled(); - Boolean expanded(); - Boolean focused(); - Boolean modal(); - Boolean multiline(); - Boolean multiselectable(); - Boolean readonly(); - Boolean required(); - Boolean selected(); - enum CheckedState { CHECKED, UNCHECKED, MIXED } - CheckedState checked(); - enum PressedState { PRESSED, RELEASED, MIXED } - PressedState pressed(); - Integer level(); - Double valuemin(); - Double valuemax(); - String autocomplete(); - String haspopup(); - String invalid(); - String orientation(); - List children(); -} diff --git a/playwright/src/main/java/com/microsoft/playwright/Dialog.java b/playwright/src/main/java/com/microsoft/playwright/Dialog.java index c08e6418..1f5f0f05 100644 --- a/playwright/src/main/java/com/microsoft/playwright/Dialog.java +++ b/playwright/src/main/java/com/microsoft/playwright/Dialog.java @@ -20,6 +20,11 @@ import java.util.*; /** * {@code Dialog} objects are dispatched by page via the [{@code event: Page.dialog}] event. + * + *

NOTE: Dialogs are dismissed automatically, unless there is a [{@code event: Page.dialog}] listener. When listener is + * present, it **must** either [{@code method: Dialog.accept}] or [{@code method: Dialog.dismiss}] the dialog - otherwise the page will + * [freeze](https://developer.mozilla.org/en-US/docs/Web/JavaScript/EventLoop#never_blocking) waiting for the dialog, and + * actions like click will never finish. */ public interface Dialog { default void accept() { diff --git a/playwright/src/main/java/com/microsoft/playwright/impl/AccessibilityImpl.java b/playwright/src/main/java/com/microsoft/playwright/impl/AccessibilityImpl.java index d758a57c..d4622e61 100644 --- a/playwright/src/main/java/com/microsoft/playwright/impl/AccessibilityImpl.java +++ b/playwright/src/main/java/com/microsoft/playwright/impl/AccessibilityImpl.java @@ -16,9 +16,8 @@ package com.microsoft.playwright.impl; -import com.google.gson.JsonObject; +import com.google.gson.*; import com.microsoft.playwright.Accessibility; -import com.microsoft.playwright.AccessibilityNode; import static com.microsoft.playwright.impl.Serialization.gson; @@ -30,11 +29,11 @@ class AccessibilityImpl implements Accessibility { } @Override - public AccessibilityNode snapshot(SnapshotOptions options) { + public String snapshot(SnapshotOptions options) { return page.withLogging("Accessibility.snapshot", () -> snapshotImpl(options)); } - private AccessibilityNode snapshotImpl(SnapshotOptions options) { + private String snapshotImpl(SnapshotOptions options) { if (options == null) { options = new SnapshotOptions(); } @@ -43,6 +42,6 @@ class AccessibilityImpl implements Accessibility { if (!json.has("rootAXNode")) { return null; } - return new AccessibilityNodeImpl(json.getAsJsonObject("rootAXNode")); + return json.getAsJsonObject("rootAXNode").toString(); } } diff --git a/playwright/src/main/java/com/microsoft/playwright/impl/AccessibilityNodeImpl.java b/playwright/src/main/java/com/microsoft/playwright/impl/AccessibilityNodeImpl.java deleted file mode 100644 index 36a8a05a..00000000 --- a/playwright/src/main/java/com/microsoft/playwright/impl/AccessibilityNodeImpl.java +++ /dev/null @@ -1,258 +0,0 @@ -/* - * 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.impl; - -import com.google.gson.JsonElement; -import com.google.gson.JsonObject; -import com.microsoft.playwright.AccessibilityNode; - -import java.util.ArrayList; -import java.util.List; - -class AccessibilityNodeImpl implements AccessibilityNode { - private final JsonObject json; - - AccessibilityNodeImpl(JsonObject json) { - this.json = json; - } - - @Override - public String role() { - return json.get("role").getAsString(); - } - - @Override - public String name() { - return json.get("name").getAsString(); - } - - @Override - public String valueString() { - if (!json.has("valueString")) { - return null; - } - return json.get("valueString").getAsString(); - } - - @Override - public Double valueNumber() { - if (!json.has("valueNumber")) { - return null; - } - return json.get("valueNumber").getAsDouble(); - } - - @Override - public String description() { - if (!json.has("description")) { - return null; - } - return json.get("description").getAsString(); - } - - @Override - public String keyshortcuts() { - if (!json.has("keyshortcuts")) { - return null; - } - return json.get("keyshortcuts").getAsString(); - } - - @Override - public String roledescription() { - if (!json.has("roledescription")) { - return null; - } - return json.get("roledescription").getAsString(); - } - - @Override - public String valuetext() { - if (!json.has("valuetext")) { - return null; - } - return json.get("valuetext").getAsString(); - } - - @Override - public Boolean disabled() { - if (!json.has("disabled")) { - return null; - } - return json.get("disabled").getAsBoolean(); - } - - @Override - public Boolean expanded() { - if (!json.has("expanded")) { - return null; - } - return json.get("expanded").getAsBoolean(); - } - - @Override - public Boolean focused() { - if (!json.has("focused")) { - return null; - } - return json.get("focused").getAsBoolean(); - } - - @Override - public Boolean modal() { - if (!json.has("modal")) { - return null; - } - return json.get("modal").getAsBoolean(); - } - - @Override - public Boolean multiline() { - if (!json.has("multiline")) { - return null; - } - return json.get("multiline").getAsBoolean(); - } - - @Override - public Boolean multiselectable() { - if (!json.has("multiselectable")) { - return null; - } - return json.get("multiselectable").getAsBoolean(); - } - - @Override - public Boolean readonly() { - if (!json.has("readonly")) { - return null; - } - return json.get("readonly").getAsBoolean(); - } - - @Override - public Boolean required() { - if (!json.has("required")) { - return null; - } - return json.get("required").getAsBoolean(); - } - - @Override - public Boolean selected() { - if (!json.has("selected")) { - return null; - } - return json.get("selected").getAsBoolean(); - } - - @Override - public CheckedState checked() { - if (!json.has("checked")) { - return null; - } - String value = json.get("checked").getAsString(); - switch (value) { - case "checked": return CheckedState.CHECKED; - case "unchecked": return CheckedState.UNCHECKED; - case "mixed": return CheckedState.MIXED; - default: throw new IllegalStateException("Unexpected value: " + value); - } - } - - @Override - public PressedState pressed() { - if (!json.has("pressed")) { - return null; - } - String value = json.get("pressed").getAsString(); - switch (value) { - case "pressed": return PressedState.PRESSED; - case "released": return PressedState.RELEASED; - case "mixed": return PressedState.MIXED; - default: throw new IllegalStateException("Unexpected value: " + value); - } - } - - @Override - public Integer level() { - if (!json.has("level")) { - return null; - } - return json.get("level").getAsInt(); - } - - @Override - public Double valuemin() { - if (!json.has("valuemin")) { - return null; - } - return json.get("valuemin").getAsDouble(); - } - - @Override - public Double valuemax() { - if (!json.has("valuemax")) { - return null; - } - return json.get("valuemax").getAsDouble(); - } - - @Override - public String autocomplete() { - if (!json.has("autocomplete")) { - return null; - } - return json.get("autocomplete").getAsString(); - } - - @Override - public String haspopup() { - if (!json.has("haspopup")) { - return null; - } - return json.get("haspopup").getAsString(); - } - - @Override - public String invalid() { - if (!json.has("invalid")) { - return null; - } - return json.get("invalid").getAsString(); - } - - @Override - public String orientation() { - if (!json.has("orientation")) { - return null; - } - return json.get("orientation").getAsString(); - } - - @Override - public List children() { - if (!json.has("children")) { - return null; - } - List result = new ArrayList<>(); - for (JsonElement e : json.getAsJsonArray("children")) { - result.add(new AccessibilityNodeImpl(e.getAsJsonObject())); - } - return result; - } -} diff --git a/playwright/src/test/java/com/microsoft/playwright/TestAccessibility.java b/playwright/src/test/java/com/microsoft/playwright/TestAccessibility.java index c29bdba5..833b7f10 100644 --- a/playwright/src/test/java/com/microsoft/playwright/TestAccessibility.java +++ b/playwright/src/test/java/com/microsoft/playwright/TestAccessibility.java @@ -16,115 +16,23 @@ package com.microsoft.playwright; -import com.google.gson.*; +import com.google.gson.Gson; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.condition.DisabledIf; import org.junit.jupiter.api.condition.EnabledIf; -import java.lang.reflect.Type; - import static org.junit.jupiter.api.Assertions.*; public class TestAccessibility extends TestBase { - private static class AccessibilityNodeSerializer implements JsonSerializer { - @Override - public JsonElement serialize(AccessibilityNode src, Type typeOfSrc, JsonSerializationContext context) { - JsonObject json = new JsonObject(); - if (src.role() != null) { - json.addProperty("role", src.role()); - } - if (src.name() != null) { - json.addProperty("name", src.name()); - } - if (src.valueString() != null) { - json.addProperty("valueString", src.valueString()); - } - if (src.valueNumber() != null) { - json.addProperty("valueNumber", src.valueNumber()); - } - if (src.description() != null) { - json.addProperty("description", src.description()); - } - if (src.keyshortcuts() != null) { - json.addProperty("keyshortcuts", src.keyshortcuts()); - } - if (src.roledescription() != null) { - json.addProperty("roledescription", src.roledescription()); - } - if (src.valuetext() != null) { - json.addProperty("valuetext", src.valuetext()); - } - if (src.disabled() != null) { - json.addProperty("disabled", src.disabled()); - } - if (src.expanded() != null) { - json.addProperty("expanded", src.expanded()); - } - if (src.focused() != null) { - json.addProperty("focused", src.focused()); - } - if (src.modal() != null) { - json.addProperty("modal", src.modal()); - } - if (src.multiline() != null) { - json.addProperty("multiline", src.multiline()); - } - if (src.multiselectable() != null) { - json.addProperty("multiselectable", src.multiselectable()); - } - if (src.readonly() != null) { - json.addProperty("readonly", src.readonly()); - } - if (src.required() != null) { - json.addProperty("required", src.required()); - } - if (src.selected() != null) { - json.addProperty("selected", src.selected()); - } - if (src.level() != null) { - json.addProperty("level", src.level()); - } - if (src.valuemin() != null) { - json.addProperty("valuemin", src.valuemin()); - } - if (src.valuemax() != null) { - json.addProperty("valuemax", src.valuemax()); - } - if (src.autocomplete() != null) { - json.addProperty("autocomplete", src.autocomplete()); - } - if (src.haspopup() != null) { - json.addProperty("haspopup", src.haspopup()); - } - if (src.invalid() != null) { - json.addProperty("invalid", src.invalid()); - } - if (src.orientation() != null) { - json.addProperty("orientation", src.orientation()); - } - if (src.checked() != null) { - json.addProperty("checked", src.checked().toString().toLowerCase()); - } - if (src.pressed() != null) { - json.addProperty("pressed", src.pressed().toString().toLowerCase()); - } - if (src.children() != null) { - JsonArray children = new JsonArray(); - for (AccessibilityNode child : src.children()) { - children.add(context.serialize(child)); - } - json.add("children", children); - } - return json; - } + static void assertNodeEquals(String expected, String actual) { + JsonElement actualJson = new Gson().fromJson(actual, JsonElement.class); + assertNodeEquals(expected, actualJson); } - private static Gson gson = new GsonBuilder() - .registerTypeHierarchyAdapter(AccessibilityNode.class, new AccessibilityNodeSerializer()).create(); - - - static void assertNodeEquals(String expected, AccessibilityNode actual) { - JsonElement actualJson = gson.toJsonTree(actual); + static void assertNodeEquals(String expected, JsonElement actualJson) { assertEquals(JsonParser.parseString(expected), actualJson); } @@ -193,45 +101,55 @@ public class TestAccessibility extends TestBase { @Test void shouldWorkWithRegularText() { page.setContent("

Hello World
"); - AccessibilityNode snapshot = page.accessibility().snapshot(); - AccessibilityNode node = snapshot.children().get(0); - assertEquals(isFirefox() ? "text leaf" : "text", node.role()); - assertEquals("Hello World", node.name()); + JsonObject snapshot = new Gson().fromJson(page.accessibility().snapshot(), JsonObject.class); + JsonObject node = snapshot.getAsJsonArray("children").get(0).getAsJsonObject(); + assertEquals(isFirefox() ? "text leaf" : "text", node.get("role").getAsString()); + assertEquals("Hello World", node.get("name").getAsString()); } @Test void roledescription() { page.setContent("
Hi
"); - AccessibilityNode snapshot = page.accessibility().snapshot(); - assertEquals("foo", snapshot.children().get(0).roledescription()); + JsonObject snapshot = new Gson().fromJson(page.accessibility().snapshot(), JsonObject.class); + assertEquals("foo", snapshot.getAsJsonArray("children") + .get(0).getAsJsonObject() + .get("roledescription").getAsString()); } @Test void orientation() { page.setContent("11"); - AccessibilityNode snapshot = page.accessibility().snapshot(); - assertEquals("vertical", snapshot.children().get(0).orientation()); + JsonObject snapshot = new Gson().fromJson(page.accessibility().snapshot(), JsonObject.class); + assertEquals("vertical", snapshot.getAsJsonArray("children") + .get(0).getAsJsonObject() + .get("orientation").getAsString()); } @Test void autocomplete() { page.setContent("
hi
"); - AccessibilityNode snapshot = page.accessibility().snapshot(); - assertEquals("list", snapshot.children().get(0).autocomplete()); + JsonObject snapshot = new Gson().fromJson(page.accessibility().snapshot(), JsonObject.class); + assertEquals("list", snapshot.getAsJsonArray("children") + .get(0).getAsJsonObject() + .get("autocomplete").getAsString()); } @Test void multiselectable() { page.setContent("
hey
"); - AccessibilityNode snapshot = page.accessibility().snapshot(); - assertEquals(true, snapshot.children().get(0).multiselectable()); + JsonObject snapshot = new Gson().fromJson(page.accessibility().snapshot(), JsonObject.class); + assertEquals(true, snapshot.getAsJsonArray("children") + .get(0).getAsJsonObject() + .get("multiselectable").getAsBoolean()); } @Test void keyshortcuts() { page.setContent("
hey
"); - AccessibilityNode snapshot = page.accessibility().snapshot(); - assertEquals("foo", snapshot.children().get(0).keyshortcuts()); + JsonObject snapshot = new Gson().fromJson(page.accessibility().snapshot(), JsonObject.class); + assertEquals("foo", snapshot.getAsJsonArray("children") + .get(0).getAsJsonObject() + .get("keyshortcuts").getAsString()); } @Test @@ -283,8 +201,8 @@ public class TestAccessibility extends TestBase { " name: 'my fake image'\n" + " }]\n" + "}"; - AccessibilityNode snapshot = page.accessibility().snapshot(); - assertNodeEquals(golden, snapshot.children().get(0)); + JsonObject snapshot = new Gson().fromJson(page.accessibility().snapshot(), JsonObject.class); + assertNodeEquals(golden, snapshot.getAsJsonArray("children").get(0)); } @Test @@ -313,42 +231,42 @@ public class TestAccessibility extends TestBase { " name: 'my fake image'\n" + " }]\n" + "}"; - AccessibilityNode snapshot = page.accessibility().snapshot(); - assertNodeEquals(golden, snapshot.children().get(0)); + JsonObject snapshot = new Gson().fromJson(page.accessibility().snapshot(), JsonObject.class); + assertNodeEquals(golden, snapshot.getAsJsonArray("children").get(0)); } @Test @EnabledIf(value="com.microsoft.playwright.TestBase#isChromium", disabledReason="skip") void plainTextFieldWithRoleShouldNotHaveChildren() { page.setContent("
Edit this image:my fake image
"); - AccessibilityNode snapshot = page.accessibility().snapshot(); + JsonObject snapshot = new Gson().fromJson(page.accessibility().snapshot(), JsonObject.class); assertNodeEquals("{\n" + " role: 'textbox',\n" + " name: '',\n" + " valueString: 'Edit this image:'\n" + - "}", snapshot.children().get(0)); + "}", snapshot.getAsJsonArray("children").get(0)); } @Test @EnabledIf(value="com.microsoft.playwright.TestBase#isChromium", disabledReason="skip") void plainTextFieldWithoutRoleShouldNotHaveContent() { page.setContent("
Edit this image:my fake image
"); - AccessibilityNode snapshot = page.accessibility().snapshot(); + JsonObject snapshot = new Gson().fromJson(page.accessibility().snapshot(), JsonObject.class); assertNodeEquals("{\n" + " role: 'generic',\n" + " name: ''\n" + - "}", snapshot.children().get(0)); + "}", snapshot.getAsJsonArray("children").get(0)); } @Test @EnabledIf(value="com.microsoft.playwright.TestBase#isChromium", disabledReason="skip") void plainTextFieldWithTabindexAndWithoutRoleShouldNotHaveContent() { page.setContent("
Edit this image:my fake image
"); - AccessibilityNode snapshot = page.accessibility().snapshot(); + JsonObject snapshot = new Gson().fromJson(page.accessibility().snapshot(), JsonObject.class); assertNodeEquals("{\n" + " role: 'generic',\n" + " name: ''\n" + - "}", snapshot.children().get(0)); + "}", snapshot.getAsJsonArray("children").get(0)); } @Test @@ -370,8 +288,8 @@ public class TestAccessibility extends TestBase { " name: 'my favorite textbox',\n" + " valueString: 'this is the inner content '\n" + "}"; - AccessibilityNode snapshot = page.accessibility().snapshot(); - assertNodeEquals(golden, snapshot.children().get(0)); + JsonObject snapshot = new Gson().fromJson(page.accessibility().snapshot(), JsonObject.class); + assertNodeEquals(golden, snapshot.getAsJsonArray("children").get(0)); } @Test @@ -385,8 +303,8 @@ public class TestAccessibility extends TestBase { " name: 'my favorite checkbox',\n" + " checked: 'checked'\n" + "}"; - AccessibilityNode snapshot = page.accessibility().snapshot(); - assertNodeEquals(golden, snapshot.children().get(0)); + JsonObject snapshot = new Gson().fromJson(page.accessibility().snapshot(), JsonObject.class); + assertNodeEquals(golden, snapshot.getAsJsonArray("children").get(0)); } @Test @@ -404,8 +322,8 @@ public class TestAccessibility extends TestBase { " name: 'this is the inner content yo',\n" + " checked: 'checked'\n" + "}"; - AccessibilityNode snapshot = page.accessibility().snapshot(); - assertNodeEquals(golden, snapshot.children().get(0)); + JsonObject snapshot = new Gson().fromJson(page.accessibility().snapshot(), JsonObject.class); + assertNodeEquals(golden, snapshot.getAsJsonArray("children").get(0)); } @Test @@ -470,20 +388,23 @@ public class TestAccessibility extends TestBase { " \n" + ""); ElementHandle root = page.querySelector("#root"); - AccessibilityNode snapshot = page.accessibility().snapshot( - new Accessibility.SnapshotOptions().withRoot(root).withInterestingOnly(false)); - assertEquals("textbox", snapshot.role()); - assertTrue(snapshot.valueString().contains("hello")); - assertTrue(snapshot.valueString().contains("world")); - assertNotNull(snapshot.children()); + JsonObject snapshot = new Gson().fromJson(page.accessibility().snapshot( + new Accessibility.SnapshotOptions().withRoot(root).withInterestingOnly(false)), + JsonObject.class); + assertEquals("textbox", snapshot.get("role").getAsString()); + assertTrue(snapshot.get("valueString").getAsString().contains("hello")); + assertTrue(snapshot.get("valueString").getAsString().contains("world")); + assertNotNull(snapshot.get("children")); } @Test void shouldWorkWhenThereIsATitle() { page.setContent("This is the title\n" + "
This is the content
"); - AccessibilityNode snapshot = page.accessibility().snapshot(); - assertEquals("This is the title", snapshot.name()); - assertEquals("This is the content", snapshot.children().get(0).name()); + JsonObject snapshot = new Gson().fromJson(page.accessibility().snapshot(), JsonObject.class); + assertEquals("This is the title", snapshot.get("name").getAsString()); + assertEquals("This is the content", snapshot.getAsJsonArray("children") + .get(0).getAsJsonObject() + .get("name").getAsString()); } } diff --git a/scripts/CLI_VERSION b/scripts/CLI_VERSION index e9735ae2..cb860591 100644 --- a/scripts/CLI_VERSION +++ b/scripts/CLI_VERSION @@ -1 +1 @@ -1.9.0-next-1612316912000 +1.9.0-next-1612383782000 diff --git a/tools/api-generator/src/main/java/com/microsoft/playwright/tools/Types.java b/tools/api-generator/src/main/java/com/microsoft/playwright/tools/Types.java index 7e13369d..6e5ebd37 100644 --- a/tools/api-generator/src/main/java/com/microsoft/playwright/tools/Types.java +++ b/tools/api-generator/src/main/java/com/microsoft/playwright/tools/Types.java @@ -143,7 +143,6 @@ class Types { // Return structures add("ConsoleMessage.location", "Object", "Location"); add("ElementHandle.boundingBox", "Object|null", "BoundingBox", new Empty()); - add("Accessibility.snapshot", "Object|null", "AccessibilityNode", new Empty()); add("WebSocket.framereceived", "Object", "FrameData", new Empty()); add("WebSocket.framesent", "Object", "FrameData", new Empty());