diff --git a/resources/testdriver.js b/resources/testdriver.js index e7df7ede41eb97..b0355af84a9418 100644 --- a/resources/testdriver.js +++ b/resources/testdriver.js @@ -1194,6 +1194,32 @@ return role; }, + /** + * Get accessibility properties for an element. + * + * @param {Element} element + * @returns {Promise} fulfilled after the accessibility properties are + * returned, or rejected in the cases the WebDriver + * command errors + */ + get_element_accessible_node: async function(element) { + let acc = await window.test_driver_internal.get_element_accessible_node(element); + return acc; + }, + + /** + * Get properties for an accessible node. + * + * @param {String} id + * @returns {Promise} fulfilled after the accessibility properties are + * returned, or rejected in the cases the WebDriver + * command errors + */ + get_accessible_node: async function(accId) { + let acc = await window.test_driver_internal.get_accessible_node(accId); + return acc; + }, + /** * Send keys to an element. * @@ -2370,6 +2396,14 @@ throw new Error("get_computed_name is a testdriver.js function which cannot be run in this context."); }, + async get_element_accessible_node(element) { + throw new Error("get_element_accessible_node is a testdriver.js function which cannot be run in this context."); + }, + + async get_accessible_node(accId) { + throw new Error("get_accessible_node is a testdriver.js function which cannot be run in this context."); + }, + async send_keys(element, keys) { if (this.in_automation) { throw new Error("send_keys() is not implemented by testdriver-vendor.js"); diff --git a/tools/wptrunner/wptrunner/executors/actions.py b/tools/wptrunner/wptrunner/executors/actions.py index 785962062822bf..0b1c76759a3ba3 100644 --- a/tools/wptrunner/wptrunner/executors/actions.py +++ b/tools/wptrunner/wptrunner/executors/actions.py @@ -26,6 +26,19 @@ def __call__(self, payload): self.protocol.cookies.delete_all_cookies() +class GetAccessibleNodeAction: + name = "get_accessible_node" + + def __init__(self, logger, protocol): + self.logger = logger + self.protocol = protocol + + def __call__(self, payload): + id = payload["accId"] + self.logger.debug("Getting accessible node: %s" % id) + return self.protocol.accessibility.get_accessible_node(id) + + class GetAllCookiesAction: name = "get_all_cookies" @@ -66,6 +79,20 @@ def __call__(self, payload): return self.protocol.accessibility.get_computed_role(element) +class GetElementAccessibleNodeAction: + name = "get_element_accessible_node" + + def __init__(self, logger, protocol): + self.logger = logger + self.protocol = protocol + + def __call__(self, payload): + selector = payload["selector"] + element = self.protocol.select.element_by_selector(selector) + self.logger.debug("Getting accessible node for element: %s" % element) + return self.protocol.accessibility.get_element_accessible_node(element) + + class GetNamedCookieAction: name = "get_named_cookie" @@ -600,6 +627,8 @@ def __call__(self, payload): GetNamedCookieAction, GetComputedLabelAction, GetComputedRoleAction, + GetElementAccessibleNodeAction, + GetAccessibleNodeAction, SendKeysAction, MinimizeWindowAction, SetWindowRectAction, diff --git a/tools/wptrunner/wptrunner/executors/executormarionette.py b/tools/wptrunner/wptrunner/executors/executormarionette.py index 37ec11553773e5..4bce6673ed24f4 100644 --- a/tools/wptrunner/wptrunner/executors/executormarionette.py +++ b/tools/wptrunner/wptrunner/executors/executormarionette.py @@ -731,6 +731,12 @@ def get_computed_label(self, element): def get_computed_role(self, element): return element.computed_role + def get_element_accessible_node(self, element): + return element.accessible_node + + def get_accessible_node(self, id): + return self.marionette.get_accessible_node(id) + class MarionetteVirtualSensorProtocolPart(VirtualSensorProtocolPart): def setup(self): diff --git a/tools/wptrunner/wptrunner/executors/protocol.py b/tools/wptrunner/wptrunner/executors/protocol.py index d5f9b0bfc4bb89..e5134175eb52b4 100644 --- a/tools/wptrunner/wptrunner/executors/protocol.py +++ b/tools/wptrunner/wptrunner/executors/protocol.py @@ -335,6 +335,18 @@ def get_computed_role(self, element): :param element: A protocol-specific handle to an element.""" pass + def get_element_accessible_node(self, element): + """Return the accessibility properties for a specific element. + + :param element: A protocol-specific handle to an element.""" + pass + + def get_accessible_node(self, id): + """Return the properties for a specific accessible node. + + :param id: The id of the accessible node.""" + pass + class WebExtensionsProtocolPart(ProtocolPart): """Protocol part for managing WebExtensions""" diff --git a/tools/wptrunner/wptrunner/testdriver-extra.js b/tools/wptrunner/wptrunner/testdriver-extra.js index 925cc6b1d27826..2efeb556b22556 100644 --- a/tools/wptrunner/wptrunner/testdriver-extra.js +++ b/tools/wptrunner/wptrunner/testdriver-extra.js @@ -495,6 +495,16 @@ return create_context_action("get_computed_role", context, {selector}); }; + window.test_driver_internal.get_element_accessible_node = function(element) { + const selector = get_selector(element); + const context = get_context(element); + return create_context_action("get_element_accessible_node", context, {selector}); + }; + + window.test_driver_internal.get_accessible_node = function(accId, context=null) { + return create_context_action("get_accessible_node", context, { accId }); + }; + window.test_driver_internal.get_named_cookie = function(name, context=null) { return create_context_action("get_named_cookie", context, {name}); }; diff --git a/wai-aria/scripts/aria-utils.js b/wai-aria/scripts/aria-utils.js index bf86dd051c30f6..45961a97243d7c 100644 --- a/wai-aria/scripts/aria-utils.js +++ b/wai-aria/scripts/aria-utils.js @@ -192,5 +192,63 @@ const AriaUtils = { this.verifyLabelsBySelector(".ex-label-only", labelTestNamePrefix); this.verifyRolesBySelector(".ex-role-only", roleTestNamePrefix); }, -}; + + /* + Asserts that the tree for a given accessible node matches the specified tree + structure. + This takes an accessible node and is not wrapped in a test. Most test files + will want to use verifyAccessibilityTree instead. + For example: +