| OLD | NEW |
| (Empty) | |
| 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 B set attribute on A |
| 31 C set attribute on B |
| 32 B set attribute on C |
| 33 A inserted parent node |
| 34 A removed parent node |
| 35 A inserted parent node |
| 36 A removed parent node</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); |
| 44 } |
| 45 function indent() { |
| 46 indentation += ' '; |
| 47 } |
| 48 function unindent() { |
| 49 indentation = indentation.substring(3); |
| 50 } |
| 51 |
| 52 // This tests recursion and the processing stack. Specifically: |
| 53 // |
| 54 // (1) Scheduling callbacks for an element that has callbacks |
| 55 // scheduled at an outer level of recursion, but that have not |
| 56 // begun to be processed yet. |
| 57 // |
| 58 // (2) Scheduling callbacks for an element that is in the middle |
| 59 // of processing callbacks at an outer level of recursion. |
| 60 // |
| 61 // (3) Scheduling callbacks for an element that exhaustively |
| 62 // processed callbacks at an outer level of recursion. |
| 63 // |
| 64 // appendChild and remove are used on a subtree containing |
| 65 // multiple custom elements. In this way it is possible to |
| 66 // schedule callbacks for multiple custom elements with one DOM |
| 67 // call. |
| 68 // |
| 69 // The test creates this tree: |
| 70 // |
| 71 // <div> |
| 72 // <x-a></x-a> |
| 73 // <x-b></x-b> |
| 74 // <x-c></x-c> |
| 75 // </div> |
| 76 // |
| 77 // x-a pushes its parent in and out of the document, thus scheduling |
| 78 // work for x-b and x-c at every level of recursion. |
| 79 // |
| 80 // Then x-b processes half its queue before setting an attribute |
| 81 // on x-c. This tests case (1) because x-c has not begun its queue |
| 82 // yet. |
| 83 // |
| 84 // x-c turns around and sets and attribute on x-b. This tests case |
| 85 // (2) because x-b is half way through processing its queue. |
| 86 // |
| 87 // x-b turns around and sets an attribute on x-a. This tests case |
| 88 // (3) because x-a has finished processing its queue. |
| 89 |
| 90 var protoA = Object.create(HTMLElement.prototype); |
| 91 var n = 0; |
| 92 protoA.enteredDocumentCallback = function () { |
| 93 log('A entered'); |
| 94 n++; |
| 95 if (n < 3) { |
| 96 log('A removing parent node'); indent(); |
| 97 this.parentNode.remove(); |
| 98 unindent(); log('A removed parent node'); |
| 99 } |
| 100 }; |
| 101 protoA.leftDocumentCallback = function () { |
| 102 log('A left'); |
| 103 log('A inserting parent node'); indent(); |
| 104 document.body.appendChild(this.parentNode); |
| 105 unindent(); log('A inserted parent node'); |
| 106 }; |
| 107 protoA.attributeChangedCallback = function (name, oldValue, newValue) { |
| 108 log('A@' + name + ' ' + oldValue + '->' + newValue); |
| 109 }; |
| 110 var A = document.register('x-a', {prototype: protoA}); |
| 111 |
| 112 var protoB = Object.create(HTMLElement.prototype); |
| 113 var m = 0; |
| 114 protoB.enteredDocumentCallback = function () { |
| 115 log('B entered'); |
| 116 m++; |
| 117 if (m == 2) { |
| 118 log('B setting attribute on C'); indent(); |
| 119 this.parentNode.querySelector('x-c').setAttribute('by', 'b'); |
| 120 unindent(); log('B set attribute on C'); |
| 121 } |
| 122 }; |
| 123 protoB.leftDocumentCallback = function () { |
| 124 log('B left'); |
| 125 }; |
| 126 protoB.attributeChangedCallback = function (name, oldValue, newValue) { |
| 127 log('B@' + name + ' ' + oldValue + '->' + newValue); |
| 128 log('B setting attribute on A'); indent(); |
| 129 this.parentNode.querySelector('x-a').setAttribute('by', 'b'); |
| 130 unindent(); log('B set attribute on A'); |
| 131 }; |
| 132 var B = document.register('x-b', {prototype: protoB}); |
| 133 |
| 134 var protoC = Object.create(HTMLElement.prototype); |
| 135 protoC.enteredDocumentCallback = function () { |
| 136 log('C entered'); |
| 137 }; |
| 138 protoC.leftDocumentCallback = function () { |
| 139 log('C left'); |
| 140 }; |
| 141 protoC.attributeChangedCallback = function (name, oldValue, newValue) { |
| 142 log('C@' + name + ' ' + oldValue + '->' + newValue); |
| 143 log('C setting attribute on B'); indent(); |
| 144 this.parentNode.querySelector('x-b').setAttribute('by', 'c'); |
| 145 unindent(); log('C set attribute on B'); |
| 146 }; |
| 147 var C = document.register('x-c', {prototype: protoC}); |
| 148 |
| 149 var div = document.createElement('div'); |
| 150 div.innerHTML = '<div><x-a></x-a><x-b></x-b><x-c></x-c></div>'; |
| 151 document.body.appendChild(div); |
| 152 |
| 153 assert_equals(buffer.join('\n'), expected.content.textContent, 'should have
generated an identical log'); |
| 154 }, 'recursively scheduled callbacks'); |
| 155 </script> |
| OLD | NEW |