summaryrefslogtreecommitdiffstats
path: root/dom/ipc/tests/browser_crash_oopiframe.js
diff options
context:
space:
mode:
Diffstat (limited to 'dom/ipc/tests/browser_crash_oopiframe.js')
-rw-r--r--dom/ipc/tests/browser_crash_oopiframe.js167
1 files changed, 167 insertions, 0 deletions
diff --git a/dom/ipc/tests/browser_crash_oopiframe.js b/dom/ipc/tests/browser_crash_oopiframe.js
new file mode 100644
index 0000000000..2cf133e5e3
--- /dev/null
+++ b/dom/ipc/tests/browser_crash_oopiframe.js
@@ -0,0 +1,167 @@
+"use strict";
+
+/**
+ * Helper function for testing frame crashing. Some tabs are opened
+ * containing frames from example.com and then the process for
+ * example.com is crashed. Notifications should apply to each tab
+ * and all should close when one of the notifications is closed.
+ *
+ * @param numTabs the number of tabs to open.
+ */
+async function testFrameCrash(numTabs) {
+ let browser, rootBC, iframeBC;
+
+ for (let count = 0; count < numTabs; count++) {
+ let tab = await BrowserTestUtils.openNewForegroundTab({
+ gBrowser,
+ url: "about:blank",
+ });
+
+ browser = tab.linkedBrowser;
+ rootBC = browser.browsingContext;
+
+ // If we load example.com in an injected subframe, we assume that this
+ // will load in its own subprocess, which we can then crash.
+ iframeBC = await SpecialPowers.spawn(browser, [], async () => {
+ let iframe = content.document.createElement("iframe");
+ iframe.setAttribute("src", "http://example.com");
+
+ content.document.body.appendChild(iframe);
+ await ContentTaskUtils.waitForEvent(iframe, "load");
+ return iframe.frameLoader.browsingContext;
+ });
+ }
+
+ is(iframeBC.parent, rootBC, "oop frame has root as parent");
+
+ let eventFiredPromise = BrowserTestUtils.waitForEvent(
+ browser,
+ "oop-browser-crashed"
+ );
+
+ BrowserTestUtils.crashFrame(
+ browser,
+ true /* shouldShowTabCrashPage */,
+ true /* shouldClearMinidumps */,
+ iframeBC
+ );
+
+ let notificationPromise = BrowserTestUtils.waitForNotificationBar(
+ gBrowser,
+ browser,
+ "subframe-crashed"
+ );
+
+ info("Waiting for oop-browser-crashed event.");
+ await eventFiredPromise.then(event => {
+ ok(!event.isTopFrame, "should not be reporting top-level frame crash");
+ ok(event.childID != 0, "childID is non-zero");
+
+ isnot(
+ event.browsingContextId,
+ rootBC,
+ "top frame browsing context id not expected."
+ );
+
+ is(
+ event.browsingContextId,
+ iframeBC.id,
+ "oop frame browsing context id expected."
+ );
+ });
+
+ if (numTabs == 1) {
+ // The BrowsingContext is re-used, but the window global might still be
+ // getting set up at this point, so wait until it's been initialized.
+ let {
+ subject: windowGlobal,
+ } = await BrowserUtils.promiseObserved("window-global-created", wgp =>
+ wgp.documentURI.spec.startsWith("about:framecrashed")
+ );
+
+ is(
+ windowGlobal,
+ iframeBC.currentWindowGlobal,
+ "Resolved on expected window global"
+ );
+
+ let newIframeURI = await SpecialPowers.spawn(iframeBC, [], async () => {
+ return content.document.documentURI;
+ });
+
+ ok(
+ newIframeURI.startsWith("about:framecrashed"),
+ "The iframe is now pointing at about:framecrashed"
+ );
+ }
+
+ // Next, check that the crash notification bar has appeared.
+ await notificationPromise;
+
+ for (let count = 1; count <= numTabs; count++) {
+ let notificationBox = gBrowser.getNotificationBox(gBrowser.browsers[count]);
+ let notification = notificationBox.currentNotification;
+ ok(notification, "Notification " + count + " should be visible");
+ is(
+ notification.getAttribute("value"),
+ "subframe-crashed",
+ "Should be showing the right notification" + count
+ );
+
+ let buttons = notification.querySelectorAll(".notification-button");
+ is(
+ buttons.length,
+ 2,
+ "Notification " + count + " should have only two buttons."
+ );
+ }
+
+ // Press the ignore button on the visible notification.
+ let notificationBox = gBrowser.getNotificationBox(gBrowser.selectedBrowser);
+ let notification = notificationBox.currentNotification;
+ notification.dismiss();
+
+ for (let count = 1; count <= numTabs; count++) {
+ let nb = gBrowser.getNotificationBox(gBrowser.browsers[count]);
+
+ await TestUtils.waitForCondition(
+ () => !nb.currentNotification,
+ "notification closed"
+ );
+
+ ok(
+ !nb.currentNotification,
+ "notification " + count + " closed when dismiss button is pressed"
+ );
+ }
+
+ for (let count = 1; count <= numTabs; count++) {
+ BrowserTestUtils.removeTab(gBrowser.selectedTab);
+ }
+}
+
+/**
+ * In this test, we crash an out-of-process iframe and
+ * verify that :
+ * 1. the "oop-browser-crashed" event is dispatched with
+ * the browsing context of the crashed oop subframe.
+ * 2. the crashed subframe is now pointing at "about:framecrashed"
+ * page.
+ */
+add_task(async function() {
+ // Open a new window with fission enabled.
+ ok(
+ SpecialPowers.useRemoteSubframes,
+ "This test only makes sense of we can use OOP iframes."
+ );
+
+ // Create the crash reporting directory if it doesn't yet exist, otherwise, a failure
+ // sometimes occurs. See bug 1687855 for fixing this.
+ const uAppDataPath = Services.dirsvc.get("UAppData", Ci.nsIFile).path;
+ let path = PathUtils.join(uAppDataPath, "Crash Reports", "pending");
+ await IOUtils.makeDirectory(path, { ignoreExisting: true });
+
+ // Test both one tab and when four tabs are opened.
+ await testFrameCrash(1);
+ await testFrameCrash(4);
+});