Changeset 289202 in webkit


Ignore:
Timestamp:
Feb 7, 2022, 2:25:15 AM (4 years ago)
Author:
Carlos Garcia Campos
Message:

[WebDriver] Add support for shadow roots
https://bugs.webkit.org/show_bug.cgi?id=230614
<rdar://problem/83667535>

Reviewed by Adrian Perez de Castro.

Source/WebDriver:

Add implementation of new shadow root commands.

  • CommandResult.cpp:

(WebDriver::CommandResult::httpStatusCode const): Handle NoSuchShadowRoot and DetachedShadowRoot errors
(WebDriver::CommandResult::errorString const): Ditto.

  • CommandResult.h:
  • Session.cpp:

(WebDriver::Session::shadowRootIdentifier): Return shadow root identifier.
(WebDriver::Session::createShadowRoot): Create shadow root elment using the shadow root identifier.
(WebDriver::Session::findElements): Add ElementIsShadowRoot parameters to handle DetachedShadowRoot error.
(WebDriver::Session::getElementShadowRoot): Return the element shadow root.

  • Session.h:
  • WebDriverService.cpp:

(WebDriver::WebDriverService::findElement): Pass ElementIsShadowRoot::No to Session::findElements().
(WebDriver::WebDriverService::findElements): Ditto.
(WebDriver::WebDriverService::findElementFromElement): Ditto.
(WebDriver::WebDriverService::findElementsFromElement): Ditto.
(WebDriver::WebDriverService::findElementFromShadowRoot):
(WebDriver::WebDriverService::findElementsFromShadowRoot):
(WebDriver::WebDriverService::getElementShadowRoot):

  • WebDriverService.h:

Source/WebKit:

Use querySelectorAll() instead of getElementsByTagName() because it is also available for shadow root.

  • UIProcess/Automation/atoms/FindNodes.js:

(tryToFindNode):

WebDriverTests:

Update test expectations.

Location:
trunk
Files:
11 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/WebDriver/ChangeLog

    r288950 r289202  
     12022-02-07  Carlos Garcia Campos  <cgarcia@igalia.com>
     2
     3        [WebDriver] Add support for shadow roots
     4        https://bugs.webkit.org/show_bug.cgi?id=230614
     5        <rdar://problem/83667535>
     6
     7        Reviewed by Adrian Perez de Castro.
     8
     9        Add implementation of new shadow root commands.
     10
     11        * CommandResult.cpp:
     12        (WebDriver::CommandResult::httpStatusCode const): Handle NoSuchShadowRoot and DetachedShadowRoot errors
     13        (WebDriver::CommandResult::errorString const): Ditto.
     14        * CommandResult.h:
     15        * Session.cpp:
     16        (WebDriver::Session::shadowRootIdentifier): Return shadow root identifier.
     17        (WebDriver::Session::createShadowRoot): Create shadow root elment using the shadow root identifier.
     18        (WebDriver::Session::findElements): Add ElementIsShadowRoot parameters to handle DetachedShadowRoot error.
     19        (WebDriver::Session::getElementShadowRoot): Return the element shadow root.
     20        * Session.h:
     21        * WebDriverService.cpp:
     22        (WebDriver::WebDriverService::findElement): Pass ElementIsShadowRoot::No to Session::findElements().
     23        (WebDriver::WebDriverService::findElements): Ditto.
     24        (WebDriver::WebDriverService::findElementFromElement): Ditto.
     25        (WebDriver::WebDriverService::findElementsFromElement): Ditto.
     26        (WebDriver::WebDriverService::findElementFromShadowRoot):
     27        (WebDriver::WebDriverService::findElementsFromShadowRoot):
     28        (WebDriver::WebDriverService::getElementShadowRoot):
     29        * WebDriverService.h:
     30
    1312022-02-02  Youenn Fablet  <youenn@apple.com>
    232
  • trunk/Source/WebDriver/CommandResult.cpp

    r278253 r289202  
    146146    case ErrorCode::NoSuchFrame:
    147147    case ErrorCode::NoSuchWindow:
     148    case ErrorCode::NoSuchShadowRoot:
    148149    case ErrorCode::StaleElementReference:
     150    case ErrorCode::DetachedShadowRoot:
    149151    case ErrorCode::InvalidSessionID:
    150152    case ErrorCode::UnknownCommand:
     
    177179    case ErrorCode::ElementNotInteractable:
    178180        return "element not interactable"_s;
     181    case ErrorCode::DetachedShadowRoot:
     182        return "detached shadow root"_s;
    179183    case ErrorCode::InvalidArgument:
    180184        return "invalid argument"_s;
     
    195199    case ErrorCode::NoSuchFrame:
    196200        return "no such frame"_s;
     201    case ErrorCode::NoSuchShadowRoot:
     202        return "no such shadow root"_s;
    197203    case ErrorCode::NoSuchWindow:
    198204        return "no such window"_s;
  • trunk/Source/WebDriver/CommandResult.h

    r278253 r289202  
    4040        ElementNotSelectable,
    4141        ElementNotInteractable,
     42        DetachedShadowRoot,
    4243        InvalidArgument,
    4344        InvalidElementState,
     
    5051        NoSuchElement,
    5152        NoSuchFrame,
     53        NoSuchShadowRoot,
    5254        NoSuchWindow,
    5355        ScriptTimeout,
  • trunk/Source/WebDriver/Session.cpp

    r282755 r289202  
    5353}
    5454
     55const String& Session::shadowRootIdentifier()
     56{
     57    // The shadow root identifier is constant defined by the spec.
     58    static NeverDestroyed<String> shadowRootID { "shadow-6066-11e4-a52e-4f735466cecf"_s };
     59    return shadowRootID;
     60}
     61
    5562Session::Session(std::unique_ptr<SessionHost>&& host)
    5663    : m_host(WTFMove(host))
     
    985992}
    986993
     994RefPtr<JSON::Object> Session::createShadowRoot(RefPtr<JSON::Value>&& value)
     995{
     996    if (!value)
     997        return nullptr;
     998
     999    auto valueObject = value->asObject();
     1000    if (!valueObject)
     1001        return nullptr;
     1002
     1003    auto elementID = valueObject->getString("session-node-" + id());
     1004    if (!elementID)
     1005        return nullptr;
     1006
     1007    auto elementObject = JSON::Object::create();
     1008    elementObject->setString(shadowRootIdentifier(), elementID);
     1009    return elementObject;
     1010}
     1011
    9871012RefPtr<JSON::Object> Session::extractElement(JSON::Value& value)
    9881013{
     
    10761101}
    10771102
    1078 void Session::findElements(const String& strategy, const String& selector, FindElementsMode mode, const String& rootElementID, Function<void (CommandResult&&)>&& completionHandler)
     1103void Session::findElements(const String& strategy, const String& selector, FindElementsMode mode, const String& rootElementID, ElementIsShadowRoot isShadowRoot, Function<void(CommandResult&&)>&& completionHandler)
    10791104{
    10801105    if (!m_currentBrowsingContext) {
     
    10831108    }
    10841109
    1085     handleUserPrompts([this, protectedThis = Ref { *this }, strategy, selector, mode, rootElementID, completionHandler = WTFMove(completionHandler)](CommandResult&& result) mutable {
     1110    handleUserPrompts([this, protectedThis = Ref { *this }, strategy, selector, mode, rootElementID, isShadowRoot, completionHandler = WTFMove(completionHandler)](CommandResult&& result) mutable {
    10861111        if (result.isError()) {
    10871112            completionHandler(WTFMove(result));
     
    11091134            parameters->setDouble("callbackTimeout"_s, m_implicitWaitTimeout + 1000);
    11101135
    1111         m_host->sendCommandToBackend("evaluateJavaScriptFunction"_s, WTFMove(parameters), [this, protectedThis, mode, completionHandler = WTFMove(completionHandler)](SessionHost::CommandResponse&& response) {
     1136        m_host->sendCommandToBackend("evaluateJavaScriptFunction"_s, WTFMove(parameters), [this, protectedThis, mode, isShadowRoot, completionHandler = WTFMove(completionHandler)](SessionHost::CommandResponse&& response) {
    11121137            if (response.isError || !response.responseObject) {
    1113                 completionHandler(CommandResult::fail(WTFMove(response.responseObject)));
     1138                auto result = CommandResult::fail(WTFMove(response.responseObject));
     1139                if (isShadowRoot == ElementIsShadowRoot::Yes && result.errorCode() == CommandResult::ErrorCode::StaleElementReference) {
     1140                    completionHandler(CommandResult::fail(CommandResult::ErrorCode::DetachedShadowRoot));
     1141                    return;
     1142                }
     1143                completionHandler(WTFMove(result));
    11141144                return;
    11151145            }
     
    11961226            if (!elementObject) {
    11971227                completionHandler(CommandResult::fail(CommandResult::ErrorCode::NoSuchElement));
     1228                return;
     1229            }
     1230            completionHandler(CommandResult::success(WTFMove(elementObject)));
     1231        });
     1232    });
     1233}
     1234
     1235void Session::getElementShadowRoot(const String& elementID, Function<void(CommandResult&&)>&& completionHandler)
     1236{
     1237    if (!m_currentBrowsingContext) {
     1238        completionHandler(CommandResult::fail(CommandResult::ErrorCode::NoSuchWindow));
     1239        return;
     1240    }
     1241
     1242    handleUserPrompts([this, protectedThis = Ref { *this }, elementID, completionHandler = WTFMove(completionHandler)](CommandResult&& result) mutable {
     1243        if (result.isError()) {
     1244            completionHandler(WTFMove(result));
     1245            return;
     1246        }
     1247
     1248        auto arguments = JSON::Array::create();
     1249        arguments->pushString(createElement(elementID)->toJSONString());
     1250
     1251        auto parameters = JSON::Object::create();
     1252        parameters->setString("browsingContextHandle"_s, m_toplevelBrowsingContext.value());
     1253        if (m_currentBrowsingContext)
     1254            parameters->setString("frameHandle"_s, m_currentBrowsingContext.value());
     1255        parameters->setString("function"_s, "function(element) { return element.shadowRoot; }"_s);
     1256        parameters->setArray("arguments"_s, WTFMove(arguments));
     1257        m_host->sendCommandToBackend("evaluateJavaScriptFunction"_s, WTFMove(parameters), [this, protectedThis, completionHandler = WTFMove(completionHandler)](SessionHost::CommandResponse&& response) {
     1258            if (response.isError || !response.responseObject) {
     1259                completionHandler(CommandResult::fail(WTFMove(response.responseObject)));
     1260                return;
     1261            }
     1262
     1263            auto valueString = response.responseObject->getString("result"_s);
     1264            if (!valueString) {
     1265                completionHandler(CommandResult::fail(CommandResult::ErrorCode::UnknownError));
     1266                return;
     1267            }
     1268
     1269            auto resultValue = JSON::Value::parseJSON(valueString);
     1270            if (!resultValue) {
     1271                completionHandler(CommandResult::fail(CommandResult::ErrorCode::UnknownError));
     1272                return;
     1273            }
     1274
     1275            auto elementObject = createShadowRoot(WTFMove(resultValue));
     1276            if (!elementObject) {
     1277                completionHandler(CommandResult::fail(CommandResult::ErrorCode::NoSuchShadowRoot));
    11981278                return;
    11991279            }
  • trunk/Source/WebDriver/Session.h

    r278253 r289202  
    5656    double implicitWaitTimeout() const { return m_implicitWaitTimeout; }
    5757    static const String& webElementIdentifier();
     58    static const String& shadowRootIdentifier();
    5859
    5960    enum class FindElementsMode { Single, Multiple };
    6061    enum class ExecuteScriptMode { Sync, Async };
     62    enum class ElementIsShadowRoot { No, Yes };
    6163
    6264    struct Cookie {
     
    9799    void minimizeWindow(Function<void (CommandResult&&)>&&);
    98100    void fullscreenWindow(Function<void (CommandResult&&)>&&);
    99     void findElements(const String& strategy, const String& selector, FindElementsMode, const String& rootElementID, Function<void (CommandResult&&)>&&);
     101    void findElements(const String& strategy, const String& selector, FindElementsMode, const String& rootElementID, ElementIsShadowRoot, Function<void(CommandResult&&)>&&);
    100102    void getActiveElement(Function<void (CommandResult&&)>&&);
     103    void getElementShadowRoot(const String& elementID, Function<void(CommandResult&&)>&&);
    101104    void isElementSelected(const String& elementID, Function<void (CommandResult&&)>&&);
    102105    void getElementAttribute(const String& elementID, const String& attribute, Function<void (CommandResult&&)>&&);
     
    147150    RefPtr<JSON::Object> createElement(RefPtr<JSON::Value>&&);
    148151    Ref<JSON::Object> createElement(const String& elementID);
     152    RefPtr<JSON::Object> createShadowRoot(RefPtr<JSON::Value>&&);
    149153    RefPtr<JSON::Object> extractElement(JSON::Value&);
    150154    String extractElementID(JSON::Value&);
  • trunk/Source/WebDriver/WebDriverService.cpp

    r278253 r289202  
    174174    { HTTPMethod::Post, "/session/$sessionId/element/$elementId/element", &WebDriverService::findElementFromElement },
    175175    { HTTPMethod::Post, "/session/$sessionId/element/$elementId/elements", &WebDriverService::findElementsFromElement },
     176    { HTTPMethod::Post, "/session/$sessionId/shadow/$shadowId/element", &WebDriverService::findElementFromShadowRoot },
     177    { HTTPMethod::Post, "/session/$sessionId/shadow/$shadowId/elements", &WebDriverService::findElementsFromShadowRoot },
    176178    { HTTPMethod::Get, "/session/$sessionId/element/active", &WebDriverService::getActiveElement },
    177179
     180    { HTTPMethod::Get, "/session/$sessionId/element/$elementId/shadow", &WebDriverService::getElementShadowRoot },
    178181    { HTTPMethod::Get, "/session/$sessionId/element/$elementId/selected", &WebDriverService::isElementSelected },
    179182    { HTTPMethod::Get, "/session/$sessionId/element/$elementId/attribute/$name", &WebDriverService::getElementAttribute },
     
    12941297}
    12951298
    1296 static std::optional<String> findElementOrCompleteWithError(JSON::Object& parameters, Function<void (CommandResult&&)>& completionHandler)
    1297 {
    1298     auto elementID = parameters.getString("elementId"_s);
     1299static std::optional<String> findElementOrCompleteWithError(JSON::Object& parameters, Function<void (CommandResult&&)>& completionHandler, Session::ElementIsShadowRoot isShadowRoot = Session::ElementIsShadowRoot::No)
     1300{
     1301    auto elementID = parameters.getString(isShadowRoot == Session::ElementIsShadowRoot::Yes ? "shadowId"_s : "elementId"_s);
    12991302    if (elementID.isEmpty()) {
    13001303        completionHandler(CommandResult::fail(CommandResult::ErrorCode::InvalidArgument));
     
    13151318}
    13161319
    1317 static bool findStrategyAndSelectorOrCompleteWithError(JSON::Object& parameters, Function<void (CommandResult&&)>& completionHandler, String& strategy, String& selector)
     1320static bool findStrategyAndSelectorOrCompleteWithError(JSON::Object& parameters, Function<void (CommandResult&&)>& completionHandler, Session::ElementIsShadowRoot isShadowRoot, String& strategy, String& selector)
    13181321{
    13191322    strategy = parameters.getString("using"_s);
     
    13271330        return false;
    13281331    }
     1332
     1333    if (isShadowRoot == Session::ElementIsShadowRoot::Yes) {
     1334        // Currently there is an opened discussion about if the following values has to be supported for a Shadow Root
     1335        // because the current implementation doesn't support them. We have them disabled for now.
     1336        // https://github.com/w3c/webdriver/issues/1610
     1337        if (strategy == "tag name" || strategy == "xpath") {
     1338            completionHandler(CommandResult::fail(CommandResult::ErrorCode::InvalidSelector));
     1339            return false;
     1340        }
     1341    }
     1342
    13291343    return true;
    13301344}
     
    13381352
    13391353    String strategy, selector;
    1340     if (!findStrategyAndSelectorOrCompleteWithError(*parameters, completionHandler, strategy, selector))
     1354    if (!findStrategyAndSelectorOrCompleteWithError(*parameters, completionHandler, Session::ElementIsShadowRoot::No, strategy, selector))
    13411355        return;
    13421356
     
    13461360            return;
    13471361        }
    1348         m_session->findElements(strategy, selector, Session::FindElementsMode::Single, emptyString(), WTFMove(completionHandler));
     1362        m_session->findElements(strategy, selector, Session::FindElementsMode::Single, emptyString(), Session::ElementIsShadowRoot::No, WTFMove(completionHandler));
    13491363    });
    13501364}
     
    13581372
    13591373    String strategy, selector;
    1360     if (!findStrategyAndSelectorOrCompleteWithError(*parameters, completionHandler, strategy, selector))
     1374    if (!findStrategyAndSelectorOrCompleteWithError(*parameters, completionHandler, Session::ElementIsShadowRoot::No, strategy, selector))
    13611375        return;
    13621376
     
    13661380            return;
    13671381        }
    1368         m_session->findElements(strategy, selector, Session::FindElementsMode::Multiple, emptyString(), WTFMove(completionHandler));
     1382        m_session->findElements(strategy, selector, Session::FindElementsMode::Multiple, emptyString(), Session::ElementIsShadowRoot::No, WTFMove(completionHandler));
    13691383    });
    13701384}
     
    13821396
    13831397    String strategy, selector;
    1384     if (!findStrategyAndSelectorOrCompleteWithError(*parameters, completionHandler, strategy, selector))
    1385         return;
    1386 
    1387     m_session->findElements(strategy, selector, Session::FindElementsMode::Single, elementID.value(), WTFMove(completionHandler));
     1398    if (!findStrategyAndSelectorOrCompleteWithError(*parameters, completionHandler, Session::ElementIsShadowRoot::No, strategy, selector))
     1399        return;
     1400    m_session->findElements(strategy, selector, Session::FindElementsMode::Single, elementID.value(), Session::ElementIsShadowRoot::No, WTFMove(completionHandler));
    13881401}
    13891402
     
    14001413
    14011414    String strategy, selector;
    1402     if (!findStrategyAndSelectorOrCompleteWithError(*parameters, completionHandler, strategy, selector))
    1403         return;
    1404 
    1405     m_session->findElements(strategy, selector, Session::FindElementsMode::Multiple, elementID.value(), WTFMove(completionHandler));
     1415    if (!findStrategyAndSelectorOrCompleteWithError(*parameters, completionHandler, Session::ElementIsShadowRoot::No, strategy, selector))
     1416        return;
     1417
     1418    m_session->findElements(strategy, selector, Session::FindElementsMode::Multiple, elementID.value(), Session::ElementIsShadowRoot::No, WTFMove(completionHandler));
     1419}
     1420
     1421void WebDriverService::findElementFromShadowRoot(RefPtr<JSON::Object>&& parameters, Function<void(CommandResult&&)>&& completionHandler)
     1422{
     1423    if (!findSessionOrCompleteWithError(*parameters, completionHandler))
     1424        return;
     1425
     1426    auto shadowID = findElementOrCompleteWithError(*parameters, completionHandler, Session::ElementIsShadowRoot::Yes);
     1427    if (!shadowID)
     1428        return;
     1429
     1430    String strategy, selector;
     1431    if (!findStrategyAndSelectorOrCompleteWithError(*parameters, completionHandler, Session::ElementIsShadowRoot::Yes, strategy, selector))
     1432        return;
     1433
     1434    m_session->findElements(strategy, selector, Session::FindElementsMode::Single, shadowID.value(), Session::ElementIsShadowRoot::Yes, WTFMove(completionHandler));
     1435}
     1436
     1437void WebDriverService::findElementsFromShadowRoot(RefPtr<JSON::Object>&& parameters, Function<void(CommandResult&&)>&& completionHandler)
     1438{
     1439    if (!findSessionOrCompleteWithError(*parameters, completionHandler))
     1440        return;
     1441
     1442    auto shadowID = findElementOrCompleteWithError(*parameters, completionHandler, Session::ElementIsShadowRoot::Yes);
     1443    if (!shadowID)
     1444        return;
     1445
     1446    String strategy, selector;
     1447    if (!findStrategyAndSelectorOrCompleteWithError(*parameters, completionHandler, Session::ElementIsShadowRoot::Yes, strategy, selector))
     1448        return;
     1449
     1450    m_session->findElements(strategy, selector, Session::FindElementsMode::Multiple, shadowID.value(), Session::ElementIsShadowRoot::Yes, WTFMove(completionHandler));
    14061451}
    14071452
     
    14201465        m_session->getActiveElement(WTFMove(completionHandler));
    14211466    });
     1467}
     1468
     1469void WebDriverService::getElementShadowRoot(RefPtr<JSON::Object>&& parameters, Function<void(CommandResult&&)>&& completionHandler)
     1470{
     1471    if (!findSessionOrCompleteWithError(*parameters, completionHandler))
     1472        return;
     1473
     1474    auto elementID = findElementOrCompleteWithError(*parameters, completionHandler);
     1475    if (!elementID)
     1476        return;
     1477
     1478    m_session->getElementShadowRoot(elementID.value(), WTFMove(completionHandler));
    14221479}
    14231480
  • trunk/Source/WebDriver/WebDriverService.h

    r278253 r289202  
    8989    void findElementFromElement(RefPtr<JSON::Object>&&, Function<void (CommandResult&&)>&&);
    9090    void findElementsFromElement(RefPtr<JSON::Object>&&, Function<void (CommandResult&&)>&&);
     91    void findElementFromShadowRoot(RefPtr<JSON::Object>&&, Function<void(CommandResult&&)>&&);
     92    void findElementsFromShadowRoot(RefPtr<JSON::Object>&&, Function<void(CommandResult&&)>&&);
    9193    void getActiveElement(RefPtr<JSON::Object>&&, Function<void (CommandResult&&)>&&);
     94    void getElementShadowRoot(RefPtr<JSON::Object>&&, Function<void(CommandResult&&)>&&);
    9295    void isElementSelected(RefPtr<JSON::Object>&&, Function<void (CommandResult&&)>&&);
    9396    void getElementAttribute(RefPtr<JSON::Object>&&, Function<void (CommandResult&&)>&&);
  • trunk/Source/WebKit/ChangeLog

    r289200 r289202  
     12022-02-07  Carlos Garcia Campos  <cgarcia@igalia.com>
     2
     3        [WebDriver] Add support for shadow roots
     4        https://bugs.webkit.org/show_bug.cgi?id=230614
     5        <rdar://problem/83667535>
     6
     7        Reviewed by Adrian Perez de Castro.
     8
     9        Use querySelectorAll() instead of getElementsByTagName() because it is also available for shadow root.
     10
     11        * UIProcess/Automation/atoms/FindNodes.js:
     12        (tryToFindNode):
     13
    1142022-02-06  Sihui Liu  <sihui_liu@apple.com>
    215
  • trunk/Source/WebKit/UIProcess/Automation/atoms/FindNodes.js

    r225388 r289202  
    6767            case "link text":
    6868                let linkTextResult = [];
    69                 for (let link of ancestorElement.getElementsByTagName("a")) {
     69                for (let link of ancestorElement.querySelectorAll("a")) {
    7070                    if (link.text.trim() == query) {
    7171                        linkTextResult.push(link);
     
    8080            case "partial link text":
    8181                let partialLinkResult = [];
    82                 for (let link of ancestorElement.getElementsByTagName("a")) {
     82                for (let link of ancestorElement.querySelectorAll("a")) {
    8383                    if (link.text.includes(query)) {
    8484                        partialLinkResult.push(link);
  • trunk/WebDriverTests/ChangeLog

    r289047 r289202  
     12022-02-07  Carlos Garcia Campos  <cgarcia@igalia.com>
     2
     3        [WebDriver] Add support for shadow roots
     4        https://bugs.webkit.org/show_bug.cgi?id=230614
     5        <rdar://problem/83667535>
     6
     7        Reviewed by Adrian Perez de Castro.
     8
     9        Update test expectations.
     10
     11        * TestExpectations.json:
     12
    1132022-02-03  Carlos Garcia Campos  <cgarcia@igalia.com>
    214
  • trunk/WebDriverTests/TestExpectations.json

    r288871 r289202  
    15701570    },
    15711571    "imported/w3c/webdriver/tests/find_element_from_shadow_root/find.py": {
    1572         "expected": { "all": { "status": ["SKIP"], "bug": "webkit.org/b/230614"}}
    1573     },
    1574     "imported/w3c/webdriver/tests/find_element_from_shadow_root/user_prompts.py": {
    1575         "expected": { "all": { "status": ["SKIP"], "bug": "webkit.org/b/230614"}}
     1572        "subtests": {
     1573            "test_find_element[tag name-a]": {
     1574                "expected": { "all": { "status": ["SKIP"]}}
     1575            },
     1576            "test_find_element[xpath-//a]": {
     1577                "expected": { "all": { "status": ["SKIP"]}}
     1578            },
     1579            "test_find_element_link_text[<a href=#>link<br>text</a>-link\\ntext]": {
     1580                "expected": {"all": {"status": ["FAIL"], "bug": "webkit.org/b/184964"}}
     1581            },
     1582            "test_find_element_link_text[<a href=# style='text-transform: uppercase'>link text</a>-LINK TEXT]": {
     1583                "expected": {"all": {"status": ["FAIL"], "bug": "webkit.org/b/184964"}}
     1584            },
     1585            "test_find_element_partial_link_text[<a href=#>partial link<br>text</a>-k\\nt]": {
     1586                "expected": {"all": {"status": ["FAIL"], "bug": "webkit.org/b/184964"}}
     1587            },
     1588            "test_find_element_partial_link_text[<a href=# style='text-transform: uppercase'>partial link text</a>-LINK]": {
     1589                "expected": {"all": {"status": ["FAIL"], "bug": "webkit.org/b/184964"}}
     1590            }
     1591        }
    15761592    },
    15771593    "imported/w3c/webdriver/tests/find_elements_from_shadow_root/find.py": {
    1578         "expected": { "all": { "status": ["SKIP"], "bug": "webkit.org/b/230614"}}
    1579     },
    1580     "imported/w3c/webdriver/tests/find_elements_from_shadow_root/user_prompts.py": {
    1581         "expected": { "all": { "status": ["SKIP"], "bug": "webkit.org/b/230614"}}
     1594        "subtests": {
     1595            "test_find_elements[tag name-a]": {
     1596                "expected": { "all": { "status": ["SKIP"]}}
     1597            },
     1598            "test_find_elements[xpath-//a]": {
     1599                "expected": { "all": { "status": ["SKIP"]}}
     1600            },
     1601            "test_find_elements_link_text[<a href=#>link<br>text</a>-link\\ntext]": {
     1602                "expected": {"all": {"status": ["FAIL"], "bug": "webkit.org/b/184964"}}
     1603            },
     1604            "test_find_elements_link_text[<a href=# style='text-transform: uppercase'>link text</a>-LINK TEXT]": {
     1605                "expected": {"all": {"status": ["FAIL"], "bug": "webkit.org/b/184964"}}
     1606            },
     1607            "test_find_elements_partial_link_text[<a href=#>partial link<br>text</a>-k\\nt]": {
     1608                "expected": {"all": {"status": ["FAIL"], "bug": "webkit.org/b/184964"}}
     1609            },
     1610            "test_find_elements_partial_link_text[<a href=# style='text-transform: uppercase'>partial link text</a>-LINK]": {
     1611                "expected": {"all": {"status": ["FAIL"], "bug": "webkit.org/b/184964"}}
     1612            }
     1613        }
    15821614    },
    15831615    "imported/w3c/webdriver/tests/get_element_shadow_root/get.py": {
    1584         "expected": { "all": { "status": ["SKIP"], "bug": "webkit.org/b/230614"}}
    1585     },
    1586     "imported/w3c/webdriver/tests/get_element_shadow_root/user_prompts.py": {
    1587         "expected": { "all": { "status": ["SKIP"], "bug": "webkit.org/b/230614"}}
     1616        "subtests": {
     1617            "test_no_top_browsing_context": {
     1618                "expected": {
     1619                    "wpe": {"status": ["FAIL"], "bug": "webkit.org/b/212950"},
     1620                    "gtk": {"status": ["FAIL"], "bug": "webkit.org/b/230612"}
     1621                }
     1622            }
     1623        }
    15881624    },
    15891625    "imported/w3c/webdriver/tests/bidi/new_session/connect.py": {
Note: See TracChangeset for help on using the changeset viewer.