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 |