diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-28 14:29:10 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-28 14:29:10 +0000 |
commit | 2aa4a82499d4becd2284cdb482213d541b8804dd (patch) | |
tree | b80bf8bf13c3766139fbacc530efd0dd9d54394c /dom/events/test/event_leak_utils.js | |
parent | Initial commit. (diff) | |
download | firefox-upstream.tar.xz firefox-upstream.zip |
Adding upstream version 86.0.1.upstream/86.0.1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'dom/events/test/event_leak_utils.js')
-rw-r--r-- | dom/events/test/event_leak_utils.js | 84 |
1 files changed, 84 insertions, 0 deletions
diff --git a/dom/events/test/event_leak_utils.js b/dom/events/test/event_leak_utils.js new file mode 100644 index 0000000000..86b26a4136 --- /dev/null +++ b/dom/events/test/event_leak_utils.js @@ -0,0 +1,84 @@ +// Any copyright is dedicated to the Public Domain. +// http://creativecommons.org/publicdomain/zero/1.0/ +"use strict"; + +// This function runs a number of tests where: +// +// 1. An iframe is created +// 2. The target callback is executed with the iframe's contentWindow as +// an argument. +// 3. The iframe is destroyed and GC is forced. +// 4. Verifies that the iframe's contentWindow has been GC'd. +// +// Different ways of destroying the iframe are checked. Simple +// remove(), destruction via bfcache, or replacement by document.open(). +// +// Please pass a target callback that exercises the API under +// test using the given window. The callback should try to leave the +// API active to increase the liklihood of provoking an API. Any activity +// should be canceled by the destruction of the window. +async function checkForEventListenerLeaks(name, target) { + // Test if we leak in the case where we do nothing special to + // the frame before removing it from the DOM. + await _eventListenerLeakStep(target, `${name} default`); + + // Test the case where we navigate the frame before removing it + // from the DOM so that the window using the target API ends up + // in bfcache. + await _eventListenerLeakStep(target, `${name} bfcache`, frame => { + frame.src = "about:blank"; + return new Promise(resolve => (frame.onload = resolve)); + }); + + // Test the case where we document.open() the frame before removing + // it from the DOM so that the window using the target API ends + // up getting replaced. + await _eventListenerLeakStep(target, `${name} document.open()`, frame => { + frame.contentDocument.open(); + frame.contentDocument.close(); + }); +} + +// ---------------- +// Internal helpers +// ---------------- + +// Utility function to create a loaded iframe. +async function _withFrame(doc, url) { + let frame = doc.createElement("iframe"); + frame.src = url; + doc.body.appendChild(frame); + await new Promise(resolve => (frame.onload = resolve)); + return frame; +} + +// This function defines the basic form of the test cases. We create an +// iframe, execute the target callback to manipulate the DOM, remove the frame +// from the DOM, and then check to see if the frame was GC'd. The caller +// may optionally pass in a callback that will be executed with the +// frame as an argument before removing it from the DOM. +async function _eventListenerLeakStep(target, name, extra) { + let frame = await _withFrame(document, "empty.html"); + + await target(frame.contentWindow); + + let weakRef = SpecialPowers.Cu.getWeakReference(frame.contentWindow); + ok(weakRef.get(), `should be able to create a weak reference - ${name}`); + + if (extra) { + await extra(frame); + } + + frame.remove(); + frame = null; + + // Perform many GC's to avoid intermittent delayed collection. + await new Promise(resolve => SpecialPowers.exactGC(resolve)); + await new Promise(resolve => SpecialPowers.exactGC(resolve)); + await new Promise(resolve => SpecialPowers.exactGC(resolve)); + + ok( + !weakRef.get(), + `iframe content window should be garbage collected - ${name}` + ); +} |