| OLD | NEW |
| (Empty) |
| 1 <!DOCTYPE html> | |
| 2 <script src="../../../resources/js-test.js"></script> | |
| 3 <script src="testutils.js"></script> | |
| 4 <body> | |
| 5 <script> | |
| 6 description('Tests that Custom Elements does not induce leaks'); | |
| 7 var jsTestIsAsync = true; | |
| 8 | |
| 9 if (!window.internals) | |
| 10 testFailed('this test requires window.internals'); | |
| 11 | |
| 12 function step1() { | |
| 13 debug('Test a custom element with minimal capturing'); | |
| 14 | |
| 15 withFrame(function (frame) { | |
| 16 // Create some upgrade candidates | |
| 17 frame.contentDocument.body.innerHTML = '<x-x><x-x></x-x></x-x>'; | |
| 18 | |
| 19 // Register a custom element | |
| 20 | |
| 21 var proto = Object.create(frame.contentWindow.HTMLElement.prototype); | |
| 22 proto.createdCallback = function () {}; | |
| 23 proto.attachedCallback = function () {}; | |
| 24 proto.detachedCallback = function () {}; | |
| 25 proto.attributeChangedCallback = function () {}; | |
| 26 | |
| 27 var ctor = frame.contentDocument.registerElement('x-x', {prototype: prot
o}); | |
| 28 | |
| 29 // Create some instances | |
| 30 | |
| 31 frame.contentDocument.createElement('x-x'); | |
| 32 frame.contentDocument.body.appendChild(new ctor()); | |
| 33 frame.contentDocument.body.firstElementChild.innerHTML = '<x-x></x-x>'; | |
| 34 | |
| 35 // Watch to see that some objects die | |
| 36 | |
| 37 observations = { | |
| 38 'frame': internals.observeGC(frame), | |
| 39 'window': internals.observeGC(frame.contentWindow), | |
| 40 'document': internals.observeGC(frame.contentDocument), | |
| 41 'proto': internals.observeGC(proto), | |
| 42 'ctor': internals.observeGC(ctor), | |
| 43 'callback': internals.observeGC(proto.attributeChangedCallback) | |
| 44 }; | |
| 45 | |
| 46 // Throw everything away | |
| 47 frame.remove(); | |
| 48 | |
| 49 // We check leaks in a separate closure. | |
| 50 checkLeaks(step2); | |
| 51 }); | |
| 52 } | |
| 53 | |
| 54 function step2() { | |
| 55 debug('Test callbacks which close over a bunch of objects'); | |
| 56 | |
| 57 withFrame(function (frame) { | |
| 58 // Register a custom element with a callback which closes over | |
| 59 // the prototype, constructor, document, window and frame. | |
| 60 | |
| 61 var contentWindow = frame.contentWindow; | |
| 62 var contentDocument = frame.contentDocument; | |
| 63 | |
| 64 var proto = Object.create(contentWindow.HTMLElement.prototype); | |
| 65 proto.attributeChangedCallback = function () { | |
| 66 var goodies = [proto, ctor, contentDocument, contentWindow, frame]; | |
| 67 goodies.forEach(function (loot) { console.log(loot); }); | |
| 68 }; | |
| 69 var ctor = contentDocument.registerElement('x-x', {prototype: proto}); | |
| 70 | |
| 71 // Create an instance; put it in the document | |
| 72 var elem = new ctor(); | |
| 73 contentDocument.body.appendChild(elem); | |
| 74 | |
| 75 // Watch to see that some objects die | |
| 76 | |
| 77 observations = { | |
| 78 'frame': internals.observeGC(frame), | |
| 79 'window': internals.observeGC(contentWindow), | |
| 80 'document': internals.observeGC(contentDocument), | |
| 81 'proto': internals.observeGC(proto), | |
| 82 'ctor': internals.observeGC(ctor), | |
| 83 'callback': internals.observeGC(proto.attributeChangedCallback) | |
| 84 }; | |
| 85 | |
| 86 // Throw everything away | |
| 87 frame.remove(); | |
| 88 checkLeaks(step3); | |
| 89 }); | |
| 90 } | |
| 91 | |
| 92 function step3() { | |
| 93 debug('Test that navigating a frame with custom elements does not leak'); | |
| 94 | |
| 95 withFrame(function (frame) { | |
| 96 // Register a custom element with a callback which closes over | |
| 97 // the prototype, constructor, document, window and frame. | |
| 98 | |
| 99 var contentWindow = frame.contentWindow; | |
| 100 var contentDocument = frame.contentDocument; | |
| 101 | |
| 102 var proto = Object.create(contentWindow.HTMLElement.prototype); | |
| 103 proto.attributeChangedCallback = function () { | |
| 104 var goodies = [proto, ctor, contentDocument, contentWindow, frame]; | |
| 105 goodies.forEach(function (loot) { console.log(loot); }); | |
| 106 }; | |
| 107 var ctor = contentDocument.registerElement('x-x', {prototype: proto}); | |
| 108 | |
| 109 // Create an instance; put it in the document *and* point to | |
| 110 // it from the window. | |
| 111 var elem = new ctor(); | |
| 112 contentDocument.body.appendChild(elem); | |
| 113 contentWindow.thePrecious = elem; | |
| 114 | |
| 115 // Watch to see that some objects die; we don't watch the | |
| 116 // window because Blink recycles the window | |
| 117 | |
| 118 observations = { | |
| 119 'document': internals.observeGC(contentDocument), | |
| 120 'proto': internals.observeGC(proto), | |
| 121 'ctor': internals.observeGC(ctor), | |
| 122 'callback': internals.observeGC(proto.attributeChangedCallback) | |
| 123 }; | |
| 124 | |
| 125 // Throw everything away | |
| 126 frame.onload = checkLeaksAndFinishTest; | |
| 127 frame.src = 'about:blank'; | |
| 128 }); | |
| 129 } | |
| 130 | |
| 131 function checkLeaksAndFinishTest() { | |
| 132 checkLeaks(finishJSTest); | |
| 133 } | |
| 134 | |
| 135 function checkLeaks(nextStep) { | |
| 136 setTimeout(function () { | |
| 137 gc(); | |
| 138 | |
| 139 // Check that everything that should have died, did die | |
| 140 for (var prop in observations) | |
| 141 shouldBeTrue('observations.' + prop + '.wasCollected'); | |
| 142 | |
| 143 observations = null; | |
| 144 | |
| 145 nextStep(); | |
| 146 }, 0); | |
| 147 } | |
| 148 | |
| 149 step1(); | |
| 150 var successfullyParsed = true; | |
| 151 </script> | |
| OLD | NEW |