Bug 1239437 - Browser mochitests for responsive.html. r=pbrosset

This commit is contained in:
J. Ryan Stinnett 2016-01-20 13:57:30 -06:00
parent bc17ebb4d3
commit 82608243d7
7 changed files with 189 additions and 23 deletions

View File

@ -69,6 +69,12 @@ window.addEventListener("unload", function onUnload() {
// Allows quick testing of actions from the console
window.dispatch = action => bootstrap.dispatch(action);
// Expose the store on window for testing
Object.defineProperty(window, "store", {
get: () => bootstrap.store,
enumerable: true,
});
/**
* Called by manager.js to add the initial viewport based on the original page.
*/

View File

@ -29,31 +29,53 @@ exports.ResponsiveUIManager = {
* @param tab
* The browser tab.
* @return Promise
* Resolved when the toggling has completed.
* Resolved when the toggling has completed. If the UI has opened,
* it is resolved to the ResponsiveUI instance for this tab. If the
* the UI has closed, there is no resolution value.
*/
toggle(window, tab) {
if (this.isActiveForTab(tab)) {
this.activeTabs.get(tab).destroy();
this.activeTabs.delete(tab);
} else {
this.runIfNeeded(window, tab);
}
// TODO: Becomes a more interesting value in a later patch
return promise.resolve();
let action = this.isActiveForTab(tab) ? "close" : "open";
return this[action + "IfNeeded"](window, tab);
},
/**
* Launches the responsive UI.
* Opens the responsive UI, if not already open.
*
* @param window
* The main browser chrome window.
* @param tab
* The browser tab.
* @return Promise
* Resolved to the ResponsiveUI instance for this tab when opening is
* complete.
*/
runIfNeeded(window, tab) {
openIfNeeded: Task.async(function*(window, tab) {
if (!this.isActiveForTab(tab)) {
this.activeTabs.set(tab, new ResponsiveUI(window, tab));
let ui = new ResponsiveUI(window, tab);
this.activeTabs.set(tab, ui);
yield ui.inited;
this.emit("on", { tab });
}
return this.getResponsiveUIForTab(tab);
}),
/**
* Closes the responsive UI, if not already closed.
*
* @param window
* The main browser chrome window.
* @param tab
* The browser tab.
* @return Promise
* Resolved (with no value) when closing is complete.
*/
closeIfNeeded(window, tab) {
if (this.isActiveForTab(tab)) {
this.activeTabs.get(tab).destroy();
this.activeTabs.delete(tab);
this.emit("off", { tab });
}
return promise.resolve();
},
/**
@ -92,26 +114,25 @@ exports.ResponsiveUIManager = {
* The GCLI command arguments.
*/
handleGcliCommand: function(window, tab, command, args) {
let completed;
switch (command) {
case "resize to":
this.runIfNeeded(window, tab);
completed = this.openIfNeeded(window, tab);
// TODO: Probably the wrong API
this.activeTabs.get(tab).setSize(args.width, args.height);
break;
case "resize on":
this.runIfNeeded(window, tab);
completed = this.openIfNeeded(window, tab);
break;
case "resize off":
if (this.isActiveForTab(tab)) {
this.activeTabs.get(tab).destroy();
this.activeTabs.delete(tab);
}
completed = this.closeIfNeeded(window, tab);
break;
case "resize toggle":
this.toggle(window, tab);
completed = this.toggle(window, tab);
break;
default:
}
completed.catch(e => console.error(e));
}
};
@ -126,9 +147,9 @@ EventEmitter.decorate(exports.ResponsiveUIManager);
* integrate the tool into the surrounding browser UI as needed.
*/
function ResponsiveUI(window, tab) {
this.window = window;
this.browserWindow = window;
this.tab = tab;
this.init();
this.inited = this.init();
}
ResponsiveUI.prototype = {
@ -136,13 +157,27 @@ ResponsiveUI.prototype = {
/**
* The main browser chrome window (that holds many tabs).
*/
window: null,
browserWindow: null,
/**
* The specific browser tab this responsive instance is for.
*/
tab: null,
/**
* Promise resovled when the UI init has completed.
*/
inited: null,
/**
* A window reference for the chrome:// document that displays the responsive
* design tool. It is safe to reference this window directly even with e10s,
* as the tool UI is always loaded in the parent process. The web content
* contained *within* the tool UI on the other hand is loaded in the child
* process.
*/
toolWindow: null,
/**
* For the moment, we open the tool by:
* 1. Recording the tab's URL
@ -161,7 +196,7 @@ ResponsiveUI.prototype = {
let contentURI = tabBrowser.documentURI.spec;
tabBrowser.loadURI(TOOL_URL);
yield tabLoaded(this.tab);
let toolWindow = tabBrowser.contentWindow;
let toolWindow = this.toolWindow = tabBrowser.contentWindow;
toolWindow.addInitialViewport(contentURI);
}),
@ -170,6 +205,8 @@ ResponsiveUI.prototype = {
tabBrowser.goBack();
this.window = null;
this.tab = null;
this.inited = null;
this.toolWindow = null;
},
};

View File

@ -20,3 +20,4 @@ DevToolsModules(
)
XPCSHELL_TESTS_MANIFESTS += ['test/unit/xpcshell.ini']
BROWSER_CHROME_MANIFESTS += ['test/browser/browser.ini']

View File

@ -0,0 +1,4 @@
{
// Extend from the shared list of defined globals for mochitests.
"extends": "../../../../.eslintrc.mochitests"
}

View File

@ -0,0 +1,7 @@
[DEFAULT]
tags = devtools
subsuite = devtools
support-files =
head.js
[browser_viewport_basics.js]

View File

@ -0,0 +1,32 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
/* TODO: Bug 1242584 should make the following comment unnecessary */
/* import-globals-from ../../../framework/test/shared-redux-head.js */
// Test viewports basics after opening, like size and location
const TEST_URL = "http://example.org/";
addRDMTask(TEST_URL, function*({ ui }) {
let store = ui.toolWindow.store;
// Wait until the viewport has been added
yield waitUntilState(store, state => state.viewports.length == 1);
// A single viewport of default size appeared
let browser = ui.toolWindow.document.querySelector(".browser");
is(browser.width, "320", "Viewport has default width");
is(browser.height, "480", "Viewport has default height");
// Browser's location should match original tab
// TODO: For the moment, we have parent process <iframe>s and we can just
// check the location directly. Bug 1240896 will change this to <iframe
// mozbrowser remote>, which is in the child process, so ContentTask or
// similar will be needed.
yield waitForFrameLoad(browser, TEST_URL);
is(browser.contentWindow.location.href, TEST_URL,
"Viewport location matches");
});

View File

@ -0,0 +1,79 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
/* eslint no-unused-vars: [2, {"vars": "local"}] */
/* import-globals-from ../../../framework/test/shared-head.js */
/* import-globals-from ../../../framework/test/shared-redux-head.js */
/* global ResponsiveUI */
Services.scriptloader.loadSubScript(
"chrome://mochitests/content/browser/devtools/client/framework/test/shared-head.js",
this);
Services.scriptloader.loadSubScript(
"chrome://mochitests/content/browser/devtools/client/framework/test/shared-redux-head.js",
this);
Services.prefs.setBoolPref("devtools.responsive.html.enabled", true);
registerCleanupFunction(() => {
Services.prefs.clearUserPref("devtools.responsive.html.enabled");
});
/**
* Open responsive design mode for the given tab.
*/
var openRDM = Task.async(function*(tab) {
info("Opening responsive design mode");
let manager = ResponsiveUI.ResponsiveUIManager;
let ui = yield manager.openIfNeeded(window, tab);
info("Responsive design mode opened");
return { ui, manager };
});
/**
* Close responsive design mode for the given tab.
*/
var closeRDM = Task.async(function*(tab) {
info("Closing responsive design mode");
let manager = ResponsiveUI.ResponsiveUIManager;
manager.closeIfNeeded(window, tab);
info("Responsive design mode closed");
});
/**
* Adds a new test task that adds a tab with the given URL, opens responsive
* design mode, runs the given generator, closes responsive design mode, and
* removes the tab.
*
* Example usage:
*
* addRDMTask(TEST_URL, function*({ ui, manager }) {
* // Your tests go here...
* });
*/
function addRDMTask(url, generator) {
add_task(function*() {
const tab = yield addTab(url);
const results = yield openRDM(tab);
try {
yield* generator(results);
} catch (err) {
ok(false, "Got an error: " + DevToolsUtils.safeErrorString(err));
}
yield closeRDM(tab);
yield removeTab(tab);
});
}
var waitForFrameLoad = Task.async(function*(frame, targetURL) {
let window = frame.contentWindow;
if ((window.document.readyState == "complete" ||
window.document.readyState == "interactive") &&
window.location.href == targetURL) {
return;
}
yield once(frame, "load");
});