| <!DOCTYPE html> |
| <html> |
| <body> |
| <p>This tests that JS wrappers of nodes enqueued to a mutation observer do not get collected.</p> |
| <pre id="log"></pre> |
| <script src="../../../resources/gc.js"></script> |
| <script> |
| |
| if (window.testRunner) |
| testRunner.dumpAsText(); |
| |
| const nodeCount = 5; |
| const iterationCount = 5; |
| |
| let elementsMap; |
| |
| async function observe() { |
| let container = document.createElement('div'); |
| container.myState = 'live'; |
| |
| const observer = new MutationObserver(() => { }); |
| observer.observe(container, {subtree: true, childList: true, attributes: true}); |
| for (let i = 0; i < nodeCount; ++i) { |
| const child = document.createElement('span'); |
| child.myState = 'live'; |
| container.appendChild(child); |
| } |
| container.setAttribute('title', 'foo'); |
| container.setAttribute('title', 'bar'); |
| container.textContent = ''; |
| |
| return observer.takeRecords(); |
| } |
| |
| function check(recordList) { |
| let deadCount = 0; |
| for (const record of recordList) { |
| if (record.target.myState != 'live') |
| deadCount++; |
| for (const node of record.addedNodes) { |
| if (node.myState != 'live') |
| deadCount++; |
| } |
| for (const node of record.removedNodes) { |
| if (node.myState != 'live') |
| deadCount++; |
| } |
| } |
| document.getElementById('log').textContent += (deadCount ? `FAIL - ${deadCount} nodes lost JS wrappers` : 'PASS') + '\n'; |
| } |
| |
| async function runAll() { |
| if (window.testRunner) |
| testRunner.waitUntilDone(); |
| |
| for (let j = 0; j < iterationCount; ++j) { |
| const records = await observe(); |
| await new Promise((resolve) => setTimeout(resolve, 0)); |
| gc(); |
| check(records); |
| } |
| |
| |
| if (window.testRunner) |
| testRunner.notifyDone(); |
| } |
| |
| runAll(); |
| |
| </script> |
| </body> |
| </html> |