5 <script src=
"../../../resources/js-test.js"></script>
10 <div id=
"console"></div>
13 window
.jsTestIsAsync
= true;
17 var subDiv
, subDiv2
, subDiv3
, text
;
20 function testBasic() {
24 debug('Testing basic aspects of subtree observation.');
27 div
= document
.createElement('div');
28 subDiv
= div
.appendChild(document
.createElement('div'));
29 subDiv
.innerHTML
= 'hello, world';
30 observer
= new MutationObserver(function(mutations
) {
31 window
.mutations
= mutations
;
34 observer
.observe(div
, {attributes
: true, characterData
: true, subtree
: true});
35 subDiv
.setAttribute('foo', 'bar');
36 subDiv
.firstChild
.textContent
= 'goodbye!';
37 setTimeout(finish
, 0);
41 debug('...attribute and characterData changes in subtree');
43 shouldBe('mutations.length', '2');
44 shouldBe('mutations[0].type', '"attributes"');
45 shouldBe('mutations[0].target', 'subDiv');
46 shouldBe('mutations[0].attributeName', '"foo"');
47 shouldBe('mutations[0].attributeNamespace', 'null');
48 shouldBe('mutations[1].type', '"characterData"');
49 shouldBe('mutations[1].target', 'subDiv.firstChild');
50 observer
.disconnect();
58 function testMultipleObservers() {
63 debug('Testing two observers at different depths.');
67 div
= document
.createElement('div');
68 subDiv
= div
.appendChild(document
.createElement('div'));
69 observer
= new MutationObserver(function(mutations
) {
70 window
.mutations
= mutations
;
72 observer2
= new MutationObserver(function(mutations
) {
73 window
.mutations2
= mutations
;
76 observer
.observe(div
, {attributes
: true, subtree
: true});
77 observer2
.observe(subDiv
, {attributes
: true});
78 subDiv
.setAttribute('foo', 'bar');
79 setTimeout(finish
, 0);
83 shouldBe('mutations.length', '1');
84 shouldBe('mutations[0].type', '"attributes"');
85 shouldBe('mutations[0].target', 'subDiv');
86 shouldBe('mutations[0].attributeName', '"foo"');
87 shouldBe('mutations[0].attributeNamespace', 'null');
88 shouldBe('mutations2.length', '1');
89 shouldBe('mutations2[0].type', '"attributes"');
90 shouldBe('mutations2[0].target', 'subDiv');
91 shouldBe('mutations2[0].attributeName', '"foo"');
92 shouldBe('mutations2[0].attributeNamespace', 'null');
93 observer
.disconnect();
94 observer2
.disconnect();
102 function testMultipleObservations() {
106 debug('Testing one observer at two different depths.');
110 div
= document
.createElement('div');
111 subDiv
= div
.appendChild(document
.createElement('div'));
112 observer
= new MutationObserver(function(mutations
) {
113 window
.mutations
= mutations
;
117 observer
.observe(div
, {attributes
: true, subtree
: true});
118 observer
.observe(subDiv
, {attributes
: true, subtree
: true});
119 subDiv
.setAttribute('foo', 'bar');
120 setTimeout(finish
, 0);
124 shouldBe('calls', '1');
125 shouldBe('mutations.length', '1');
126 shouldBe('mutations[0].type', '"attributes"');
127 shouldBe('mutations[0].target', 'subDiv');
128 shouldBe('mutations[0].attributeName', '"foo"');
129 shouldBe('mutations[0].attributeNamespace', 'null');
130 observer
.disconnect();
138 function testTransientDetachedBasic() {
142 debug('Testing that transiently detached nodes are still observed via subtree.');
145 div
= document
.createElement('div');
146 subDiv
= div
.appendChild(document
.createElement('div'));
147 subDiv
.innerHTML
= 'hello, world';
148 observer
= new MutationObserver(function(mutations
) {
149 window
.mutations
= mutations
;
152 observer
.observe(div
, {attributes
: true, characterData
: true, subtree
: true});
153 subDiv
.setAttribute('foo', 'bar');
154 div
.removeChild(subDiv
);
155 subDiv
.setAttribute('test', 'test');
156 setTimeout(checkDeliveredAndChangeAgain
, 0);
159 function checkDeliveredAndChangeAgain() {
160 debug('...both changes should be received. Change detached subDiv again.');
162 shouldBe('mutations.length', '2');
163 shouldBe('mutations[0].type', '"attributes"');
164 shouldBe('mutations[0].target', 'subDiv');
165 shouldBe('mutations[0].attributeName', '"foo"');
166 shouldBe('mutations[1].type', '"attributes"');
167 shouldBe('mutations[1].target', 'subDiv');
168 shouldBe('mutations[1].attributeName', '"test"');
171 subDiv
.setAttribute('foo', 'baz');
173 setTimeout(checkNotDeliveredAndReattach
);
176 function checkNotDeliveredAndReattach() {
177 debug('...transient subtree observation was stopped after delivery, so subDiv change should not be received. Reattach and change again.');
179 shouldBe('mutations', 'null');
182 div
.appendChild(subDiv
);
183 subDiv
.setAttribute('foo', 'bat');
185 setTimeout(checkDeliveredAndReobserve
);
188 function checkDeliveredAndReobserve() {
189 debug('...reattached subtree should now be observable. Try detaching and re-observing.');
191 shouldBe('mutations.length', '1');
192 shouldBe('mutations[0].type', '"attributes"');
193 shouldBe('mutations[0].target', 'subDiv');
194 shouldBe('mutations[0].attributeName', '"foo"');
197 div
.removeChild(subDiv
);
198 subDiv
.firstChild
.textContent
= 'badbye';
199 observer
.observe(div
, {attributes
: true, characterData
: true, subtree
: true});
200 subDiv
.setAttribute('foo', 'boo');
207 debug('...The change made before re-observing should be received, but not the one after.');
209 shouldBe('mutations.length', '1');
210 shouldBe('mutations[0].type', '"characterData"');
211 shouldBe('mutations[0].target', 'subDiv.firstChild');
213 observer
.disconnect();
220 function testTransientDetachedDetailed() {
224 debug('Testing correct behavior of transient observation with complex movement .');
227 div
= document
.createElement('div');
228 subDiv
= div
.appendChild(document
.createElement('div'));
229 subDiv2
= subDiv
.appendChild(document
.createElement('div'));
230 subDiv2
.innerHTML
= 'hello, world';
231 subDiv3
= document
.createElement('div');
233 observer
= new MutationObserver(function(mutations
) {
234 window
.mutations
= mutations
;
237 observer
.observe(div
, {attributes
: true, characterData
: true, subtree
: true});
238 div
.removeChild(subDiv
);
239 subDiv
.removeChild(subDiv2
);
240 text
= subDiv2
.removeChild(subDiv2
.firstChild
);
242 subDiv
.setAttribute('a', 'a');
243 subDiv2
.setAttribute('b', 'b');
244 text
.textContent
= 'c';
245 subDiv3
.appendChild(subDiv2
);
246 subDiv3
.setAttribute('d', 'd');
247 subDiv2
.setAttribute('e', 'e');
248 div
.appendChild(subDiv3
);
249 subDiv3
.setAttribute('f', 'f');
250 subDiv2
.setAttribute('g', 'g');
252 setTimeout(finish
, 0);
256 debug('...All changes should be received except for setting the "d" attribute on subDiv3 before it was reachable from div.');
258 shouldBe('mutations.length', '6');
259 shouldBe('mutations[0].type', '"attributes"');
260 shouldBe('mutations[0].target', 'subDiv');
261 shouldBe('mutations[0].attributeName', '"a"');
263 shouldBe('mutations[1].type', '"attributes"');
264 shouldBe('mutations[1].target', 'subDiv2');
265 shouldBe('mutations[1].attributeName', '"b"');
267 shouldBe('mutations[2].type', '"characterData"');
268 shouldBe('mutations[2].target', 'text');
270 shouldBe('mutations[3].type', '"attributes"');
271 shouldBe('mutations[3].target', 'subDiv2');
272 shouldBe('mutations[3].attributeName', '"e"');
274 shouldBe('mutations[4].type', '"attributes"');
275 shouldBe('mutations[4].target', 'subDiv3');
276 shouldBe('mutations[4].attributeName', '"f"');
278 shouldBe('mutations[5].type', '"attributes"');
279 shouldBe('mutations[5].target', 'subDiv2');
280 shouldBe('mutations[5].attributeName', '"g"');
282 observer
.disconnect();
289 var tests
= [testBasic
, testMultipleObservers
, testMultipleObservations
, testTransientDetachedBasic
, testTransientDetachedDetailed
];
292 function runNextTest() {
293 if (testIndex
< tests
.length
)
294 tests
[testIndex
++]();
299 description('Test WebKitMutationObserver.observe on a subtree');