Layout Test inspector/debugger/dom-breakpoints.html fails on chromium linux debug...
[WebKit-https.git] / LayoutTests / fast / mutation / observe-attributes.html
1 <!DOCTYPE html>
2 <html>
3 <head>
4 <meta charset="utf-8">
5 <script src="../js/resources/js-test-pre.js"></script>
6 </head>
7 <body>
8 <p id=description></p>
9 <div id="console"></div>
10 <script>
11
12 window.jsTestIsAsync = true;
13 var mutations, mutations2, mutationsWithOldValue;
14 var calls;
15
16 function testBasic() {
17     var div;
18     var observer;
19
20     function start() {
21         debug('Testing basic aspects of attribute observation.');
22
23         mutations = null;
24         div = document.createElement('div');
25         div.setAttribute('bar', 'foo');
26
27         observer = new WebKitMutationObserver(function(m) {
28             mutations = m;
29         });
30
31         observer.observe(div, { attributes: true, characterData: true });
32         div.setAttribute('foo', 'bar');
33         div.removeAttribute('bar');
34         setTimeout(checkDisconnectAndMutate, 0);
35     }
36
37     function checkDisconnectAndMutate() {
38         debug('...can attribute changes be observed at all');
39
40         shouldBe('mutations.length', '2');
41         shouldBe('mutations[0].type', '"attributes"');
42         shouldBe('mutations[0].attributeName', '"foo"');
43         shouldBe('mutations[0].attributeNamespace', 'null');
44         shouldBe('mutations[1].type', '"attributes"');
45         shouldBe('mutations[1].attributeName', '"bar"');
46         shouldBe('mutations[1].attributeNamespace', 'null');
47
48         mutations = null;
49         observer.disconnect();
50         div.setAttribute('foo', 'baz');
51         setTimeout(checkNotDeliveredAndMutateMultiple, 0);
52     }
53
54     function checkNotDeliveredAndMutateMultiple() {
55         debug('...observer.disconnect() should prevent further delivery of mutations.');
56
57         shouldBe('mutations', 'null');
58         observer.observe(div, { attributes: true });
59         div.setAttribute('foo', 'bat');
60         div.setAttribute('bar', 'foo');
61         setTimeout(finish);
62     }
63
64     function finish() {
65         debug('...re-observing after disconnect works with the same observer.');
66
67         shouldBe('mutations.length', '2');
68         shouldBe('mutations[0].type', '"attributes"');
69         shouldBe('mutations[0].attributeName', '"foo"');
70         shouldBe('mutations[0].attributeNamespace', 'null');
71         shouldBe('mutations[1].type', '"attributes"');
72         shouldBe('mutations[1].attributeName', '"bar"');
73         shouldBe('mutations[1].attributeNamespace', 'null');
74         observer.disconnect();
75         debug('');
76         runNextTest();
77     }
78
79     start();
80 }
81
82 function testWrongType() {
83     var div;
84     var observer;
85
86     function start() {
87         debug('Testing that observing without specifying "attributes" does not result in hearing about attribute changes.');
88
89         mutations = null;
90         div = document.createElement('div');
91         observer = new WebKitMutationObserver(function(m) {
92             mutations = m;
93         });
94
95         observer.observe(div, { childList: true, characterData: true });
96         div.setAttribute('foo', 'bar');
97         setTimeout(finish, 0);
98     }
99
100     function finish() {
101         shouldBe('mutations', 'null');
102         observer.disconnect();
103         debug('');
104         runNextTest();
105     }
106
107     start();
108 }
109
110 function testMultipleRegistration() {
111     var div;
112     var observer;
113
114     function start() {
115         debug('Testing that re-observing the same node with the same observer has the effect of resetting the options.');
116
117                 calls = 0;
118         mutations = null;
119         div = document.createElement('div');
120         observer = new WebKitMutationObserver(function(m) {
121             mutations = m;
122                         calls++;
123         });
124
125         observer.observe(div, { attributes: true, characterData: true });
126         observer.observe(div, { attributes: true });
127         div.setAttribute('foo', 'bar');
128         setTimeout(checkDisconnectAndMutate, 0);
129     }
130
131     function checkDisconnectAndMutate() {
132         shouldBe('calls', '1');
133         shouldBe('mutations.length', '1');
134         shouldBe('mutations[0].type', '"attributes"');
135         shouldBe('mutations[0].attributeName', '"foo"');
136         mutations = null;
137         observer.observe(div, { attributes: true, characterData: true });
138         observer.observe(div, { childList: true });
139         div.setAttribute('foo', 'baz');
140         setTimeout(finish, 0);
141     }
142
143     function finish() {
144         shouldBe('mutations', 'null');
145         observer.disconnect();
146         debug('');
147         runNextTest();
148     }
149
150     start();
151 }
152
153 function testMultipleObservers() {
154     var div;
155     var observer;
156     var observer2;
157
158     function start() {
159         debug('Testing that multiple observers can be registered to a given node and both receive mutations.');
160         mutations = null;
161         div = document.createElement('div');
162         observer = new WebKitMutationObserver(function(m) {
163             mutations = m;
164         });
165         observer2 = new WebKitMutationObserver(function(m) {
166             mutations2 = m;
167         });
168         observer.observe(div, { attributes: true });
169         observer2.observe(div, { attributes: true });
170         div.setAttribute('foo', 'bar');
171         setTimeout(finish, 0);
172     }
173
174     function finish() {
175         shouldBe('mutations.length', '1');
176         shouldBe('mutations[0].type', '"attributes"');
177         shouldBe('mutations[0].attributeName', '"foo"');
178         shouldBe('mutations2.length', '1');
179         shouldBe('mutations2[0].type', '"attributes"');
180         shouldBe('mutations2[0].attributeName', '"foo"');
181         observer.disconnect();
182         observer2.disconnect();
183         debug('');
184         runNextTest();
185     }
186
187     start();
188 }
189
190 function testNamespaceURI() {
191     var div;
192     var observer;
193
194     function start() {
195         debug('Testing that "attributeNamespace" value is delivered properly.');
196         mutations = null;
197         div = document.createElement('div');
198         observer = new WebKitMutationObserver(function(m) {
199             mutations = m;
200         });
201
202         observer.observe(div, { attributes: true, childList: true });
203         div.setAttributeNS('http://www.foo.com/bar', 'foo', 'bar');
204         setTimeout(finish, 0);    
205     }
206
207     function finish() {
208         shouldBe('mutations.length', '1');
209         shouldBe('mutations[0].type', '"attributes"');
210         shouldBe('mutations[0].attributeName', '"foo"');
211         shouldBe('mutations[0].attributeNamespace', '"http://www.foo.com/bar"');        
212         observer.disconnect();
213         debug('');
214         runNextTest();
215     }
216
217     start();
218 }
219
220 function testPropertyAccess() {
221     var img, a;
222     var observer;
223
224     function start() {
225         debug('Testing that modifications to node properties which delegate to attribute storage deliver mutations.');
226         mutations = null;
227         img = document.createElement('img');
228         a = document.createElement('a');
229
230         observer = new WebKitMutationObserver(function(m) {
231             mutations = m;
232         });
233
234         observer.observe(img, { attributes: true });
235         observer.observe(a, { attributes: true });
236
237         img.src = 'baz.png';
238         a.href = 'foo.html';
239
240         setTimeout(finish, 0);
241     }
242
243     function finish() {
244         shouldBe('mutations.length', '2');
245         shouldBe('mutations[0].type', '"attributes"');
246         shouldBe('mutations[0].attributeName', '"src"');
247         shouldBe('mutations[1].type', '"attributes"');
248         shouldBe('mutations[1].attributeName', '"href"');
249         observer.disconnect();
250         debug('');
251         runNextTest();
252     }
253
254     start();
255 }
256
257 function testOrderingWrtDOMSubtreeModified() {
258     var div, div2, subDiv;
259     var observer;
260     var listener;
261
262     function start() {
263         debug('Testing mutation records are enqueued for attributes before DOMSubtreeModified is dispatched.');
264
265         mutations = null;
266         div = document.body.appendChild(document.createElement('div'));
267         div2 = document.body.appendChild(document.createElement('div'));
268
269         subDiv = div.appendChild(document.createElement('div'));
270
271         observer = new WebKitMutationObserver(function(m) {
272             mutations = m;
273         });
274
275         listener = function(e) {
276             div2.setAttribute('baz', 'bat');
277         }
278
279         div.addEventListener('DOMSubtreeModified', listener);
280         observer.observe(subDiv, { attributes: true });
281         observer.observe(div2, { attributes: true });
282
283         subDiv.setAttribute('foo', 'bar');
284
285         setTimeout(finish, 0);
286     }
287
288     function finish() {
289         shouldBe('mutations.length', '2');
290         shouldBe('mutations[0].type', '"attributes"');
291         shouldBe('mutations[0].attributeName', '"foo"');
292         shouldBe('mutations[1].type', '"attributes"');
293         shouldBe('mutations[1].attributeName', '"baz"');
294         div.removeEventListener(listener);
295         document.body.removeChild(div);
296         observer.disconnect();
297         debug('');
298         runNextTest();
299     }
300
301     start();
302 }
303
304 function testOldValue() {
305     var div;
306     var observer;
307
308     function start() {
309         debug('Testing basic oldValue delivery.');
310         mutations = null;
311         div = document.createElement('div');
312         div.setAttribute('bar', 'boo');
313         
314         observer = new WebKitMutationObserver(function(mutations) {
315             window.mutations = mutations;
316         });
317         observer.observe(div, { attributes: true, attributeOldValue: true });
318         div.setAttribute('foo', 'bar');
319         div.setAttribute('foo', 'baz');
320         div.removeAttribute('bar');
321         div.removeAttribute('non-existant');
322         setTimeout(finish, 0);
323     }
324
325     function finish() {
326         shouldBe('mutations.length', '3');
327         shouldBe('mutations[0].type', '"attributes"');
328         shouldBe('mutations[0].attributeName', '"foo"');
329         shouldBe('mutations[0].oldValue', 'null');
330         shouldBe('mutations[1].type', '"attributes"');
331         shouldBe('mutations[1].attributeName', '"foo"');
332         shouldBe('mutations[1].oldValue', '"bar"');
333         shouldBe('mutations[2].type', '"attributes"');
334         shouldBe('mutations[2].attributeName', '"bar"');
335         shouldBe('mutations[2].oldValue', '"boo"');
336         observer.disconnect();
337         debug('');
338         runNextTest();
339     }
340
341     start();
342 }
343
344 function testOldValueAsRequested() {
345     var div;
346     var observerWithOldValue;
347     var observer;
348
349     function start() {
350         debug('Testing that oldValue is delivered as requested (or not).');
351         mutationsWithOldValue = null;
352         mutations = null;
353         div = document.createElement('div');
354         div.setAttribute('foo', 'bar');
355         observerWithOldValue = new WebKitMutationObserver(function(mutations) {
356             window.mutationsWithOldValue = mutations;
357         });
358         observer = new WebKitMutationObserver(function(mutations) {
359             window.mutations = mutations;
360         });
361         observerWithOldValue.observe(div, { attributes: true, attributeOldValue: true });
362         observer.observe(div, { attributes: true });
363         div.setAttribute('foo', 'baz');
364         setTimeout(finish, 0);
365     }
366
367     function finish() {
368         shouldBe('mutationsWithOldValue.length', '1');
369         shouldBe('mutationsWithOldValue[0].type', '"attributes"');
370         shouldBe('mutationsWithOldValue[0].attributeName', '"foo"');
371         shouldBe('mutationsWithOldValue[0].oldValue', '"bar"');
372         shouldBe('mutations.length', '1');
373         shouldBe('mutations[0].type', '"attributes"');
374         shouldBe('mutations[0].attributeName', '"foo"');
375         shouldBe('mutations[0].oldValue', 'null');
376         observerWithOldValue.disconnect();
377         observer.disconnect();
378         debug('');
379         runNextTest();
380     }
381
382     start();
383 }
384
385 function testOldValueUnionMultipleObservations() {
386     var div;
387     var span;
388     var observer;
389
390     function start() {
391         debug('An observer with multiple observations will get attributeOldValue if any entries request it.');
392         mutations = null;
393         div = document.createElement('div');
394         span = div.appendChild(document.createElement('span'));
395         span.setAttribute('foo', 'bar');
396         observer = new WebKitMutationObserver(function(mutations) {
397             window.mutations = mutations;
398         });
399         observer.observe(div, { attributes: true, attributeOldValue: true, subtree: true });
400         observer.observe(span, { attributes: true });
401         span.setAttribute('foo', 'baz');
402         setTimeout(finish, 0);
403     }
404
405     function finish() {
406         shouldBe('mutations.length', '1');
407         shouldBe('mutations[0].type', '"attributes"');
408         shouldBe('mutations[0].attributeName', '"foo"');
409         shouldBe('mutations[0].oldValue', '"bar"');
410         observer.disconnect();
411         debug('');
412         runNextTest();
413     }
414
415     start();
416 }
417
418 function testIDLAttribute() {
419     var div;
420     var observer;
421
422     function start() {
423         debug('Testing setting an attribute via reflected IDL attribute.');
424         mutations = null;
425         div = document.createElement('div');
426         observer = new WebKitMutationObserver(function(mutations) {
427             window.mutations = mutations;
428         });
429         observer.observe(div, { attributes: true, attributeOldValue: true });
430         div.id = 'foo';
431         div.id = 'bar';
432         setTimeout(finish, 0);
433     }
434
435     function finish() {
436         shouldBe('mutations.length', '2');
437         shouldBe('mutations[0].type', '"attributes"');
438         shouldBe('mutations[0].attributeName', '"id"');
439         shouldBe('mutations[0].oldValue', 'null');
440         shouldBe('mutations[1].type', '"attributes"');
441         shouldBe('mutations[1].attributeName', '"id"');
442         shouldBe('mutations[1].oldValue', '"foo"');
443         observer.disconnect();
444         debug('');
445         runNextTest();
446     }
447
448     start();
449 }
450
451 function testAttributeFilter() {
452     var div, path;
453     var observer;
454
455     function start() {
456         debug('Testing that attributeFilter works as expected and ignores case with HTML elements.');
457
458         mutations = null;
459         observer = new WebKitMutationObserver(function(m) {
460             mutations = m;
461         });
462
463         div = document.createElement('div');
464         observer.observe(div, { attributes: true, attributeFilter: ['foo', 'bar', 'booM'] });
465         div.setAttribute('foo', 'foo');
466         div.setAttribute('bar', 'bar');
467         div.setAttribute('baz', 'baz');
468         div.setAttribute('BOOm', 'boom');
469
470         setTimeout(finish, 0);
471     }
472
473     function finish() {
474         debug('...only foo, bar & boom should be received.');
475
476         shouldBe('mutations.length', '3');
477         shouldBe('mutations[0].type', '"attributes"');
478         shouldBe('mutations[0].attributeName', '"foo"');
479         shouldBe('mutations[0].attributeNamespace', 'null');
480         shouldBe('mutations[1].type', '"attributes"');
481         shouldBe('mutations[1].attributeName', '"bar"');
482         shouldBe('mutations[1].attributeNamespace', 'null');
483         shouldBe('mutations[2].type', '"attributes"');
484         shouldBe('mutations[2].attributeName', '"boom"');
485         shouldBe('mutations[2].attributeNamespace', 'null');
486         observer.disconnect();
487         debug('');
488         runNextTest();
489     }
490
491     start();
492 }
493
494 function testAttributeFilterSubtree() {
495     var div, div2, div3;
496     var observer;
497
498     function start() {
499         debug('Testing the behavior of attributeFilter when the same observer observes at multiple nodes in a subtree with different filter options.');
500
501         mutations = null;
502         observer = new WebKitMutationObserver(function(m) {
503             mutations = m;
504         });
505
506         div = document.createElement('div');
507         div2 = div.appendChild(document.createElement('div'));
508         div3 = div2.appendChild(document.createElement('div'));
509
510         observer.observe(div, { attributes: true, subtree: true, attributeFilter: ['foo', 'bar'] });
511         observer.observe(div2, { attributes: true, subtree: true, attributeFilter: ['bar', 'bat'] });
512
513         div3.setAttribute('foo', 'foo');
514         div3.setAttribute('bar', 'bar');
515         div3.setAttribute('bat', 'bat');
516         div3.setAttribute('baz', 'baz');
517
518         setTimeout(checkAndObserveAll, 0);
519     }
520
521     function checkAndObserveAll() {
522         debug('...only foo, bar & bat should be received.');
523
524         shouldBe('mutations.length', '3');
525         shouldBe('mutations[0].type', '"attributes"');
526         shouldBe('mutations[0].attributeName', '"foo"');
527         shouldBe('mutations[0].attributeNamespace', 'null');
528         shouldBe('mutations[1].type', '"attributes"');
529         shouldBe('mutations[1].attributeName', '"bar"');
530         shouldBe('mutations[1].attributeNamespace', 'null');
531         shouldBe('mutations[2].type', '"attributes"');
532         shouldBe('mutations[2].attributeName', '"bat"');
533         shouldBe('mutations[2].attributeNamespace', 'null');
534
535         observer.observe(div2, { attributes: true, subtree: true });
536         div3.setAttribute('bar', 'bar');
537         div3.setAttribute('bat', 'bat');
538         div3.setAttribute('baz', 'baz');
539
540         setTimeout(finish, 0);
541     }
542
543     function finish() {
544         debug('...bar, bat & baz should all be received.');
545
546         shouldBe('mutations.length', '3');
547         shouldBe('mutations[0].type', '"attributes"');
548         shouldBe('mutations[0].attributeName', '"bar"');
549         shouldBe('mutations[0].attributeNamespace', 'null');
550         shouldBe('mutations[1].type', '"attributes"');
551         shouldBe('mutations[1].attributeName', '"bat"');
552         shouldBe('mutations[1].attributeNamespace', 'null');
553         shouldBe('mutations[2].type', '"attributes"');
554         shouldBe('mutations[2].attributeName', '"baz"');
555         shouldBe('mutations[2].attributeNamespace', 'null');
556
557         observer.disconnect();
558         debug('');
559         runNextTest();
560     }
561
562     start();
563 }
564
565 function testAttributeFilterNonHTMLElement() {
566     var path;
567     var observer;
568
569     function start() {
570         debug('Testing that attributeFilter respects case with non-HTML elements.');
571
572         mutations = null;
573         observer = new WebKitMutationObserver(function(m) {
574             mutations = m;
575         });
576
577         path = document.createElementNS('http://www.w3.org/2000/svg', 'path');
578         observer.observe(path, { attributes: true, attributeFilter: ['pathLength'] });
579         path.setAttributeNS('http://www.w3.org/2000/svg', 'pathLength', '200');
580         path.setAttributeNS('http://www.w3.org/2000/svg', 'pathlength', '200');
581
582         setTimeout(finish, 0);
583     }
584
585     function finish() {
586         debug('...pathLength should be received.');
587
588         shouldBe('mutations.length', '1');
589         shouldBe('mutations[0].type', '"attributes"');
590         shouldBe('mutations[0].attributeName', '"pathLength"');
591         shouldBe('mutations[0].attributeNamespace', '"http://www.w3.org/2000/svg"');
592         observer.disconnect();
593         debug('');
594         runNextTest();
595     }
596
597     start();
598 }
599
600 function testAttributeFilterNonHTMLDocument() {
601     var svgDoc, div, path;
602     var observer;
603
604     function start() {
605         debug('Testing that attributeFilter respects case with non-HTML elements.');
606
607         svgDoc = document.implementation.createDocument('http://www.w3.org/2000/svg', 'svg', 'svg');
608         mutations = null;
609         observer = new WebKitMutationObserver(function(m) {
610             mutations = m;
611         });
612
613         div = svgDoc.createElement('div');
614         observer.observe(div, { attributes: true, attributeFilter: ['ID', 'id', 'booM'] });
615         div.setAttribute('ID', 'ID');
616         div.setAttribute('id', 'id');
617         div.setAttribute('baz', 'baz');
618         div.setAttribute('booM', 'boom');
619         div.setAttribute('BOOm', 'boom');
620
621         path = svgDoc.createElementNS('http://www.w3.org/2000/svg', 'path');
622         observer.observe(path, { attributes: true, attributeFilter: ['pathLength'] });
623         path.setAttributeNS('http://www.w3.org/2000/svg', 'pathLength', '200');
624         path.setAttributeNS('http://www.w3.org/2000/svg', 'pathlength', '200');
625
626         setTimeout(finish, 0);
627     }
628
629     function finish() {
630         debug('...only ID, id, booM, pathLength should be received.');
631
632         shouldBe('mutations.length', '4');
633         shouldBe('mutations[0].type', '"attributes"');
634         shouldBe('mutations[0].attributeName', '"ID"');
635         shouldBe('mutations[0].attributeNamespace', 'null');
636         shouldBe('mutations[1].type', '"attributes"');
637         shouldBe('mutations[1].attributeName', '"id"');
638         shouldBe('mutations[1].attributeNamespace', 'null');
639         shouldBe('mutations[2].type', '"attributes"');
640         shouldBe('mutations[2].attributeName', '"booM"');
641         shouldBe('mutations[2].attributeNamespace', 'null');
642         shouldBe('mutations[3].type', '"attributes"');
643         shouldBe('mutations[3].attributeName', '"pathLength"');
644         shouldBe('mutations[3].attributeNamespace', '"http://www.w3.org/2000/svg"');
645
646         observer.disconnect();
647         debug('');
648         runNextTest();
649     }
650
651     start();
652 }
653
654 function testStyleAttributePropertyAccess() {
655     var div, path;
656     var observer;
657
658     function start() {
659         debug('Testing that modifying an elements style property dispatches Mutation Records.');
660
661         mutations = null;
662         observer = new WebKitMutationObserver(function(m) {
663             mutations = m;
664         });
665
666         div = document.createElement('div');
667         div.setAttribute('style', 'color: yellow; width: 100px; ');
668         observer.observe(div, { attributes: true });
669         div.style.color = 'red';
670         div.style.width = '200px';
671         div.style.color = 'blue';
672
673         setTimeout(checkAndContinue, 0);
674     }
675
676     function checkAndContinue() {
677         shouldBe('mutations.length', '3');
678         shouldBe('mutations[0].type', '"attributes"');
679         shouldBe('mutations[0].attributeName', '"style"');
680         shouldBe('mutations[0].oldValue', 'null');
681         shouldBe('mutations[1].type', '"attributes"');
682         shouldBe('mutations[1].attributeName', '"style"');
683         shouldBe('mutations[1].oldValue', 'null');
684         shouldBe('mutations[2].type', '"attributes"');
685         shouldBe('mutations[2].attributeName', '"style"');
686         shouldBe('mutations[2].oldValue', 'null');
687
688         mutations = null;
689         div.getAttribute('style');
690         setTimeout(finish, 0);
691     }
692
693     function finish() {
694         debug('...mutation record created.');
695
696         shouldBe('mutations', 'null');
697
698         observer.disconnect();
699         debug('');
700         runNextTest();
701     }
702
703     start();
704 }
705
706 function testStyleAttributePropertyAccessOldValue() {
707     var div, path;
708     var observer;
709
710     function start() {
711         debug('Testing that modifying an elements style property dispatches Mutation Records with correct oldValues.');
712
713         mutations = null;
714         observer = new WebKitMutationObserver(function(m) {
715             mutations = m;
716         });
717
718         div = document.createElement('div');
719         div.setAttribute('style', 'color: yellow; width: 100px; ');
720         observer.observe(div, { attributes: true, attributeOldValue: true });
721         div.style.color = 'red';
722         div.style.width = '200px';
723         div.style.color = 'blue';
724
725         setTimeout(checkAndContinue, 0);
726     }
727
728     function checkAndContinue() {
729         shouldBe('mutations.length', '3');
730         shouldBe('mutations[0].type', '"attributes"');
731         shouldBe('mutations[0].attributeName', '"style"');
732         shouldBe('mutations[0].oldValue', '"color: yellow; width: 100px; "');
733         shouldBe('mutations[1].type', '"attributes"');
734         shouldBe('mutations[1].attributeName', '"style"');
735         shouldBe('mutations[1].oldValue', '"width: 100px; color: red; "');
736         shouldBe('mutations[2].type', '"attributes"');
737         shouldBe('mutations[2].attributeName', '"style"');
738         shouldBe('mutations[2].oldValue', '"color: red; width: 200px; "');
739
740         mutations = null;
741         div.getAttribute('style');
742         setTimeout(finish, 0);
743     }
744
745     function finish() {
746         debug('...mutation record created.');
747
748         shouldBe('mutations', 'null');
749
750         observer.disconnect();
751         debug('');
752         runNextTest();
753     }
754
755     start();
756 }
757
758 function testStyleAttributePropertyAccessIgnoreNoop() {
759     var div, path;
760     var observer;
761
762     function start() {
763         debug('Testing that a no-op style property mutation does not create Mutation Records.');
764
765         mutations = null;
766         observer = new WebKitMutationObserver(function(m) {
767             mutations = m;
768         });
769
770         div = document.createElement('div');
771         div.setAttribute('style', 'color: yellow; width: 100px; ');
772         observer.observe(div, { attributes: true });
773         div.style.removeProperty('height');
774
775         setTimeout(finish, 0);
776     }
777
778     function finish() {
779         shouldBe('mutations', 'null');
780
781         observer.disconnect();
782         debug('');
783         runNextTest();
784     }
785
786     start();
787 }
788
789 var tests = [
790     testBasic,
791     testWrongType,
792     testMultipleRegistration,
793     testMultipleObservers,
794     testNamespaceURI,
795     testPropertyAccess,
796     testOrderingWrtDOMSubtreeModified,
797     testOldValue,
798     testOldValueAsRequested,
799     testOldValueUnionMultipleObservations,
800     testIDLAttribute,
801     testAttributeFilter,
802     testAttributeFilterSubtree,
803     testAttributeFilterNonHTMLElement,
804     testAttributeFilterNonHTMLDocument,
805     testStyleAttributePropertyAccess,
806     testStyleAttributePropertyAccessOldValue,
807     testStyleAttributePropertyAccessIgnoreNoop
808 ];
809 var testIndex = 0;
810
811 function runNextTest() {
812     if (testIndex < tests.length)
813         tests[testIndex++]();
814     else
815         finishJSTest();
816 }
817
818 description('Test WebKitMutationObserver.observe on attributes');
819
820 if (!window.WebKitMutationObserver)
821     testFailed('This test requires ENABLE(MUTATION_OBSERVERS)');
822 else
823     runNextTest();
824
825 </script>
826 <script src="../js/resources/js-test-post.js"></script>
827 </body>
828 </html>