Rename getAssignedNodes to assignedNodes and support flattened option
[WebKit-https.git] / LayoutTests / fast / shadow-dom / HTMLSlotElement-interface.html
1 <!DOCTYPE html>
2 <html>
3 <head>
4 <title>Shadow DOM: HTMLSlotElement interface</title>
5 <meta name="author" title="Ryosuke Niwa" href="mailto:rniwa@webkit.org">
6 <meta name="assert" content="HTMLSlotElement must exist on window with name attribute and getAssignedNode() method">
7 <link rel="help" href="https://w3c.github.io/webcomponents/spec/shadow/#the-slot-element">
8 <script src="../../resources/testharness.js"></script>
9 <script src="../../resources/testharnessreport.js"></script>
10 <link rel='stylesheet' href='../../resources/testharness.css'>
11 </head>
12 <body>
13 <div id="log"></div>
14 <script>
15
16 test(function () {
17     assert_true('HTMLSlotElement' in window, 'HTMLSlotElement must be defined on window');
18     assert_equals(HTMLSlotElement.prototype.__proto__, HTMLElement.prototype, 'HTMLSlotElement should inherit from HTMLElement');
19     assert_true(document.createElement('slot') instanceof HTMLSlotElement, 'slot element should be an instance of HTMLSlotElement');
20     assert_true(document.createElement('slot') instanceof HTMLElement, 'slot element should be an instance of HTMLElement');
21 }, 'HTMLSlotElement must be defined on window');
22
23 test(function () {
24     assert_true('name' in HTMLSlotElement.prototype, '"name" attribute must be defined on HTMLSlotElement.prototype');
25
26     var slotElement = document.createElement('slot');
27     assert_equals(slotElement.name, '', '"name" attribute must return the empty string when "name" content attribute is not set');
28
29     slotElement.setAttribute('name', 'foo');
30     assert_equals(slotElement.name, 'foo', '"name" attribute must return the value of the "name" content attribute');
31
32     slotElement.name = 'bar';
33     assert_equals(slotElement.name, 'bar', '"name" attribute must return the assigned value');
34     assert_equals(slotElement.getAttribute('name'), 'bar', '"name" attribute must update the "name" content attribute');
35 }, '"name" attribute on HTMLSlotElement must reflect "name" attribute');
36
37 function testSlotOutsideShadowTree(options)
38 {
39     test(function () {
40         assert_true('assignedNodes' in HTMLSlotElement.prototype, '"assignedNodes" method must be defined on HTMLSlotElement.prototype');
41
42         var slotElement = document.createElement('slot');
43         assert_array_equals(slotElement.assignedNodes(options), [], 'assignedNodes() must return an empty array when the slot element is not in any tree');
44
45         document.body.appendChild(slotElement);
46         assert_array_equals(slotElement.assignedNodes(options), [], 'assignedNodes() must return an empty array when the slot element is in a document tree');
47
48     }, 'assignedNodes(' + (options ? JSON.stringify(options) : '')
49         + ') on a HTMLSlotElement must return an empty array when the slot element is not in a tree or in a document tree');
50 }
51
52 testSlotOutsideShadowTree(null);
53 testSlotOutsideShadowTree({flattened: false});
54 testSlotOutsideShadowTree({flattened: true});
55
56 function testSingleLevelOfSlotting(options)
57 {
58     test(function () {
59         assert_true('assignedNodes' in HTMLSlotElement.prototype, '"assignedNodes" method must be defined on HTMLSlotElement.prototype');
60
61         var shadowHost = document.createElement('div');
62         var child = document.createElement('p');
63
64         var shadowRoot = shadowHost.attachShadow({mode: 'open'});
65         var slotElement = document.createElement('slot');
66         shadowRoot.appendChild(slotElement);
67
68         assert_array_equals(slotElement.assignedNodes(options), [], 'assignedNodes() must return an empty array when there are no nodes in the shadow tree');
69
70         shadowHost.appendChild(child);
71         assert_array_equals(slotElement.assignedNodes(options), [child], 'assignedNodes() on a default slot must return an element without slot element');
72
73         child.setAttribute('slot', 'foo');
74         assert_array_equals(slotElement.assignedNodes(options), [], 'assignedNodes() on a default slot must not return an element with non-empty slot attribute');
75
76         child.setAttribute('slot', '');
77         assert_array_equals(slotElement.assignedNodes(options), [child], 'assignedNodes() on a default slot must return an element with empty slot attribute');
78
79         slotElement.setAttribute('name', 'bar');
80         assert_array_equals(slotElement.assignedNodes(options), [], 'assignedNodes() on a named slot must not return an element with empty slot attribute');
81
82         slotElement.setAttribute('name', '');
83         assert_array_equals(slotElement.assignedNodes(options), [child], 'assignedNodes() on an empty name slot must return an element with empty slot attribute');
84
85     }, 'assignedNodes(' + (options ? JSON.stringify(options) : '') + ') must return the list of assigned nodes when none of the assigned nodes themselves are slots');
86 }
87
88 testSingleLevelOfSlotting(null);
89 testSingleLevelOfSlotting({flattened: false});
90 testSingleLevelOfSlotting({flattened: true});
91
92 function testMutatingSlottedContents(options)
93 {
94     test(function () {
95         var shadowHost = document.createElement('div');
96         var p = document.createElement('p');
97         var b = document.createElement('b');
98         shadowHost.appendChild(p);
99         shadowHost.appendChild(b);
100
101         var shadowRoot = shadowHost.attachShadow({mode: 'open'});
102         var slotElement = document.createElement('slot');
103         shadowRoot.appendChild(slotElement);
104
105         assert_array_equals(slotElement.assignedNodes(options), [p, b], 'assignedNodes must return the distributed nodes');
106
107         slotElement.name = 'foo';
108         assert_array_equals(slotElement.assignedNodes(options), [], 'assignedNodes must be empty when there are no matching elements for the slot name');
109
110         b.slot = 'foo';
111         assert_array_equals(slotElement.assignedNodes(options), [b], 'assignedNodes must return the nodes with the matching slot name');
112
113         p.slot = 'foo';
114         assert_array_equals(slotElement.assignedNodes(options), [p, b], 'assignedNodes must return the nodes with the matching slot name in the tree order');
115
116         slotElement.removeAttribute('name');
117         assert_array_equals(slotElement.assignedNodes(options), [], 'assignedNodes must be empty for a default slot when all elements have "slot" attributes specified');
118
119     }, 'assignedNodes(' + (options ? JSON.stringify(options) : '') + ') must update when slot and name attributes are modified');
120 }
121
122 testMutatingSlottedContents(null);
123 testMutatingSlottedContents({flattened: false});
124 testMutatingSlottedContents({flattened: true});
125
126 function testMutatingSlotName(options)
127 {
128     test(function () {
129         var shadowHost = document.createElement('div');
130         var child = document.createElement('span');
131         shadowHost.appendChild(child);
132
133         var shadowRoot = shadowHost.attachShadow({mode: 'open'});
134         var slotElement = document.createElement('slot');
135         slotElement.name = 'foo';
136         shadowRoot.appendChild(slotElement);
137
138         assert_array_equals(slotElement.assignedNodes(options), [], 'assignedNodes must be empty when there are no matching elements for the slot name');
139
140         slotElement.removeAttribute('name');
141         assert_array_equals(slotElement.assignedNodes(options), [child], 'assignedNodes must be empty when there are no matching elements for the slot name');
142
143     }, 'assignedNodes must update when a default slot is introduced dynamically by a slot rename');
144 }
145
146 testMutatingSlotName(null);
147 testMutatingSlottedContents({flattened: false});
148 testMutatingSlottedContents({flattened: true});
149
150 function testInsertingAndRemovingSlots(options)
151 {
152     test(function () {
153         var shadowHost = document.createElement('div');
154         var p = document.createElement('p');
155         var text = document.createTextNode('');
156         var comment = document.createComment('');
157         var processingInstruction = document.createProcessingInstruction('target', 'data');
158         var b = document.createElement('b');
159         shadowHost.appendChild(p);
160         shadowHost.appendChild(text);
161         shadowHost.appendChild(comment);
162         shadowHost.appendChild(processingInstruction);
163         shadowHost.appendChild(b);
164
165         var shadowRoot = shadowHost.attachShadow({mode: 'open'});
166
167         var firstSlotElement = document.createElement('slot');
168         shadowRoot.appendChild(firstSlotElement);
169
170         var secondSlotElement = document.createElement('slot');
171         shadowRoot.appendChild(secondSlotElement);
172
173         assert_array_equals(firstSlotElement.assignedNodes(options), [p, text, b],
174             'assignedNodes on a default slot must return the elements without slot attributes and text nodes');
175         assert_array_equals(secondSlotElement.assignedNodes(options), [],
176             'assignedNodes on the second unnamed slot element must return an empty array');
177
178         shadowRoot.removeChild(firstSlotElement);
179         assert_array_equals(firstSlotElement.assignedNodes(options), [],
180             'assignedNodes on a detached formerly-default slot must return an empty array');
181         assert_array_equals(secondSlotElement.assignedNodes(options), [p, text, b],
182             'assignedNodes on the second unnamed slot element after removing the first must return the elements without slot attributes and text nodes');
183
184         shadowRoot.removeChild(secondSlotElement);
185         shadowRoot.appendChild(secondSlotElement);
186         assert_array_equals(firstSlotElement.assignedNodes(options), [],
187             'Removing and re-inserting a default slot must not change the result of assignedNodes on a detached slot');
188         assert_array_equals(secondSlotElement.assignedNodes(options), [p, text, b],
189             'Removing and re-inserting a default slot must not change the result of assignedNodes');
190
191         shadowRoot.insertBefore(firstSlotElement, secondSlotElement);
192         assert_array_equals(firstSlotElement.assignedNodes(options), [p, text, b],
193             'assignedNodes on a newly inserted unnamed slot element must return the elements without slot attributes and text nodes');
194         assert_array_equals(secondSlotElement.assignedNodes(options), [],
195             'assignedNodes on formerly-first but now second unnamed slot element must return an empty array');
196
197     }, 'assignedNodes must update when slot elements are inserted or removed');
198 }
199
200 testInsertingAndRemovingSlots(null);
201 testInsertingAndRemovingSlots({flattened: false});
202 testInsertingAndRemovingSlots({flattened: true});
203
204 test(function () {
205     var outerHost = document.createElement('div');
206     var outerChild = document.createElement('span');
207     outerHost.appendChild(outerChild);
208
209     var outerShadow = outerHost.attachShadow({mode: 'closed'});
210     var innerHost = document.createElement('div');
211     var outerSlot = document.createElement('slot');
212     var innerChild = document.createElement('b');
213     outerShadow.appendChild(innerHost);
214     innerHost.appendChild(outerSlot);
215     innerHost.appendChild(innerChild);
216
217     var innerShadow = innerHost.attachShadow({mode: 'closed'});
218     var innerSlot = document.createElement('slot');
219     innerShadow.appendChild(innerSlot);
220
221     assert_array_equals(outerSlot.assignedNodes(), [outerChild], 'assignedNodes() on a default slot must return the assigned nodes');
222     assert_array_equals(outerSlot.assignedNodes({flatten: false}), [outerChild], 'assignedNodes({flatten: false}) on a default slot must return the assigned nodes');
223     assert_array_equals(outerSlot.assignedNodes({flatten: true}), [outerChild], 'assignedNodes({flatten: true}) on a default slot must return the assigned nodes if they are not themselves slots');
224
225     assert_array_equals(innerSlot.assignedNodes(), [outerSlot, innerChild], 'assignedNodes() on a default slot must return the assigned nodes');
226     assert_array_equals(innerSlot.assignedNodes({flatten: false}), [outerSlot, innerChild], 'assignedNodes({flatten: false}) on a default slot must return the assigned nodes');
227     assert_array_equals(innerSlot.assignedNodes({flatten: true}), [outerChild, innerChild], 'assignedNodes({flatten: true}) on a default slot must return the distributed nodes');
228
229     outerSlot.name = 'foo';
230     assert_array_equals(outerSlot.assignedNodes(), [], 'assignedNodes() on a named slot must return an empty array if there are no matching elements');
231     assert_array_equals(outerSlot.assignedNodes({flatten: false}), [], 'assignedNodes({flatten: false}) on a named slot must return an empty array if there are no matching elements');
232     assert_array_equals(outerSlot.assignedNodes({flatten: true}), [], 'assignedNodes({flatten: true}) on a named slot must return an empty array if there are no matching elements');
233
234     assert_array_equals(innerSlot.assignedNodes(), [outerSlot, innerChild], 'assignedNodes() on a default slot must return the assigned nodes');
235     assert_array_equals(innerSlot.assignedNodes({flatten: false}), [outerSlot, innerChild], 'assignedNodes({flatten: false}) on a default slot must return the assigned nodes');
236     assert_array_equals(innerSlot.assignedNodes({flatten: true}), [innerChild], 'assignedNodes({flatten: true}) on a default slot must return the distributed nodes');
237
238     outerChild.slot = 'foo';
239     assert_array_equals(outerSlot.assignedNodes(), [outerChild], 'assignedNodes() on a named slot must return matching elements');
240     assert_array_equals(outerSlot.assignedNodes({flatten: false}), [outerChild], 'assignedNodes({flatten: false}) on a named slot must return matching elements');
241     assert_array_equals(outerSlot.assignedNodes({flatten: true}), [outerChild], 'assignedNodes({flatten: true}) on a named slot must return matching elements');
242
243     assert_array_equals(innerSlot.assignedNodes(), [outerSlot, innerChild], 'assignedNodes() on a default slot must return the assigned nodes');
244     assert_array_equals(innerSlot.assignedNodes({flatten: false}), [outerSlot, innerChild], 'assignedNodes({flatten: false}) on a default slot must return the assigned nodes');
245     assert_array_equals(innerSlot.assignedNodes({flatten: true}), [outerChild, innerChild], 'assignedNodes({flatten: true}) on a default slot must return the distributed nodes');
246
247     var newInnerSlot = document.createElement('slot');
248     innerShadow.insertBefore(newInnerSlot, innerSlot);
249     assert_array_equals(newInnerSlot.assignedNodes(), [outerSlot, innerChild], 'assignedNodes() on a default slot must return the assigned nodes');
250     assert_array_equals(newInnerSlot.assignedNodes({flatten: false}), [outerSlot, innerChild], 'assignedNodes({flatten: false}) on a default slot must return the assigned nodes');
251     assert_array_equals(newInnerSlot.assignedNodes({flatten: true}), [outerChild, innerChild], 'assignedNodes({flatten: true}) on a default slot must return the distributed nodes');
252
253     assert_array_equals(innerSlot.assignedNodes(), [], 'assignedNodes() on a nameless slot element which appears after a default slot must return an empty array');
254     assert_array_equals(innerSlot.assignedNodes({flatten: false}), [], 'assignedNodes({flatten: false}) on a nameless slot element which appears after a default slot must return an empty array');
255     assert_array_equals(innerSlot.assignedNodes({flatten: true}), [], 'assignedNodes({flatten: true}) on a nameless slot element which appears after a default slot must return an empty array');
256
257     innerShadow.removeChild(newInnerSlot);
258     assert_array_equals(newInnerSlot.assignedNodes(), [], 'assignedNodes() must return an empty array when the slot element is not in any tree');
259     assert_array_equals(newInnerSlot.assignedNodes({flatten: false}), [], 'assignedNodes({flatten: false}) must return an empty array when the slot element is not in any tree');
260     assert_array_equals(newInnerSlot.assignedNodes({flatten: true}), [], 'assignedNodes({flatten: true}) must return an empty array when the slot element is not in any tree');
261
262     assert_array_equals(innerSlot.assignedNodes(), [outerSlot, innerChild], 'assignedNodes() on a default slot must return the assigned nodes');
263     assert_array_equals(innerSlot.assignedNodes({flatten: false}), [outerSlot, innerChild], 'assignedNodes({flatten: false}) on a default slot must return the assigned nodes');
264     assert_array_equals(innerSlot.assignedNodes({flatten: true}), [outerChild, innerChild], 'assignedNodes({flatten: true}) on a default slot must return the distributed nodes');
265
266 }, 'assignedNodes({flatten: true}) must return the distributed nodes, and assignedNodes() and assignedNodes({flatten: false}) must returned the assigned nodes');
267
268 </script>
269 </body>
270 </html>