Diff
Modified: trunk/Source/WebCore/ChangeLog (220739 => 220740)
--- trunk/Source/WebCore/ChangeLog 2017-08-15 06:51:49 UTC (rev 220739)
+++ trunk/Source/WebCore/ChangeLog 2017-08-15 07:03:13 UTC (rev 220740)
@@ -1,3 +1,16 @@
+2017-08-14 Carlos Garcia Campos <cgar...@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.fra...@apple.com>
Remove Proximity Events and related code
Modified: trunk/Source/WebCore/html/HTMLOptGroupElement.h (220739 => 220740)
--- trunk/Source/WebCore/html/HTMLOptGroupElement.h 2017-08-15 06:51:49 UTC (rev 220739)
+++ trunk/Source/WebCore/html/HTMLOptGroupElement.h 2017-08-15 07:03:13 UTC (rev 220740)
@@ -34,7 +34,7 @@
static Ref<HTMLOptGroupElement> create(const QualifiedName&, Document&);
bool isDisabledFormControl() const final;
- HTMLSelectElement* ownerSelectElement() const;
+ WEBCORE_EXPORT HTMLSelectElement* ownerSelectElement() const;
WEBCORE_EXPORT String groupLabelText() const;
Modified: trunk/Source/WebCore/html/HTMLOptionElement.h (220739 => 220740)
--- trunk/Source/WebCore/html/HTMLOptionElement.h 2017-08-15 06:51:49 UTC (rev 220739)
+++ trunk/Source/WebCore/html/HTMLOptionElement.h 2017-08-15 07:03:13 UTC (rev 220740)
@@ -49,9 +49,9 @@
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;
@@ -59,7 +59,7 @@
bool ownElementDisabled() const { return m_disabled; }
- bool isDisabledFormControl() const final;
+ WEBCORE_EXPORT bool isDisabledFormControl() const final;
String textIndentedToRespectGroupLabel() const;
Modified: trunk/Source/WebDriver/ChangeLog (220739 => 220740)
--- trunk/Source/WebDriver/ChangeLog 2017-08-15 06:51:49 UTC (rev 220739)
+++ trunk/Source/WebDriver/ChangeLog 2017-08-15 07:03:13 UTC (rev 220740)
@@ -1,3 +1,30 @@
+2017-08-14 Carlos Garcia Campos <cgar...@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 <clo...@igalia.com>
Fix build warning in WebDriverService.h
Modified: trunk/Source/WebDriver/CommandResult.cpp (220739 => 220740)
--- trunk/Source/WebDriver/CommandResult.cpp 2017-08-15 06:51:49 UTC (rev 220739)
+++ trunk/Source/WebDriver/CommandResult.cpp 2017-08-15 07:03:13 UTC (rev 220740)
@@ -106,6 +106,8 @@
m_errorCode = ErrorCode::Timeout;
else if (errorName == "NoJavaScriptDialog")
m_errorCode = ErrorCode::NoSuchAlert;
+ else if (errorName == "ElementNotSelectable")
+ m_errorCode = ErrorCode::ElementNotSelectable;
break;
}
@@ -127,6 +129,7 @@
// 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:
@@ -162,6 +165,8 @@
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:
Modified: trunk/Source/WebDriver/CommandResult.h (220739 => 220740)
--- trunk/Source/WebDriver/CommandResult.h 2017-08-15 06:51:49 UTC (rev 220739)
+++ trunk/Source/WebDriver/CommandResult.h 2017-08-15 07:03:13 UTC (rev 220740)
@@ -41,6 +41,7 @@
// https://www.w3.org/TR/webdriver/#handling-errors
enum class ErrorCode {
ElementClickIntercepted,
+ ElementNotSelectable,
ElementNotInteractable,
InvalidArgument,
InvalidElementState,
Modified: trunk/Source/WebDriver/Session.cpp (220739 => 220740)
--- trunk/Source/WebDriver/Session.cpp 2017-08-15 06:51:49 UTC (rev 220739)
+++ trunk/Source/WebDriver/Session.cpp 2017-08-15 07:03:13 UTC (rev 220740)
@@ -1191,6 +1191,21 @@
});
}
+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) {
@@ -1200,7 +1215,7 @@
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;
@@ -1214,9 +1229,27 @@
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));
+ });
});
}
Modified: trunk/Source/WebDriver/Session.h (220739 => 220740)
--- trunk/Source/WebDriver/Session.h 2017-08-15 06:51:49 UTC (rev 220739)
+++ trunk/Source/WebDriver/Session.h 2017-08-15 07:03:13 UTC (rev 220740)
@@ -137,6 +137,8 @@
};
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&&)>&&);
Modified: trunk/Source/WebKit/ChangeLog (220739 => 220740)
--- trunk/Source/WebKit/ChangeLog 2017-08-15 06:51:49 UTC (rev 220739)
+++ trunk/Source/WebKit/ChangeLog 2017-08-15 07:03:13 UTC (rev 220740)
@@ -1,3 +1,31 @@
+2017-08-14 Carlos Garcia Campos <cgar...@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.fra...@apple.com>
Remove Proximity Events and related code
Modified: trunk/Source/WebKit/UIProcess/Automation/Automation.json (220739 => 220740)
--- trunk/Source/WebKit/UIProcess/Automation/Automation.json 2017-08-15 06:51:49 UTC (rev 220739)
+++ trunk/Source/WebKit/UIProcess/Automation/Automation.json 2017-08-15 07:03:13 UTC (rev 220740)
@@ -59,7 +59,8 @@
"MissingParameter",
"InvalidParameter",
"InvalidSelector",
- "ElementNotInteractable"
+ "ElementNotInteractable",
+ "ElementNotSelectable"
]
},
{
@@ -430,6 +431,16 @@
"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.",
"parameters": [
Modified: trunk/Source/WebKit/UIProcess/Automation/WebAutomationSession.cpp (220739 => 220740)
--- trunk/Source/WebKit/UIProcess/Automation/WebAutomationSession.cpp 2017-08-15 06:51:49 UTC (rev 220739)
+++ trunk/Source/WebKit/UIProcess/Automation/WebAutomationSession.cpp 2017-08-15 07:03:13 UTC (rev 220740)
@@ -845,6 +845,37 @@
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);
Modified: trunk/Source/WebKit/UIProcess/Automation/WebAutomationSession.h (220739 => 220740)
--- trunk/Source/WebKit/UIProcess/Automation/WebAutomationSession.h 2017-08-15 06:51:49 UTC (rev 220739)
+++ trunk/Source/WebKit/UIProcess/Automation/WebAutomationSession.h 2017-08-15 07:03:13 UTC (rev 220740)
@@ -133,6 +133,7 @@
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;
@@ -176,6 +177,7 @@
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);
@@ -241,6 +243,9 @@
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;
Modified: trunk/Source/WebKit/UIProcess/Automation/WebAutomationSession.messages.in (220739 => 220740)
--- trunk/Source/WebKit/UIProcess/Automation/WebAutomationSession.messages.in 2017-08-15 06:51:49 UTC (rev 220739)
+++ trunk/Source/WebKit/UIProcess/Automation/WebAutomationSession.messages.in 2017-08-15 07:03:13 UTC (rev 220740)
@@ -28,6 +28,8 @@
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)
Modified: trunk/Source/WebKit/WebProcess/Automation/WebAutomationSessionProxy.cpp (220739 => 220740)
--- trunk/Source/WebKit/WebProcess/Automation/WebAutomationSessionProxy.cpp 2017-08-15 06:51:49 UTC (rev 220739)
+++ trunk/Source/WebKit/WebProcess/Automation/WebAutomationSessionProxy.cpp 2017-08-15 07:03:13 UTC (rev 220740)
@@ -48,6 +48,9 @@
#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>
@@ -503,6 +506,32 @@
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);
@@ -527,9 +556,12 @@
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();
@@ -542,15 +574,65 @@
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;
Modified: trunk/Source/WebKit/WebProcess/Automation/WebAutomationSessionProxy.h (220739 => 220740)
--- trunk/Source/WebKit/WebProcess/Automation/WebAutomationSessionProxy.h 2017-08-15 06:51:49 UTC (rev 220739)
+++ trunk/Source/WebKit/WebProcess/Automation/WebAutomationSessionProxy.h 2017-08-15 07:03:13 UTC (rev 220740)
@@ -65,6 +65,7 @@
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);
Modified: trunk/Source/WebKit/WebProcess/Automation/WebAutomationSessionProxy.messages.in (220739 => 220740)
--- trunk/Source/WebKit/WebProcess/Automation/WebAutomationSessionProxy.messages.in 2017-08-15 06:51:49 UTC (rev 220739)
+++ trunk/Source/WebKit/WebProcess/Automation/WebAutomationSessionProxy.messages.in 2017-08-15 07:03:13 UTC (rev 220740)
@@ -32,6 +32,8 @@
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)