https://bugs.webkit.org/show_bug.cgi?id=174710
<rdar://problem/
33459305>
Reviewed by Brian Burg.
Source/WebCore:
Export WebCore symbols required by WebKit layer.
* html/HTMLOptGroupElement.h:
* html/HTMLOptionElement.h:
Source/WebDriver:
Option elements are considered as a special case by the specification. When clicking an option element, we
should get its container and use it when scrolling into view and calculating in-view center point instead of the
option element itself. Then, we should not emulate a click, but change the selected status of the option element
like if it were done by a user action, firing the corresponding events. Now we check whether the element is an
option to call selectOptionElement() or performMouseInteraction().
This fixes more than 20 selenium tests.
* CommandResult.cpp:
(WebDriver::CommandResult::CommandResult): Handle ElementNotSelectable protocol error.
(WebDriver::CommandResult::httpStatusCode const): Add ElementNotSelectable.
(WebDriver::CommandResult::errorString const): Ditto.
* CommandResult.h:
* Session.cpp:
(WebDriver::Session::selectOptionElement): Ask automation to select the given option element.
(WebDriver::Session::elementClick): Call selectOptionElement() or performMouseInteraction() depending on whether
the element is an option or not.
* Session.h:
Source/WebKit:
Add selectOptionElement method to automation to select an option element according to the WebDriver
specification.
14.1 Element Click.
https://w3c.github.io/webdriver/webdriver-spec.html#element-click
* UIProcess/Automation/Automation.json: Add selectOptionElement method and ElementNotSelectable error.
* UIProcess/Automation/WebAutomationSession.cpp:
(WebKit::WebAutomationSession::selectOptionElement):Send SelectOptionElement message to the web process.
(WebKit::WebAutomationSession::didSelectOptionElement): Notify the driver.
* UIProcess/Automation/WebAutomationSession.h:
* UIProcess/Automation/WebAutomationSession.messages.in: Add DidSelectOptionElement message.
* WebProcess/Automation/WebAutomationSessionProxy.cpp:
(WebKit::elementContainer): Helper to get the container of an element according to the spec.
(WebKit::WebAutomationSessionProxy::computeElementLayout): Use the container element to scroll the view and
compute the in-view center point.
(WebKit::WebAutomationSessionProxy::selectOptionElement): Use HTMLSelectElement::optionSelectedByUser().
* WebProcess/Automation/WebAutomationSessionProxy.h:
* WebProcess/Automation/WebAutomationSessionProxy.messages.in: Add SelectOptionElement message.
git-svn-id: https://svn.webkit.org/repository/webkit/trunk@220740
268f45cc-cd09-0410-ab3c-
d52691b4dbfc
+2017-08-14 Carlos Garcia Campos <cgarcia@igalia.com>
+
+ WebDriver: handle click events on option elements
+ https://bugs.webkit.org/show_bug.cgi?id=174710
+ <rdar://problem/33459305>
+
+ Reviewed by Brian Burg.
+
+ Export WebCore symbols required by WebKit layer.
+
+ * html/HTMLOptGroupElement.h:
+ * html/HTMLOptionElement.h:
+
2017-08-14 Simon Fraser <simon.fraser@apple.com>
Remove Proximity Events and related code
static Ref<HTMLOptGroupElement> create(const QualifiedName&, Document&);
bool isDisabledFormControl() const final;
- HTMLSelectElement* ownerSelectElement() const;
+ WEBCORE_EXPORT HTMLSelectElement* ownerSelectElement() const;
WEBCORE_EXPORT String groupLabelText() const;
WEBCORE_EXPORT void setSelected(bool);
#if ENABLE(DATALIST_ELEMENT)
- HTMLDataListElement* ownerDataListElement() const;
+ WEBCORE_EXPORT HTMLDataListElement* ownerDataListElement() const;
#endif
- HTMLSelectElement* ownerSelectElement() const;
+ WEBCORE_EXPORT HTMLSelectElement* ownerSelectElement() const;
WEBCORE_EXPORT String label() const;
String displayLabel() const;
bool ownElementDisabled() const { return m_disabled; }
- bool isDisabledFormControl() const final;
+ WEBCORE_EXPORT bool isDisabledFormControl() const final;
String textIndentedToRespectGroupLabel() const;
+2017-08-14 Carlos Garcia Campos <cgarcia@igalia.com>
+
+ WebDriver: handle click events on option elements
+ https://bugs.webkit.org/show_bug.cgi?id=174710
+ <rdar://problem/33459305>
+
+ Reviewed by Brian Burg.
+
+ Option elements are considered as a special case by the specification. When clicking an option element, we
+ should get its container and use it when scrolling into view and calculating in-view center point instead of the
+ option element itself. Then, we should not emulate a click, but change the selected status of the option element
+ like if it were done by a user action, firing the corresponding events. Now we check whether the element is an
+ option to call selectOptionElement() or performMouseInteraction().
+
+ This fixes more than 20 selenium tests.
+
+ * CommandResult.cpp:
+ (WebDriver::CommandResult::CommandResult): Handle ElementNotSelectable protocol error.
+ (WebDriver::CommandResult::httpStatusCode const): Add ElementNotSelectable.
+ (WebDriver::CommandResult::errorString const): Ditto.
+ * CommandResult.h:
+ * Session.cpp:
+ (WebDriver::Session::selectOptionElement): Ask automation to select the given option element.
+ (WebDriver::Session::elementClick): Call selectOptionElement() or performMouseInteraction() depending on whether
+ the element is an option or not.
+ * Session.h:
+
2017-08-11 Carlos Alberto Lopez Perez <clopez@igalia.com>
Fix build warning in WebDriverService.h
m_errorCode = ErrorCode::Timeout;
else if (errorName == "NoJavaScriptDialog")
m_errorCode = ErrorCode::NoSuchAlert;
+ else if (errorName == "ElementNotSelectable")
+ m_errorCode = ErrorCode::ElementNotSelectable;
break;
}
// https://www.w3.org/TR/webdriver/#handling-errors
switch (m_errorCode.value()) {
case ErrorCode::ElementClickIntercepted:
+ case ErrorCode::ElementNotSelectable:
case ErrorCode::ElementNotInteractable:
case ErrorCode::InvalidArgument:
case ErrorCode::InvalidElementState:
switch (m_errorCode.value()) {
case ErrorCode::ElementClickIntercepted:
return ASCIILiteral("element click intercepted");
+ case ErrorCode::ElementNotSelectable:
+ return ASCIILiteral("element not selectable");
case ErrorCode::ElementNotInteractable:
return ASCIILiteral("element not interactable");
case ErrorCode::InvalidArgument:
// https://www.w3.org/TR/webdriver/#handling-errors
enum class ErrorCode {
ElementClickIntercepted,
+ ElementNotSelectable,
ElementNotInteractable,
InvalidArgument,
InvalidElementState,
});
}
+void Session::selectOptionElement(const String& elementID, Function<void (CommandResult&&)>&& completionHandler)
+{
+ RefPtr<InspectorObject> parameters = InspectorObject::create();
+ parameters->setString(ASCIILiteral("browsingContextHandle"), m_toplevelBrowsingContext.value());
+ parameters->setString(ASCIILiteral("frameHandle"), m_currentBrowsingContext.value());
+ parameters->setString(ASCIILiteral("nodeHandle"), elementID);
+ m_host->sendCommandToBackend(ASCIILiteral("selectOptionElement"), WTFMove(parameters), [this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)](SessionHost::CommandResponse&& response) {
+ if (response.isError) {
+ completionHandler(CommandResult::fail(WTFMove(response.responseObject)));
+ return;
+ }
+ completionHandler(CommandResult::success());
+ });
+}
+
void Session::elementClick(const String& elementID, Function<void (CommandResult&&)>&& completionHandler)
{
if (!m_toplevelBrowsingContext) {
OptionSet<ElementLayoutOption> options = ElementLayoutOption::ScrollIntoViewIfNeeded;
options |= ElementLayoutOption::UseViewportCoordinates;
- computeElementLayout(elementID, options, [this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)](std::optional<Rect>&& rect, std::optional<Point>&& inViewCenter, bool isObscured, RefPtr<InspectorObject>&& error) mutable {
+ computeElementLayout(elementID, options, [this, protectedThis = makeRef(*this), elementID, completionHandler = WTFMove(completionHandler)](std::optional<Rect>&& rect, std::optional<Point>&& inViewCenter, bool isObscured, RefPtr<InspectorObject>&& error) mutable {
if (!rect || error) {
completionHandler(CommandResult::fail(WTFMove(error)));
return;
return;
}
- performMouseInteraction(inViewCenter.value().x, inViewCenter.value().y, MouseButton::Left, MouseInteraction::SingleClick, WTFMove(completionHandler));
+ getElementTagName(elementID, [this, elementID, inViewCenter = WTFMove(inViewCenter), isObscured, completionHandler = WTFMove(completionHandler)](CommandResult&& result) mutable {
+ bool isOptionElement = false;
+ if (!result.isError()) {
+ String tagName;
+ if (result.result()->asString(tagName))
+ isOptionElement = tagName == "option";
+ }
- waitForNavigationToComplete(WTFMove(completionHandler));
+ Function<void (CommandResult&&)> continueAfterClickFunction = [this, completionHandler = WTFMove(completionHandler)](CommandResult&& result) mutable {
+ if (result.isError()) {
+ completionHandler(WTFMove(result));
+ return;
+ }
+
+ waitForNavigationToComplete(WTFMove(completionHandler));
+ };
+ if (isOptionElement)
+ selectOptionElement(elementID, WTFMove(continueAfterClickFunction));
+ else
+ performMouseInteraction(inViewCenter.value().x, inViewCenter.value().y, MouseButton::Left, MouseInteraction::SingleClick, WTFMove(continueAfterClickFunction));
+ });
});
}
};
void computeElementLayout(const String& elementID, OptionSet<ElementLayoutOption>, Function<void (std::optional<Rect>&&, std::optional<Point>&&, bool, RefPtr<Inspector::InspectorObject>&&)>&&);
+ void selectOptionElement(const String& elementID, Function<void (CommandResult&&)>&&);
+
enum class MouseButton { None, Left, Middle, Right };
enum class MouseInteraction { Move, Down, Up, SingleClick, DoubleClick };
void performMouseInteraction(int x, int y, MouseButton, MouseInteraction, Function<void (CommandResult&&)>&&);
+2017-08-14 Carlos Garcia Campos <cgarcia@igalia.com>
+
+ WebDriver: handle click events on option elements
+ https://bugs.webkit.org/show_bug.cgi?id=174710
+ <rdar://problem/33459305>
+
+ Reviewed by Brian Burg.
+
+ Add selectOptionElement method to automation to select an option element according to the WebDriver
+ specification.
+
+ 14.1 Element Click.
+ https://w3c.github.io/webdriver/webdriver-spec.html#element-click
+
+ * UIProcess/Automation/Automation.json: Add selectOptionElement method and ElementNotSelectable error.
+ * UIProcess/Automation/WebAutomationSession.cpp:
+ (WebKit::WebAutomationSession::selectOptionElement):Send SelectOptionElement message to the web process.
+ (WebKit::WebAutomationSession::didSelectOptionElement): Notify the driver.
+ * UIProcess/Automation/WebAutomationSession.h:
+ * UIProcess/Automation/WebAutomationSession.messages.in: Add DidSelectOptionElement message.
+ * WebProcess/Automation/WebAutomationSessionProxy.cpp:
+ (WebKit::elementContainer): Helper to get the container of an element according to the spec.
+ (WebKit::WebAutomationSessionProxy::computeElementLayout): Use the container element to scroll the view and
+ compute the in-view center point.
+ (WebKit::WebAutomationSessionProxy::selectOptionElement): Use HTMLSelectElement::optionSelectedByUser().
+ * WebProcess/Automation/WebAutomationSessionProxy.h:
+ * WebProcess/Automation/WebAutomationSessionProxy.messages.in: Add SelectOptionElement message.
+
2017-08-14 Simon Fraser <simon.fraser@apple.com>
Remove Proximity Events and related code
"MissingParameter",
"InvalidParameter",
"InvalidSelector",
- "ElementNotInteractable"
+ "ElementNotInteractable",
+ "ElementNotSelectable"
]
},
{
],
"async": true
},
+ {
+ "name": "selectOptionElement",
+ "description": "Selects the given option element. In case of container with multiple options enabled, the element selectedness is toggled.",
+ "parameters": [
+ { "name": "browsingContextHandle", "$ref": "BrowsingContextHandle", "description": "The handle for the browsing context." },
+ { "name": "frameHandle", "$ref": "FrameHandle", "description": "The handle for the frame that contains the element." },
+ { "name": "nodeHandle", "$ref": "NodeHandle", "description": "The handle of the element to use." }
+ ],
+ "async": true
+ },
{
"name": "isShowingJavaScriptDialog",
"description": "Checks if a browsing context is showing a JavaScript alert, confirm, or prompt dialog.",
callback->sendSuccess(WTFMove(rectObject), WTFMove(inViewCenterPointObject), isObscured);
}
+void WebAutomationSession::selectOptionElement(Inspector::ErrorString& errorString, const String& browsingContextHandle, const String& frameHandle, const String& nodeHandle, Ref<SelectOptionElementCallback>&& callback)
+{
+ WebPageProxy* page = webPageProxyForHandle(browsingContextHandle);
+ if (!page)
+ FAIL_WITH_PREDEFINED_ERROR(WindowNotFound);
+
+ std::optional<uint64_t> frameID = webFrameIDForHandle(frameHandle);
+ if (!frameID)
+ FAIL_WITH_PREDEFINED_ERROR(FrameNotFound);
+
+ uint64_t callbackID = m_nextSelectOptionElementCallbackID++;
+ m_selectOptionElementCallbacks.set(callbackID, WTFMove(callback));
+
+ page->process().send(Messages::WebAutomationSessionProxy::SelectOptionElement(page->pageID(), frameID.value(), nodeHandle, callbackID), 0);
+}
+
+void WebAutomationSession::didSelectOptionElement(uint64_t callbackID, const String& errorType)
+{
+ auto callback = m_selectOptionElementCallbacks.take(callbackID);
+ if (!callback)
+ return;
+
+ if (!errorType.isEmpty()) {
+ callback->sendFailure(STRING_FOR_PREDEFINED_ERROR_MESSAGE(errorType));
+ return;
+ }
+
+ callback->sendSuccess();
+}
+
+
void WebAutomationSession::isShowingJavaScriptDialog(Inspector::ErrorString& errorString, const String& browsingContextHandle, bool* result)
{
ASSERT(m_client);
void resolveChildFrameHandle(Inspector::ErrorString&, const String& browsingContextHandle, const String* optionalFrameHandle, const int* optionalOrdinal, const String* optionalName, const String* optionalNodeHandle, Ref<ResolveChildFrameHandleCallback>&&) override;
void resolveParentFrameHandle(Inspector::ErrorString&, const String& browsingContextHandle, const String& frameHandle, Ref<ResolveParentFrameHandleCallback>&&) override;
void computeElementLayout(Inspector::ErrorString&, const String& browsingContextHandle, const String& frameHandle, const String& nodeHandle, const bool* optionalScrollIntoViewIfNeeded, const bool* useViewportCoordinates, Ref<Inspector::AutomationBackendDispatcherHandler::ComputeElementLayoutCallback>&&) override;
+ void selectOptionElement(Inspector::ErrorString&, const String& browsingContextHandle, const String& frameHandle, const String& nodeHandle, Ref<Inspector::AutomationBackendDispatcherHandler::SelectOptionElementCallback>&&) override;
void isShowingJavaScriptDialog(Inspector::ErrorString&, const String& browsingContextHandle, bool* result) override;
void dismissCurrentJavaScriptDialog(Inspector::ErrorString&, const String& browsingContextHandle) override;
void acceptCurrentJavaScriptDialog(Inspector::ErrorString&, const String& browsingContextHandle) override;
void didResolveChildFrame(uint64_t callbackID, uint64_t frameID, const String& errorType);
void didResolveParentFrame(uint64_t callbackID, uint64_t frameID, const String& errorType);
void didComputeElementLayout(uint64_t callbackID, WebCore::IntRect, std::optional<WebCore::IntPoint>, bool isObscured, const String& errorType);
+ void didSelectOptionElement(uint64_t callbackID, const String& errorType);
void didTakeScreenshot(uint64_t callbackID, const ShareableBitmap::Handle&, const String& errorType);
void didGetCookiesForFrame(uint64_t callbackID, Vector<WebCore::Cookie>, const String& errorType);
void didDeleteCookie(uint64_t callbackID, const String& errorType);
uint64_t m_nextDeleteCookieCallbackID { 1 };
HashMap<uint64_t, RefPtr<Inspector::AutomationBackendDispatcherHandler::DeleteSingleCookieCallback>> m_deleteCookieCallbacks;
+ uint64_t m_nextSelectOptionElementCallbackID { 1 };
+ HashMap<uint64_t, RefPtr<Inspector::AutomationBackendDispatcherHandler::SelectOptionElementCallback>> m_selectOptionElementCallbacks;
+
RunLoop::Timer<WebAutomationSession> m_loadTimer;
Vector<String> m_filesToSelectForFileUpload;
DidComputeElementLayout(uint64_t callbackID, WebCore::IntRect rect, std::optional<WebCore::IntPoint> inViewCenterPoint, bool isObscured, String errorType)
+ DidSelectOptionElement(uint64_t callbackID, String errorType)
+
DidTakeScreenshot(uint64_t callbackID, WebKit::ShareableBitmap::Handle imageDataHandle, String errorType)
DidGetCookiesForFrame(uint64_t callbackID, Vector<WebCore::Cookie> cookies, String errorType)
#include <WebCore/FrameTree.h>
#include <WebCore/FrameView.h>
#include <WebCore/HTMLFrameElementBase.h>
+#include <WebCore/HTMLOptGroupElement.h>
+#include <WebCore/HTMLOptionElement.h>
+#include <WebCore/HTMLSelectElement.h>
#include <WebCore/JSElement.h>
#include <WebCore/MainFrame.h>
#include <wtf/UUID.h>
return clientCenterPoint;
}
+static WebCore::Element* containerElementForElement(WebCore::Element& element)
+{
+ // §13. Element State.
+ // https://w3c.github.io/webdriver/webdriver-spec.html#dfn-container.
+ if (is<WebCore::HTMLOptionElement>(element)) {
+ auto& optionElement = downcast<WebCore::HTMLOptionElement>(element);
+#if ENABLE(DATALIST_ELEMENT)
+ if (auto* parentElement = optionElement.ownerDataListElement())
+ return parentElement;
+#endif
+ if (auto* parentElement = optionElement.ownerSelectElement())
+ return parentElement;
+
+ return nullptr;
+ }
+
+ if (is<WebCore::HTMLOptGroupElement>(element)) {
+ if (auto* parentElement = downcast<WebCore::HTMLOptGroupElement>(element).ownerSelectElement())
+ return parentElement;
+
+ return nullptr;
+ }
+
+ return &element;
+}
+
void WebAutomationSessionProxy::computeElementLayout(uint64_t pageID, uint64_t frameID, String nodeHandle, bool scrollIntoViewIfNeeded, bool useViewportCoordinates, uint64_t callbackID)
{
WebPage* page = WebProcess::singleton().webPage(pageID);
return;
}
- if (scrollIntoViewIfNeeded) {
+ auto* containerElement = containerElementForElement(*coreElement);
+ if (scrollIntoViewIfNeeded && containerElement) {
+ // §14.1 Element Click. Step 4. Scroll into view the element’s container.
+ // https://w3c.github.io/webdriver/webdriver-spec.html#element-click
+ containerElement->scrollIntoViewIfNeeded(false);
// FIXME: Wait in an implementation-specific way up to the session implicit wait timeout for the element to become in view.
- coreElement->scrollIntoViewIfNeeded(false);
}
WebCore::IntRect rect = coreElement->clientRect();
bool isObscured = false;
std::optional<WebCore::IntPoint> inViewCenter;
- if (auto clientCenterPoint = elementInViewClientCenterPoint(*coreElement, isObscured)) {
- inViewCenter = WebCore::IntPoint(coreFrameView->clientToDocumentPoint(clientCenterPoint.value()));
- if (useViewportCoordinates)
- inViewCenter = coreFrameView->contentsToRootView(inViewCenter.value());
+ if (containerElement) {
+ if (auto clientCenterPoint = elementInViewClientCenterPoint(*containerElement, isObscured)) {
+ inViewCenter = WebCore::IntPoint(coreFrameView->clientToDocumentPoint(clientCenterPoint.value()));
+ if (useViewportCoordinates)
+ inViewCenter = coreFrameView->contentsToRootView(inViewCenter.value());
+ }
}
WebProcess::singleton().parentProcessConnection()->send(Messages::WebAutomationSession::DidComputeElementLayout(callbackID, rect, inViewCenter, isObscured, String()), 0);
}
+void WebAutomationSessionProxy::selectOptionElement(uint64_t pageID, uint64_t frameID, String nodeHandle, uint64_t callbackID)
+{
+ WebPage* page = WebProcess::singleton().webPage(pageID);
+ if (!page) {
+ String windowNotFoundErrorType = Inspector::Protocol::AutomationHelpers::getEnumConstantValue(Inspector::Protocol::Automation::ErrorMessage::WindowNotFound);
+ WebProcess::singleton().parentProcessConnection()->send(Messages::WebAutomationSession::DidSelectOptionElement(callbackID, windowNotFoundErrorType), 0);
+ return;
+ }
+
+ WebFrame* frame = frameID ? WebProcess::singleton().webFrame(frameID) : page->mainWebFrame();
+ if (!frame || !frame->coreFrame() || !frame->coreFrame()->view()) {
+ String frameNotFoundErrorType = Inspector::Protocol::AutomationHelpers::getEnumConstantValue(Inspector::Protocol::Automation::ErrorMessage::FrameNotFound);
+ WebProcess::singleton().parentProcessConnection()->send(Messages::WebAutomationSession::DidSelectOptionElement(callbackID, frameNotFoundErrorType), 0);
+ return;
+ }
+
+ WebCore::Element* coreElement = elementForNodeHandle(*frame, nodeHandle);
+ if (!coreElement || (!is<WebCore::HTMLOptionElement>(coreElement) && !is<WebCore::HTMLOptGroupElement>(coreElement))) {
+ String nodeNotFoundErrorType = Inspector::Protocol::AutomationHelpers::getEnumConstantValue(Inspector::Protocol::Automation::ErrorMessage::NodeNotFound);
+ WebProcess::singleton().parentProcessConnection()->send(Messages::WebAutomationSession::DidSelectOptionElement(callbackID, nodeNotFoundErrorType), 0);
+ return;
+ }
+
+ String elementNotInteractableErrorType = Inspector::Protocol::AutomationHelpers::getEnumConstantValue(Inspector::Protocol::Automation::ErrorMessage::ElementNotInteractable);
+ if (is<WebCore::HTMLOptGroupElement>(coreElement)) {
+ WebProcess::singleton().parentProcessConnection()->send(Messages::WebAutomationSession::DidSelectOptionElement(callbackID, elementNotInteractableErrorType), 0);
+ return;
+ }
+
+ auto& optionElement = downcast<WebCore::HTMLOptionElement>(*coreElement);
+ auto* selectElement = optionElement.ownerSelectElement();
+ if (!selectElement) {
+ WebProcess::singleton().parentProcessConnection()->send(Messages::WebAutomationSession::DidSelectOptionElement(callbackID, elementNotInteractableErrorType), 0);
+ return;
+ }
+
+ if (selectElement->isDisabledFormControl() || optionElement.isDisabledFormControl()) {
+ String elementNotSelectableErrorType = Inspector::Protocol::AutomationHelpers::getEnumConstantValue(Inspector::Protocol::Automation::ErrorMessage::ElementNotSelectable);
+ WebProcess::singleton().parentProcessConnection()->send(Messages::WebAutomationSession::DidSelectOptionElement(callbackID, elementNotSelectableErrorType), 0);
+ return;
+ }
+
+ // FIXME: According to the spec we should fire mouse over, move and down events, then input and change, and finally mouse up and click.
+ // optionSelectedByUser() will fire input and change events if needed, but all other events should be fired manually here.
+ selectElement->optionSelectedByUser(optionElement.index(), true, selectElement->multiple());
+ WebProcess::singleton().parentProcessConnection()->send(Messages::WebAutomationSession::DidSelectOptionElement(callbackID, { }), 0);
+}
+
void WebAutomationSessionProxy::takeScreenshot(uint64_t pageID, uint64_t callbackID)
{
ShareableBitmap::Handle handle;
void resolveParentFrame(uint64_t pageID, uint64_t frameID, uint64_t callbackID);
void focusFrame(uint64_t pageID, uint64_t frameID);
void computeElementLayout(uint64_t pageID, uint64_t frameID, String nodeHandle, bool scrollIntoViewIfNeeded, bool useViewportCoordinates, uint64_t callbackID);
+ void selectOptionElement(uint64_t pageID, uint64_t frameID, String nodeHandle, uint64_t callbackID);
void takeScreenshot(uint64_t pageID, uint64_t callbackID);
void getCookiesForFrame(uint64_t pageID, uint64_t frameID, uint64_t callbackID);
void deleteCookie(uint64_t pageID, uint64_t frameID, String cookieName, uint64_t callbackID);
ComputeElementLayout(uint64_t pageID, uint64_t frameID, String nodeHandle, bool scrollIntoViewIfNeeded, bool useViewportCoordinates, uint64_t callbackID)
+ SelectOptionElement(uint64_t pageID, uint64_t frameID, String nodeHandle, uint64_t callbackID)
+
TakeScreenshot(uint64_t pageID, uint64_t callbackID)
GetCookiesForFrame(uint64_t pageID, uint64_t frameID, uint64_t callbackID)