Source code
Revision control
Copy as Markdown
Other Tools
Test Info:
- Manifest: dom/console/tests/browser.toml
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
"use strict";
// dom/console/tests/ is in extraMochitestTestPaths, which shadows the
// auto-detected browser-test config for browser_* files in this directory.
/* global BrowserTestUtils */
//
// A system module's console.error stores messages under a filename key.
// inner-window-destroyed only clears numeric window ID keys, so the message
// persists. If the message arguments include an object whose global is a
// chrome window, that window leaks.
//
// The fix derives the storage key from the argument's window global (like
// can clear it.
const HELPER_MODULE =
// When a system module logs an object from a window global, the message
// should be keyed by that window's ID so inner-window-destroyed clears it.
add_task(async function test_argument_global_is_window() {
let storage = Cc["@mozilla.org/consoleAPI-storage;1"].getService(
Ci.nsIConsoleAPIStorage
);
let win = await BrowserTestUtils.openNewBrowserWindow();
let winId = String(win.windowGlobalChild.innerWindowId);
win.leak = function () {
ChromeUtils.importESModule(HELPER_MODULE).logError(
new this.TypeError("leak test")
);
};
win.leak();
let byWindow = storage.getEvents(winId);
ok(
byWindow.some(e => e.level === "error"),
"Console event stored under window ID, not module filename"
);
is(
storage.getEvents(HELPER_MODULE).length,
0,
"No events stored under module filename key"
);
await BrowserTestUtils.closeWindow(win);
is(
storage.getEvents(winId).length,
0,
"Console events cleared on window destruction"
);
});
// window ID, the event should not be cached: its arguments could keep the
// destroyed window's global alive.
add_task(async function test_late_event_for_destroyed_window() {
let storage = Cc["@mozilla.org/consoleAPI-storage;1"].getService(
Ci.nsIConsoleAPIStorage
);
let win = await BrowserTestUtils.openNewBrowserWindow();
let winId = String(win.windowGlobalChild.innerWindowId);
let obj = new win.Object();
obj.toString = () => "leak test object";
// Sanity check: while the window is alive, recordEvent caches the event.
storage.recordEvent(winId, {
level: "warn",
arguments: ["early event"],
timeStamp: Date.now(),
wrappedJSObject: null,
});
is(
storage.getEvents(winId).length,
1,
"Event recorded while window is alive is cached"
);
await BrowserTestUtils.closeWindow(win);
is(
storage.getEvents(winId).length,
0,
"Cached events cleared on window destruction"
);
// Simulate a late console message arriving after inner-window-destroyed.
storage.recordEvent(winId, {
level: "warn",
arguments: [obj],
timeStamp: Date.now(),
wrappedJSObject: null,
});
is(
storage.getEvents(winId).length,
0,
"Late event for destroyed window was not cached"
);
});
// When a system module logs an error created inside a Sandbox whose
// prototype is a window, the message should still be keyed by that
// window's ID.
add_task(async function test_argument_global_is_sandbox() {
let storage = Cc["@mozilla.org/consoleAPI-storage;1"].getService(
Ci.nsIConsoleAPIStorage
);
let win = await BrowserTestUtils.openNewBrowserWindow();
let winId = String(win.windowGlobalChild.innerWindowId);
ChromeUtils.importESModule(HELPER_MODULE).logSandboxError(win);
let byWindow = storage.getEvents(winId);
ok(
byWindow.some(e => e.level === "error"),
"Sandbox error stored under window ID"
);
is(
storage.getEvents(HELPER_MODULE).length,
0,
"No events stored under module filename key"
);
await BrowserTestUtils.closeWindow(win);
is(
storage.getEvents(winId).length,
0,
"Sandbox error cleared on window destruction"
);
});