2 <script src=
"../../../resources/testharness.js"></script>
3 <script src=
"../../../resources/testharnessreport.js"></script>
5 <template id=
"expected">A entered
8 A inserting parent node
10 A removing parent node
12 A inserting parent node
17 B setting attribute on C
24 C setting attribute on B
28 B setting attribute on A
39 // Helpers for logging
43 buffer
.push(indentation
+ msg
);
45 function indented(msg
) {
50 indentation
= indentation
.substring(3);
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
71 // The test creates this tree:
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
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);
94 protoA
.attachedCallback = function () {
98 indented('A removing parent node');
99 this.parentNode
.remove();
103 protoA
.detachedCallback = function () {
105 indented('A inserting parent node');
106 document
.body
.appendChild(this.parentNode
);
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);
116 protoB
.attachedCallback = function () {
120 indented('B setting attribute on C');
121 this.parentNode
.querySelector('x-c').setAttribute('by', 'b');
125 protoB
.detachedCallback = function () {
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');
134 var B
= document
.registerElement('x-b', {prototype: protoB
});
136 var protoC
= Object
.create(HTMLElement
.prototype);
137 protoC
.attachedCallback = function () {
140 protoC
.detachedCallback = function () {
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');
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');