Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / third_party / WebKit / LayoutTests / fast / dom / custom / processing-stack-recursion.html
blob27fcf5829225cab35f8e57113a5721fb65c96d04
1 <!DOCTYPE html>
2 <script src="../../../resources/testharness.js"></script>
3 <script src="../../../resources/testharnessreport.js"></script>
4 <body>
5 <template id="expected">A entered
6 A removing parent node
7 A left
8 A inserting parent node
9 A entered
10 A removing parent node
11 A left
12 A inserting parent node
13 A entered
14 B entered
15 B left
16 B entered
17 B setting attribute on C
18 C entered
19 C left
20 C entered
21 C left
22 C entered
23 C@by null->b
24 C setting attribute on B
25 B left
26 B entered
27 B@by null->c
28 B setting attribute on A
29 A@by null->b
30 done
31 done
32 done
33 done
34 done
35 done
36 done</template>
37 <script>
38 test(function () {
39 // Helpers for logging
40 var buffer = [];
41 var indentation = '';
42 function log(msg) {
43 buffer.push(indentation + msg);
45 function indented(msg) {
46 log(msg);
47 indentation += ' ';
49 function unindent() {
50 indentation = indentation.substring(3);
51 log('done');
54 // This tests recursion and the processing stack. Specifically:
56 // (1) Scheduling callbacks for an element that has callbacks
57 // scheduled at an outer level of recursion, but that have not
58 // begun to be processed yet.
60 // (2) Scheduling callbacks for an element that is in the middle
61 // of processing callbacks at an outer level of recursion.
63 // (3) Scheduling callbacks for an element that exhaustively
64 // processed callbacks at an outer level of recursion.
66 // appendChild and remove are used on a subtree containing
67 // multiple custom elements. In this way it is possible to
68 // schedule callbacks for multiple custom elements with one DOM
69 // call.
71 // The test creates this tree:
73 // <div>
74 // <x-a></x-a>
75 // <x-b></x-b>
76 // <x-c></x-c>
77 // </div>
79 // x-a pushes its parent in and out of the document, thus scheduling
80 // work for x-b and x-c at every level of recursion.
82 // Then x-b processes half its queue before setting an attribute
83 // on x-c. This tests case (1) because x-c has not begun its queue
84 // yet.
86 // x-c turns around and sets and attribute on x-b. This tests case
87 // (2) because x-b is half way through processing its queue.
89 // x-b turns around and sets an attribute on x-a. This tests case
90 // (3) because x-a has finished processing its queue.
92 var protoA = Object.create(HTMLElement.prototype);
93 var n = 0;
94 protoA.attachedCallback = function () {
95 log('A entered');
96 n++;
97 if (n < 3) {
98 indented('A removing parent node');
99 this.parentNode.remove();
100 unindent();
103 protoA.detachedCallback = function () {
104 log('A left');
105 indented('A inserting parent node');
106 document.body.appendChild(this.parentNode);
107 unindent();
109 protoA.attributeChangedCallback = function (name, oldValue, newValue) {
110 log('A@' + name + ' ' + oldValue + '->' + newValue);
112 var A = document.registerElement('x-a', {prototype: protoA});
114 var protoB = Object.create(HTMLElement.prototype);
115 var m = 0;
116 protoB.attachedCallback = function () {
117 log('B entered');
118 m++;
119 if (m == 2) {
120 indented('B setting attribute on C');
121 this.parentNode.querySelector('x-c').setAttribute('by', 'b');
122 unindent();
125 protoB.detachedCallback = function () {
126 log('B left');
128 protoB.attributeChangedCallback = function (name, oldValue, newValue) {
129 log('B@' + name + ' ' + oldValue + '->' + newValue);
130 indented('B setting attribute on A');
131 this.parentNode.querySelector('x-a').setAttribute('by', 'b');
132 unindent();
134 var B = document.registerElement('x-b', {prototype: protoB});
136 var protoC = Object.create(HTMLElement.prototype);
137 protoC.attachedCallback = function () {
138 log('C entered');
140 protoC.detachedCallback = function () {
141 log('C left');
143 protoC.attributeChangedCallback = function (name, oldValue, newValue) {
144 log('C@' + name + ' ' + oldValue + '->' + newValue);
145 indented('C setting attribute on B');
146 this.parentNode.querySelector('x-b').setAttribute('by', 'c');
147 unindent();
149 var C = document.registerElement('x-c', {prototype: protoC});
151 var div = document.createElement('div');
152 div.innerHTML = '<div><x-a></x-a><x-b></x-b><x-c></x-c></div>';
153 document.body.appendChild(div);
155 assert_equals(buffer.join('\n'), expected.content.textContent, 'should have generated an identical log');
156 }, 'recursively scheduled callbacks');
157 </script>