Source code

Revision control

Copy as Markdown

Other Tools

Test Info: Warnings

/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set sts=2 sw=2 et tw=80: */
"use strict";
const {
Management: {
global: { tabTracker },
},
} = ChromeUtils.importESModule("resource://gre/modules/Extension.sys.mjs");
const {
ExtensionUtils: { promiseObserved },
} = ChromeUtils.importESModule("resource://gre/modules/ExtensionUtils.sys.mjs");
class TestHangReport {
constructor(addonId, scriptBrowser) {
this.addonId = addonId;
this.scriptBrowser = scriptBrowser;
this.QueryInterface = ChromeUtils.generateQI(["nsIHangReport"]);
}
userCanceled() {}
terminateScript() {}
isReportForBrowserOrChildren(frameLoader) {
return (
!this.scriptBrowser || this.scriptBrowser.frameLoader === frameLoader
);
}
}
function dispatchHangReport(extensionId, scriptBrowser) {
const hangObserved = promiseObserved("process-hang-report");
Services.obs.notifyObservers(
new TestHangReport(extensionId, scriptBrowser),
"process-hang-report"
);
return hangObserved;
}
function background() {
let onPerformanceWarningDetails = null;
browser.runtime.onPerformanceWarning.addListener(details => {
onPerformanceWarningDetails = details;
});
browser.test.onMessage.addListener(message => {
if (message === "get-on-performance-warning-details") {
browser.test.sendMessage(
"on-performance-warning-details",
onPerformanceWarningDetails
);
onPerformanceWarningDetails = null;
}
});
}
async function expectOnPerformanceWarningDetails(
extension,
expectedOnPerformanceWarningDetails
) {
extension.sendMessage("get-on-performance-warning-details");
let actualOnPerformanceWarningDetails = await extension.awaitMessage(
"on-performance-warning-details"
);
Assert.deepEqual(
actualOnPerformanceWarningDetails,
expectedOnPerformanceWarningDetails,
expectedOnPerformanceWarningDetails
? "runtime.onPerformanceWarning fired with correct details"
: "runtime.onPerformanceWarning didn't fire"
);
}
add_task(async function test_should_fire_on_process_hang_report() {
const description =
"Slow extension content script caused a page hang, user was warned.";
const extension = ExtensionTestUtils.loadExtension({ background });
await extension.startup();
const notificationPromise = BrowserTestUtils.waitForGlobalNotificationBar(
window,
"process-hang"
);
const tabs = await Promise.all([
BrowserTestUtils.openNewForegroundTab(gBrowser),
BrowserTestUtils.openNewForegroundTab(gBrowser),
]);
// Warning event shouldn't have fired initially.
await expectOnPerformanceWarningDetails(extension, null);
// Hang report fired for the extension and first tab. Warning event with first
// tab ID expected.
await dispatchHangReport(extension.id, tabs[0].linkedBrowser);
await expectOnPerformanceWarningDetails(extension, {
category: "content_script",
severity: "high",
description,
tabId: tabTracker.getId(tabs[0]),
});
// Hang report fired for different extension, no warning event expected.
await dispatchHangReport("wrong-addon-id", tabs[0].linkedBrowser);
await expectOnPerformanceWarningDetails(extension, null);
// Non-extension hang report fired, no warning event expected.
await dispatchHangReport(null, tabs[0].linkedBrowser);
await expectOnPerformanceWarningDetails(extension, null);
// Hang report fired for the extension and second tab. Warning event with
// second tab ID expected.
await dispatchHangReport(extension.id, tabs[1].linkedBrowser);
await expectOnPerformanceWarningDetails(extension, {
category: "content_script",
severity: "high",
description,
tabId: tabTracker.getId(tabs[1]),
});
// Hang report fired for the extension with no associated tab. Warning event
// with no tab ID expected.
await dispatchHangReport(extension.id, null);
await expectOnPerformanceWarningDetails(extension, {
category: "content_script",
severity: "high",
description,
});
await Promise.all(tabs.map(BrowserTestUtils.removeTab));
await extension.unload();
// Wait for the process-hang warning bar to be displayed, then ensure it's
// cleared to avoid clobbering other tests.
const notification = await notificationPromise;
Assert.ok(notification.isConnected, "Notification still present");
notification.buttonContainer.querySelector("[label='Stop']").click();
});