Changeset 220740 in webkit


Ignore:
Timestamp:
Aug 15, 2017 12:03:13 AM (7 years ago)
Author:
Carlos Garcia Campos
Message:

WebDriver: handle click events on option elements
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.
Location:
trunk/Source
Files:
16 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/WebCore/ChangeLog

    r220734 r220740  
     12017-08-14  Carlos Garcia Campos  <cgarcia@igalia.com>
     2
     3        WebDriver: handle click events on option elements
     4        https://bugs.webkit.org/show_bug.cgi?id=174710
     5        <rdar://problem/33459305>
     6
     7        Reviewed by Brian Burg.
     8
     9        Export WebCore symbols required by WebKit layer.
     10
     11        * html/HTMLOptGroupElement.h:
     12        * html/HTMLOptionElement.h:
     13
    1142017-08-14  Simon Fraser  <simon.fraser@apple.com>
    215
  • trunk/Source/WebCore/html/HTMLOptGroupElement.h

    r208179 r220740  
    3535
    3636    bool isDisabledFormControl() const final;
    37     HTMLSelectElement* ownerSelectElement() const;
     37    WEBCORE_EXPORT HTMLSelectElement* ownerSelectElement() const;
    3838   
    3939    WEBCORE_EXPORT String groupLabelText() const;
  • trunk/Source/WebCore/html/HTMLOptionElement.h

    r217168 r220740  
    5050
    5151#if ENABLE(DATALIST_ELEMENT)
    52     HTMLDataListElement* ownerDataListElement() const;
     52    WEBCORE_EXPORT HTMLDataListElement* ownerDataListElement() const;
    5353#endif
    54     HTMLSelectElement* ownerSelectElement() const;
     54    WEBCORE_EXPORT HTMLSelectElement* ownerSelectElement() const;
    5555
    5656    WEBCORE_EXPORT String label() const;
     
    6060    bool ownElementDisabled() const { return m_disabled; }
    6161
    62     bool isDisabledFormControl() const final;
     62    WEBCORE_EXPORT bool isDisabledFormControl() const final;
    6363
    6464    String textIndentedToRespectGroupLabel() const;
  • trunk/Source/WebDriver/ChangeLog

    r220584 r220740  
     12017-08-14  Carlos Garcia Campos  <cgarcia@igalia.com>
     2
     3        WebDriver: handle click events on option elements
     4        https://bugs.webkit.org/show_bug.cgi?id=174710
     5        <rdar://problem/33459305>
     6
     7        Reviewed by Brian Burg.
     8
     9        Option elements are considered as a special case by the specification. When clicking an option element, we
     10        should get its container and use it when scrolling into view and calculating in-view center point instead of the
     11        option element itself. Then, we should not emulate a click, but change the selected status of the option element
     12        like if it were done by a user action, firing the corresponding events. Now we check whether the element is an
     13        option to call selectOptionElement() or performMouseInteraction().
     14
     15        This fixes more than 20 selenium tests.
     16
     17        * CommandResult.cpp:
     18        (WebDriver::CommandResult::CommandResult): Handle ElementNotSelectable protocol error.
     19        (WebDriver::CommandResult::httpStatusCode const): Add ElementNotSelectable.
     20        (WebDriver::CommandResult::errorString const): Ditto.
     21        * CommandResult.h:
     22        * Session.cpp:
     23        (WebDriver::Session::selectOptionElement): Ask automation to select the given option element.
     24        (WebDriver::Session::elementClick): Call selectOptionElement() or performMouseInteraction() depending on whether
     25        the element is an option or not.
     26        * Session.h:
     27
    1282017-08-11  Carlos Alberto Lopez Perez  <clopez@igalia.com>
    229
  • trunk/Source/WebDriver/CommandResult.cpp

    r220394 r220740  
    107107        else if (errorName == "NoJavaScriptDialog")
    108108            m_errorCode = ErrorCode::NoSuchAlert;
     109        else if (errorName == "ElementNotSelectable")
     110            m_errorCode = ErrorCode::ElementNotSelectable;
    109111
    110112        break;
     
    128130    switch (m_errorCode.value()) {
    129131    case ErrorCode::ElementClickIntercepted:
     132    case ErrorCode::ElementNotSelectable:
    130133    case ErrorCode::ElementNotInteractable:
    131134    case ErrorCode::InvalidArgument:
     
    163166    case ErrorCode::ElementClickIntercepted:
    164167        return ASCIILiteral("element click intercepted");
     168    case ErrorCode::ElementNotSelectable:
     169        return ASCIILiteral("element not selectable");
    165170    case ErrorCode::ElementNotInteractable:
    166171        return ASCIILiteral("element not interactable");
  • trunk/Source/WebDriver/CommandResult.h

    r220388 r220740  
    4242    enum class ErrorCode {
    4343        ElementClickIntercepted,
     44        ElementNotSelectable,
    4445        ElementNotInteractable,
    4546        InvalidArgument,
  • trunk/Source/WebDriver/Session.cpp

    r220388 r220740  
    11921192}
    11931193
     1194void Session::selectOptionElement(const String& elementID, Function<void (CommandResult&&)>&& completionHandler)
     1195{
     1196    RefPtr<InspectorObject> parameters = InspectorObject::create();
     1197    parameters->setString(ASCIILiteral("browsingContextHandle"), m_toplevelBrowsingContext.value());
     1198    parameters->setString(ASCIILiteral("frameHandle"), m_currentBrowsingContext.value());
     1199    parameters->setString(ASCIILiteral("nodeHandle"), elementID);
     1200    m_host->sendCommandToBackend(ASCIILiteral("selectOptionElement"), WTFMove(parameters), [this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)](SessionHost::CommandResponse&& response) {
     1201        if (response.isError) {
     1202            completionHandler(CommandResult::fail(WTFMove(response.responseObject)));
     1203            return;
     1204        }
     1205        completionHandler(CommandResult::success());
     1206    });
     1207}
     1208
    11941209void Session::elementClick(const String& elementID, Function<void (CommandResult&&)>&& completionHandler)
    11951210{
     
    12011216    OptionSet<ElementLayoutOption> options = ElementLayoutOption::ScrollIntoViewIfNeeded;
    12021217    options |= ElementLayoutOption::UseViewportCoordinates;
    1203     computeElementLayout(elementID, options, [this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)](std::optional<Rect>&& rect, std::optional<Point>&& inViewCenter, bool isObscured, RefPtr<InspectorObject>&& error) mutable {
     1218    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 {
    12041219        if (!rect || error) {
    12051220            completionHandler(CommandResult::fail(WTFMove(error)));
     
    12151230        }
    12161231
    1217         performMouseInteraction(inViewCenter.value().x, inViewCenter.value().y, MouseButton::Left, MouseInteraction::SingleClick, WTFMove(completionHandler));
    1218 
    1219         waitForNavigationToComplete(WTFMove(completionHandler));
     1232        getElementTagName(elementID, [this, elementID, inViewCenter = WTFMove(inViewCenter), isObscured, completionHandler = WTFMove(completionHandler)](CommandResult&& result) mutable {
     1233            bool isOptionElement = false;
     1234            if (!result.isError()) {
     1235                String tagName;
     1236                if (result.result()->asString(tagName))
     1237                    isOptionElement = tagName == "option";
     1238            }
     1239
     1240            Function<void (CommandResult&&)> continueAfterClickFunction = [this, completionHandler = WTFMove(completionHandler)](CommandResult&& result) mutable {
     1241                if (result.isError()) {
     1242                    completionHandler(WTFMove(result));
     1243                    return;
     1244                }
     1245
     1246                waitForNavigationToComplete(WTFMove(completionHandler));
     1247            };
     1248            if (isOptionElement)
     1249                selectOptionElement(elementID, WTFMove(continueAfterClickFunction));
     1250            else
     1251                performMouseInteraction(inViewCenter.value().x, inViewCenter.value().y, MouseButton::Left, MouseInteraction::SingleClick, WTFMove(continueAfterClickFunction));
     1252        });
    12201253    });
    12211254}
  • trunk/Source/WebDriver/Session.h

    r220388 r220740  
    138138    void computeElementLayout(const String& elementID, OptionSet<ElementLayoutOption>, Function<void (std::optional<Rect>&&, std::optional<Point>&&, bool, RefPtr<Inspector::InspectorObject>&&)>&&);
    139139
     140    void selectOptionElement(const String& elementID, Function<void (CommandResult&&)>&&);
     141
    140142    enum class MouseButton { None, Left, Middle, Right };
    141143    enum class MouseInteraction { Move, Down, Up, SingleClick, DoubleClick };
  • trunk/Source/WebKit/ChangeLog

    r220734 r220740  
     12017-08-14  Carlos Garcia Campos  <cgarcia@igalia.com>
     2
     3        WebDriver: handle click events on option elements
     4        https://bugs.webkit.org/show_bug.cgi?id=174710
     5        <rdar://problem/33459305>
     6
     7        Reviewed by Brian Burg.
     8
     9        Add selectOptionElement method to automation to select an option element according to the WebDriver
     10        specification.
     11
     12        14.1 Element Click.
     13        https://w3c.github.io/webdriver/webdriver-spec.html#element-click
     14
     15        * UIProcess/Automation/Automation.json: Add selectOptionElement method and ElementNotSelectable error.
     16        * UIProcess/Automation/WebAutomationSession.cpp:
     17        (WebKit::WebAutomationSession::selectOptionElement):Send SelectOptionElement message to the web process.
     18        (WebKit::WebAutomationSession::didSelectOptionElement): Notify the driver.
     19        * UIProcess/Automation/WebAutomationSession.h:
     20        * UIProcess/Automation/WebAutomationSession.messages.in: Add DidSelectOptionElement message.
     21        * WebProcess/Automation/WebAutomationSessionProxy.cpp:
     22        (WebKit::elementContainer): Helper to get the container of an element according to the spec.
     23        (WebKit::WebAutomationSessionProxy::computeElementLayout): Use the container element to scroll the view and
     24        compute the in-view center point.
     25        (WebKit::WebAutomationSessionProxy::selectOptionElement): Use HTMLSelectElement::optionSelectedByUser().
     26        * WebProcess/Automation/WebAutomationSessionProxy.h:
     27        * WebProcess/Automation/WebAutomationSessionProxy.messages.in: Add SelectOptionElement message.
     28
    1292017-08-14  Simon Fraser  <simon.fraser@apple.com>
    230
  • trunk/Source/WebKit/UIProcess/Automation/Automation.json

    r220394 r220740  
    6060                "InvalidParameter",
    6161                "InvalidSelector",
    62                 "ElementNotInteractable"
     62                "ElementNotInteractable",
     63                "ElementNotSelectable"
    6364            ]
    6465        },
     
    431432        },
    432433        {
     434            "name": "selectOptionElement",
     435            "description": "Selects the given option element. In case of container with multiple options enabled, the element selectedness is toggled.",
     436            "parameters": [
     437                { "name": "browsingContextHandle", "$ref": "BrowsingContextHandle", "description": "The handle for the browsing context." },
     438                { "name": "frameHandle", "$ref": "FrameHandle", "description": "The handle for the frame that contains the element." },
     439                { "name": "nodeHandle", "$ref": "NodeHandle", "description": "The handle of the element to use." }
     440            ],
     441            "async": true
     442        },
     443        {
    433444            "name": "isShowingJavaScriptDialog",
    434445            "description": "Checks if a browsing context is showing a JavaScript alert, confirm, or prompt dialog.",
  • trunk/Source/WebKit/UIProcess/Automation/WebAutomationSession.cpp

    r220394 r220740  
    846846}
    847847
     848void WebAutomationSession::selectOptionElement(Inspector::ErrorString& errorString, const String& browsingContextHandle, const String& frameHandle, const String& nodeHandle, Ref<SelectOptionElementCallback>&& callback)
     849{
     850    WebPageProxy* page = webPageProxyForHandle(browsingContextHandle);
     851    if (!page)
     852        FAIL_WITH_PREDEFINED_ERROR(WindowNotFound);
     853
     854    std::optional<uint64_t> frameID = webFrameIDForHandle(frameHandle);
     855    if (!frameID)
     856        FAIL_WITH_PREDEFINED_ERROR(FrameNotFound);
     857
     858    uint64_t callbackID = m_nextSelectOptionElementCallbackID++;
     859    m_selectOptionElementCallbacks.set(callbackID, WTFMove(callback));
     860
     861    page->process().send(Messages::WebAutomationSessionProxy::SelectOptionElement(page->pageID(), frameID.value(), nodeHandle, callbackID), 0);
     862}
     863
     864void WebAutomationSession::didSelectOptionElement(uint64_t callbackID, const String& errorType)
     865{
     866    auto callback = m_selectOptionElementCallbacks.take(callbackID);
     867    if (!callback)
     868        return;
     869
     870    if (!errorType.isEmpty()) {
     871        callback->sendFailure(STRING_FOR_PREDEFINED_ERROR_MESSAGE(errorType));
     872        return;
     873    }
     874
     875    callback->sendSuccess();
     876}
     877
     878
    848879void WebAutomationSession::isShowingJavaScriptDialog(Inspector::ErrorString& errorString, const String& browsingContextHandle, bool* result)
    849880{
  • trunk/Source/WebKit/UIProcess/Automation/WebAutomationSession.h

    r220317 r220740  
    134134    void resolveParentFrameHandle(Inspector::ErrorString&, const String& browsingContextHandle, const String& frameHandle, Ref<ResolveParentFrameHandleCallback>&&) override;
    135135    void computeElementLayout(Inspector::ErrorString&, const String& browsingContextHandle, const String& frameHandle, const String& nodeHandle, const bool* optionalScrollIntoViewIfNeeded, const bool* useViewportCoordinates, Ref<Inspector::AutomationBackendDispatcherHandler::ComputeElementLayoutCallback>&&) override;
     136    void selectOptionElement(Inspector::ErrorString&, const String& browsingContextHandle, const String& frameHandle, const String& nodeHandle, Ref<Inspector::AutomationBackendDispatcherHandler::SelectOptionElementCallback>&&) override;
    136137    void isShowingJavaScriptDialog(Inspector::ErrorString&, const String& browsingContextHandle, bool* result) override;
    137138    void dismissCurrentJavaScriptDialog(Inspector::ErrorString&, const String& browsingContextHandle) override;
     
    177178    void didResolveParentFrame(uint64_t callbackID, uint64_t frameID, const String& errorType);
    178179    void didComputeElementLayout(uint64_t callbackID, WebCore::IntRect, std::optional<WebCore::IntPoint>, bool isObscured, const String& errorType);
     180    void didSelectOptionElement(uint64_t callbackID, const String& errorType);
    179181    void didTakeScreenshot(uint64_t callbackID, const ShareableBitmap::Handle&, const String& errorType);
    180182    void didGetCookiesForFrame(uint64_t callbackID, Vector<WebCore::Cookie>, const String& errorType);
     
    242244    HashMap<uint64_t, RefPtr<Inspector::AutomationBackendDispatcherHandler::DeleteSingleCookieCallback>> m_deleteCookieCallbacks;
    243245
     246    uint64_t m_nextSelectOptionElementCallbackID { 1 };
     247    HashMap<uint64_t, RefPtr<Inspector::AutomationBackendDispatcherHandler::SelectOptionElementCallback>> m_selectOptionElementCallbacks;
     248
    244249    RunLoop::Timer<WebAutomationSession> m_loadTimer;
    245250    Vector<String> m_filesToSelectForFileUpload;
  • trunk/Source/WebKit/UIProcess/Automation/WebAutomationSession.messages.in

    r220314 r220740  
    2929    DidComputeElementLayout(uint64_t callbackID, WebCore::IntRect rect, std::optional<WebCore::IntPoint> inViewCenterPoint, bool isObscured, String errorType)
    3030
     31    DidSelectOptionElement(uint64_t callbackID, String errorType)
     32
    3133    DidTakeScreenshot(uint64_t callbackID, WebKit::ShareableBitmap::Handle imageDataHandle, String errorType)
    3234
  • trunk/Source/WebKit/WebProcess/Automation/WebAutomationSessionProxy.cpp

    r220314 r220740  
    4949#include <WebCore/FrameView.h>
    5050#include <WebCore/HTMLFrameElementBase.h>
     51#include <WebCore/HTMLOptGroupElement.h>
     52#include <WebCore/HTMLOptionElement.h>
     53#include <WebCore/HTMLSelectElement.h>
    5154#include <WebCore/JSElement.h>
    5255#include <WebCore/MainFrame.h>
     
    504507}
    505508
     509static WebCore::Element* containerElementForElement(WebCore::Element& element)
     510{
     511    // §13. Element State.
     512    // https://w3c.github.io/webdriver/webdriver-spec.html#dfn-container.
     513    if (is<WebCore::HTMLOptionElement>(element)) {
     514        auto& optionElement = downcast<WebCore::HTMLOptionElement>(element);
     515#if ENABLE(DATALIST_ELEMENT)
     516        if (auto* parentElement = optionElement.ownerDataListElement())
     517            return parentElement;
     518#endif
     519        if (auto* parentElement = optionElement.ownerSelectElement())
     520            return parentElement;
     521
     522        return nullptr;
     523    }
     524
     525    if (is<WebCore::HTMLOptGroupElement>(element)) {
     526        if (auto* parentElement = downcast<WebCore::HTMLOptGroupElement>(element).ownerSelectElement())
     527            return parentElement;
     528
     529        return nullptr;
     530    }
     531
     532    return &element;
     533}
     534
    506535void WebAutomationSessionProxy::computeElementLayout(uint64_t pageID, uint64_t frameID, String nodeHandle, bool scrollIntoViewIfNeeded, bool useViewportCoordinates, uint64_t callbackID)
    507536{
     
    528557    }
    529558
    530     if (scrollIntoViewIfNeeded) {
     559    auto* containerElement = containerElementForElement(*coreElement);
     560    if (scrollIntoViewIfNeeded && containerElement) {
     561        // §14.1 Element Click. Step 4. Scroll into view the element’s container.
     562        // https://w3c.github.io/webdriver/webdriver-spec.html#element-click
     563        containerElement->scrollIntoViewIfNeeded(false);
    531564        // FIXME: Wait in an implementation-specific way up to the session implicit wait timeout for the element to become in view.
    532         coreElement->scrollIntoViewIfNeeded(false);
    533565    }
    534566
     
    543575    bool isObscured = false;
    544576    std::optional<WebCore::IntPoint> inViewCenter;
    545     if (auto clientCenterPoint = elementInViewClientCenterPoint(*coreElement, isObscured)) {
    546         inViewCenter = WebCore::IntPoint(coreFrameView->clientToDocumentPoint(clientCenterPoint.value()));
    547         if (useViewportCoordinates)
    548             inViewCenter = coreFrameView->contentsToRootView(inViewCenter.value());
     577    if (containerElement) {
     578        if (auto clientCenterPoint = elementInViewClientCenterPoint(*containerElement, isObscured)) {
     579            inViewCenter = WebCore::IntPoint(coreFrameView->clientToDocumentPoint(clientCenterPoint.value()));
     580            if (useViewportCoordinates)
     581                inViewCenter = coreFrameView->contentsToRootView(inViewCenter.value());
     582        }
    549583    }
    550584
    551585    WebProcess::singleton().parentProcessConnection()->send(Messages::WebAutomationSession::DidComputeElementLayout(callbackID, rect, inViewCenter, isObscured, String()), 0);
     586}
     587
     588void WebAutomationSessionProxy::selectOptionElement(uint64_t pageID, uint64_t frameID, String nodeHandle, uint64_t callbackID)
     589{
     590    WebPage* page = WebProcess::singleton().webPage(pageID);
     591    if (!page) {
     592        String windowNotFoundErrorType = Inspector::Protocol::AutomationHelpers::getEnumConstantValue(Inspector::Protocol::Automation::ErrorMessage::WindowNotFound);
     593        WebProcess::singleton().parentProcessConnection()->send(Messages::WebAutomationSession::DidSelectOptionElement(callbackID, windowNotFoundErrorType), 0);
     594        return;
     595    }
     596
     597    WebFrame* frame = frameID ? WebProcess::singleton().webFrame(frameID) : page->mainWebFrame();
     598    if (!frame || !frame->coreFrame() || !frame->coreFrame()->view()) {
     599        String frameNotFoundErrorType = Inspector::Protocol::AutomationHelpers::getEnumConstantValue(Inspector::Protocol::Automation::ErrorMessage::FrameNotFound);
     600        WebProcess::singleton().parentProcessConnection()->send(Messages::WebAutomationSession::DidSelectOptionElement(callbackID, frameNotFoundErrorType), 0);
     601        return;
     602    }
     603
     604    WebCore::Element* coreElement = elementForNodeHandle(*frame, nodeHandle);
     605    if (!coreElement || (!is<WebCore::HTMLOptionElement>(coreElement) && !is<WebCore::HTMLOptGroupElement>(coreElement))) {
     606        String nodeNotFoundErrorType = Inspector::Protocol::AutomationHelpers::getEnumConstantValue(Inspector::Protocol::Automation::ErrorMessage::NodeNotFound);
     607        WebProcess::singleton().parentProcessConnection()->send(Messages::WebAutomationSession::DidSelectOptionElement(callbackID, nodeNotFoundErrorType), 0);
     608        return;
     609    }
     610
     611    String elementNotInteractableErrorType = Inspector::Protocol::AutomationHelpers::getEnumConstantValue(Inspector::Protocol::Automation::ErrorMessage::ElementNotInteractable);
     612    if (is<WebCore::HTMLOptGroupElement>(coreElement)) {
     613        WebProcess::singleton().parentProcessConnection()->send(Messages::WebAutomationSession::DidSelectOptionElement(callbackID, elementNotInteractableErrorType), 0);
     614        return;
     615    }
     616
     617    auto& optionElement = downcast<WebCore::HTMLOptionElement>(*coreElement);
     618    auto* selectElement = optionElement.ownerSelectElement();
     619    if (!selectElement) {
     620        WebProcess::singleton().parentProcessConnection()->send(Messages::WebAutomationSession::DidSelectOptionElement(callbackID, elementNotInteractableErrorType), 0);
     621        return;
     622    }
     623
     624    if (selectElement->isDisabledFormControl() || optionElement.isDisabledFormControl()) {
     625        String elementNotSelectableErrorType = Inspector::Protocol::AutomationHelpers::getEnumConstantValue(Inspector::Protocol::Automation::ErrorMessage::ElementNotSelectable);
     626        WebProcess::singleton().parentProcessConnection()->send(Messages::WebAutomationSession::DidSelectOptionElement(callbackID, elementNotSelectableErrorType), 0);
     627        return;
     628    }
     629
     630    // FIXME: According to the spec we should fire mouse over, move and down events, then input and change, and finally mouse up and click.
     631    // optionSelectedByUser() will fire input and change events if needed, but all other events should be fired manually here.
     632    selectElement->optionSelectedByUser(optionElement.index(), true, selectElement->multiple());
     633    WebProcess::singleton().parentProcessConnection()->send(Messages::WebAutomationSession::DidSelectOptionElement(callbackID, { }), 0);
    552634}
    553635
  • trunk/Source/WebKit/WebProcess/Automation/WebAutomationSessionProxy.h

    r219649 r220740  
    6666    void focusFrame(uint64_t pageID, uint64_t frameID);
    6767    void computeElementLayout(uint64_t pageID, uint64_t frameID, String nodeHandle, bool scrollIntoViewIfNeeded, bool useViewportCoordinates, uint64_t callbackID);
     68    void selectOptionElement(uint64_t pageID, uint64_t frameID, String nodeHandle, uint64_t callbackID);
    6869    void takeScreenshot(uint64_t pageID, uint64_t callbackID);
    6970    void getCookiesForFrame(uint64_t pageID, uint64_t frameID, uint64_t callbackID);
  • trunk/Source/WebKit/WebProcess/Automation/WebAutomationSessionProxy.messages.in

    r203245 r220740  
    3333    ComputeElementLayout(uint64_t pageID, uint64_t frameID, String nodeHandle, bool scrollIntoViewIfNeeded, bool useViewportCoordinates, uint64_t callbackID)
    3434
     35    SelectOptionElement(uint64_t pageID, uint64_t frameID, String nodeHandle, uint64_t callbackID)
     36
    3537    TakeScreenshot(uint64_t pageID, uint64_t callbackID)
    3638
Note: See TracChangeset for help on using the changeset viewer.