4 * Opens a number of tabs containing an out-of-process iframe.
6 * @param numTabs the number of tabs to open.
7 * @returns the browsing context of the iframe in the last tab opened.
9 async function openTestTabs(numTabs) {
12 for (let count = 0; count < numTabs; count++) {
13 let tab = await BrowserTestUtils.openNewForegroundTab({
18 // If we load example.com in an injected subframe, we assume that this
19 // will load in its own subprocess, which we can then crash.
20 iframeBC = await SpecialPowers.spawn(tab.linkedBrowser, [], async () => {
21 let iframe = content.document.createElement("iframe");
22 iframe.setAttribute("src", "http://example.com");
24 content.document.body.appendChild(iframe);
25 await ContentTaskUtils.waitForEvent(iframe, "load");
26 return iframe.frameLoader.browsingContext;
34 * Helper function for testing frame crashing. Some tabs are opened
35 * containing frames from example.com and then the process for
36 * example.com is crashed. Notifications should apply to each tab
37 * and all should close when one of the notifications is closed.
39 * @param numTabs the number of tabs to open.
41 async function testFrameCrash(numTabs) {
42 let iframeBC = await openTestTabs(numTabs);
43 let browser = gBrowser.selectedBrowser;
44 let rootBC = browser.browsingContext;
46 is(iframeBC.parent, rootBC, "oop frame has root as parent");
48 let eventFiredPromise = BrowserTestUtils.waitForEvent(
53 BrowserTestUtils.crashFrame(
55 true /* shouldShowTabCrashPage */,
56 true /* shouldClearMinidumps */,
60 let notificationPromise = BrowserTestUtils.waitForNotificationBar(
66 info("Waiting for oop-browser-crashed event.");
67 await eventFiredPromise.then(event => {
68 ok(!event.isTopFrame, "should not be reporting top-level frame crash");
69 ok(event.childID != 0, "childID is non-zero");
72 event.browsingContextId,
74 "top frame browsing context id not expected."
78 event.browsingContextId,
80 "oop frame browsing context id expected."
85 // The BrowsingContext is re-used, but the window global might still be
86 // getting set up at this point, so wait until it's been initialized.
87 let { subject: windowGlobal } = await BrowserUtils.promiseObserved(
88 "window-global-created",
89 wgp => wgp.documentURI.spec.startsWith("about:framecrashed")
94 iframeBC.currentWindowGlobal,
95 "Resolved on expected window global"
98 let newIframeURI = await SpecialPowers.spawn(iframeBC, [], async () => {
99 return content.document.documentURI;
103 newIframeURI.startsWith("about:framecrashed"),
104 "The iframe is now pointing at about:framecrashed"
107 let title = await SpecialPowers.spawn(iframeBC, [], async () => {
108 await content.document.l10n.ready;
109 return content.document.documentElement.getAttribute("title");
111 ok(title, "The iframe has a non-empty tooltip.");
114 // Next, check that the crash notification bar has appeared.
115 await notificationPromise;
117 for (let count = 1; count <= numTabs; count++) {
118 let notificationBox = gBrowser.getNotificationBox(gBrowser.browsers[count]);
119 let notification = notificationBox.currentNotification;
120 ok(notification, "Notification " + count + " should be visible");
122 notification.getAttribute("value"),
124 "Should be showing the right notification" + count
127 let buttons = notification.buttonContainer.querySelectorAll(
128 ".notification-button"
133 "Notification " + count + " should have only one button."
135 let links = notification.supportLinkEls;
139 "Notification " + count + " should have only one link."
142 notification.messageText.textContent.length,
143 "Notification " + count + " should have a crash msg."
147 // Press the ignore button on the visible notification.
148 let notificationBox = gBrowser.getNotificationBox(gBrowser.selectedBrowser);
149 let notification = notificationBox.currentNotification;
151 // Make sure all of the notifications were closed when one of them was closed.
152 let closedPromises = [];
153 for (let count = 1; count <= numTabs; count++) {
154 let nb = gBrowser.getNotificationBox(gBrowser.browsers[count]);
156 BrowserTestUtils.waitForMutationCondition(
159 () => !nb.currentNotification
164 notification.dismiss();
165 await Promise.all(closedPromises);
167 for (let count = 1; count <= numTabs; count++) {
168 BrowserTestUtils.removeTab(gBrowser.selectedTab);
173 * In this test, we crash an out-of-process iframe and
175 * 1. the "oop-browser-crashed" event is dispatched with
176 * the browsing context of the crashed oop subframe.
177 * 2. the crashed subframe is now pointing at "about:framecrashed"
180 add_task(async function test_crashframe() {
181 // Open a new window with fission enabled.
183 SpecialPowers.useRemoteSubframes,
184 "This test only makes sense of we can use OOP iframes."
187 // Create the crash reporting directory if it doesn't yet exist, otherwise, a failure
188 // sometimes occurs. See bug 1687855 for fixing this.
189 const uAppDataPath = Services.dirsvc.get("UAppData", Ci.nsIFile).path;
190 let path = PathUtils.join(uAppDataPath, "Crash Reports", "pending");
191 await IOUtils.makeDirectory(path, { ignoreExisting: true });
193 // Test both one tab and when four tabs are opened.
194 await testFrameCrash(1);
195 await testFrameCrash(4);
198 // This test checks that no notification shows when there is no minidump available. It
199 // simulates the steps that occur during a crash, once with a dumpID and once without.
200 add_task(async function test_nominidump() {
201 for (let dumpID of [null, "8888"]) {
202 let iframeBC = await openTestTabs(1);
204 let childID = iframeBC.currentWindowGlobal.domProcess.childID;
206 let notificationPromise;
208 notificationPromise = BrowserTestUtils.waitForNotificationBar(
210 gBrowser.selectedBrowser,
215 gBrowser.selectedBrowser.dispatchEvent(
216 new FrameCrashedEvent("oop-browser-crashed", {
217 browsingContextID: iframeBC,
224 let bag = Cc["@mozilla.org/hash-property-bag;1"].createInstance(
225 Ci.nsIWritablePropertyBag
227 bag.setProperty("abnormal", "true");
228 bag.setProperty("childID", iframeBC.currentWindowGlobal.domProcess.childID);
230 bag.setProperty("dumpID", dumpID);
233 Services.obs.notifyObservers(bag, "ipc:content-shutdown");
235 await notificationPromise;
236 let notificationBox = gBrowser.getNotificationBox(gBrowser.selectedBrowser);
237 let notification = notificationBox.currentNotification;
239 dumpID ? notification : !notification,
240 "notification shown for browser with no minidump"
243 BrowserTestUtils.removeTab(gBrowser.selectedTab);