| <!DOCTYPE html> | |
| <head> | |
| <script src="../resources/gc.js"></script> | |
| <body> | |
| <pre id="log">This tests removing the root node of IntersectionObserver. The root node should be eligible for GC. | |
| </pre> | |
| <script> | |
| function createRoot(rootId) | |
| { | |
| const container = document.createElement('div'); | |
| container.innerHTML = `<div id="${rootId}" class="root" style="position:absolute"><div class="target" style="width: 100px; height: 100px; background-color: green"></div></div>`; | |
| const root = container.getElementsByClassName('root')[0]; | |
| root.remove(); | |
| return root; | |
| } | |
| let initialNodeCount = 0; | |
| window.onload = () => { | |
| if (!window.testRunner || !window.internals) { | |
| log.textContent += 'FAIL - This test requires internals'; | |
| return; | |
| } | |
| if (internals.numberOfIntersectionObservers(document)) { | |
| log.textContent += 'FAIL - Initial intersection observer count is not zero'; | |
| return; | |
| } | |
| initialNodeCount = internals.referencingNodeCount(document); | |
| testRunner.dumpAsText(); | |
| testRunner.waitUntilDone(); | |
| setTimeout(() => testRunner.notifyDone(), 5000); | |
| runTest(1); | |
| } | |
| const totalTestCount = 20; | |
| function runTest(testNumber) { | |
| log.textContent += `Test ${testNumber}: `; | |
| const rootId = 'root-' + testNumber; | |
| let root = createRoot(rootId); | |
| root.alive = true; | |
| document.body.appendChild(root); | |
| let observer = new IntersectionObserver(() => { }, { root }); | |
| let target = root.getElementsByClassName('target')[0]; | |
| if (observer.root != root) | |
| return testFailed(testNumber, 'observer.root != root after construction'); | |
| observer.observe(target); | |
| root.remove(); | |
| root = null; | |
| target = null; | |
| requestAnimationFrame(function () { | |
| observer.takeRecords(); | |
| gc(); | |
| if (!observer.root) | |
| return testFailed(testNumber, 'observer.root is null'); | |
| if (observer.root.id != rootId) | |
| return testFailed(testNumber, `observer.root.id (${observer.root.id}) != rootId (${rootId}) after running rAF and GC`); | |
| if (!observer.root.alive) | |
| return testFailed(testNumber, 'observer.alive is false'); | |
| observer = null; | |
| gc(); | |
| log.textContent += 'PASS\n'; | |
| if (testNumber < totalTestCount) | |
| setTimeout(() => runTest(testNumber + 1), 0); | |
| else | |
| setTimeout(() => finish(testNumber), 0); | |
| }); | |
| } | |
| function testFailed(testNumber, error) | |
| { | |
| log.textContent += `FAIL: ${error}\n`; | |
| finish(testNumber); | |
| } | |
| function finish(finishedTestCount) | |
| { | |
| log.textContent += 'Node count: '; | |
| log.textContent += (internals.referencingNodeCount(document) < initialNodeCount + 2 * finishedTestCount * 0.8) ? 'PASS' : 'FAIL - Less than 20% of the root nodes were collected'; | |
| log.textContent += '\n'; | |
| log.textContent += 'Intersection observer count: '; | |
| log.textContent += (internals.numberOfIntersectionObservers(document) < finishedTestCount * 0.8) ? 'PASS' : 'FAIL - Less than 20% of the intersection observers were collected'; | |
| log.textContent += '\n'; | |
| testRunner.notifyDone(); | |
| } | |
| </script> | |
| </body> | |
| </html> |