Move parseFontFaceDescriptor to CSSPropertyParser.cpp
[chromium-blink-merge.git] / third_party / WebKit / LayoutTests / fast / dom / MutationObserver / observe-attributes.html
blob9a41ff6ee3e16511676c242d94b2886b0c9b86cf
1 <!DOCTYPE html>
2 <script src="../../../resources/js-test.js"></script>
3 <script>
5 window.jsTestIsAsync = true;
6 var mutations, mutations2, mutationsWithOldValue;
7 var calls;
8 var div;
10 function testBasic() {
11 var div;
12 var observer;
14 function start() {
15 debug('Testing basic aspects of attribute observation.');
17 mutations = null;
18 div = document.createElement('div');
19 div.setAttribute('bar', 'foo');
21 observer = new MutationObserver(function(m) {
22 mutations = m;
23 });
25 observer.observe(div, { attributes: true, characterData: true });
26 div.setAttribute('foo', 'bar');
27 div.removeAttribute('bar');
28 setTimeout(checkDisconnectAndMutate, 0);
31 function checkDisconnectAndMutate() {
32 debug('...can attribute changes be observed at all');
34 shouldBe('mutations.length', '2');
35 shouldBe('mutations[0].type', '"attributes"');
36 shouldBe('mutations[0].attributeName', '"foo"');
37 shouldBe('mutations[0].attributeNamespace', 'null');
38 shouldBe('mutations[1].type', '"attributes"');
39 shouldBe('mutations[1].attributeName', '"bar"');
40 shouldBe('mutations[1].attributeNamespace', 'null');
42 mutations = null;
43 observer.disconnect();
44 div.setAttribute('foo', 'baz');
45 setTimeout(checkNotDeliveredAndMutateMultiple, 0);
48 function checkNotDeliveredAndMutateMultiple() {
49 debug('...observer.disconnect() should prevent further delivery of mutations.');
51 shouldBe('mutations', 'null');
52 observer.observe(div, { attributes: true });
53 div.setAttribute('foo', 'bat');
54 div.setAttribute('bar', 'foo');
55 setTimeout(finish);
58 function finish() {
59 debug('...re-observing after disconnect works with the same observer.');
61 shouldBe('mutations.length', '2');
62 shouldBe('mutations[0].type', '"attributes"');
63 shouldBe('mutations[0].attributeName', '"foo"');
64 shouldBe('mutations[0].attributeNamespace', 'null');
65 shouldBe('mutations[1].type', '"attributes"');
66 shouldBe('mutations[1].attributeName', '"bar"');
67 shouldBe('mutations[1].attributeNamespace', 'null');
68 observer.disconnect();
69 debug('');
70 runNextTest();
73 start();
76 function testWrongType() {
77 var div;
78 var observer;
80 function start() {
81 debug('Testing that observing without specifying "attributes" does not result in hearing about attribute changes.');
83 mutations = null;
84 div = document.createElement('div');
85 observer = new MutationObserver(function(m) {
86 mutations = m;
87 });
89 observer.observe(div, { childList: true, characterData: true });
90 div.setAttribute('foo', 'bar');
91 setTimeout(finish, 0);
94 function finish() {
95 shouldBe('mutations', 'null');
96 observer.disconnect();
97 debug('');
98 runNextTest();
101 start();
104 function testMultipleRegistration() {
105 var div;
106 var observer;
108 function start() {
109 debug('Testing that re-observing the same node with the same observer has the effect of resetting the options.');
111 calls = 0;
112 mutations = null;
113 div = document.createElement('div');
114 observer = new MutationObserver(function(m) {
115 mutations = m;
116 calls++;
119 observer.observe(div, { attributes: true, characterData: true });
120 observer.observe(div, { attributes: true });
121 div.setAttribute('foo', 'bar');
122 setTimeout(checkDisconnectAndMutate, 0);
125 function checkDisconnectAndMutate() {
126 shouldBe('calls', '1');
127 shouldBe('mutations.length', '1');
128 shouldBe('mutations[0].type', '"attributes"');
129 shouldBe('mutations[0].attributeName', '"foo"');
130 mutations = null;
131 observer.observe(div, { attributes: true, characterData: true });
132 observer.observe(div, { childList: true });
133 div.setAttribute('foo', 'baz');
134 setTimeout(finish, 0);
137 function finish() {
138 shouldBe('mutations', 'null');
139 observer.disconnect();
140 debug('');
141 runNextTest();
144 start();
147 function testMultipleObservers() {
148 var div;
149 var observer;
150 var observer2;
152 function start() {
153 debug('Testing that multiple observers can be registered to a given node and both receive mutations.');
154 mutations = null;
155 div = document.createElement('div');
156 observer = new MutationObserver(function(m) {
157 mutations = m;
159 observer2 = new MutationObserver(function(m) {
160 mutations2 = m;
162 observer.observe(div, { attributes: true });
163 observer2.observe(div, { attributes: true });
164 div.setAttribute('foo', 'bar');
165 setTimeout(finish, 0);
168 function finish() {
169 shouldBe('mutations.length', '1');
170 shouldBe('mutations[0].type', '"attributes"');
171 shouldBe('mutations[0].attributeName', '"foo"');
172 shouldBe('mutations2.length', '1');
173 shouldBe('mutations2[0].type', '"attributes"');
174 shouldBe('mutations2[0].attributeName', '"foo"');
175 observer.disconnect();
176 observer2.disconnect();
177 debug('');
178 runNextTest();
181 start();
184 function testNamespaceURI() {
185 var div;
186 var observer;
188 function start() {
189 debug('Testing that "attributeNamespace" value is delivered properly.');
190 mutations = null;
191 div = document.createElement('div');
192 observer = new MutationObserver(function(m) {
193 mutations = m;
196 observer.observe(div, { attributes: true, childList: true });
197 div.setAttributeNS('http://www.foo.com/bar', 'foo', 'bar');
198 setTimeout(finish, 0);
201 function finish() {
202 shouldBe('mutations.length', '1');
203 shouldBe('mutations[0].type', '"attributes"');
204 shouldBe('mutations[0].attributeName', '"foo"');
205 shouldBe('mutations[0].attributeNamespace', '"http://www.foo.com/bar"');
206 observer.disconnect();
207 debug('');
208 runNextTest();
211 start();
214 function testPropertyAccess() {
215 var img, a;
216 var observer;
218 function start() {
219 debug('Testing that modifications to node properties which delegate to attribute storage deliver mutations.');
220 mutations = null;
221 img = document.createElement('img');
222 a = document.createElement('a');
224 observer = new MutationObserver(function(m) {
225 mutations = m;
228 observer.observe(img, { attributes: true });
229 observer.observe(a, { attributes: true });
231 img.src = 'baz.png';
232 a.href = 'foo.html';
234 setTimeout(finish, 0);
237 function finish() {
238 shouldBe('mutations.length', '2');
239 shouldBe('mutations[0].type', '"attributes"');
240 shouldBe('mutations[0].attributeName', '"src"');
241 shouldBe('mutations[1].type', '"attributes"');
242 shouldBe('mutations[1].attributeName', '"href"');
243 observer.disconnect();
244 debug('');
245 runNextTest();
248 start();
251 function testOrderingWrtDOMSubtreeModified() {
252 var div, div2, subDiv;
253 var observer;
254 var listener;
256 function start() {
257 debug('Testing mutation records are enqueued for attributes before DOMSubtreeModified is dispatched.');
259 mutations = null;
260 div = document.body.appendChild(document.createElement('div'));
261 div2 = document.body.appendChild(document.createElement('div'));
263 subDiv = div.appendChild(document.createElement('div'));
265 observer = new MutationObserver(function(m) {
266 mutations = m;
269 listener = function(e) {
270 div2.setAttribute('baz', 'bat');
273 div.addEventListener('DOMSubtreeModified', listener);
274 observer.observe(subDiv, { attributes: true });
275 observer.observe(div2, { attributes: true });
277 subDiv.setAttribute('foo', 'bar');
279 setTimeout(finish, 0);
282 function finish() {
283 shouldBe('mutations.length', '2');
284 shouldBe('mutations[0].type', '"attributes"');
285 shouldBe('mutations[0].attributeName', '"foo"');
286 shouldBe('mutations[1].type', '"attributes"');
287 shouldBe('mutations[1].attributeName', '"baz"');
288 div.removeEventListener('DOMSubtreeModified', listener);
289 document.body.removeChild(div);
290 observer.disconnect();
291 debug('');
292 runNextTest();
295 start();
298 function testOldValue() {
299 var div;
300 var observer;
302 function start() {
303 debug('Testing basic oldValue delivery.');
304 mutations = null;
305 div = document.createElement('div');
306 div.setAttribute('bar', 'boo');
308 observer = new MutationObserver(function(mutations) {
309 window.mutations = mutations;
311 observer.observe(div, { attributes: true, attributeOldValue: true });
312 div.setAttribute('foo', 'bar');
313 div.setAttribute('foo', 'baz');
314 div.removeAttribute('bar');
315 div.removeAttribute('non-existant');
316 setTimeout(finish, 0);
319 function finish() {
320 shouldBe('mutations.length', '3');
321 shouldBe('mutations[0].type', '"attributes"');
322 shouldBe('mutations[0].attributeName', '"foo"');
323 shouldBe('mutations[0].oldValue', 'null');
324 shouldBe('mutations[1].type', '"attributes"');
325 shouldBe('mutations[1].attributeName', '"foo"');
326 shouldBe('mutations[1].oldValue', '"bar"');
327 shouldBe('mutations[2].type', '"attributes"');
328 shouldBe('mutations[2].attributeName', '"bar"');
329 shouldBe('mutations[2].oldValue', '"boo"');
330 observer.disconnect();
331 debug('');
332 runNextTest();
335 start();
338 function testOldValueAsRequested() {
339 var div;
340 var observerWithOldValue;
341 var observer;
343 function start() {
344 debug('Testing that oldValue is delivered as requested (or not).');
345 mutationsWithOldValue = null;
346 mutations = null;
347 div = document.createElement('div');
348 div.setAttribute('foo', 'bar');
349 observerWithOldValue = new MutationObserver(function(mutations) {
350 window.mutationsWithOldValue = mutations;
352 observer = new MutationObserver(function(mutations) {
353 window.mutations = mutations;
355 observerWithOldValue.observe(div, { attributes: true, attributeOldValue: true });
356 observer.observe(div, { attributes: true });
357 div.setAttribute('foo', 'baz');
358 setTimeout(finish, 0);
361 function finish() {
362 shouldBe('mutationsWithOldValue.length', '1');
363 shouldBe('mutationsWithOldValue[0].type', '"attributes"');
364 shouldBe('mutationsWithOldValue[0].attributeName', '"foo"');
365 shouldBe('mutationsWithOldValue[0].oldValue', '"bar"');
366 shouldBe('mutations.length', '1');
367 shouldBe('mutations[0].type', '"attributes"');
368 shouldBe('mutations[0].attributeName', '"foo"');
369 shouldBe('mutations[0].oldValue', 'null');
370 observerWithOldValue.disconnect();
371 observer.disconnect();
372 debug('');
373 runNextTest();
376 start();
379 function testOldValueUnionMultipleObservations() {
380 var div;
381 var span;
382 var observer;
384 function start() {
385 debug('An observer with multiple observations will get attributeOldValue if any entries request it.');
386 mutations = null;
387 div = document.createElement('div');
388 span = div.appendChild(document.createElement('span'));
389 span.setAttribute('foo', 'bar');
390 observer = new MutationObserver(function(mutations) {
391 window.mutations = mutations;
393 observer.observe(div, { attributes: true, attributeOldValue: true, subtree: true });
394 observer.observe(span, { attributes: true });
395 span.setAttribute('foo', 'baz');
396 setTimeout(finish, 0);
399 function finish() {
400 shouldBe('mutations.length', '1');
401 shouldBe('mutations[0].type', '"attributes"');
402 shouldBe('mutations[0].attributeName', '"foo"');
403 shouldBe('mutations[0].oldValue', '"bar"');
404 observer.disconnect();
405 debug('');
406 runNextTest();
409 start();
412 function testIDLAttribute() {
413 var div;
414 var observer;
416 function start() {
417 debug('Testing setting an attribute via reflected IDL attribute.');
418 mutations = null;
419 div = document.createElement('div');
420 observer = new MutationObserver(function(mutations) {
421 window.mutations = mutations;
423 observer.observe(div, { attributes: true, attributeOldValue: true });
424 div.id = 'foo';
425 div.id = 'bar';
426 div.id = null;
427 setTimeout(finish, 0);
430 function finish() {
431 shouldBe('mutations.length', '3');
432 shouldBe('mutations[0].type', '"attributes"');
433 shouldBe('mutations[0].attributeName', '"id"');
434 shouldBe('mutations[0].oldValue', 'null');
435 shouldBe('mutations[1].type', '"attributes"');
436 shouldBe('mutations[1].attributeName', '"id"');
437 shouldBe('mutations[1].oldValue', '"foo"');
438 shouldBe('mutations[2].type', '"attributes"');
439 shouldBe('mutations[2].attributeName', '"id"');
440 shouldBe('mutations[2].oldValue', '"bar"');
441 observer.disconnect();
442 debug('');
443 runNextTest();
446 start();
449 function testAttributeFilter() {
450 var div, path;
451 var observer;
453 function start() {
454 debug('Testing that attributeFilter works as expected and observes case with HTML elements.');
456 mutations = null;
457 observer = new MutationObserver(function(m) {
458 mutations = m;
461 div = document.createElement('div');
462 observer.observe(div, { attributes: true, attributeFilter: ['foo', 'bar', 'booM'] });
463 div.setAttribute('foo', 'foo');
464 div.setAttribute('bar', 'bar');
465 div.setAttribute('baz', 'baz');
466 div.setAttribute('BOOm', 'boom');
468 setTimeout(finish, 0);
471 function finish() {
472 debug('...only foo and bar should be received.');
474 shouldBe('mutations.length', '2');
475 shouldBe('mutations[0].type', '"attributes"');
476 shouldBe('mutations[0].attributeName', '"foo"');
477 shouldBe('mutations[0].attributeNamespace', 'null');
478 shouldBe('mutations[1].type', '"attributes"');
479 shouldBe('mutations[1].attributeName', '"bar"');
480 shouldBe('mutations[1].attributeNamespace', 'null');
481 observer.disconnect();
482 debug('');
483 runNextTest();
486 start();
489 function testAttributeFilterSubtree() {
490 var div, div2, div3;
491 var observer;
493 function start() {
494 debug('Testing the behavior of attributeFilter when the same observer observes at multiple nodes in a subtree with different filter options.');
496 mutations = null;
497 observer = new MutationObserver(function(m) {
498 mutations = m;
501 div = document.createElement('div');
502 div2 = div.appendChild(document.createElement('div'));
503 div3 = div2.appendChild(document.createElement('div'));
505 observer.observe(div, { attributes: true, subtree: true, attributeFilter: ['foo', 'bar'] });
506 observer.observe(div2, { attributes: true, subtree: true, attributeFilter: ['bar', 'bat'] });
508 div3.setAttribute('foo', 'foo');
509 div3.setAttribute('bar', 'bar');
510 div3.setAttribute('bat', 'bat');
511 div3.setAttribute('baz', 'baz');
513 setTimeout(checkAndObserveAll, 0);
516 function checkAndObserveAll() {
517 debug('...only foo, bar & bat should be received.');
519 shouldBe('mutations.length', '3');
520 shouldBe('mutations[0].type', '"attributes"');
521 shouldBe('mutations[0].attributeName', '"foo"');
522 shouldBe('mutations[0].attributeNamespace', 'null');
523 shouldBe('mutations[1].type', '"attributes"');
524 shouldBe('mutations[1].attributeName', '"bar"');
525 shouldBe('mutations[1].attributeNamespace', 'null');
526 shouldBe('mutations[2].type', '"attributes"');
527 shouldBe('mutations[2].attributeName', '"bat"');
528 shouldBe('mutations[2].attributeNamespace', 'null');
530 observer.observe(div2, { attributes: true, subtree: true });
531 div3.setAttribute('bar', 'bar');
532 div3.setAttribute('bat', 'bat');
533 div3.setAttribute('baz', 'baz');
535 setTimeout(finish, 0);
538 function finish() {
539 debug('...bar, bat & baz should all be received.');
541 shouldBe('mutations.length', '3');
542 shouldBe('mutations[0].type', '"attributes"');
543 shouldBe('mutations[0].attributeName', '"bar"');
544 shouldBe('mutations[0].attributeNamespace', 'null');
545 shouldBe('mutations[1].type', '"attributes"');
546 shouldBe('mutations[1].attributeName', '"bat"');
547 shouldBe('mutations[1].attributeNamespace', 'null');
548 shouldBe('mutations[2].type', '"attributes"');
549 shouldBe('mutations[2].attributeName', '"baz"');
550 shouldBe('mutations[2].attributeNamespace', 'null');
552 observer.disconnect();
553 debug('');
554 runNextTest();
557 start();
560 function testAttributeFilterNonHTMLElement() {
561 var path;
562 var observer;
564 function start() {
565 debug('Testing that setting an attributeFilter filters out namespaced attributes.');
567 mutations = null;
568 observer = new MutationObserver(function(m) {
569 mutations = m;
572 path = document.createElementNS('http://www.w3.org/2000/svg', 'path');
573 observer.observe(path, { attributes: true, attributeFilter: ['pathLength'] });
574 path.setAttributeNS('http://www.w3.org/2000/svg', 'pathLength', '200');
576 setTimeout(finish, 0);
579 function finish() {
580 debug('...pathLength should not be received.');
582 shouldBeNull('mutations');
583 observer.disconnect();
584 debug('');
585 runNextTest();
588 start();
591 function testAttributeFilterNonHTMLDocument() {
592 var svgDoc, div, path;
593 var observer;
595 function start() {
596 debug('Testing that attributeFilter respects case with non-HTML elements.');
598 svgDoc = document.implementation.createDocument('http://www.w3.org/2000/svg', 'svg');
599 mutations = null;
600 observer = new MutationObserver(function(m) {
601 mutations = m;
604 div = svgDoc.createElement('div');
605 observer.observe(div, { attributes: true, attributeFilter: ['ID', 'id', 'booM'] });
606 div.setAttribute('ID', 'ID');
607 div.setAttribute('id', 'id');
608 div.setAttribute('baz', 'baz');
609 div.setAttribute('booM', 'boom');
610 div.setAttribute('BOOm', 'boom');
612 setTimeout(finish, 0);
615 function finish() {
616 debug('...only ID, id, booM should be received.');
618 shouldBe('mutations.length', '3');
619 shouldBe('mutations[0].type', '"attributes"');
620 shouldBe('mutations[0].attributeName', '"ID"');
621 shouldBe('mutations[0].attributeNamespace', 'null');
622 shouldBe('mutations[1].type', '"attributes"');
623 shouldBe('mutations[1].attributeName', '"id"');
624 shouldBe('mutations[1].attributeNamespace', 'null');
625 shouldBe('mutations[2].type', '"attributes"');
626 shouldBe('mutations[2].attributeName', '"booM"');
627 shouldBe('mutations[2].attributeNamespace', 'null');
629 observer.disconnect();
630 debug('');
631 runNextTest();
634 start();
637 function testStyleAttributePropertyAccess() {
638 var div, path;
639 var observer;
641 function start() {
642 debug('Testing that modifying an elements style property dispatches Mutation Records.');
644 mutations = null;
645 observer = new MutationObserver(function(m) {
646 mutations = m;
649 div = document.createElement('div');
650 div.setAttribute('style', 'color: yellow; width: 100px;');
651 observer.observe(div, { attributes: true });
652 div.style.color = 'red';
653 div.style.width = '200px';
654 div.style.color = 'blue';
656 setTimeout(checkAndContinue, 0);
659 function checkAndContinue() {
660 shouldBe('mutations.length', '3');
661 shouldBe('mutations[0].type', '"attributes"');
662 shouldBe('mutations[0].attributeName', '"style"');
663 shouldBe('mutations[0].oldValue', 'null');
664 shouldBe('mutations[1].type', '"attributes"');
665 shouldBe('mutations[1].attributeName', '"style"');
666 shouldBe('mutations[1].oldValue', 'null');
667 shouldBe('mutations[2].type', '"attributes"');
668 shouldBe('mutations[2].attributeName', '"style"');
669 shouldBe('mutations[2].oldValue', 'null');
671 mutations = null;
672 div.getAttribute('style');
673 setTimeout(finish, 0);
676 function finish() {
677 debug('...mutation record created.');
679 shouldBe('mutations', 'null');
681 observer.disconnect();
682 debug('');
683 runNextTest();
686 start();
689 function testStyleAttributePropertyAccessOldValue() {
690 var div, path;
691 var observer;
693 function start() {
694 debug('Testing that modifying an elements style property dispatches Mutation Records with correct oldValues.');
696 mutations = null;
697 observer = new MutationObserver(function(m) {
698 mutations = m;
701 div = document.createElement('div');
702 div.setAttribute('style', 'color: yellow; width: 100px;');
703 observer.observe(div, { attributes: true, attributeOldValue: true });
704 div.style.color = 'red';
705 div.style.width = '200px';
706 div.style.color = 'blue';
708 setTimeout(checkAndContinue, 0);
711 function checkAndContinue() {
712 shouldBe('mutations.length', '3');
713 shouldBe('mutations[0].type', '"attributes"');
714 shouldBe('mutations[0].attributeName', '"style"');
715 shouldBe('mutations[0].oldValue', '"color: yellow; width: 100px;"');
716 shouldBe('mutations[1].type', '"attributes"');
717 shouldBe('mutations[1].attributeName', '"style"');
718 shouldBe('mutations[1].oldValue', '"color: red; width: 100px;"');
719 shouldBe('mutations[2].type', '"attributes"');
720 shouldBe('mutations[2].attributeName', '"style"');
721 shouldBe('mutations[2].oldValue', '"color: red; width: 200px;"');
723 mutations = null;
724 div.getAttribute('style');
725 setTimeout(finish, 0);
728 function finish() {
729 debug('...mutation record created.');
731 shouldBe('mutations', 'null');
733 observer.disconnect();
734 debug('');
735 runNextTest();
738 start();
741 function testStyleAttributePropertyAccessIgnoreNoop() {
742 var div, path;
743 var observer;
745 function start() {
746 debug('Testing that a no-op style property mutation does not create Mutation Records.');
748 mutations = null;
749 observer = new MutationObserver(function(m) {
750 mutations = m;
753 div = document.createElement('div');
754 div.setAttribute('style', 'color: yellow; width: 100px;');
755 observer.observe(div, { attributes: true });
756 div.style.removeProperty('height');
758 setTimeout(finish, 0);
761 function finish() {
762 shouldBe('mutations', 'null');
764 observer.disconnect();
765 debug('');
766 runNextTest();
769 start();
772 function testMutateThroughAttrNodeValue() {
773 var observer;
775 function start() {
776 debug('Test that mutating an attribute through an attr node delivers mutation records');
778 mutations = null;
779 observer = new MutationObserver(function(mutations) {
780 window.mutations = mutations;
783 div = document.createElement('div');
784 div.setAttribute('data-test', 'foo');
785 observer.observe(div, { attributes: true, attributeOldValue: true });
786 div.attributes['data-test'].value = 'bar';
788 setTimeout(finish, 0);
791 function finish() {
792 shouldBe('mutations.length', '1');
793 shouldBe('mutations[0].target', 'div');
794 shouldBe('mutations[0].type', '"attributes"');
795 shouldBe('mutations[0].attributeName', '"data-test"');
796 shouldBe('mutations[0].oldValue', '"foo"');
798 observer.disconnect();
799 debug('');
800 runNextTest();
803 start();
806 function testSetAndRemoveAttributeNode() {
807 var observer;
809 function start() {
810 debug('Test that mutating via setAttributeNode delivers mutation records');
812 mutations = null;
813 observer = new MutationObserver(function(mutations) {
814 window.mutations = mutations;
817 div = document.createElement('div');
818 div.id = 'myId';
819 div.setAttribute('data-test', 'foo');
820 observer.observe(div, { attributes: true, attributeOldValue: true });
821 var attr = document.createAttribute('data-test');
822 attr.value = 'bar';
823 div.setAttributeNode(attr);
824 attr = document.createAttribute('data-other');
825 attr.value = 'baz';
826 div.setAttributeNode(attr);
827 div.removeAttributeNode(div.attributes['id']);
829 setTimeout(finish, 0);
832 function finish() {
833 shouldBe('mutations.length', '3');
834 shouldBe('mutations[0].target', 'div');
835 shouldBe('mutations[0].type', '"attributes"');
836 shouldBe('mutations[0].attributeName', '"data-test"');
837 shouldBe('mutations[0].oldValue', '"foo"');
838 shouldBe('mutations[1].target', 'div');
839 shouldBe('mutations[1].type', '"attributes"');
840 shouldBe('mutations[1].attributeName', '"data-other"');
841 shouldBe('mutations[1].oldValue', 'null');
842 shouldBe('mutations[2].target', 'div');
843 shouldBe('mutations[2].type', '"attributes"');
844 shouldBe('mutations[2].attributeName', '"id"');
845 shouldBe('mutations[2].oldValue', '"myId"');
847 observer.disconnect();
848 debug('');
849 runNextTest();
852 start();
855 function testMixedNodeAndElementOperations() {
856 var observer;
858 function start() {
859 debug('Test that setAttribute on an attribute with an existing Attr delivers mutation records');
861 mutations = null;
862 observer = new MutationObserver(function(mutations) {
863 window.mutations = mutations;
866 div = document.createElement('div');
867 var attr = document.createAttribute('data-test');
868 attr.value = 'foo';
869 div.setAttributeNode(attr);
870 observer.observe(div, { attributes: true, attributeOldValue: true });
871 div.setAttribute('data-test', 'bar');
873 setTimeout(finish, 0);
876 function finish() {
877 shouldBe('mutations.length', '1');
878 shouldBe('mutations[0].target', 'div');
879 shouldBe('mutations[0].type', '"attributes"');
880 shouldBe('mutations[0].attributeName', '"data-test"');
881 shouldBe('mutations[0].oldValue', '"foo"');
883 observer.disconnect();
884 debug('');
885 runNextTest();
888 start();
891 function testNamedNodeMapOperations() {
892 var observer;
894 function start() {
895 debug('Test that setNamedItem and removeNamedItem deliver mutation records');
897 mutations = null;
898 observer = new MutationObserver(function(mutations) {
899 window.mutations = mutations;
902 div = document.createElement('div');
903 div.setAttribute('data-test', 'foo');
904 observer.observe(div, { attributes: true, attributeOldValue: true });
905 var attr = document.createAttribute('data-test');
906 attr.value = 'bar';
907 div.attributes.setNamedItem(attr);
908 div.attributes.removeNamedItem('data-test');
910 setTimeout(finish, 0);
913 function finish() {
914 shouldBe('mutations.length', '2');
915 shouldBe('mutations[0].target', 'div');
916 shouldBe('mutations[0].type', '"attributes"');
917 shouldBe('mutations[0].attributeName', '"data-test"');
918 shouldBe('mutations[0].oldValue', '"foo"');
919 shouldBe('mutations[1].target', 'div');
920 shouldBe('mutations[1].type', '"attributes"');
921 shouldBe('mutations[1].attributeName', '"data-test"');
922 shouldBe('mutations[1].oldValue', '"bar"');
924 observer.disconnect();
925 debug('');
926 runNextTest();
929 start();
932 var tests = [
933 testBasic,
934 testWrongType,
935 testMultipleRegistration,
936 testMultipleObservers,
937 testNamespaceURI,
938 testPropertyAccess,
939 testOrderingWrtDOMSubtreeModified,
940 testOldValue,
941 testOldValueAsRequested,
942 testOldValueUnionMultipleObservations,
943 testIDLAttribute,
944 testAttributeFilter,
945 testAttributeFilterSubtree,
946 testAttributeFilterNonHTMLElement,
947 testAttributeFilterNonHTMLDocument,
948 testStyleAttributePropertyAccess,
949 testStyleAttributePropertyAccessOldValue,
950 testStyleAttributePropertyAccessIgnoreNoop,
951 testMutateThroughAttrNodeValue,
952 testSetAndRemoveAttributeNode,
953 testMixedNodeAndElementOperations,
954 testNamedNodeMapOperations
956 var testIndex = 0;
958 function runNextTest() {
959 if (testIndex < tests.length)
960 tests[testIndex++]();
961 else
962 finishJSTest();
965 description('Test WebKitMutationObserver.observe on attributes');
967 runNextTest();
968 </script>