Bug 1240896 - Port browser_device_width.js to new RDM. r=gl

This also adds the test infrastructure for detecting content resizing.

MozReview-Commit-ID: H3bkAOkpMbs
This commit is contained in:
J. Ryan Stinnett 2016-04-01 14:32:28 -05:00
Родитель 6379a92120
Коммит 6c4bc0307f
10 изменённых файлов: 166 добавлений и 2 удалений

Просмотреть файл

@ -39,6 +39,14 @@ let App = createClass({
this.props.dispatch(changeDevice(id, device));
},
onContentResize({ width, height }) {
window.postMessage({
type: "content-resize",
width,
height,
}, "*");
},
onExit() {
window.postMessage({ type: "exit" }, "*");
},
@ -64,8 +72,9 @@ let App = createClass({
} = this.props;
let {
onChangeViewportDevice,
onBrowserMounted,
onChangeViewportDevice,
onContentResize,
onExit,
onResizeViewport,
onRotateViewport,
@ -88,6 +97,7 @@ let App = createClass({
viewports,
onBrowserMounted,
onChangeViewportDevice,
onContentResize,
onRotateViewport,
onResizeViewport,
})

Просмотреть файл

@ -30,6 +30,7 @@ module.exports = createClass({
propTypes: {
location: Types.location.isRequired,
onBrowserMounted: PropTypes.func.isRequired,
onContentResize: PropTypes.func.isRequired,
},
/**
@ -37,8 +38,16 @@ module.exports = createClass({
* various features, like floating scrollbars.
*/
componentDidMount: Task.async(function*() {
let { onContentResize } = this;
let browser = this.refs.browserContainer.querySelector("iframe.browser");
let mm = browser.frameLoader.messageManager;
// Notify tests when the content has received a resize event. This is not
// quite the same timing as when we _set_ a new size around the browser,
// since it still needs to do async work before the content is actually
// resized to match.
mm.addMessageListener("ResponsiveMode:OnContentResize", onContentResize);
let ready = waitForMessage(mm, "ResponsiveMode:ChildScriptReady");
mm.loadFrameScript("resource://devtools/client/responsivedesign/" +
"responsivedesign-child.js", true);
@ -60,11 +69,22 @@ module.exports = createClass({
}),
componentWillUnmount() {
let { onContentResize } = this;
let browser = this.refs.browserContainer.querySelector("iframe.browser");
let mm = browser.frameLoader.messageManager;
mm.removeMessageListener("ResponsiveMode:OnContentResize", onContentResize);
mm.sendAsyncMessage("ResponsiveMode:Stop");
},
onContentResize(msg) {
let { onContentResize } = this.props;
let { width, height } = msg.data;
onContentResize({
width,
height,
});
},
render() {
let {
location,

Просмотреть файл

@ -28,6 +28,7 @@ module.exports = createClass({
viewport: PropTypes.shape(Types.viewport).isRequired,
onBrowserMounted: PropTypes.func.isRequired,
onChangeViewportDevice: PropTypes.func.isRequired,
onContentResize: PropTypes.func.isRequired,
onResizeViewport: PropTypes.func.isRequired,
onRotateViewport: PropTypes.func.isRequired,
},
@ -118,6 +119,7 @@ module.exports = createClass({
viewport,
onBrowserMounted,
onChangeViewportDevice,
onContentResize,
onResizeViewport,
onRotateViewport,
} = this.props;
@ -154,6 +156,7 @@ module.exports = createClass({
Browser({
location,
onBrowserMounted,
onContentResize,
})
),
dom.div({

Просмотреть файл

@ -22,6 +22,7 @@ module.exports = createClass({
viewport: PropTypes.shape(Types.viewport).isRequired,
onBrowserMounted: PropTypes.func.isRequired,
onChangeViewportDevice: PropTypes.func.isRequired,
onContentResize: PropTypes.func.isRequired,
onResizeViewport: PropTypes.func.isRequired,
onRotateViewport: PropTypes.func.isRequired,
},
@ -59,6 +60,7 @@ module.exports = createClass({
location,
screenshot,
viewport,
onContentResize,
onBrowserMounted,
} = this.props;
@ -79,6 +81,7 @@ module.exports = createClass({
viewport,
onBrowserMounted,
onChangeViewportDevice,
onContentResize,
onResizeViewport,
onRotateViewport,
}),

Просмотреть файл

@ -21,6 +21,7 @@ module.exports = createClass({
viewports: PropTypes.arrayOf(PropTypes.shape(Types.viewport)).isRequired,
onBrowserMounted: PropTypes.func.isRequired,
onChangeViewportDevice: PropTypes.func.isRequired,
onContentResize: PropTypes.func.isRequired,
onResizeViewport: PropTypes.func.isRequired,
onRotateViewport: PropTypes.func.isRequired,
},
@ -33,6 +34,7 @@ module.exports = createClass({
viewports,
onBrowserMounted,
onChangeViewportDevice,
onContentResize,
onResizeViewport,
onRotateViewport,
} = this.props;
@ -50,6 +52,7 @@ module.exports = createClass({
viewport,
onBrowserMounted,
onChangeViewportDevice,
onContentResize,
onResizeViewport,
onRotateViewport,
});

Просмотреть файл

@ -115,6 +115,14 @@ window.addInitialViewport = contentURI => {
}
};
/**
* Called by manager.js when tests want to check the viewport size.
*/
window.getViewportSize = () => {
let { width, height } = bootstrap.store.getState().viewports[0];
return { width, height };
};
/**
* Called by manager.js to set viewport size from GCLI.
*/
@ -125,3 +133,10 @@ window.setViewportSize = (width, height) => {
console.error(e);
}
};
/**
* Called by manager.js when tests want to use the viewport's message manager.
*/
window.getViewportMessageManager = () => {
return document.querySelector("iframe.browser").frameLoader;
};

Просмотреть файл

@ -195,10 +195,10 @@ ResponsiveUI.prototype = {
tabBrowser.loadURI(TOOL_URL);
yield tabLoaded(this.tab);
let toolWindow = this.toolWindow = tabBrowser.contentWindow;
toolWindow.addEventListener("message", this);
yield waitForMessage(toolWindow, "init");
toolWindow.addInitialViewport(contentURI);
yield waitForMessage(toolWindow, "browser-mounted");
toolWindow.addEventListener("message", this);
}),
destroy() {
@ -219,6 +219,13 @@ ResponsiveUI.prototype = {
}
switch (event.data.type) {
case "content-resize":
let { width, height } = event.data;
this.emit("content-resize", {
width,
height,
});
break;
case "exit":
toolWindow.removeEventListener(event.type, this);
ResponsiveUIManager.closeIfNeeded(window, tab);
@ -226,13 +233,23 @@ ResponsiveUI.prototype = {
}
},
getViewportSize() {
return this.toolWindow.getViewportSize();
},
setViewportSize: Task.async(function*(width, height) {
yield this.inited;
this.toolWindow.setViewportSize(width, height);
}),
getViewportMessageManager() {
return this.toolWindow.getViewportMessageManager();
},
};
EventEmitter.decorate(ResponsiveUI.prototype);
function waitForMessage(win, type) {
let deferred = promise.defer();

Просмотреть файл

@ -8,6 +8,7 @@ support-files =
!/devtools/client/framework/test/shared-head.js
!/devtools/client/framework/test/shared-redux-head.js
[browser_device_width.js]
[browser_exit_button.js]
[browser_resize_cmd.js]
[browser_screenshot_button.js]

Просмотреть файл

@ -0,0 +1,66 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
const TEST_URL = "about:logo";
addRDMTask(TEST_URL, function*({ ui, manager }) {
ok(ui, "An instance of the RDM should be attached to the tab.");
yield setViewportSize(ui, manager, 110, 500);
info("Checking initial width/height properties.");
yield doInitialChecks(ui);
info("Changing the RDM size");
yield setViewportSize(ui, manager, 90, 500);
info("Checking for screen props");
yield checkScreenProps(ui);
info("Setting docShell.deviceSizeIsPageSize to false");
yield ContentTask.spawn(ui.getViewportMessageManager(), {}, function*() {
let docShell = content.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIWebNavigation)
.QueryInterface(Ci.nsIDocShell);
docShell.deviceSizeIsPageSize = false;
});
info("Checking for screen props once again.");
yield checkScreenProps2(ui);
});
function* doInitialChecks(ui) {
let { innerWidth, matchesMedia } = yield grabContentInfo(ui);
is(innerWidth, 110, "initial width should be 110px");
ok(!matchesMedia, "media query shouldn't match.");
}
function* checkScreenProps(ui) {
let { matchesMedia, screen } = yield grabContentInfo(ui);
ok(matchesMedia, "media query should match");
isnot(window.screen.width, screen.width,
"screen.width should not be the size of the screen.");
is(screen.width, 90, "screen.width should be the page width");
is(screen.height, 500, "screen.height should be the page height");
}
function* checkScreenProps2(ui) {
let { matchesMedia, screen } = yield grabContentInfo(ui);
ok(!matchesMedia, "media query should be re-evaluated.");
is(window.screen.width, screen.width,
"screen.width should be the size of the screen.");
}
function grabContentInfo(ui) {
return ContentTask.spawn(ui.getViewportMessageManager(), {}, function*() {
return {
screen: {
width: content.screen.width,
height: content.screen.height
},
innerWidth: content.innerWidth,
matchesMedia: content.matchMedia("(max-device-width:100px)").matches
};
});
}

Просмотреть файл

@ -94,3 +94,29 @@ var waitForFrameLoad = Task.async(function*(frame, targetURL) {
}
yield once(frame, "load");
});
function waitForViewportResizeTo(ui, width, height) {
return new Promise(resolve => {
let onResize = (_, data) => {
if (data.width != width || data.height != height) {
return;
}
ui.off("content-resize", onResize);
info(`Got content-resize to ${width} x ${height}`);
resolve();
};
info(`Waiting for content-resize to ${width} x ${height}`);
ui.on("content-resize", onResize);
});
}
var setViewportSize = Task.async(function*(ui, manager, width, height) {
let size = ui.getViewportSize();
info(`Current size: ${size.width} x ${size.height}, ` +
`set to: ${width} x ${height}`);
if (size.width != width || size.height != height) {
let resized = waitForViewportResizeTo(ui, width, height);
ui.setViewportSize(width, height);
yield resized;
}
});