зеркало из https://github.com/mozilla/gecko-dev.git
83 строки
3.0 KiB
JavaScript
83 строки
3.0 KiB
JavaScript
// 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}`);
|
|
}
|
|
|