diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 00:47:55 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 00:47:55 +0000 |
commit | 26a029d407be480d791972afb5975cf62c9360a6 (patch) | |
tree | f435a8308119effd964b339f76abb83a57c29483 /testing/web-platform/tests/wai-aria/scripts/aria-utils.js | |
parent | Initial commit. (diff) | |
download | firefox-26a029d407be480d791972afb5975cf62c9360a6.tar.xz firefox-26a029d407be480d791972afb5975cf62c9360a6.zip |
Adding upstream version 124.0.1.upstream/124.0.1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'testing/web-platform/tests/wai-aria/scripts/aria-utils.js')
-rw-r--r-- | testing/web-platform/tests/wai-aria/scripts/aria-utils.js | 196 |
1 files changed, 196 insertions, 0 deletions
diff --git a/testing/web-platform/tests/wai-aria/scripts/aria-utils.js b/testing/web-platform/tests/wai-aria/scripts/aria-utils.js new file mode 100644 index 0000000000..ec53464c18 --- /dev/null +++ b/testing/web-platform/tests/wai-aria/scripts/aria-utils.js @@ -0,0 +1,196 @@ +/* Utilities related to WAI-ARIA */ + +const AriaUtils = { + + /* + Tests simple role assignment: <div role="alert">x</div> + Not intended for nested, context-dependent, or other complex role tests. + + Ex: AriaUtils.assignAndVerifyRolesByRoleNames(["group", "main", "button"]) + + */ + assignAndVerifyRolesByRoleNames: function(roleNames) { + if (!Array.isArray(roleNames) || !roleNames.length) { + throw `Param roleNames of assignAndVerifyRolesByRoleNames("${roleNames}") should be an array containing at least one role string.`; + } + for (const role of roleNames) { + promise_test(async t => { + let el = document.createElement("div"); + el.appendChild(document.createTextNode("x")); + el.setAttribute("role", role); // el.role not yet supported by Gecko. + document.body.appendChild(el); + const computedRole = await test_driver.get_computed_role(el); + assert_equals(computedRole, role, el.outerHTML); + }, `role: ${role}`); + } + }, + + + /* + Tests computed ROLE of all elements matching selector + against the string value of their data-expectedrole attribute. + + Ex: <div role="list" + data-testname="optional unique test name" + data-expectedrole="list" + class="ex"> + + AriaUtils.verifyRolesBySelector(".ex") + + */ + verifyRolesBySelector: function(selector, roleTestNamePrefix) { + const els = document.querySelectorAll(selector); + if (!els.length) { + throw `Selector passed in verifyRolesBySelector("${selector}") should match at least one element.`; + } + for (const el of els) { + let role = el.getAttribute("data-expectedrole"); + let testName = el.getAttribute("data-testname") || role; // data-testname optional if role is unique per test file + if (typeof roleTestNamePrefix !== "undefined") { + testName = roleTestNamePrefix + testName; + } + promise_test(async t => { + const expectedRole = el.getAttribute("data-expectedrole"); + const computedRole = await test_driver.get_computed_role(el); + assert_equals(computedRole, expectedRole, el.outerHTML); + }, `${testName}`); + } + }, + + + /* + Tests computed ROLE of selected elements matching selector + against the string value of provided roles array. + + Ex: <foo + data-testname="verify fooRole or barRole role on span" + class="ex-foo-or-bar"> + + AriaUtils.verifyRoleOrVariantRolesBySelector(".ex-foo-or-bar", ["fooRole", "barRole"]); + + See also helper function verifyGenericRolesBySelector shorthand of the above using ["generic", "", "none"]. + + Note: This function should not be used to circumvent unexpected interop differences in implementations. + It should only be used in specific cases (like "generic") determined by ARIA WG or other spec maintainers to be acceptable for the purposes of testing. + + */ + verifyRoleOrVariantRolesBySelector: function(selector, roles) { + const els = document.querySelectorAll(selector); + if (!els.length) { + throw `Selector "${selector}" should match at least one element.`; + } + if (!roles.length || roles.length < 2) { + throw `Roles array ["${roles.join('", "')}"] should include at least two strings, a primary role and at least one acceptable implementation-specific variant. E.g. ["generic", "", "none"]…`; + } + for (const el of els) { + let testName = el.getAttribute("data-testname"); + promise_test(async t => { + const expectedRoles = roles; + const computedRole = await test_driver.get_computed_role(el); + for (role of roles){ + if (computedRole === role) { + return assert_equals(computedRole, role, `Computed Role: "${computedRole}" matches one of the acceptable role strings in ["${roles.join('", "')}"]: ${el.outerHTML}`); + } + } + return assert_false(true, `Computed Role: "${computedRole}" does not match any of the acceptable role strings in ["${roles.join('", "')}"]: ${el.outerHTML}`); + }, `${testName}`); + } + }, + + + /* + Helper function for "generic" ROLE tests. + + Ex: <span + data-testname="verify generic, none, or empty computed role on span" + class="ex-generic"> + + AriaUtils.verifyGenericRolesBySelector(".ex-generic"); + + This helper function is equivalant to AriaUtils.verifyRoleOrVariantRolesBySelector(".ex-generic", ["generic", "", "none"]); + See various issues and discussions linked from https://github.com/web-platform-tests/interop-accessibility/issues/48 + + */ + verifyGenericRolesBySelector: function(selector) { + // ARIA WG determined implementation variants "none" (Chromium), and the empty string "" (WebKit), are sufficiently equivalent to "generic" for WPT test verification of HTML-AAM. + // See various discussions linked from https://github.com/web-platform-tests/interop-accessibility/issues/48 + this.verifyRoleOrVariantRolesBySelector(selector, ["generic", "", "none"]); + }, + + + /* + Tests computed LABEL of all elements matching selector + against the string value of their data-expectedlabel attribute. + + Ex: <div aria-label="foo" + data-testname="optional unique test name" + data-expectedlabel="foo" + class="ex"> + + AriaUtils.verifyLabelsBySelector(".ex") + + */ + verifyLabelsBySelector: function(selector, labelTestNamePrefix) { + const els = document.querySelectorAll(selector); + if (!els.length) { + throw `Selector passed in verifyLabelsBySelector("${selector}") should match at least one element.`; + } + for (const el of els) { + let label = el.getAttribute("data-expectedlabel"); + let testName = el.getAttribute("data-testname") || label; // data-testname optional if label is unique per test file + if (typeof labelTestNamePrefix !== "undefined") { + testName = labelTestNamePrefix + testName; + } + promise_test(async t => { + const expectedLabel = el.getAttribute("data-expectedlabel"); + let computedLabel = await test_driver.get_computed_label(el); + assert_not_equals(computedLabel, null, `get_computed_label(el) shouldn't return null for ${el.outerHTML}`); + + // See: + // - https://github.com/w3c/accname/pull/165 + // - https://github.com/w3c/accname/issues/192 + // - https://github.com/w3c/accname/issues/208 + // + // AccName references HTML's definition of ASCII Whitespace + // https://infra.spec.whatwg.org/#ascii-whitespace + // which matches tab (\t), newline (\n), formfeed (\f), return (\r), and regular space (\u0020). + // but it does NOT match non-breaking space (\xA0,\u00A0) and others matched by \s + const asciiWhitespace = /[\t\n\f\r\u0020]+/g; + computedLabel = computedLabel.replace(asciiWhitespace, '\u0020').replace(/^\u0020|\u0020$/g, ''); + + assert_equals(computedLabel, expectedLabel, el.outerHTML); + }, `${testName}`); + } + }, + + + /* + Tests computed LABEL and ROLE of all elements matching selector using existing + verifyLabelsBySelector(), verifyRolesBySelector() functions and passes a test name prefix + to ensure uniqueness. + + Ex: <div aria-label="foo" role="button" + data-testname="div with role=button is labelled via aria-label" + data-expectedlabel="foo" + data-expectedrole="button" + class="ex-role-and-label"> + + AriaUtils.verifyRolesAndLabelsBySelector(".ex-role-and-label") + + */ + verifyRolesAndLabelsBySelector: function(selector) { + let labelTestNamePrefix = "Label: "; + let roleTestNamePrefix = "Role: "; + const els = document.querySelectorAll(selector); + if (!els.length) { + throw `Selector passed in verifyRolesAndLabelsBySelector("${selector}") should match at least one element.`; + } + for (const el of els) { + el.classList.add("ex-label-only"); + el.classList.add("ex-role-only"); + } + this.verifyLabelsBySelector(".ex-label-only", labelTestNamePrefix); + this.verifyRolesBySelector(".ex-role-only", roleTestNamePrefix); + }, +}; + |