Bug 854796: Anchor, area elements without href shouldn't have link role, r=Jamie,devtools-reviewers

Per the HTML-AAM spec, a and area elements without href attributes should have
generic roles. This revision implements this preference by creating hypertext
accessibles when said elements lack href attributes (or click listeners). A
byproduct of this change is recognizing that a elements have no intrinsic role
mapping; they could be generics or links. This revision handles situations
where href or click listeners might appear or dissapear, and recreates the
accessibles when necessary. Since image map areas are handled by their
containing image maps, this revision specializes HTMLAreaAccessible::NativeRole
to account for the discrepancy that we can't account for in the markup map.
This revision also changes the relevant WPT test expectations, updates existing
tests that this change affects, and adds tests to verify that changing href
and click listeners dynamically changes the role appropriately.

Differential Revision: https://phabricator.services.mozilla.com/D183550
This commit is contained in:
Nathan LaPre 2023-07-24 19:31:29 +00:00
Родитель ad3cf4e0b8
Коммит f8b9470054
22 изменённых файлов: 344 добавлений и 83 удалений

Просмотреть файл

@ -8,6 +8,12 @@
MARKUPMAP(
a,
[](Element* aElement, LocalAccessible* aContext) -> LocalAccessible* {
// An anchor element without an href attribute and without a click
// listener should be a generic.
if (!aElement->HasAttr(nsGkAtoms::href) &&
!nsCoreUtils::HasClickListener(aElement)) {
return new HyperTextAccessibleWrap(aElement, aContext->Document());
}
// Only some roles truly enjoy life as HTMLLinkAccessibles, for
// details see closed bug 494807.
const nsRoleMapEntry* roleMapEntry = aria::GetRoleMap(aElement);
@ -18,7 +24,7 @@ MARKUPMAP(
return new HTMLLinkAccessible(aElement, aContext->Document());
},
roles::LINK)
0)
MARKUPMAP(abbr, New_HyperText, 0)

Просмотреть файл

@ -442,17 +442,33 @@ nsAccessibilityService::ListenersChanged(nsIArray* aEventChanges) {
content == document->DocumentNode()->GetRootElement())) {
acc = document;
}
if (!acc && content->IsElement() &&
content->AsElement()->IsHTMLElement(nsGkAtoms::area)) {
// For area accessibles, we have to recreate the entire image map,
// since the image map accessible manages the tree itself. The click
// listener change may require us to update the role for the
// accessible associated with the area element.
LocalAccessible* areaAcc =
document->GetAccessibleEvenIfNotInMap(content);
if (areaAcc && areaAcc->LocalParent()) {
document->RecreateAccessible(areaAcc->LocalParent()->GetContent());
}
}
if (!acc && nsCoreUtils::HasClickListener(content)) {
// Create an accessible for a inaccessible element having click event
// handler.
document->ContentInserted(content, content->GetNextSibling());
} else if (acc) {
if (acc->IsHTMLLink() && !acc->AsHTMLLink()->IsLinked()) {
// Notify of a LINKED state change if an HTML link gets a click
// listener but does not have an href attribute.
RefPtr<AccEvent> linkedChangeEvent =
new AccStateChangeEvent(acc, states::LINKED);
document->FireDelayedEvent(linkedChangeEvent);
if ((acc->IsHTMLLink() && !acc->AsHTMLLink()->IsLinked()) ||
(content->IsElement() &&
content->AsElement()->IsHTMLElement(nsGkAtoms::a) &&
!acc->IsHTMLLink())) {
// An HTML link without an href attribute should have a generic
// role, unless it has a click listener. Since we might have gained
// or lost a click listener here, recreate the accessible so that we
// can create the correct type of accessible. If it was a link, it
// may no longer be one. If it wasn't, it may become one.
document->RecreateAccessible(content);
}
// A click listener change might mean losing or gaining an action.

Просмотреть файл

@ -1803,6 +1803,33 @@ bool DocAccessible::UpdateAccessibleOnAttrChange(dom::Element* aElement,
return true;
}
if (aAttribute == nsGkAtoms::href &&
!nsCoreUtils::HasClickListener(aElement)) {
// If the href is added or removed for a or area elements without click
// listeners, we need to recreate the accessible since the role might have
// changed. Without an href or click listener, the accessible must be a
// generic.
if (aElement->IsHTMLElement(nsGkAtoms::a)) {
LocalAccessible* acc = GetAccessible(aElement);
if (!acc) {
return false;
}
if (acc->IsHTMLLink() != aElement->HasAttr(nsGkAtoms::href)) {
RecreateAccessible(aElement);
return true;
}
} else if (aElement->IsHTMLElement(nsGkAtoms::area)) {
// For area accessibles, we have to recreate the entire image map, since
// the image map accessible manages the tree itself.
LocalAccessible* areaAcc = GetAccessibleEvenIfNotInMap(aElement);
if (!areaAcc || !areaAcc->LocalParent()) {
return false;
}
RecreateAccessible(areaAcc->LocalParent()->GetContent());
return true;
}
}
if (aElement->IsHTMLElement(nsGkAtoms::img) && aAttribute == nsGkAtoms::alt) {
// If alt text changes on an img element, we may want to create or remove an
// accessible for that img.

Просмотреть файл

@ -9,6 +9,7 @@
#include "EventTree.h"
#include "Role.h"
#include "nsCoreUtils.h"
#include "nsIFrame.h"
#include "nsImageFrame.h"
#include "nsImageMap.h"
@ -105,6 +106,19 @@ HTMLAreaAccessible::HTMLAreaAccessible(nsIContent* aContent,
////////////////////////////////////////////////////////////////////////////////
// HTMLAreaAccessible: LocalAccessible
role HTMLAreaAccessible::NativeRole() const {
// A link element without an href attribute and without a click listener
// should be reported as a generic.
if (mContent->IsElement()) {
dom::Element* element = mContent->AsElement();
if (!element->HasAttr(nsGkAtoms::href) &&
!nsCoreUtils::HasClickListener(element)) {
return roles::TEXT;
}
}
return HTMLLinkAccessible::NativeRole();
}
ENameValueFlag HTMLAreaAccessible::NativeName(nsString& aName) const {
ENameValueFlag nameFlag = LocalAccessible::NativeName(aName);
if (!aName.IsEmpty()) return nameFlag;

Просмотреть файл

@ -61,6 +61,9 @@ class HTMLAreaAccessible final : public HTMLLinkAccessible {
return false;
}
// LocalAccessible
virtual role NativeRole() const override;
protected:
// LocalAccessible
virtual ENameValueFlag NativeName(nsString& aName) const override;

Просмотреть файл

@ -92,6 +92,10 @@ addAccessibleTask(
src="http://example.com/a11y/accessible/tests/mochitest/moz.png">
</a>
<a id="link4" onmousedown=""></a>
<a id="link5" onclick=""></a>
<a id="link6" onmouseup=""></a>
<div>
<label for="TextBox_t2" id="label1">
<span>Explicit</span>
@ -117,6 +121,9 @@ addAccessibleTask(
await _testActions("link2", ["click"], gClickEvents);
await _testActions("link3", ["jump"], gClickEvents);
await _testActions("link3img", ["click ancestor"], gClickEvents);
await _testActions("link4", ["click"], gClickEvents);
await _testActions("link5", ["click"], gClickEvents);
await _testActions("link6", ["click"], gClickEvents);
await _testActions("label1", ["click"], gClickEvents);
await _testActions("p_in_clickable_div", ["click ancestor"], gClickEvents);
@ -171,16 +178,24 @@ addAccessibleTask(
await _testActions("onclick_img", ["showlongdesc"]);
// Remove 'href' from link and test linkable child
const link1Acc = findAccessibleChildByID(docAcc, "link1");
let link1Acc = findAccessibleChildByID(docAcc, "link1");
is(
link1Acc.firstChild.getActionName(0),
"click ancestor",
"linkable child has click ancestor action"
);
let onRecreation = waitForEvents({
expected: [
[EVENT_HIDE, link1Acc],
[EVENT_SHOW, "link1"],
],
});
await invokeContentTask(browser, [], () => {
let link1 = content.document.getElementById("link1");
link1.removeAttribute("href");
});
await onRecreation;
link1Acc = findAccessibleChildByID(docAcc, "link1");
await untilCacheIs(() => link1Acc.actionCount, 0, "link has no actions");
is(link1Acc.firstChild.actionCount, 0, "linkable child's actions removed");

Просмотреть файл

@ -338,6 +338,7 @@ const markupTests = [
<span id="l1">test2</span>
<span id="l2">test3</span>
<a id="a"
href=""
aria-label="test1"
aria-labelledby="l1 l2"
title="test4">test5</a>`,
@ -350,6 +351,7 @@ const markupTests = [
<span id="l1">test2</span>
<span id="l2">test3</span>
<a id="a-img"
href=""
aria-label="test1"
aria-labelledby="l1 l2"
title="test4"><img alt="test5"/></a>`,

Просмотреть файл

@ -280,7 +280,7 @@ addAccessibleTask(
addAccessibleTask(
`<a id="link" href="https://example.com/">Test</a>`,
async function (browser, docAcc) {
const link = findAccessibleChildByID(docAcc, "link");
let link = findAccessibleChildByID(docAcc, "link");
is(link.value, "https://example.com/", "link initial value correct");
const textLeaf = link.firstChild;
is(textLeaf.value, "https://example.com/", "link initial value correct");
@ -294,11 +294,27 @@ addAccessibleTask(
);
info("Removing link href");
let onRecreation = waitForEvents({
expected: [
[EVENT_HIDE, link],
[EVENT_SHOW, "link"],
],
});
await invokeSetAttribute(browser, "link", "href");
await onRecreation;
link = findAccessibleChildByID(docAcc, "link");
await untilCacheIs(() => link.value, "", "link value empty after removal");
info("Setting link href");
onRecreation = waitForEvents({
expected: [
[EVENT_HIDE, link],
[EVENT_SHOW, "link"],
],
});
await invokeSetAttribute(browser, "link", "href", "https://example.com/");
await onRecreation;
link = findAccessibleChildByID(docAcc, "link");
await untilCacheIs(
() => link.value,
"https://example.com/",

Просмотреть файл

@ -5,6 +5,6 @@
</head>
<body id="body">
<div id="container1"> <img src="http://example.com/a11y/accessible/tests/mochitest/moz.png"> <img id="img1" src="http://example.com/a11y/accessible/tests/mochitest/moz.png"> <img src="http://example.com/a11y/accessible/tests/mochitest/moz.png"> </div>
<div id="container2-parent"> <a id="container2"></a> <a><img src="http://example.com/a11y/accessible/tests/mochitest/moz.png"></a> </div>
<div id="container2-parent"> <a id="container2" href=""></a> <a href=""><img src="http://example.com/a11y/accessible/tests/mochitest/moz.png"></a> </div>
</body>
</html>

Просмотреть файл

@ -39,18 +39,6 @@ addAccessibleTask(
}
);
function waitForLinkedChange(id, isEnabled) {
return waitForEvent(EVENT_STATE_CHANGE, e => {
e.QueryInterface(nsIAccessibleStateChangeEvent);
return (
e.state == STATE_LINKED &&
!e.isExtraState &&
isEnabled == e.isEnabled &&
id == getAccessibleDOMNodeID(e.accessible)
);
});
}
/**
* Test linked vs unlinked anchor tags
*/
@ -92,36 +80,39 @@ addAccessibleTask(
"bare <a> gets correct group role"
);
let stateChanged = waitForLinkedChange("link1", false);
let onRecreation = waitForEvent(EVENT_SHOW, "link1");
await SpecialPowers.spawn(browser, [], () => {
content.document.getElementById("link1").removeAttribute("href");
});
await stateChanged;
await onRecreation;
link1 = getNativeInterface(accDoc, "link1");
is(
link1.getAttributeValue("AXRole"),
"AXGroup",
"<a> stripped from href gets group role"
);
stateChanged = waitForLinkedChange("link2", false);
onRecreation = waitForEvent(EVENT_SHOW, "link2");
await SpecialPowers.spawn(browser, [], () => {
content.document.getElementById("link2").removeAttribute("onclick");
});
await stateChanged;
await onRecreation;
link2 = getNativeInterface(accDoc, "link2");
is(
link2.getAttributeValue("AXRole"),
"AXGroup",
"<a> stripped from onclick gets group role"
);
stateChanged = waitForLinkedChange("link3", true);
onRecreation = waitForEvent(EVENT_SHOW, "link3");
await SpecialPowers.spawn(browser, [], () => {
content.document
.getElementById("link3")
// eslint-disable-next-line @microsoft/sdl/no-insecure-url
.setAttribute("href", "http://example.com");
});
await stateChanged;
await onRecreation;
link3 = getNativeInterface(accDoc, "link3");
is(
link3.getAttributeValue("AXRole"),
"AXLink",
@ -212,7 +203,7 @@ addAccessibleTask(
link5
.getAttributeValue("AXLinkedUIElements")[0]
.getAttributeValue("AXTitle"),
"I have a name",
"",
"Link 5 is linked to a named element"
);
is(

Просмотреть файл

@ -14,6 +14,7 @@ skip-if = true || (verify && !debug && (os == 'linux')) #Bug 1445513
[browser_css_content_visibility.js]
[browser_general.js]
[browser_lazy_tabs.js]
[browser_link.js]
[browser_searchbar.js]
[browser_shadowdom.js]
[browser_test_nsIAccessibleDocument_URL.js]

Просмотреть файл

@ -0,0 +1,208 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
/* import-globals-from ../../mochitest/role.js */
loadScripts({ name: "role.js", dir: MOCHITESTS_DIR });
/**
* Verify that an anchor element reports a generic role without an href
* attribute and reports a LINK role with it present. Verify that these roles
* change as the attribute appears and disappears.
*/
addAccessibleTask(
`
<a id="link">test</a>
`,
async function (browser, accDoc) {
let link = findAccessibleChildByID(accDoc, "link");
is(link.role, ROLE_TEXT, "Checking role of anchor element without href");
let onHideAndShow = waitForEvents({
expected: [
[EVENT_HIDE, link],
[EVENT_SHOW, "link"],
],
});
info("Adding an href to the anchor element");
await invokeContentTask(browser, [], () => {
content.document.getElementById("link").setAttribute("href", "#");
});
await onHideAndShow;
link = findAccessibleChildByID(accDoc, "link");
is(link.role, ROLE_LINK, "Checking role of anchor element with href");
onHideAndShow = waitForEvents({
expected: [
[EVENT_HIDE, link],
[EVENT_SHOW, "link"],
],
});
info("Removing the href from the anchor element");
await invokeContentTask(browser, [], () => {
content.document.getElementById("link").removeAttribute("href");
});
await onHideAndShow;
link = findAccessibleChildByID(accDoc, "link");
is(link.role, ROLE_TEXT, "Checking role of anchor element without href");
},
{
chrome: true,
topLevel: true,
iframe: true,
remoteIframe: true,
}
);
/**
* Verify that an anchor element reports a generic role without a click listener
* and reports a LINK role with it present. Verify that these roles change as
* the click listener appears.
*/
addAccessibleTask(
`
<a id="link">test</a>
`,
async function (browser, accDoc) {
let link = findAccessibleChildByID(accDoc, "link");
is(
link.role,
ROLE_TEXT,
"Checking role of anchor element without click listener"
);
let onHideAndShow = waitForEvents({
expected: [
[EVENT_HIDE, link],
[EVENT_SHOW, "link"],
],
});
info("Adding a click listener to the anchor element");
await invokeContentTask(browser, [], () => {
content.document
.getElementById("link")
.addEventListener("click", () => {});
});
await onHideAndShow;
link = findAccessibleChildByID(accDoc, "link");
is(
link.role,
ROLE_LINK,
"Checking role of anchor element with click listener"
);
},
{
chrome: true,
topLevel: true,
iframe: true,
remoteIframe: true,
}
);
/**
* Verify that an area element reports a generic role without an href
* attribute and reports a LINK role with it present. Verify that these roles
* change as the attribute appears and disappears.
*/
addAccessibleTask(
`
<map name="map">
<area id="link">
</map>
<img id="img" usemap="#map" src="http://example.com/a11y/accessible/tests/mochitest/letters.gif">
`,
async function (browser, accDoc) {
let link = findAccessibleChildByID(accDoc, "link");
is(link.role, ROLE_TEXT, "Checking role of area element without href");
let img = findAccessibleChildByID(accDoc, "img");
let onHideAndShow = waitForEvents({
expected: [
[EVENT_HIDE, img],
[EVENT_SHOW, "img"],
],
});
info("Adding an href to the area element");
await invokeContentTask(browser, [], () => {
content.document.getElementById("link").setAttribute("href", "#");
});
await onHideAndShow;
link = findAccessibleChildByID(accDoc, "link");
is(link.role, ROLE_LINK, "Checking role of area element with href");
img = findAccessibleChildByID(accDoc, "img");
onHideAndShow = waitForEvents({
expected: [
[EVENT_HIDE, img],
[EVENT_SHOW, "img"],
],
});
info("Removing the href from the area element");
await invokeContentTask(browser, [], () => {
content.document.getElementById("link").removeAttribute("href");
});
await onHideAndShow;
link = findAccessibleChildByID(accDoc, "link");
is(link.role, ROLE_TEXT, "Checking role of area element without href");
},
{
chrome: true,
topLevel: true,
iframe: true,
remoteIframe: true,
}
);
/**
* Verify that an area element reports a generic role without a click listener
* and reports a LINK role with it present. Verify that these roles change as
* the click listener appears.
*/
addAccessibleTask(
`
<map name="map">
<area id="link">
</map>
<img id="img" usemap="#map" src="http://example.com/a11y/accessible/tests/mochitest/letters.gif">
`,
async function (browser, accDoc) {
let link = findAccessibleChildByID(accDoc, "link");
is(
link.role,
ROLE_TEXT,
"Checking role of area element without click listener"
);
let img = findAccessibleChildByID(accDoc, "img");
let onHideAndShow = waitForEvents({
expected: [
[EVENT_HIDE, img],
[EVENT_SHOW, "img"],
],
});
info("Adding a click listener to the area element");
await invokeContentTask(browser, [], () => {
content.document
.getElementById("link")
.addEventListener("click", () => {});
});
await onHideAndShow;
link = findAccessibleChildByID(accDoc, "link");
is(
link.role,
ROLE_LINK,
"Checking role of area element with click listener"
);
},
{
chrome: true,
topLevel: true,
iframe: true,
remoteIframe: true,
}
);

Просмотреть файл

@ -74,7 +74,7 @@
},
{
ID: "link2",
actionName: "click",
actionName: "jump",
events: CLICK_EVENTS,
},
{
@ -86,7 +86,7 @@
},
{
ID: "link3",
actionName: "click",
actionName: "jump",
events: CLICK_EVENTS,
},
{
@ -98,7 +98,7 @@
},
{
ID: "link4",
actionName: "click",
actionName: "jump",
events: CLICK_EVENTS,
},
{
@ -132,13 +132,13 @@
<a href="about:mozilla" id="link1" target="_blank" rel="opener">
<img src="../moz.png" id="img1">
</a>
<a id="link2" onmousedown="">
<a id="link2" href="" onmousedown="">
<img src="../moz.png" id="img2">
</a>
<a id="link3" onclick="">
<a id="link3" href="" onclick="">
<img src="../moz.png" id="img3">
</a>
<a id="link4" onmouseup="">
<a id="link4" href="" onmouseup="">
<img src="../moz.png" id="img4">
</a>
</body>

Просмотреть файл

@ -75,10 +75,6 @@
getNode("div").removeAttribute("tabindex");
await p;
p = waitForEvent(...focusableStateChange("link", false));
getNode("link").removeAttribute("href");
await p;
info("add contenteditable");
// Expect editable change on non-input,
// and don't expect event on a native input.
@ -121,8 +117,6 @@
<div id="div">Hello</div>
<a id="link" href="#">A link</a>
<input id="input" value="Hello">
</body>
</html>

Просмотреть файл

@ -138,21 +138,6 @@
await p;
}
async function testLinked() {
let p = waitForStateChange("link1", STATE_LINKED, false, false);
getNode("link1").removeAttribute("href");
await p;
p = waitForStateChange("link2", STATE_LINKED, false, false);
getNode("link2").removeAttribute("onclick");
await p;
p = waitForStateChange("link3", STATE_LINKED, true, false);
// eslint-disable-next-line @microsoft/sdl/no-insecure-url
getNode("link3").setAttribute("href", "http://example.com");
await p;
}
async function testHasPopup() {
let p = waitForStateChange("popupButton", STATE_HASPOPUP, true, false);
getNode("popupButton").setAttribute("aria-haspopup", "true");
@ -433,8 +418,6 @@
await testReadonlyUntilEditable();
await testLinked();
await testHasPopup();
await toggleStateChange("textbox", "aria-multiline", EXT_STATE_MULTI_LINE, true);
@ -537,10 +520,6 @@
<input id="text1">
<a id="link1" href="#">I am a link link</a>
<a id="link2" onclick="console.log('hi')">I am a link-ish link</a>
<a id="link3">I am a non-link link</a>
<div id="textbox" role="textbox" aria-multiline="false">hello</div>
<form id="form">

Просмотреть файл

@ -142,18 +142,17 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=418368
// Named anchor, should never have state_linked
var namedAnchorAcc = getAccessible("namedAnchor",
[nsIAccessibleHyperLink]);
testThis("namedAnchor", namedAnchorAcc, ROLE_LINK, 1,
"This should never be of state_linked", true, 196, 197);
testStates(namedAnchorAcc, STATE_SELECTABLE,
0, (STATE_FOCUSABLE | STATE_LINKED));
testThis("namedAnchor", namedAnchorAcc, ROLE_TEXT, 1,
null, true, 196, 197);
testStates(namedAnchorAcc, 0, 0, (STATE_FOCUSABLE | STATE_LINKED));
testAction("namedAnchor", namedAnchorAcc, "");
// ////////////////////////////////////////////////////////////////////////
// No link (hasn't any attribute), should never have state_linked
var noLinkAcc = getAccessible("noLink",
[nsIAccessibleHyperLink]);
testThis("noLink", noLinkAcc, ROLE_LINK, 1,
"This should never be of state_linked", true, 254, 255);
testThis("noLink", noLinkAcc, ROLE_TEXT, 1,
null, true, 254, 255);
testStates(noLinkAcc, 0, 0, (STATE_FOCUSABLE | STATE_LINKED));
testAction("noLink", noLinkAcc, "");

Просмотреть файл

@ -66,7 +66,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=428248
testThis("LinkWithSpan", 116, 5, "Heise Online");
// Named anchor
testThis("namedAnchor", 193, 6, "This should never be of state_linked");
testThis("namedAnchor", 193, 6, null);
// Paragraph with link
var p2 = getAccessible("p2", [nsIAccessibleHyperText]);

Просмотреть файл

@ -214,7 +214,6 @@
// strange cases
testStates("aria_link_link", STATE_LINKED);
testStates("aria_link_anchor", STATE_SELECTABLE);
// some landmarks that break accessibility for these native elements
// Note that these are illegal uses by web authors as per WAI-ARIA in HTML
@ -553,7 +552,6 @@
<!-- strange edge case: please don't do this in the wild -->
<a id="aria_link_link" role="link" href="foo">link</a>
<a id="aria_link_anchor" role="link" name="link_anchor">link</a>
<!-- landmarks: links -->
<a id="aria_application_link" role="application" href="foo">app</a>

Просмотреть файл

@ -187,7 +187,7 @@
on the image cache state and what optimizations layout was able to
apply. -->
<div id="container1"><img src="../moz.png"> <img id="img1" src="../moz.png"> <img src="../moz.png"></div>
<div><a id="container2"></a> <a><img src="../moz.png"></a></div>
<div><a id="container2" href=""></a> <a href=""><img src="../moz.png"></a></div>
<div id="container3">
<div id="c3_inner" role="presentation">

Просмотреть файл

@ -16,7 +16,6 @@ const {
[KEYBOARD]: {
FOCUSABLE_NO_SEMANTICS,
FOCUSABLE_POSITIVE_TABINDEX,
INTERACTIVE_NO_ACTION,
INTERACTIVE_NOT_FOCUSABLE,
MOUSE_INTERACTIVE_ONLY,
NO_FOCUS_VISIBLE,
@ -61,10 +60,7 @@ add_task(async function () {
[
"Interactive accesible (link with no attributes) with no accessible actions.",
"#link-1",
{
score: FAIL,
issue: INTERACTIVE_NO_ACTION,
},
null,
],
["Interactive accessible (link with valid href).", "#link-2", null],
["Interactive accessible (link with # as href).", "#link-3", null],

Просмотреть файл

@ -483,11 +483,7 @@ add_task(async function () {
],
["<embed> with video data type and aria-label", "#embed-3", null],
["<embed> with video data type and aria-labelledby", "#embed-4", null],
[
"Link with no inner content",
"#link-1",
{ score: FAIL, issue: INTERACTIVE_NO_NAME },
],
["Link with no inner content", "#link-1", null],
["Link with inner content", "#link-2", null],
[
"Link with href and no inner content",

Просмотреть файл

@ -15,7 +15,7 @@
expected: FAIL
[el-a-no-href]
expected: FAIL
expected: PASS
[el-search]
expected: FAIL