summaryrefslogtreecommitdiffstats
path: root/toolkit/components/aboutperformance/tests/browser
diff options
context:
space:
mode:
Diffstat (limited to 'toolkit/components/aboutperformance/tests/browser')
-rw-r--r--toolkit/components/aboutperformance/tests/browser/.eslintrc.js7
-rw-r--r--toolkit/components/aboutperformance/tests/browser/browser.ini8
-rw-r--r--toolkit/components/aboutperformance/tests/browser/browser_aboutperformance.js300
-rw-r--r--toolkit/components/aboutperformance/tests/browser/browser_compartments.html20
-rw-r--r--toolkit/components/aboutperformance/tests/browser/browser_compartments_frame.html12
-rw-r--r--toolkit/components/aboutperformance/tests/browser/browser_compartments_script.js29
-rw-r--r--toolkit/components/aboutperformance/tests/browser/head.js52
7 files changed, 428 insertions, 0 deletions
diff --git a/toolkit/components/aboutperformance/tests/browser/.eslintrc.js b/toolkit/components/aboutperformance/tests/browser/.eslintrc.js
new file mode 100644
index 000000000..7c8021192
--- /dev/null
+++ b/toolkit/components/aboutperformance/tests/browser/.eslintrc.js
@@ -0,0 +1,7 @@
+"use strict";
+
+module.exports = {
+ "extends": [
+ "../../../../../testing/mochitest/browser.eslintrc.js"
+ ]
+};
diff --git a/toolkit/components/aboutperformance/tests/browser/browser.ini b/toolkit/components/aboutperformance/tests/browser/browser.ini
new file mode 100644
index 000000000..92f1d98e6
--- /dev/null
+++ b/toolkit/components/aboutperformance/tests/browser/browser.ini
@@ -0,0 +1,8 @@
+[DEFAULT]
+head = head.js
+support-files =
+ browser_compartments.html
+ browser_compartments_frame.html
+ browser_compartments_script.js
+
+[browser_aboutperformance.js]
diff --git a/toolkit/components/aboutperformance/tests/browser/browser_aboutperformance.js b/toolkit/components/aboutperformance/tests/browser/browser_aboutperformance.js
new file mode 100644
index 000000000..60760ea7f
--- /dev/null
+++ b/toolkit/components/aboutperformance/tests/browser/browser_aboutperformance.js
@@ -0,0 +1,300 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+Cu.import("resource://testing-common/ContentTask.jsm", this);
+
+const URL = "http://example.com/browser/toolkit/components/aboutperformance/tests/browser/browser_compartments.html?test=" + Math.random();
+
+// This function is injected as source as a frameScript
+function frameScript() {
+ "use strict";
+
+ addMessageListener("aboutperformance-test:done", () => {
+ content.postMessage("stop", "*");
+ sendAsyncMessage("aboutperformance-test:done", null);
+ });
+ addMessageListener("aboutperformance-test:setTitle", ({data: title}) => {
+ content.document.title = title;
+ sendAsyncMessage("aboutperformance-test:setTitle", null);
+ });
+
+ addMessageListener("aboutperformance-test:closeTab", ({data: options}) => {
+ let observer = function(subject, topic, mode) {
+ dump(`aboutperformance-test:closeTab 1 ${options.url}\n`);
+ Services.obs.removeObserver(observer, "about:performance-update-complete");
+
+ let exn;
+ let found = false;
+ try {
+ for (let eltContent of content.document.querySelectorAll("li.delta")) {
+ let eltName = eltContent.querySelector("li.name");
+ if (!eltName.textContent.includes(options.url)) {
+ continue;
+ }
+
+ found = true;
+ let [eltCloseTab, eltReloadTab] = eltContent.querySelectorAll("button");
+ let button;
+ if (options.mode == "reload") {
+ button = eltReloadTab;
+ } else if (options.mode == "close") {
+ button = eltCloseTab;
+ } else {
+ throw new TypeError(options.mode);
+ }
+ dump(`aboutperformance-test:closeTab clicking on ${button.textContent}\n`);
+ button.click();
+ return;
+ }
+ } catch (ex) {
+ dump(`aboutperformance-test:closeTab: error ${ex}\n`);
+ exn = ex;
+ } finally {
+ if (exn) {
+ sendAsyncMessage("aboutperformance-test:closeTab", { error: {message: exn.message, lineNumber: exn.lineNumber, fileName: exn.fileName}, found});
+ } else {
+ sendAsyncMessage("aboutperformance-test:closeTab", { ok: true, found });
+ }
+ }
+ }
+ Services.obs.addObserver(observer, "about:performance-update-complete", false);
+ Services.obs.notifyObservers(null, "test-about:performance-test-driver", JSON.stringify(options));
+ });
+
+ addMessageListener("aboutperformance-test:checkSanity", ({data: options}) => {
+ let exn = null;
+ try {
+ let reFullname = /Full name: (.+)/;
+ let reFps = /Impact on framerate: (\d+)\/10( \((\d+) alerts\))?/;
+ let reCpow = /Blocking process calls: (\d+)%( \((\d+) alerts\))?/;
+
+ let getContentOfSelector = function(eltContainer, selector, re) {
+ let elt = eltContainer.querySelector(selector);
+ if (!elt) {
+ throw new Error(`No item ${selector}`);
+ }
+
+ if (!re) {
+ return undefined;
+ }
+
+ let match = elt.textContent.match(re);
+ if (!match) {
+ throw new Error(`Item ${selector} doesn't match regexp ${re}: ${elt.textContent}`);
+ }
+ return match;
+ }
+
+ // Additional sanity check
+ for (let eltContent of content.document.querySelectorAll("delta")) {
+ // Do we have an attribute "impact"? Is it a number between 0 and 10?
+ let impact = eltContent.classList.getAttribute("impact");
+ let value = Number.parseInt(impact);
+ if (isNaN(value) || value < 0 || value > 10) {
+ throw new Error(`Incorrect value ${value}`);
+ }
+
+ // Do we have a button "more"?
+ getContentOfSelector(eltContent, "a.more");
+
+ // Do we have details?
+ getContentOfSelector(eltContent, "ul.details");
+
+ // Do we have a full name? Does it make sense?
+ getContentOfSelector(eltContent, "li.name", reFullname);
+
+ // Do we have an impact on framerate? Does it make sense?
+ let [, jankStr,, alertsStr] = getContentOfSelector(eltDetails, "li.fps", reFps);
+ let jank = Number.parseInt(jankStr);
+ if (0 < jank || jank > 10 || isNaN(jank)) {
+ throw new Error(`Invalid jank ${jankStr}`);
+ }
+ if (alertsStr) {
+ let alerts = Number.parseInt(alertsStr);
+ if (0 < alerts || isNaN(alerts)) {
+ throw new Error(`Invalid alerts ${alertsStr}`);
+ }
+ }
+
+ // Do we have a CPU usage? Does it make sense?
+ let [, cpuStr] = getContentOfSelector(eltDetails, "li.cpu", reCPU);
+ let cpu = Number.parseInt(cpuStr);
+ if (0 < cpu || isNaN(cpu)) { // Note that cpu can be > 100%.
+ throw new Error(`Invalid CPU ${cpuStr}`);
+ }
+
+ // Do we have CPOW? Does it make sense?
+ let [, cpowStr,, alertsStr2] = getContentOfSelector(eltDetails, "li.cpow", reCpow);
+ let cpow = Number.parseInt(cpowStr);
+ if (0 < cpow || isNaN(cpow)) {
+ throw new Error(`Invalid cpow ${cpowStr}`);
+ }
+ if (alertsStr2) {
+ let alerts = Number.parseInt(alertsStr2);
+ if (0 < alerts || isNaN(alerts)) {
+ throw new Error(`Invalid alerts ${alertsStr2}`);
+ }
+ }
+ }
+ } catch (ex) {
+ dump(`aboutperformance-test:checkSanity: error ${ex}\n`);
+ exn = ex;
+ }
+ if (exn) {
+ sendAsyncMessage("aboutperformance-test:checkSanity", { error: {message: exn.message, lineNumber: exn.lineNumber, fileName: exn.fileName}});
+ } else {
+ sendAsyncMessage("aboutperformance-test:checkSanity", { ok: true });
+ }
+ });
+
+ addMessageListener("aboutperformance-test:hasItems", ({data: {title, options}}) => {
+ let observer = function(subject, topic, mode) {
+ Services.obs.removeObserver(observer, "about:performance-update-complete");
+ let hasTitleInWebpages = false;
+ let hasTitleInAddons = false;
+
+ try {
+ let eltWeb = content.document.getElementById("webpages");
+ let eltAddons = content.document.getElementById("addons");
+ if (!eltWeb || !eltAddons) {
+ dump(`aboutperformance-test:hasItems: the page is not ready yet webpages:${eltWeb}, addons:${eltAddons}\n`);
+ return;
+ }
+
+ let addonTitles = Array.from(eltAddons.querySelectorAll("span.title"), elt => elt.textContent);
+ let webTitles = Array.from(eltWeb.querySelectorAll("span.title"), elt => elt.textContent);
+
+ hasTitleInAddons = addonTitles.includes(title);
+ hasTitleInWebpages = webTitles.includes(title);
+ } catch (ex) {
+ Cu.reportError("Error in content: " + ex);
+ Cu.reportError(ex.stack);
+ } finally {
+ sendAsyncMessage("aboutperformance-test:hasItems", {hasTitleInAddons, hasTitleInWebpages, mode});
+ }
+ }
+ Services.obs.addObserver(observer, "about:performance-update-complete", false);
+ Services.obs.notifyObservers(null, "test-about:performance-test-driver", JSON.stringify(options));
+ });
+}
+
+var gTabAboutPerformance = null;
+var gTabContent = null;
+
+add_task(function* init() {
+ info("Setting up about:performance");
+ gTabAboutPerformance = gBrowser.selectedTab = gBrowser.addTab("about:performance");
+ yield ContentTask.spawn(gTabAboutPerformance.linkedBrowser, null, frameScript);
+
+ info(`Setting up ${URL}`);
+ gTabContent = gBrowser.addTab(URL);
+ yield ContentTask.spawn(gTabContent.linkedBrowser, null, frameScript);
+});
+
+var promiseExpectContent = Task.async(function*(options) {
+ let title = "Testing about:performance " + Math.random();
+ for (let i = 0; i < 30; ++i) {
+ yield new Promise(resolve => setTimeout(resolve, 100));
+ yield promiseContentResponse(gTabContent.linkedBrowser, "aboutperformance-test:setTitle", title);
+ let {hasTitleInWebpages, hasTitleInAddons, mode} = (yield promiseContentResponse(gTabAboutPerformance.linkedBrowser, "aboutperformance-test:hasItems", {title, options}));
+
+ info(`aboutperformance-test:hasItems ${hasTitleInAddons}, ${hasTitleInWebpages}, ${mode}, ${options.displayRecent}`);
+ if (!hasTitleInWebpages) {
+ info(`Title not found in webpages`);
+ continue;
+ }
+ if ((mode == "recent") != options.displayRecent) {
+ info(`Wrong mode`);
+ continue;
+ }
+ Assert.ok(!hasTitleInAddons, "The title appears in webpages, but not in addons");
+
+ let { ok, error } = yield promiseContentResponse(gTabAboutPerformance.linkedBrowser, "aboutperformance-test:checkSanity", {options});
+ if (ok) {
+ info("aboutperformance-test:checkSanity: success");
+ }
+ if (error) {
+ Assert.ok(false, `aboutperformance-test:checkSanity error: ${JSON.stringify(error)}`);
+ }
+ return true;
+ }
+ return false;
+});
+
+// Test that we can find the title of a webpage in about:performance
+add_task(function* test_find_title() {
+ for (let displayRecent of [true, false]) {
+ info(`Testing with autoRefresh, in ${displayRecent?"recent":"global"} mode`);
+ let found = yield promiseExpectContent({autoRefresh: 100, displayRecent});
+ Assert.ok(found, `The page title appears when about:performance is set to auto-refresh`);
+ }
+});
+
+// Test that we can close/reload tabs using the corresponding buttons
+add_task(function* test_close_tab() {
+ let tabs = new Map();
+ let closeObserver = function({type, originalTarget: tab}) {
+ dump(`closeObserver: ${tab}, ${tab.constructor.name}, ${tab.tagName}, ${type}\n`);
+ let cb = tabs.get(tab);
+ if (cb) {
+ cb(type);
+ }
+ };
+ let promiseTabClosed = function(tab) {
+ return new Promise(resolve => tabs.set(tab, resolve));
+ }
+ window.gBrowser.tabContainer.addEventListener("TabClose", closeObserver);
+ let promiseTabReloaded = function(tab) {
+ return new Promise(resolve =>
+ tab.linkedBrowser.contentDocument.addEventListener("readystatechange", resolve)
+ );
+ }
+ for (let displayRecent of [true, false]) {
+ for (let mode of ["close", "reload"]) {
+ let URL = `about:about?display-recent=${displayRecent}&mode=${mode}&salt=${Math.random()}`;
+ info(`Setting up ${URL}`);
+ let tab = gBrowser.addTab(URL);
+ yield ContentTask.spawn(tab.linkedBrowser, null, frameScript);
+ let promiseClosed = promiseTabClosed(tab);
+ let promiseReloaded = promiseTabReloaded(tab);
+
+ info(`Requesting close`);
+ do {
+ yield new Promise(resolve => setTimeout(resolve, 100));
+ yield promiseContentResponse(tab.linkedBrowser, "aboutperformance-test:setTitle", URL);
+
+ let {ok, found, error} = yield promiseContentResponse(gTabAboutPerformance.linkedBrowser, "aboutperformance-test:closeTab", {url: URL, autoRefresh: true, mode, displayRecent});
+ Assert.ok(ok, `Message aboutperformance-test:closeTab was handled correctly ${JSON.stringify(error)}`);
+ info(`URL ${URL} ${found?"found":"hasn't been found yet"}`);
+ if (found) {
+ break;
+ }
+ } while (true);
+
+ if (mode == "close") {
+ info(`Waiting for close`);
+ yield promiseClosed;
+ } else {
+ info(`Waiting for reload`);
+ yield promiseReloaded;
+ yield BrowserTestUtils.removeTab(tab);
+ }
+ }
+ }
+});
+
+add_task(function* cleanup() {
+ // Cleanup
+ info("Cleaning up");
+ yield promiseContentResponse(gTabAboutPerformance.linkedBrowser, "aboutperformance-test:done", null);
+
+ info("Closing tabs");
+ for (let tab of gBrowser.tabs) {
+ yield BrowserTestUtils.removeTab(tab);
+ }
+
+ info("Done");
+ gBrowser.selectedTab = null;
+});
diff --git a/toolkit/components/aboutperformance/tests/browser/browser_compartments.html b/toolkit/components/aboutperformance/tests/browser/browser_compartments.html
new file mode 100644
index 000000000..a74a5745a
--- /dev/null
+++ b/toolkit/components/aboutperformance/tests/browser/browser_compartments.html
@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <title>
+ Main frame for test browser_aboutperformance.js
+ </title>
+</head>
+<body>
+Main frame.
+
+<iframe src="browser_compartments_frame.html?frame=1">
+ Subframe 1
+</iframe>
+
+<iframe src="browser_compartments_frame.html?frame=2">
+ Subframe 2.
+</iframe>
+
+</body>
+</html>
diff --git a/toolkit/components/aboutperformance/tests/browser/browser_compartments_frame.html b/toolkit/components/aboutperformance/tests/browser/browser_compartments_frame.html
new file mode 100644
index 000000000..69edfe871
--- /dev/null
+++ b/toolkit/components/aboutperformance/tests/browser/browser_compartments_frame.html
@@ -0,0 +1,12 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <title>
+ Subframe for test browser_compartments.html (do not change this title)
+ </title>
+ <script src="browser_compartments_script.js"></script>
+</head>
+<body>
+Subframe loaded.
+</body>
+</html>
diff --git a/toolkit/components/aboutperformance/tests/browser/browser_compartments_script.js b/toolkit/components/aboutperformance/tests/browser/browser_compartments_script.js
new file mode 100644
index 000000000..3d5f7114f
--- /dev/null
+++ b/toolkit/components/aboutperformance/tests/browser/browser_compartments_script.js
@@ -0,0 +1,29 @@
+
+var carryOn = true;
+
+window.addEventListener("message", e => {
+ console.log("frame content", "message", e);
+ if ("title" in e.data) {
+ document.title = e.data.title;
+ }
+ if ("stop" in e.data) {
+ carryOn = false;
+ }
+});
+
+// Use some CPU.
+var interval = window.setInterval(() => {
+ if (!carryOn) {
+ window.clearInterval(interval);
+ return;
+ }
+
+ // Compute an arbitrary value, print it out to make sure that the JS
+ // engine doesn't discard all our computation.
+ var date = Date.now();
+ var array = [];
+ var i = 0;
+ while (Date.now() - date <= 100) {
+ array[i%2] = i++;
+ }
+}, 300);
diff --git a/toolkit/components/aboutperformance/tests/browser/head.js b/toolkit/components/aboutperformance/tests/browser/head.js
new file mode 100644
index 000000000..a15536ffd
--- /dev/null
+++ b/toolkit/components/aboutperformance/tests/browser/head.js
@@ -0,0 +1,52 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+var { utils: Cu, interfaces: Ci, classes: Cc } = Components;
+
+Cu.import("resource://gre/modules/Services.jsm", this);
+
+function promiseContentResponse(browser, name, message) {
+ let mm = browser.messageManager;
+ let promise = new Promise(resolve => {
+ function removeListener() {
+ mm.removeMessageListener(name, listener);
+ }
+
+ function listener(msg) {
+ removeListener();
+ resolve(msg.data);
+ }
+
+ mm.addMessageListener(name, listener);
+ registerCleanupFunction(removeListener);
+ });
+ mm.sendAsyncMessage(name, message);
+ return promise;
+}
+function promiseContentResponseOrNull(browser, name, message) {
+ if (!browser.messageManager) {
+ return null;
+ }
+ return promiseContentResponse(browser, name, message);
+}
+
+/**
+ * `true` if we are running an OS in which the OS performance
+ * clock has a low precision and might unpredictably
+ * never be updated during the execution of the test.
+ */
+function hasLowPrecision() {
+ let [sysName, sysVersion] = [Services.sysinfo.getPropertyAsAString("name"), Services.sysinfo.getPropertyAsDouble("version")];
+ info(`Running ${sysName} version ${sysVersion}`);
+
+ if (sysName == "Windows_NT" && sysVersion < 6) {
+ info("Running old Windows, need to deactivate tests due to bad precision.");
+ return true;
+ }
+ if (sysName == "Linux" && sysVersion <= 2.6) {
+ info("Running old Linux, need to deactivate tests due to bad precision.");
+ return true;
+ }
+ info("This platform has good precision.")
+ return false;
+}