diff options
Diffstat (limited to 'toolkit/components/aboutperformance/tests/browser/browser_aboutperformance.js')
-rw-r--r-- | toolkit/components/aboutperformance/tests/browser/browser_aboutperformance.js | 300 |
1 files changed, 300 insertions, 0 deletions
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; +}); |