summaryrefslogtreecommitdiffstats
path: root/devtools/client/memory/test/browser/head.js
diff options
context:
space:
mode:
Diffstat (limited to 'devtools/client/memory/test/browser/head.js')
-rw-r--r--devtools/client/memory/test/browser/head.js248
1 files changed, 248 insertions, 0 deletions
diff --git a/devtools/client/memory/test/browser/head.js b/devtools/client/memory/test/browser/head.js
new file mode 100644
index 000000000..cb9b470ff
--- /dev/null
+++ b/devtools/client/memory/test/browser/head.js
@@ -0,0 +1,248 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Load the shared test helpers into this compartment.
+Services.scriptloader.loadSubScript(
+ "chrome://mochitests/content/browser/devtools/client/framework/test/shared-head.js",
+ this);
+
+// Load the shared Redux helpers into this compartment.
+Services.scriptloader.loadSubScript(
+ "chrome://mochitests/content/browser/devtools/client/framework/test/shared-redux-head.js",
+ this);
+
+var { censusDisplays, snapshotState: states } = require("devtools/client/memory/constants");
+var { L10N } = require("devtools/client/memory/utils");
+
+Services.prefs.setBoolPref("devtools.memory.enabled", true);
+
+/**
+ * Open the memory panel for the given tab.
+ */
+this.openMemoryPanel = Task.async(function* (tab) {
+ info("Opening memory panel.");
+ const target = TargetFactory.forTab(tab);
+ const toolbox = yield gDevTools.showToolbox(target, "memory");
+ info("Memory panel shown successfully.");
+ let panel = toolbox.getCurrentPanel();
+ return { tab, panel };
+});
+
+/**
+ * Close the memory panel for the given tab.
+ */
+this.closeMemoryPanel = Task.async(function* (tab) {
+ info("Closing memory panel.");
+ const target = TargetFactory.forTab(tab);
+ const toolbox = gDevTools.getToolbox(target);
+ yield toolbox.destroy();
+ info("Closed memory panel successfully.");
+});
+
+/**
+ * Return a test function that adds a tab with the given url, opens the memory
+ * panel, runs the given generator, closes the memory panel, removes the tab,
+ * and finishes.
+ *
+ * Example usage:
+ *
+ * this.test = makeMemoryTest(TEST_URL, function* ({ tab, panel }) {
+ * // Your tests go here...
+ * });
+ */
+function makeMemoryTest(url, generator) {
+ return Task.async(function* () {
+ waitForExplicitFinish();
+
+ // It can take a long time to save a snapshot to disk, read the snapshots
+ // back from disk, and finally perform analyses on them.
+ requestLongerTimeout(2);
+
+ const tab = yield addTab(url);
+ const results = yield openMemoryPanel(tab);
+
+ try {
+ yield* generator(results);
+ } catch (err) {
+ ok(false, "Got an error: " + DevToolsUtils.safeErrorString(err));
+ }
+
+ yield closeMemoryPanel(tab);
+ yield removeTab(tab);
+
+ finish();
+ });
+}
+
+function dumpn(msg) {
+ dump(`MEMORY-TEST: ${msg}\n`);
+}
+
+/**
+ * Returns a promise that will resolve when the provided store matches
+ * the expected array. expectedStates is an array of dominatorTree states.
+ * Expectations :
+ * - store.getState().snapshots.length == expected.length
+ * - snapshots[i].dominatorTree.state == expected[i]
+ *
+ * @param {Store} store
+ * @param {Array<string>} expectedStates [description]
+ * @return {Promise}
+ */
+function waitUntilDominatorTreeState(store, expected) {
+ let predicate = () => {
+ let snapshots = store.getState().snapshots;
+ return snapshots.length === expected.length &&
+ expected.every((state, i) => {
+ return snapshots[i].dominatorTree &&
+ snapshots[i].dominatorTree.state === state;
+ });
+ };
+ info(`Waiting for dominator trees to be of state: ${expected}`);
+ return waitUntilState(store, predicate);
+}
+
+function takeSnapshot(window) {
+ let { gStore, document } = window;
+ let snapshotCount = gStore.getState().snapshots.length;
+ info("Taking snapshot...");
+ document.querySelector(".devtools-toolbar .take-snapshot").click();
+ return waitUntilState(gStore, () => gStore.getState().snapshots.length === snapshotCount + 1);
+}
+
+function clearSnapshots(window) {
+ let { gStore, document } = window;
+ document.querySelector(".devtools-toolbar .clear-snapshots").click();
+ return waitUntilState(gStore, () => gStore.getState().snapshots.every(
+ (snapshot) => snapshot.state !== states.READ)
+ );
+}
+
+/**
+ * Sets the current requested display and waits for the selected snapshot to use
+ * it and complete the new census that entails.
+ */
+function setCensusDisplay(window, display) {
+ info(`Setting census display to ${display}...`);
+ let { gStore, gHeapAnalysesClient } = window;
+ // XXX: Should handle this via clicking the DOM, but React doesn't
+ // fire the onChange event, so just change it in the store.
+ // window.document.querySelector(`.select-display`).value = type;
+ gStore.dispatch(require("devtools/client/memory/actions/census-display")
+ .setCensusDisplayAndRefresh(gHeapAnalysesClient, display));
+
+ return waitUntilState(window.gStore, () => {
+ let selected = window.gStore.getState().snapshots.find(s => s.selected);
+ return selected.state === states.READ &&
+ selected.census &&
+ selected.census.state === censusState.SAVED &&
+ selected.census.display === display;
+ });
+}
+
+/**
+ * Get the snapshot tatus text currently displayed, or null if none is
+ * displayed.
+ *
+ * @param {Document} document
+ */
+function getDisplayedSnapshotStatus(document) {
+ const status = document.querySelector(".snapshot-status");
+ return status ? status.textContent.trim() : null;
+}
+
+/**
+ * Get the index of the currently selected snapshot.
+ *
+ * @return {Number}
+ */
+function getSelectedSnapshotIndex(store) {
+ let snapshots = store.getState().snapshots;
+ let selectedSnapshot = snapshots.find(s => s.selected);
+ return snapshots.indexOf(selectedSnapshot);
+}
+
+/**
+ * Returns a promise that will resolve when the snapshot with provided index
+ * becomes selected.
+ *
+ * @return {Promise}
+ */
+function waitUntilSnapshotSelected(store, snapshotIndex) {
+ return waitUntilState(store, state =>
+ state.snapshots[snapshotIndex] &&
+ state.snapshots[snapshotIndex].selected === true);
+}
+
+
+/**
+ * Wait until the state has censuses in a certain state.
+ *
+ * @return {Promise}
+ */
+function waitUntilCensusState(store, getCensus, expected) {
+ let predicate = () => {
+ let snapshots = store.getState().snapshots;
+
+ info("Current census state:" +
+ snapshots.map(x => getCensus(x) ? getCensus(x).state : null));
+
+ return snapshots.length === expected.length &&
+ expected.every((state, i) => {
+ let census = getCensus(snapshots[i]);
+ return (state === "*") ||
+ (!census && !state) ||
+ (census && census.state === state);
+ });
+ };
+ info(`Waiting for snapshot censuses to be of state: ${expected}`);
+ return waitUntilState(store, predicate);
+}
+
+/**
+ * Mock out the requestAnimationFrame.
+ *
+ * @return {Object}
+ * @function nextFrame
+ * Call the last queued function
+ * @function raf
+ * The mocked raf function
+ * @function timesCalled
+ * How many times the RAF has been called
+ */
+function createRAFMock() {
+ let queuedFns = [];
+ let mock = { timesCalled: 0 };
+
+ mock.nextFrame = function () {
+ let thisQueue = queuedFns;
+ queuedFns = [];
+ for (var i = 0; i < thisQueue.length; i++) {
+ thisQueue[i]();
+ }
+ };
+
+ mock.raf = function (fn) {
+ mock.timesCalled++;
+ queuedFns.push(fn);
+ };
+ return mock;
+}
+
+/**
+ * Test to see if two floats are equivalent.
+ *
+ * @param {Float} a
+ * @param {Float} b
+ * @return {Boolean}
+ */
+function floatEquality(a, b) {
+ const EPSILON = 0.00000000001;
+ const equals = Math.abs(a - b) < EPSILON;
+ if (!equals) {
+ info(`${a} not equal to ${b}`);
+ }
+ return equals;
+}