Re-sync dom web-platform-tests from upstream
[WebKit-https.git] / LayoutTests / imported / w3c / web-platform-tests / dom / nodes / aria-element-reflection.tentative.html
1 <!DOCTYPE HTML>
2 <html>
3   <head>
4     <meta charset="utf-8" />
5     <title>Element Reflection for aria-activedescendant and aria-errormessage</title>
6     <link rel=help href="https://whatpr.org/html/3917/common-dom-interfaces.html#reflecting-content-attributes-in-idl-attributes:element">
7     <link rel="author" title="Meredith Lane" href="meredithl@chromium.org">
8     <script src="/resources/testharness.js"></script>
9     <script src="/resources/testharnessreport.js"></script>
10   </head>
11   <div id="activedescendant" aria-activedescendant="x"></div>
12
13   <div id="parent-listbox" role="listbox" aria-activedescendant="i1">
14     <div role="option" id="i1">Item 1</div>
15     <div role="option" id="i2">Item 2</div>
16   </div>
17
18   <script>
19   test(function(t) {
20     const ancestor = document.getElementById("parent-listbox");
21     assert_equals(activedescendant.ariaActiveDescendantElement, null,
22                   "invalid ID for relationship returns null");
23
24     const descendant1 = document.getElementById("i1");
25     const descendant2 = document.getElementById("i2");
26
27     // Element reference should be set if the content attribute was included.
28     assert_equals(ancestor.getAttribute("aria-activedescendant"), "i1", "check content attribute after parsing.");
29     assert_equals(ancestor.ariaActiveDescendantElement, i1, "check idl attribute after parsing.");
30
31     // If we set the content attribute, the element reference should reflect this.
32     ancestor.setAttribute("aria-activedescendant", "i2");
33     assert_equals(ancestor.ariaActiveDescendantElement, descendant2, "setting the content attribute updates the element reference.");
34
35     // Setting the element reference should be reflected in the content attribute.
36     ancestor.ariaActiveDescendantElement = descendant1;
37     assert_equals(ancestor.ariaActiveDescendantElement, descendant1, "getter should return the right element reference.");
38     assert_equals(ancestor.getAttribute("aria-activedescendant"), "i1", "content attribute should reflect the element reference.");
39
40     // Both content and IDL attribute should be nullable.
41     ancestor.ariaActiveDescendantElement = null;
42     assert_equals(ancestor.ariaActiveDescendantElement, null);
43     assert_false(ancestor.hasAttribute("aria-activedescendant"));
44     assert_equals(ancestor.getAttribute("aria-activedescendant"), null, "nullifying the idl attribute removes the content attribute.");
45
46     // Setting content attribute to non-existent or non compatible element should nullify the IDL attribute.
47     // Reset the element to an existant one.
48     ancestor.setAttribute("aria-activedescendant", "i1");
49     assert_equals(ancestor.ariaActiveDescendantElement, i1, "reset attribute.");
50
51     ancestor.setAttribute("aria-activedescendant", "non-existent-element");
52     assert_equals(ancestor.getAttribute("aria-activedescendant"), "non-existent-element");
53     assert_equals(ancestor.ariaActiveDescendantElement, null,"non-DOM content attribute should null the element reference");
54   }, "aria-activedescendant element reflection");
55   </script>
56
57   <div id="parent-listbox-2" role="listbox" aria-activedescendant="option1">
58     <div role="option" id="option1">Item 1</div>
59     <div role="option" id="option2">Item 2</div>
60   </div>
61
62   <script>
63   test(function(t) {
64     const ancestor = document.getElementById("parent-listbox-2");
65     const option1 = document.getElementById("option1");
66     const option2 = document.getElementById("option2");
67     assert_equals(ancestor.ariaActiveDescendantElement, option1);
68
69     option1.removeAttribute("id");
70     option2.setAttribute("id", "option1");
71     const option2Duplicate = document.getElementById("option1");
72     assert_equals(option2, option2Duplicate);
73
74     assert_equals(ancestor.ariaActiveDescendantElement, option2);
75   }, "If the content attribute is set directly, the IDL attribute getter always returns the first element whose ID matches the content attribute.");
76   </script>
77
78   <div id="blank-id-parent" role="listbox">
79     <div role="option" id="multiple-id"></div>
80     <div role="option" id="multiple-id"></div>
81   </div>
82
83   <script>
84   test(function(t) {
85     const ancestor = document.getElementById("blank-id-parent");
86
87     // Get second child of parent. This violates the setting of a reflected element
88     // as it will not be the first child of the parent with that ID, which should
89     // result in an empty string for the content attribute.
90     ancestor.ariaActiveDescendantElement = ancestor.children[1];
91     assert_true(ancestor.hasAttribute("aria-activedescendant"));
92     assert_equals(ancestor.getAttribute("aria-activedescendant"), "");
93     assert_equals(ancestor.ariaActiveDescendantElement, ancestor.children[1]);
94   }, "Setting the IDL attribute to an element which is not the first element in DOM order with its ID causes the content attribute to be an empty string");
95   </script>
96
97   <div id="outer-container">
98     <p id="light-paragraph">Hello world!</p>
99     <span class="shadow-host">
100     </span>
101   </div>
102
103   <script>
104   test(function(t) {
105     const shadowElement = document.querySelector(".shadow-host");
106     const shadow = shadowElement.attachShadow({mode: "open"});
107     const link = document.createElement("a");
108     shadow.appendChild(link);
109
110     const lightPara = document.getElementById("light-paragraph");
111     assert_equals(lightPara.ariaActiveDescendantElement, null);
112
113     // The given element crosses a shadow dom boundary, so it cannot be
114     // set as an element reference.
115     lightPara.ariaActiveDescendantElement = link;
116     assert_equals(lightPara.ariaActiveDescendantElement, null);
117
118     // The given element crosses a shadow dom boundary (upwards), so
119     // can be used as an element reference, but the content attribute
120     // should reflect the empty string.
121     link.ariaActiveDescendantElement = lightPara;
122     assert_equals(link.ariaActiveDescendantElement, lightPara);
123     assert_equals(link.getAttribute("aria-activedescendant"), "");
124   }, "Setting an element reference that crosses into a shadow tree is disallowed, but setting one that is in a shadow inclusive ancestor is allowed.");
125   </script>
126
127   <input id="startTime" ></input>
128   <span id="errorMessage">Invalid Time</span>
129
130   <script>
131   test(function(t) {
132     const inputElement = document.getElementById("startTime");
133     const errorMessage = document.getElementById("errorMessage");
134
135     inputElement.ariaErrorMessageElement = errorMessage;
136     assert_equals(inputElement.getAttribute("aria-errormessage"), "errorMessage");
137
138     inputElement.ariaErrorMessageElement = null;
139     assert_equals(inputElement.ariaErrorMessageElement, null, "blah");
140     assert_false(inputElement.hasAttribute("aria-errormessage"));
141
142     inputElement.setAttribute("aria-errormessage", "errorMessage");
143     assert_equals(inputElement.ariaErrorMessageElement, errorMessage);
144
145   }, "aria-errormessage");
146
147   </script>
148
149   <label>
150     Password:
151     <input id="password-field" type="password" aria-details="pw">
152   </label>
153
154   <ul>
155     <li id="list-item-1">First description.</li>
156     <li id="list-item-2">Second description.</li>
157   </ul>
158
159   <script>
160
161   test(function(t) {
162     const inputElement = document.getElementById("password-field");
163     const ul1 = document.getElementById("list-item-1");
164     const ul2 = document.getElementById("list-item-2");
165
166     assert_equals(inputElement.ariaDetailsElement, null);
167     inputElement.ariaDetailsElement = ul1;
168     assert_equals(inputElement.getAttribute("aria-details"), "list-item-1");
169
170     inputElement.ariaDetailsElement = ul2;
171     assert_equals(inputElement.getAttribute("aria-details"), "list-item-2");
172   }, "aria-details");
173   </script>
174
175   <div id="old-parent" role="listbox" aria-activedescendant="content-attr-element">
176     <div role="option" id="content-attr-element">Item 1</div>
177     <div role="option" id="idl-attr-element">Item 2</div>
178   </div>
179
180   <script>
181
182   test(function(t) {
183     const deletionParent = document.getElementById("old-parent");
184
185     const descendant1 = document.getElementById("content-attr-element");
186     const descendant2 = document.getElementById("idl-attr-element");
187
188     // Deleting an element set via the content attribute.
189     assert_equals(deletionParent.getAttribute("aria-activedescendant"), "content-attr-element");
190     assert_equals(deletionParent.ariaActiveDescendantElement, descendant1);
191
192     deletionParent.removeChild(descendant1);
193     assert_equals(deletionParent.getAttribute("aria-activedescendant"), "content-attr-element");
194     assert_equals(deletionParent.ariaActiveDescendantElement, null);
195
196     // Deleting an element set via the IDL attribute.
197     deletionParent.ariaActiveDescendantElement = descendant2;
198     assert_equals(deletionParent.getAttribute("aria-activedescendant"), "idl-attr-element");
199
200     deletionParent.removeChild(descendant2);
201     assert_equals(deletionParent.ariaActiveDescendantElement, null);
202
203     // The content attribute will still reflect the id.
204     assert_equals(deletionParent.getAttribute("aria-activedescendant"), "idl-attr-element");
205   }, "Deleting a reflected element should return null for the IDL attribute and cause the content attribute to become stale.");
206   </script>
207
208   <div id="parent" role="listbox" aria-activedescendant="original">
209     <div role="option" id="original">Item 1</div>
210     <div role="option" id="element-with-persistant-id">Item 2</div>
211   </div>
212
213   <script>
214   test(function(t) {
215     const parentNode = document.getElementById("parent");
216     const changingIdElement = document.getElementById("original");
217     const persistantIDElement = document.getElementById("element-with-persistant-id");
218
219     assert_equals(parentNode.ariaActiveDescendantElement, changingIdElement);
220
221     // Modify the id attribute.
222     changingIdElement.setAttribute("id", "new-id");
223
224     // The content attribute still reflects the old id, and we expect the
225     // Element reference to be null as there is no DOM node with id "original"
226     assert_equals(parentNode.getAttribute("aria-activedescendant"), "original");
227     assert_equals(parentNode.ariaActiveDescendantElement, null, "Element set via content attribute with a changed id will return null on getting");
228
229     parentNode.ariaActiveDescendantElement = changingIdElement;
230     assert_equals(parentNode.getAttribute("aria-activedescendant"), "new-id");
231
232     // The explicitly set element takes precendance over the content attribute.
233     // This means that we still return the same element reference, but the
234     // content attribute reflects the old id.
235     changingIdElement.setAttribute("id", "newer-id");
236     assert_equals(parentNode.ariaActiveDescendantElement, changingIdElement, "explicitly set element is still present even after the id has been changed");
237     assert_equals(parentNode.getAttribute("aria-activedescendant"), "new-id", "content attribute reflects the id that was present upon explicitly setting the element reference.");
238   }, "Changing the ID of an element causes the content attribute to become out of sync.");
239   </script>
240
241   <div id="light-parent" role="listbox">
242     <div role="option" id="light-element">Hello world!</div>
243   </div>
244   <div id="shadowHost"></div>
245
246   <script>
247   test(function(t) {
248     const shadowElement = document.getElementById("shadowHost");
249     const shadowHost = shadowElement.attachShadow({mode: "open"});
250     const lightParent = document.getElementById("light-parent");
251     const optionElement = document.getElementById("light-element");
252
253     lightParent.ariaActiveDescendantElement = optionElement;
254     assert_equals(lightParent.ariaActiveDescendantElement, optionElement);
255
256     // Move the referenced element into shadow DOM.
257     shadowHost.appendChild(optionElement);
258     assert_equals(lightParent.ariaActiveDescendantElement, null);
259     assert_equals(lightParent.getAttribute("aria-activedescendant"), "light-element");
260
261     // Move the referenced element back into light DOM.
262     lightParent.appendChild(optionElement);
263     assert_equals(lightParent.ariaActiveDescendantElement, optionElement);
264   }, "Reparenting an element into a descendant shadow scope nullifies the element reference.");
265   </script>
266 </html>