This commit is contained in:
Phil Ringnalda 2016-01-10 15:39:55 -08:00
Родитель 4f1cbcd738 bd528af5a4
Коммит e3c6e3b2d4
34 изменённых файлов: 748 добавлений и 735 удалений

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

@ -32,9 +32,9 @@ function test() {
is(tabState.entries[0].url, baseURL + 0, "... but not more");
// visit yet another anchor (appending it to session history)
runInContent(tab.linkedBrowser, function(win) {
win.document.querySelector("a").click();
}, null).then(flushAndCheck);
ContentTask.spawn(tab.linkedBrowser, null, function() {
content.window.document.querySelector("a").click();
}).then(flushAndCheck);
function flushAndCheck() {
TabStateFlusher.flush(tab.linkedBrowser).then(check);

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

@ -42,9 +42,9 @@ function checkState(tab) {
// deserialized in the content scope. And in this case, since RegExps are
// not currently Xrayable (see bug 1014991), trying to pull |obj3| (a RegExp)
// off of an Xrayed Object won't work. So we need to waive.
runInContent(tab.linkedBrowser, function(win, state) {
ContentTask.spawn(tab.linkedBrowser, aEvent.state, function(state) {
return Cu.waiveXrays(state).obj3.toString();
}, aEvent.state).then(function(stateStr) {
}).then(function(stateStr) {
is(stateStr, '/^a$/', "second popstate object.");
// Make sure that the new-elem node is present in the document. If it's
@ -92,13 +92,13 @@ function test() {
// testURL (state object: null) <-- oldest
// testURL (state object: {obj1:1})
// testURL?page2 (state object: {obj3:/^a$/}) <-- newest
function contentTest(win) {
let history = win.history;
function contentTest() {
let history = content.window.history;
history.pushState({obj1:1}, "title-obj1");
history.pushState({obj2:2}, "title-obj2", "?page2");
history.replaceState({obj3:/^a$/}, "title-obj3");
}
runInContent(browser, contentTest, null).then(function() {
ContentTask.spawn(browser, null, contentTest).then(function() {
return TabStateFlusher.flush(tab.linkedBrowser);
}).then(() => {
let state = ss.getTabState(tab);

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

@ -216,12 +216,6 @@ addMessageListener("ss-test:click", function ({data}) {
sendAsyncMessage("ss-test:click");
});
addMessageListener("ss-test:run", function({data, objects}) {
let f = eval('(' + data.code + ')');
let result = f(content, objects.arg);
sendAsyncMessage("ss-test:runFinished", result);
});
addEventListener("load", function(event) {
let subframe = event.target != content.document;
sendAsyncMessage("ss-test:loadEvent", {subframe: subframe, url: event.target.documentURI});

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

@ -449,16 +449,6 @@ function promiseNewWindowLoaded(aOptions) {
return new Promise(resolve => whenNewWindowLoaded(aOptions, resolve));
}
function runInContent(browser, func, arg, callback = null) {
let deferred = Promise.defer();
let mm = browser.messageManager;
mm.sendAsyncMessage("ss-test:run", {code: func.toSource()}, {arg: arg});
mm.addMessageListener("ss-test:runFinished", ({data}) => deferred.resolve(data));
return deferred.promise;
}
/**
* This waits for the browser-delayed-startup-finished notification of a given
* window. It indicates that the windows has loaded completely and is ready to

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

@ -5,6 +5,11 @@
],
// All globals made available in the test environment.
"globals": {
"DevToolsUtils": true,
"gDevTools": true,
"once": true,
"synthesizeKeyFromKeyTag": true,
"TargetFactory": true,
"waitForTick": true,
}
}

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

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

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

@ -1,6 +1,8 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
///////////////////
//
// Whitelisting this test.
@ -14,15 +16,15 @@ function test() {
.hasAttribute("responsivemode");
}
helpers.addTabWithToolbar("data:text/html;charset=utf-8,hi", function(options) {
helpers.addTabWithToolbar("data:text/html;charset=utf-8,hi", (options) => {
return helpers.audit(options, [
{
setup: "resize toggle",
check: {
input: 'resize toggle',
hints: '',
markup: 'VVVVVVVVVVVVV',
status: 'VALID'
input: "resize toggle",
hints: "",
markup: "VVVVVVVVVVVVV",
status: "VALID"
},
exec: {
output: ""
@ -34,10 +36,10 @@ function test() {
{
setup: "resize toggle",
check: {
input: 'resize toggle',
hints: '',
markup: 'VVVVVVVVVVVVV',
status: 'VALID'
input: "resize toggle",
hints: "",
markup: "VVVVVVVVVVVVV",
status: "VALID"
},
exec: {
output: ""
@ -49,10 +51,10 @@ function test() {
{
setup: "resize on",
check: {
input: 'resize on',
hints: '',
markup: 'VVVVVVVVV',
status: 'VALID'
input: "resize on",
hints: "",
markup: "VVVVVVVVV",
status: "VALID"
},
exec: {
output: ""
@ -64,10 +66,10 @@ function test() {
{
setup: "resize off",
check: {
input: 'resize off',
hints: '',
markup: 'VVVVVVVVVV',
status: 'VALID'
input: "resize off",
hints: "",
markup: "VVVVVVVVVV",
status: "VALID"
},
exec: {
output: ""
@ -79,10 +81,10 @@ function test() {
{
setup: "resize to 400 400",
check: {
input: 'resize to 400 400',
hints: '',
markup: 'VVVVVVVVVVVVVVVVV',
status: 'VALID',
input: "resize to 400 400",
hints: "",
markup: "VVVVVVVVVVVVVVVVV",
status: "VALID",
args: {
width: { value: 400 },
height: { value: 400 },
@ -98,10 +100,10 @@ function test() {
{
setup: "resize off",
check: {
input: 'resize off',
hints: '',
markup: 'VVVVVVVVVV',
status: 'VALID'
input: "resize off",
hints: "",
markup: "VVVVVVVVVV",
status: "VALID"
},
exec: {
output: ""

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

@ -1,62 +1,68 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
function test() {
let instance;
let mgr = ResponsiveUI.ResponsiveUIManager;
"use strict";
waitForExplicitFinish();
add_task(function*() {
let tab = yield addTab("about:logo");
let {rdm} = yield openRDM(tab);
ok(rdm, "An instance of the RDM should be attached to the tab.");
rdm.setSize(110, 500);
gBrowser.selectedTab = gBrowser.addTab("about:logo");
gBrowser.selectedBrowser.addEventListener("load", function onload() {
gBrowser.selectedBrowser.removeEventListener("load", onload, true);
startTest();
}, true);
info("Checking initial width/height properties.");
yield doInitialChecks();
function startTest() {
mgr.once("on", function() {executeSoon(onUIOpen)});
document.getElementById("Tools:ResponsiveUI").doCommand();
}
function onUIOpen() {
instance = mgr.getResponsiveUIForTab(gBrowser.selectedTab);
instance.stack.setAttribute("notransition", "true");
ok(instance, "instance of the module is attached to the tab.");
instance.setSize(110, 500);
ok(content.innerWidth, 110, "initial width is valid");
let mql = content.matchMedia("(max-device-width:100px)")
ok(!mql.matches, "media query doesn't match.");
mql.addListener(onMediaChange);
instance.setSize(90, 500);
}
function onMediaChange(mql) {
mql.removeListener(onMediaChange);
ok(mql.matches, "media query matches.");
ok(window.screen.width != content.screen.width, "screen.width is not the size of the screen.");
is(content.screen.width, 90, "screen.width is the width of the page.");
is(content.screen.height, 500, "screen.height is the height of the page.");
info("Changing the RDM size");
rdm.setSize(90, 500);
info("Checking for screen props");
yield checkScreenProps();
info("Setting docShell.deviceSizeIsPageSize to false");
yield ContentTask.spawn(gBrowser.selectedBrowser, {}, function*() {
let docShell = content.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIWebNavigation)
.QueryInterface(Ci.nsIDocShell);
mql.addListener(onMediaChange2);
docShell.deviceSizeIsPageSize = false;
}
});
function onMediaChange2(mql) {
mql.removeListener(onMediaChange);
ok(!mql.matches, "media query has been re-evaluated.");
ok(window.screen.width == content.screen.width, "screen.width is not the size of the screen.");
instance.stack.removeAttribute("notransition");
document.getElementById("Tools:ResponsiveUI").doCommand();
gBrowser.removeCurrentTab();
finish();
}
info("Checking for screen props once again.");
yield checkScreenProps2();
yield closeRDM(rdm);
});
function* doInitialChecks() {
let {innerWidth, matchesMedia} = yield grabContentInfo();
is(innerWidth, 110, "initial width should be 110px");
ok(!matchesMedia, "media query shouldn't match.");
}
function* checkScreenProps() {
let {matchesMedia, screen} = yield grabContentInfo();
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() {
let {matchesMedia, screen} = yield grabContentInfo();
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() {
return ContentTask.spawn(gBrowser.selectedBrowser, {}, function*() {
return {
screen: {
width: content.screen.width,
height: content.screen.height
},
innerWidth: content.innerWidth,
matchesMedia: content.matchMedia("(max-device-width:100px)").matches
};
});
}

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

@ -35,7 +35,8 @@ add_task(function*() {
info("Try growing the viewport and checking the applied styles");
yield testGrow(view, inspector, rdm);
gBrowser.removeCurrentTab();
yield closeRDM(rdm);
yield closeToolbox();
});
function* testShrink(computedView, inspector, rdm) {

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

@ -25,7 +25,7 @@ add_task(function*() {
yield addTab(TEST_URI);
info("Open the responsive design mode and set its size to 500x500 to start");
let {rdm, manager} = yield openRDM();
let {rdm} = yield openRDM();
rdm.setSize(500, 500);
info("Open the inspector, rule-view and select the test node");
@ -41,11 +41,12 @@ add_task(function*() {
info("Check that ESC still opens the split console");
yield testEscapeOpensSplitConsole(inspector);
yield closeToolbox();
info("Test the state of the RDM menu item");
yield testMenuItem(manager);
yield testMenuItem(rdm);
Services.prefs.clearUserPref("devtools.toolbox.splitconsoleEnabled");
gBrowser.removeCurrentTab();
});
function* testShrink(ruleView, rdm) {
@ -79,19 +80,14 @@ function* testEscapeOpensSplitConsole(inspector) {
ok(inspector._toolbox._splitConsole, "Console is split after pressing ESC.");
}
function* testMenuItem(manager) {
function* testMenuItem(rdm) {
is(document.getElementById("Tools:ResponsiveUI").getAttribute("checked"),
"true",
"The menu item is checked");
"true", "The menu item is checked");
info("Toggle off the RDM");
let onManagerOff = manager.once("off");
manager.toggle(window, gBrowser.selectedTab);
yield onManagerOff;
yield closeRDM(rdm);
is(document.getElementById("Tools:ResponsiveUI").getAttribute("checked"),
"false",
"The menu item is unchecked");
"false", "The menu item is unchecked");
}
function numberOfRules(ruleView) {

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

@ -1,309 +1,255 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
thisTestLeaksUncaughtRejectionsAndShouldBeFixed("Protocol error (unknownError): Error: Got an invalid root window in DocumentWalker");
"use strict";
function test() {
waitForExplicitFinish();
add_task(function*() {
SimpleTest.requestCompleteLog();
Task.spawn(function*() {
let tab = yield addTab("data:text/html,mop");
function extractSizeFromString(str) {
let numbers = str.match(/(\d+)[^\d]*(\d+)/);
if (numbers) {
return [numbers[1], numbers[2]];
} else {
return [null, null];
}
}
let {rdm, manager} = yield openRDM(tab, "menu");
let container = gBrowser.getBrowserContainer();
is(container.getAttribute("responsivemode"), "true",
"Should be in responsive mode.");
is(document.getElementById("Tools:ResponsiveUI").getAttribute("checked"),
"true", "Menu item should be checked");
function processStringAsKey(str) {
for (let i = 0, l = str.length; i < l; i++) {
EventUtils.synthesizeKey(str.charAt(i), {});
}
}
ok(rdm, "An instance of the RDM should be attached to the tab.");
yield addTab("data:text/html,mop");
let originalWidth = (yield getSizing()).width;
let mgr = ResponsiveUI.ResponsiveUIManager;
let documentLoaded = waitForDocLoadComplete();
gBrowser.loadURI("data:text/html;charset=utf-8,mop" +
"<div style%3D'height%3A5000px'><%2Fdiv>");
yield documentLoaded;
synthesizeKeyFromKeyTag(document.getElementById("key_responsiveUI"));
let newWidth = (yield getSizing()).width;
is(originalWidth, newWidth, "Floating scrollbars shouldn't change the width");
yield once(mgr, "on");
yield rdm._test_notifyOnResize();
yield waitForTick();
// Is it open?
let container = gBrowser.getBrowserContainer();
is(container.getAttribute("responsivemode"), "true", "In responsive mode.");
yield testPresets(rdm, manager);
// Menus are correctly updated?
is(document.getElementById("Tools:ResponsiveUI").getAttribute("checked"), "true", "menus checked");
info("Testing mouse resizing");
yield testManualMouseResize(rdm, manager);
let instance = mgr.getResponsiveUIForTab(gBrowser.selectedTab);
ok(instance, "instance of the module is attached to the tab.");
info("Testing mouse resizing with shift key");
yield testManualMouseResize(rdm, manager, "shift");
let originalWidth = content.innerWidth;
info("Testing mouse resizing with ctrl key");
yield testManualMouseResize(rdm, manager, "ctrl");
let documentLoaded = waitForDocLoadComplete();
content.location = "data:text/html;charset=utf-8,mop<div style%3D'height%3A5000px'><%2Fdiv>";
yield documentLoaded;
info("Testing resizing with user custom keyboard input");
yield testResizeUsingCustomInput(rdm, manager);
let newWidth = content.innerWidth;
is(originalWidth, newWidth, "Floating scrollbars are presents");
info("Testing invalid keyboard input");
yield testInvalidUserInput(rdm);
yield instance._test_notifyOnResize();
info("Testing rotation");
yield testRotate(rdm, manager);
yield nextTick();
let {width: widthBeforeClose, height: heightBeforeClose} = yield getSizing();
instance.transitionsEnabled = false;
info("Restarting responsive mode");
yield closeRDM(rdm);
({rdm} = yield openRDM(tab, "keyboard"));
// Starting from length - 4 because last 3 items are not presets : separator, addbutton and removebutton
for (let c = instance.menulist.firstChild.childNodes.length - 4; c >= 0; c--) {
let item = instance.menulist.firstChild.childNodes[c];
let [width, height] = extractSizeFromString(item.getAttribute("label"));
let onContentResize = once(mgr, "contentResize");
instance.menulist.selectedIndex = c;
yield onContentResize;
is(content.innerWidth, width, "preset " + c + ": dimension valid (width)");
is(content.innerHeight, height, "preset " + c + ": dimension valid (height)");
}
let currentSize = yield getSizing();
is(currentSize.width, widthBeforeClose, "width should be restored");
is(currentSize.height, heightBeforeClose, "height should be restored");
// test custom
container = gBrowser.getBrowserContainer();
is(container.getAttribute("responsivemode"), "true", "In responsive mode.");
is(document.getElementById("Tools:ResponsiveUI").getAttribute("checked"),
"true", "menu item should be checked");
instance.setSize(100, 100);
let isWinXP = navigator.userAgent.indexOf("Windows NT 5.1") != -1;
if (!isWinXP) {
yield testScreenshot(rdm);
}
yield once(mgr, "contentResize");
yield closeRDM(rdm);
is(document.getElementById("Tools:ResponsiveUI").getAttribute("checked"),
"false", "menu item should be unchecked");
});
let initialWidth = content.innerWidth;
let initialHeight = content.innerHeight;
function* testPresets(rdm, manager) {
// Starting from length - 4 because last 3 items are not presets :
// the separator, the add button and the remove button
for (let c = rdm.menulist.firstChild.childNodes.length - 4; c >= 0; c--) {
let item = rdm.menulist.firstChild.childNodes[c];
let [width, height] = extractSizeFromString(item.getAttribute("label"));
let onContentResize = once(manager, "contentResize");
rdm.menulist.selectedIndex = c;
yield onContentResize;
is(initialWidth, 100, "Width reset to 100");
is(initialHeight, 100, "Height reset to 100");
let x = 2, y = 2;
EventUtils.synthesizeMouse(instance.resizer, x, y, {type: "mousedown"}, window);
x += 20; y += 10;
EventUtils.synthesizeMouse(instance.resizer, x, y, {type: "mousemove"}, window);
EventUtils.synthesizeMouse(instance.resizer, x, y, {type: "mouseup"}, window);
yield once(mgr, "contentResize");
let expectedWidth = initialWidth + 20;
let expectedHeight = initialHeight + 10;
info("initial width: " + initialWidth);
info("initial height: " + initialHeight);
is(content.innerWidth, expectedWidth, "Size correctly updated (width).");
is(content.innerHeight, expectedHeight, "Size correctly updated (height).");
is(instance.menulist.selectedIndex, -1, "Custom menuitem cannot be selected");
let label = instance.menulist.firstChild.firstChild.getAttribute("label");
let value = instance.menulist.value;
isnot(label, value, "Label from the menulist item is different than the value of the menulist")
let [width, height] = extractSizeFromString(label);
is(width, expectedWidth, "Label updated (width).");
is(height, expectedHeight, "Label updated (height).");
[width, height] = extractSizeFromString(value);
is(width, expectedWidth, "Value updated (width).");
is(height, expectedHeight, "Value updated (height).");
// With "shift" key pressed
instance.setSize(100, 100);
yield once(mgr, "contentResize");
initialWidth = content.innerWidth;
initialHeight = content.innerHeight;
x = 2; y = 2;
EventUtils.synthesizeMouse(instance.resizer, x, y, {type: "mousedown"}, window);
x += 23; y += 13;
EventUtils.synthesizeMouse(instance.resizer, x, y, {type: "mousemove", shiftKey: true}, window);
EventUtils.synthesizeMouse(instance.resizer, x, y, {type: "mouseup"}, window);
yield once(mgr, "contentResize");
expectedWidth = initialWidth + 20;
expectedHeight = initialHeight + 10;
is(content.innerWidth, expectedWidth, "with shift: Size correctly updated (width).");
is(content.innerHeight, expectedHeight, "with shift: Size correctly updated (height).");
is(instance.menulist.selectedIndex, -1, "with shift: Custom menuitem cannot be selected");
label = instance.menulist.firstChild.firstChild.getAttribute("label");
value = instance.menulist.value;
isnot(label, value, "Label from the menulist item is different than the value of the menulist");
[width, height] = extractSizeFromString(label);
is(width, expectedWidth, "Label updated (width).");
is(height, expectedHeight, "Label updated (height).");
[width, height] = extractSizeFromString(value);
is(width, expectedWidth, "Value updated (width).");
is(height, expectedHeight, "Value updated (height).");
// With "ctrl" key pressed
instance.setSize(100, 100);
yield once(mgr, "contentResize");
initialWidth = content.innerWidth;
initialHeight = content.innerHeight;
x = 2; y = 2;
EventUtils.synthesizeMouse(instance.resizer, x, y, {type: "mousedown"}, window);
x += 60; y += 30;
EventUtils.synthesizeMouse(instance.resizer, x, y, {type: "mousemove", ctrlKey: true}, window);
EventUtils.synthesizeMouse(instance.resizer, x, y, {type: "mouseup"}, window);
yield once(mgr, "contentResize");
expectedWidth = initialWidth + 10;
expectedHeight = initialHeight + 5;
is(content.innerWidth, expectedWidth, "with ctrl: Size correctly updated (width).");
is(content.innerHeight, expectedHeight, "with ctrl: Size correctly updated (height).");
is(instance.menulist.selectedIndex, -1, "with ctrl: Custom menuitem cannot be selected");
label = instance.menulist.firstChild.firstChild.getAttribute("label");
value = instance.menulist.value;
isnot(label, value, "Label from the menulist item is different than the value of the menulist");
[width, height] = extractSizeFromString(label);
is(width, expectedWidth, "Label updated (width).");
is(height, expectedHeight, "Label updated (height).");
[width, height] = extractSizeFromString(value);
is(width, expectedWidth, "Value updated (width).");
is(height, expectedHeight, "Value updated (height).");
// Test custom input
initialWidth = content.innerWidth;
initialHeight = content.innerHeight;
expectedWidth = initialWidth - 20;
expectedHeight = initialHeight - 10;
let index = instance.menulist.selectedIndex;
let userInput = expectedWidth + " x " + expectedHeight;
instance.menulist.inputField.value = "";
instance.menulist.focus();
processStringAsKey(userInput);
// While typing, the size should not change
is(content.innerWidth, initialWidth, "Size hasn't changed (width).");
is(content.innerHeight, initialHeight, "Size hasn't changed (height).");
// Only the `change` event must change the size
EventUtils.synthesizeKey("VK_RETURN", {});
yield once(mgr, "contentResize");
is(content.innerWidth, expectedWidth, "Size correctly updated (width).");
is(content.innerHeight, expectedHeight, "Size correctly updated (height).");
is(instance.menulist.selectedIndex, -1, "Custom menuitem cannot be selected");
label = instance.menulist.firstChild.firstChild.getAttribute("label");
value = instance.menulist.value;
isnot(label, value, "Label from the menulist item is different than the value of the menulist");
[width, height] = extractSizeFromString(label);
is(width, expectedWidth, "Label updated (width).");
is(height, expectedHeight, "Label updated (height).");
[width, height] = extractSizeFromString(value);
is(width, expectedWidth, "Value updated (width).");
is(height, expectedHeight, "Value updated (height).");
// Invalid input
initialWidth = content.innerWidth;
initialHeight = content.innerHeight;
index = instance.menulist.selectedIndex;
let expectedValue = initialWidth + "\u00D7" + initialHeight;
let expectedLabel = instance.menulist.firstChild.firstChild.getAttribute("label");
userInput = "I'm wrong";
instance.menulist.inputField.value = "";
instance.menulist.focus();
processStringAsKey(userInput);
EventUtils.synthesizeKey("VK_RETURN", {});
is(content.innerWidth, initialWidth, "Size hasn't changed (width).");
is(content.innerHeight, initialHeight, "Size hasn't changed (height).");
is(instance.menulist.selectedIndex, index, "Selected item hasn't changed.");
is(instance.menulist.value, expectedValue, "Value has been reset")
label = instance.menulist.firstChild.firstChild.getAttribute("label");
is(label, expectedLabel, "Custom menuitem's label hasn't changed");
// Rotate
initialWidth = content.innerWidth;
initialHeight = content.innerHeight;
info("rotate");
instance.rotate();
yield once(mgr, "contentResize");
is(content.innerWidth, initialHeight, "The width is now the height.");
is(content.innerHeight, initialWidth, "The height is now the width.");
[width, height] = extractSizeFromString(instance.menulist.firstChild.firstChild.getAttribute("label"));
is(width, initialHeight, "Label updated (width).");
is(height, initialWidth, "Label updated (height).");
let widthBeforeClose = content.innerWidth;
let heightBeforeClose = content.innerHeight;
// Restart
mgr.toggle(window, gBrowser.selectedTab);
yield once(mgr, "off");
mgr.toggle(window, gBrowser.selectedTab);
yield once(mgr, "on");
container = gBrowser.getBrowserContainer();
is(container.getAttribute("responsivemode"), "true", "In responsive mode.");
// Menus are correctly updated?
is(document.getElementById("Tools:ResponsiveUI").getAttribute("checked"), "true", "menus checked");
is(content.innerWidth, widthBeforeClose, "width restored.");
is(content.innerHeight, heightBeforeClose, "height restored.");
// Screenshot
let isWinXP = navigator.userAgent.indexOf("Windows NT 5.1") != -1;
if (!isWinXP) {
info("screenshot");
instance.screenshot("responsiveui");
let FileUtils = (Cu.import("resource://gre/modules/FileUtils.jsm", {})).FileUtils;
while(true) {
// while(true) until we find the file.
// no need for a timeout, the test will get killed anyway.
let file = FileUtils.getFile("DfltDwnld", [ "responsiveui.png" ]);
if (file.exists()) {
ok(true, "Screenshot file exists");
file.remove(false);
break;
}
info("checking if file exists in 200ms");
yield wait(200);
}
}
mgr.toggle(window, gBrowser.selectedTab);
yield once(mgr, "off");
// Menus are correctly updated?
is(document.getElementById("Tools:ResponsiveUI").getAttribute("checked"), "false", "menu unchecked");
delete instance;
gBrowser.removeCurrentTab();
finish();
});
let {width: contentWidth, height: contentHeight} = yield getSizing();
is(contentWidth, width, "preset" + c + ": the width should be changed");
is(contentHeight, height, "preset" + c + ": the height should be changed");
}
}
function* testManualMouseResize(rdm, manager, pressedKey) {
rdm.setSize(100, 100);
yield once(manager, "contentResize");
let {width: initialWidth, height: initialHeight} = yield getSizing();
is(initialWidth, 100, "Width should be reset to 100");
is(initialHeight, 100, "Height should be reset to 100");
let x = 2, y = 2;
EventUtils.synthesizeMouse(rdm.resizer, x, y, {type: "mousedown"}, window);
let mouseMoveParams = {type: "mousemove"};
if (pressedKey == "shift") {
x += 23; y += 10;
mouseMoveParams.shiftKey = true;
} else if (pressedKey == "ctrl") {
x += 120; y += 60;
mouseMoveParams.ctrlKey = true;
} else {
x += 20; y += 10;
}
EventUtils.synthesizeMouse(rdm.resizer, x, y, mouseMoveParams, window);
EventUtils.synthesizeMouse(rdm.resizer, x, y, {type: "mouseup"}, window);
yield once(manager, "contentResize");
let expectedWidth = initialWidth + 20;
let expectedHeight = initialHeight + 10;
info("initial width: " + initialWidth);
info("initial height: " + initialHeight);
yield verifyResize(rdm, expectedWidth, expectedHeight);
}
function* testResizeUsingCustomInput(rdm, manager) {
let {width: initialWidth, height: initialHeight} = yield getSizing();
let expectedWidth = initialWidth - 20, expectedHeight = initialHeight - 10;
let userInput = expectedWidth + " x " + expectedHeight;
rdm.menulist.inputField.value = "";
rdm.menulist.focus();
processStringAsKey(userInput);
// While typing, the size should not change
let currentSize = yield getSizing();
is(currentSize.width, initialWidth, "Typing shouldn't change the width");
is(currentSize.height, initialHeight, "Typing shouldn't change the height");
// Only the `change` event must change the size
EventUtils.synthesizeKey("VK_RETURN", {});
yield once(manager, "contentResize");
yield verifyResize(rdm, expectedWidth, expectedHeight);
}
function* testInvalidUserInput(rdm) {
let {width: initialWidth, height: initialHeight} = yield getSizing();
let index = rdm.menulist.selectedIndex;
let expectedValue = initialWidth + "\u00D7" + initialHeight;
let expectedLabel = rdm.menulist.firstChild.firstChild.getAttribute("label");
let userInput = "I'm wrong";
rdm.menulist.inputField.value = "";
rdm.menulist.focus();
processStringAsKey(userInput);
EventUtils.synthesizeKey("VK_RETURN", {});
let currentSize = yield getSizing();
is(currentSize.width, initialWidth, "Width should not change");
is(currentSize.height, initialHeight, "Height should not change");
is(rdm.menulist.selectedIndex, index, "Selected item should not change.");
is(rdm.menulist.value, expectedValue, "Value should be reset");
let label = rdm.menulist.firstChild.firstChild.getAttribute("label");
is(label, expectedLabel, "Custom menuitem's label should not change");
}
function* testRotate(rdm, manager) {
rdm.setSize(100, 200);
yield once(manager, "contentResize");
let {width: initialWidth, height: initialHeight} = yield getSizing();
rdm.rotate();
yield once(manager, "contentResize");
let newSize = yield getSizing();
is(newSize.width, initialHeight, "The width should now be the height.");
is(newSize.height, initialWidth, "The height should now be the width.");
let label = rdm.menulist.firstChild.firstChild.getAttribute("label");
let [width, height] = extractSizeFromString(label);
is(width, initialHeight, "Width in label should be updated");
is(height, initialWidth, "Height in label should be updated");
}
function* verifyResize(rdm, expectedWidth, expectedHeight) {
let currentSize = yield getSizing();
is(currentSize.width, expectedWidth, "Width should now change");
is(currentSize.height, expectedHeight, "Height should now change");
is(rdm.menulist.selectedIndex, -1, "Custom menuitem cannot be selected");
let label = rdm.menulist.firstChild.firstChild.getAttribute("label");
let value = rdm.menulist.value;
isnot(label, value,
"The menulist item label should be different than the menulist value");
let [width, height] = extractSizeFromString(label);
is(width, expectedWidth, "Width in label should be updated");
is(height, expectedHeight, "Height in label should be updated");
[width, height] = extractSizeFromString(value);
is(width, expectedWidth, "Value should be updated with new width");
is(height, expectedHeight, "Value should be updated with new height");
}
function* testScreenshot(rdm) {
info("Testing screenshot");
rdm.screenshot("responsiveui");
let {FileUtils} = Cu.import("resource://gre/modules/FileUtils.jsm", {});
while (true) {
// while(true) until we find the file.
// no need for a timeout, the test will get killed anyway.
let file = FileUtils.getFile("DfltDwnld", [ "responsiveui.png" ]);
if (file.exists()) {
ok(true, "Screenshot file exists");
file.remove(false);
break;
}
info("checking if file exists in 200ms");
yield wait(200);
}
}
function* getSizing() {
let browser = gBrowser.selectedBrowser;
let sizing = yield ContentTask.spawn(browser, {}, function*() {
return {
width: content.innerWidth,
height: content.innerHeight
};
});
return sizing;
}
function extractSizeFromString(str) {
let numbers = str.match(/(\d+)[^\d]*(\d+)/);
if (numbers) {
return [numbers[1], numbers[2]];
}
return [null, null];
}
function processStringAsKey(str) {
for (let i = 0, l = str.length; i < l; i++) {
EventUtils.synthesizeKey(str.charAt(i), {});
}
}

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

@ -7,19 +7,14 @@ const TEST_URI = "http://mochi.test:8888/browser/devtools/client/" +
"responsivedesign/test/touch.html";
add_task(function*() {
yield addTab(TEST_URI);
let mgr = ResponsiveUI.ResponsiveUIManager;
let mgrOn = once(mgr, "on");
mgr.toggle(window, gBrowser.selectedTab);
yield mgrOn;
let tab = yield addTab(TEST_URI);
let {rdm} = yield openRDM(tab);
yield testWithNoTouch();
yield mgr.getResponsiveUIForTab(gBrowser.selectedTab).enableTouch();
yield rdm.enableTouch();
yield testWithTouch();
yield mgr.getResponsiveUIForTab(gBrowser.selectedTab).disableTouch();
yield rdm.disableTouch();
yield testWithNoTouch();
let mgrOff = once(mgr, "off");
mgr.toggle(window, gBrowser.selectedTab);
yield mgrOff;
yield closeRDM(rdm);
});
function* testWithNoTouch() {
@ -30,7 +25,7 @@ function* testWithNoTouch() {
x += 20; y += 10;
yield BrowserTestUtils.synthesizeMouse("div", x, y,
{ type: "mousemove", isSynthesized: false }, gBrowser.selectedBrowser);
is(div.style.transform, "none", "touch didn't work");
is(div.style.transform, "none", "touch shouldn't work");
yield BrowserTestUtils.synthesizeMouse("div", x, y,
{ type: "mouseup", isSynthesized: false }, gBrowser.selectedBrowser);
}
@ -43,8 +38,8 @@ function* testWithTouch() {
x += 20; y += 10;
yield BrowserTestUtils.synthesizeMouse("div", x, y,
{ type: "mousemove", isSynthesized: false }, gBrowser.selectedBrowser);
is(div.style.transform, "translate(20px, 10px)", "touch worked");
is(div.style.transform, "translate(20px, 10px)", "touch should work");
yield BrowserTestUtils.synthesizeMouse("div", x, y,
{ type: "mouseup", isSynthesized: false }, gBrowser.selectedBrowser);
is(div.style.transform, "none", "end event worked");
is(div.style.transform, "none", "end event should work");
}

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

@ -1,145 +1,129 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
function test() {
waitForExplicitFinish();
SimpleTest.requestCompleteLog();
"use strict";
let instance, deletedPresetA, deletedPresetB, oldPrompt;
add_task(function*() {
let tab = yield addTab("data:text/html;charset=utf8,Test RDM custom presets");
function getPresetIndex(presetLabel) {
function testOnePreset(c) {
if (c == 0) {
return -1;
}
instance.menulist.selectedIndex = c;
let {rdm} = yield openRDM(tab);
let item = instance.menulist.firstChild.childNodes[c];
if (item.getAttribute("label") === presetLabel) {
return c;
} else {
return testOnePreset(c - 1);
}
let oldPrompt = Services.prompt;
Services.prompt = {
value: "",
returnBool: true,
prompt: function(parent, dialogTitle, text, value, checkMsg, checkState) {
value.value = this.value;
return this.returnBool;
}
return testOnePreset(instance.menulist.firstChild.childNodes.length - 4);
}
};
Task.spawn(function*() {
yield addTab("data:text/html;charset=utf8,test custom presets in responsive mode");
let mgr = ResponsiveUI.ResponsiveUIManager;
synthesizeKeyFromKeyTag(document.getElementById("key_responsiveUI"));
yield once(mgr, "on");
oldPrompt = Services.prompt;
Services.prompt = {
value: "",
returnBool: true,
prompt: function(aParent, aDialogTitle, aText, aValue, aCheckMsg, aCheckState) {
aValue.value = this.value;
return this.returnBool;
}
};
registerCleanupFunction(() => Services.prompt = oldPrompt);
// Is it open?
let container = gBrowser.getBrowserContainer();
is(container.getAttribute("responsivemode"), "true", "In responsive mode.");
instance = mgr.getResponsiveUIForTab(gBrowser.selectedTab);
ok(instance, "instance of the module is attached to the tab.");
instance.transitionsEnabled = false;
yield instance._test_notifyOnResize();
// Tries to add a custom preset and cancel the prompt
let idx = instance.menulist.selectedIndex;
let presetCount = instance.presets.length;
Services.prompt.value = "";
Services.prompt.returnBool = false;
instance.addbutton.doCommand();
is(idx, instance.menulist.selectedIndex, "selected item didn't change after add preset and cancel");
is(presetCount, instance.presets.length, "number of presets didn't change after add preset and cancel");
// Adds the custom preset with "Testing preset"
Services.prompt.value = "Testing preset";
Services.prompt.returnBool = true;
let customHeight = 123, customWidth = 456;
instance.startResizing({});
instance.setSize(customWidth, customHeight);
instance.stopResizing({});
instance.addbutton.doCommand();
// Force document reflow to avoid intermittent failures.
info("document height " + document.height);
instance.close();
info("waiting for responsive mode to turn off");
yield once(mgr, "off");
// We're still in the loop of initializing the responsive mode.
// Let's wait next loop to stop it.
yield nextTick();
synthesizeKeyFromKeyTag(document.getElementById("key_responsiveUI"));
yield once(mgr, "on");
is(container.getAttribute("responsivemode"), "true", "In responsive mode.");
instance = mgr.getResponsiveUIForTab(gBrowser.selectedTab);
let customPresetIndex = getPresetIndex("456" + "\u00D7" + "123 (Testing preset)");
info(customPresetIndex);
ok(customPresetIndex >= 0, "is the previously added preset (idx = " + customPresetIndex + ") in the list of items");
let resizePromise = instance._test_notifyOnResize();
instance.menulist.selectedIndex = customPresetIndex;
yield resizePromise;
is(content.innerWidth, 456, "add preset, and selected in the list, dimension valid (width)");
is(content.innerHeight, 123, "add preset, and selected in the list, dimension valid (height)");
instance.removebutton.doCommand();
instance.menulist.selectedIndex = 2;
deletedPresetA = instance.menulist.selectedItem.getAttribute("label");
instance.removebutton.doCommand();
instance.menulist.selectedIndex = 2;
deletedPresetB = instance.menulist.selectedItem.getAttribute("label");
instance.removebutton.doCommand();
yield nextTick();
instance.close();
yield once(mgr, "off");
synthesizeKeyFromKeyTag(document.getElementById("key_responsiveUI"));
info("waiting for responsive mode to turn on");
yield once(mgr, "on");
instance = mgr.getResponsiveUIForTab(gBrowser.selectedTab);
customPresetIndex = getPresetIndex(deletedPresetA);
is(customPresetIndex, -1, "deleted preset " + deletedPresetA + " is not in the list anymore");
customPresetIndex = getPresetIndex(deletedPresetB);
is(customPresetIndex, -1, "deleted preset " + deletedPresetB + " is not in the list anymore");
yield nextTick();
gBrowser.removeCurrentTab();
finish();
registerCleanupFunction(() => {
Services.prompt = oldPrompt;
});
// Is it open?
let container = gBrowser.getBrowserContainer();
is(container.getAttribute("responsivemode"), "true",
"Should be in responsive mode.");
ok(rdm, "RDM instance should be attached to the tab.");
yield rdm._test_notifyOnResize();
// Tries to add a custom preset and cancel the prompt
let idx = rdm.menulist.selectedIndex;
let presetCount = rdm.presets.length;
Services.prompt.value = "";
Services.prompt.returnBool = false;
rdm.addbutton.doCommand();
is(idx, rdm.menulist.selectedIndex,
"selected item shouldn't change after add preset and cancel");
is(presetCount, rdm.presets.length,
"number of presets shouldn't change after add preset and cancel");
// Adds the custom preset with "Testing preset"
Services.prompt.value = "Testing preset";
Services.prompt.returnBool = true;
let customHeight = 123, customWidth = 456;
rdm.startResizing({});
rdm.setSize(customWidth, customHeight);
rdm.stopResizing({});
rdm.addbutton.doCommand();
// Force document reflow to avoid intermittent failures.
info("document height " + document.height);
yield closeRDM(rdm);
// We're still in the loop of initializing the responsive mode.
// Let's wait next loop to stop it.
yield waitForTick();
({rdm} = yield openRDM(tab));
is(container.getAttribute("responsivemode"), "true",
"Should be in responsive mode.");
let presetLabel = "456" + "\u00D7" + "123 (Testing preset)";
let customPresetIndex = getPresetIndex(rdm, presetLabel);
info(customPresetIndex);
ok(customPresetIndex >= 0, "(idx = " + customPresetIndex + ") should be the" +
" previously added preset in the list of items");
let resizePromise = rdm._test_notifyOnResize();
rdm.menulist.selectedIndex = customPresetIndex;
yield resizePromise;
let browser = gBrowser.selectedBrowser;
let props = yield ContentTask.spawn(browser, {}, function*() {
let {innerWidth, innerHeight} = content;
return {innerWidth, innerHeight};
});
is(props.innerWidth, 456, "Selecting preset should change the width");
is(props.innerHeight, 123, "Selecting preset should change the height");
rdm.removebutton.doCommand();
rdm.menulist.selectedIndex = 2;
let deletedPresetA = rdm.menulist.selectedItem.getAttribute("label");
rdm.removebutton.doCommand();
rdm.menulist.selectedIndex = 2;
let deletedPresetB = rdm.menulist.selectedItem.getAttribute("label");
rdm.removebutton.doCommand();
yield closeRDM(rdm);
yield waitForTick();
({rdm} = yield openRDM(tab));
customPresetIndex = getPresetIndex(rdm, deletedPresetA);
is(customPresetIndex, -1,
"Deleted preset " + deletedPresetA + " should not be in the list anymore");
customPresetIndex = getPresetIndex(rdm, deletedPresetB);
is(customPresetIndex, -1,
"Deleted preset " + deletedPresetB + " should not be in the list anymore");
yield closeRDM(rdm);
});
function getPresetIndex(rdm, presetLabel) {
function testOnePreset(c) {
if (c == 0) {
return -1;
}
rdm.menulist.selectedIndex = c;
let item = rdm.menulist.firstChild.childNodes[c];
if (item.getAttribute("label") === presetLabel) {
return c;
}
return testOnePreset(c - 1);
}
return testOnePreset(rdm.menulist.firstChild.childNodes.length - 4);
}

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

@ -3,12 +3,14 @@
"use strict";
let testDir = gTestPath.substr(0, gTestPath.lastIndexOf("/"));
// shared-head.js handles imports, constants, and utility functions
Services.scriptloader.loadSubScript("chrome://mochitests/content/browser/devtools/client/framework/test/shared-head.js", this);
let sharedHeadURI = testDir + "../../../framework/test/shared-head.js";
Services.scriptloader.loadSubScript(sharedHeadURI, this);
// Import the GCLI test helper
var testDir = gTestPath.substr(0, gTestPath.lastIndexOf("/"));
Services.scriptloader.loadSubScript(testDir + "../../../commandline/test/helpers.js", this);
let gcliHelpersURI = testDir + "../../../commandline/test/helpers.js";
Services.scriptloader.loadSubScript(gcliHelpersURI, this);
DevToolsUtils.testing = true;
registerCleanupFunction(() => {
@ -21,22 +23,41 @@ registerCleanupFunction(() => {
/**
* Open the Responsive Design Mode
* @param {Tab} The browser tab to open it into (defaults to the selected tab).
* @return {Promise} Resolves to the instance of the responsive design mode.
* @param {method} The method to use to open the RDM (values: menu, keyboard)
* @return {rdm, manager} Returns the RUI instance and the manager
*/
function openRDM(tab = gBrowser.selectedTab) {
return new Promise(resolve => {
let manager = ResponsiveUI.ResponsiveUIManager;
var openRDM = Task.async(function*(tab = gBrowser.selectedTab,
method = "menu") {
let manager = ResponsiveUI.ResponsiveUIManager;
let mgrOn = once(manager, "on");
if (method == "menu") {
document.getElementById("Tools:ResponsiveUI").doCommand();
executeSoon(() => {
let rdm = manager.getResponsiveUIForTab(tab);
rdm.stack.setAttribute("notransition", "true");
registerCleanupFunction(function() {
rdm.stack.removeAttribute("notransition");
});
resolve({rdm, manager});
});
} else {
synthesizeKeyFromKeyTag(document.getElementById("key_responsiveUI"));
}
yield mgrOn;
let rdm = manager.getResponsiveUIForTab(tab);
rdm.transitionsEnabled = false;
registerCleanupFunction(() => {
rdm.transitionsEnabled = true;
});
}
return {rdm, manager};
});
/**
* Close a responsive mode instance
* @param {rdm} ResponsiveUI instance for the tab
*/
var closeRDM = Task.async(function*(rdm) {
let mgr = ResponsiveUI.ResponsiveUIManager;
if (!rdm) {
rdm = mgr.getResponsiveUIForTab(gBrowser.selectedTab);
}
let mgrOff = mgr.once("off");
rdm.close();
yield mgrOff;
});
/**
* Open the toolbox, with the inspector tool visible.
@ -77,6 +98,11 @@ var openInspector = Task.async(function*() {
};
});
var closeToolbox = Task.async(function*() {
let target = TargetFactory.forTab(gBrowser.selectedTab);
yield gDevTools.closeToolbox(target);
});
/**
* Wait for the toolbox frame to receive focus after it loads
* @param {Toolbox} toolbox
@ -164,67 +190,30 @@ var addTab = Task.async(function* (url) {
return tab;
});
/**
* Wait for eventName on target.
* @param {Object} target An observable object that either supports on/off or
* addEventListener/removeEventListener
* @param {String} eventName
* @param {Boolean} useCapture Optional, for addEventListener/removeEventListener
* @return A promise that resolves when the event has been handled
*/
function once(target, eventName, useCapture=false) {
info("Waiting for event: '" + eventName + "' on " + target + ".");
let deferred = promise.defer();
for (let [add, remove] of [
["addEventListener", "removeEventListener"],
["addListener", "removeListener"],
["on", "off"]
]) {
if ((add in target) && (remove in target)) {
target[add](eventName, function onEvent(...aArgs) {
info("Got event: '" + eventName + "' on " + target + ".");
target[remove](eventName, onEvent, useCapture);
deferred.resolve.apply(deferred, aArgs);
}, useCapture);
break;
}
}
return deferred.promise;
}
function wait(ms) {
let def = promise.defer();
setTimeout(def.resolve, ms);
return def.promise;
}
function nextTick() {
let def = promise.defer();
executeSoon(() => def.resolve())
return def.promise;
}
/**
* Waits for the next load to complete in the current browser.
*
* @return promise
*/
function waitForDocLoadComplete(aBrowser=gBrowser) {
function waitForDocLoadComplete(aBrowser = gBrowser) {
let deferred = promise.defer();
let progressListener = {
onStateChange: function (webProgress, req, flags, status) {
onStateChange: function(webProgress, req, flags, status) {
let docStop = Ci.nsIWebProgressListener.STATE_IS_NETWORK |
Ci.nsIWebProgressListener.STATE_STOP;
info("Saw state " + flags.toString(16) + " and status " + status.toString(16));
info(`Saw state ${flags.toString(16)} and status ${status.toString(16)}`);
// When a load needs to be retargetted to a new process it is cancelled
// with NS_BINDING_ABORTED so ignore that case
if ((flags & docStop) == docStop && status != Cr.NS_BINDING_ABORTED) {
aBrowser.removeProgressListener(progressListener);
info("Browser loaded " + aBrowser.contentWindow.location);
info("Browser loaded");
deferred.resolve();
}
},

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

@ -74,6 +74,7 @@ support-files =
test-console-extras.html
test-console-replaced-api.html
test-console-server-logging.sjs
test-console-server-logging-array.sjs
test-console.html
test-console-workers.html
test-console-table.html

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

@ -37,10 +37,41 @@ add_task(function* () {
yield updateServerLoggingListener(hud);
});
add_task(function* () {
const TEST_URI = "http://example.com/browser/devtools/client/webconsole/test/test-console-server-logging-array.sjs";
yield loadTab(TEST_URI);
let hud = yield openConsole();
// Set logging filter and wait till it's set on the backend
hud.setFilterState("serverlog", true);
yield updateServerLoggingListener(hud);
BrowserReloadSkipCache();
// Note that the test is also checking out the (printf like)
// formatters and encoding of UTF8 characters (see the one at the end).
let text = "Object { best: \"Firefox\", reckless: \"Chrome\", new_ie: \"Safari\", new_new_ie: \"Edge\" }";
yield waitForMessages({
webconsole: hud,
messages: [{
text: text,
category: CATEGORY_SERVER,
severity: SEVERITY_LOG,
}],
})
// Clean up filter
hud.setFilterState("serverlog", false);
yield updateServerLoggingListener(hud);
});
function updateServerLoggingListener(hud) {
let deferred = promise.defer();
hud.ui._updateServerLoggingListener(response => {
deferred.resolve(response);
});
return deferred.promise;
}
}

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

@ -0,0 +1,32 @@
/*
* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/
*/
function handleRequest(request, response)
{
var page = "<!DOCTYPE html><html>" +
"<head><meta charset='utf-8'></head>" +
"<body><p>hello world!</p></body>" +
"</html>";
var data = {
"version": "4.1.0",
"columns": ["log", "backtrace", "type"],
"rows":[[
[{ "best": "Firefox", "reckless": "Chrome", "new_ie": "Safari", "new_new_ie": "Edge"}],
"C:\\src\\www\\serverlogging\\test7.php:4:1",
""
]],
};
// Put log into headers.
var value = b64EncodeUnicode(JSON.stringify(data));
response.setHeader("X-ChromeLogger-Data", value, false);
response.write(page);
}
function b64EncodeUnicode(str) {
return btoa(unescape(encodeURIComponent(str)));
}

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

@ -29,4 +29,4 @@ function handleRequest(request, response)
function b64EncodeUnicode(str) {
return btoa(unescape(encodeURIComponent(str)));
}
}

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

@ -0,0 +1,101 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2; js-indent-level: 2 -*- */
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
const { ActorPool } = require("devtools/server/actors/common");
const { createValueGrip } = require("devtools/server/actors/object");
const { ActorClass } = require("devtools/server/protocol");
/**
* An actor for a specified stack frame.
*/
let FrameActor = ActorClass({
typeName: "frame",
/**
* Creates the Frame actor.
*
* @param frame Debugger.Frame
* The debuggee frame.
* @param threadActor ThreadActor
* The parent thread actor for this frame.
*/
initialize: function(frame, threadActor) {
this.frame = frame;
this.threadActor = threadActor;
},
/**
* A pool that contains frame-lifetime objects, like the environment.
*/
_frameLifetimePool: null,
get frameLifetimePool() {
if (!this._frameLifetimePool) {
this._frameLifetimePool = new ActorPool(this.conn);
this.conn.addActorPool(this._frameLifetimePool);
}
return this._frameLifetimePool;
},
/**
* Finalization handler that is called when the actor is being evicted from
* the pool.
*/
disconnect: function() {
this.conn.removeActorPool(this._frameLifetimePool);
this._frameLifetimePool = null;
},
/**
* Returns a frame form for use in a protocol message.
*/
form: function() {
let threadActor = this.threadActor;
let form = { actor: this.actorID,
type: this.frame.type };
if (this.frame.type === "call") {
form.callee = createValueGrip(this.frame.callee, threadActor._pausePool,
threadActor.objectGrip);
}
if (this.frame.environment) {
let envActor = threadActor.createEnvironmentActor(
this.frame.environment,
this.frameLifetimePool
);
form.environment = envActor.form();
}
form.this = createValueGrip(this.frame.this, threadActor._pausePool,
threadActor.objectGrip);
form.arguments = this._args();
if (this.frame.script) {
var generatedLocation = this.threadActor.sources.getFrameLocation(this.frame);
form.where = {
source: generatedLocation.generatedSourceActor.form(),
line: generatedLocation.generatedLine,
column: generatedLocation.generatedColumn
};
}
if (!this.frame.older) {
form.oldest = true;
}
return form;
},
_args: function() {
if (!this.frame.arguments) {
return [];
}
return this.frame.arguments.map(arg => createValueGrip(arg,
this.threadActor._pausePool, this.threadActor.objectGrip));
}
});
exports.FrameActor = FrameActor;

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

@ -97,6 +97,8 @@
color: hsl(216,33%,97%);
text-shadow: none;
border: 1px solid rgba(255,255,255,0.2);
}
:-moz-native-anonymous .box-model-nodeinfobar-container[hide-arrow] > .box-model-nodeinfobar {
@ -106,26 +108,35 @@
/* Arrows */
:-moz-native-anonymous .box-model-nodeinfobar-container > .box-model-nodeinfobar:before {
left: calc(50% - 8px);
border: 8px solid rgba(255,255,255,0.2);
}
:-moz-native-anonymous .box-model-nodeinfobar-container > .box-model-nodeinfobar:after {
left: calc(50% - 7px);
border: 7px solid hsl(214,13%,24%);
}
:-moz-native-anonymous .box-model-nodeinfobar-container > .box-model-nodeinfobar:before,
:-moz-native-anonymous .box-model-nodeinfobar-container > .box-model-nodeinfobar:after {
content: "";
display: none;
position: absolute;
left: calc(50% - 8px);
height: 0;
width: 0;
border: 8px solid hsl(214,13%,24%);
border-left-color: transparent;
border-right-color: transparent;
}
:-moz-native-anonymous .box-model-nodeinfobar-container[position="top"]:not([hide-arrow]) > .box-model-nodeinfobar:before {
:-moz-native-anonymous .box-model-nodeinfobar-container[position="top"]:not([hide-arrow]) > .box-model-nodeinfobar:before,
:-moz-native-anonymous .box-model-nodeinfobar-container[position="top"]:not([hide-arrow]) > .box-model-nodeinfobar:after {
border-bottom: 0;
top: 100%;
display: block;
}
:-moz-native-anonymous .box-model-nodeinfobar-container[position="bottom"]:not([hide-arrow]) > .box-model-nodeinfobar:before {
:-moz-native-anonymous .box-model-nodeinfobar-container[position="bottom"]:not([hide-arrow]) > .box-model-nodeinfobar:before,
:-moz-native-anonymous .box-model-nodeinfobar-container[position="bottom"]:not([hide-arrow]) > .box-model-nodeinfobar:after {
border-top: 0;
bottom: 100%;
display: block;

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

@ -24,6 +24,7 @@ DevToolsModules(
'director-manager.js',
'director-registry.js',
'eventlooplag.js',
'frame.js',
'framerate.js',
'gcli.js',
'heap-snapshot-file.js',

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

@ -9,6 +9,7 @@
const Services = require("Services");
const { Cc, Ci, Cu, components, ChromeWorker } = require("chrome");
const { ActorPool, OriginalLocation, GeneratedLocation } = require("devtools/server/actors/common");
const { FrameActor } = require("devtools/server/actors/frame");
const { ObjectActor, createValueGrip, longStringGrip } = require("devtools/server/actors/object");
const { DebuggerServer } = require("devtools/server/main");
const DevToolsUtils = require("devtools/shared/DevToolsUtils");
@ -2972,92 +2973,6 @@ update(PauseScopedObjectActor.prototype.requestTypes, {
"threadGrip": PauseScopedObjectActor.prototype.onThreadGrip,
});
/**
* Creates an actor for the specified stack frame.
*
* @param aFrame Debugger.Frame
* The debuggee frame.
* @param aThreadActor ThreadActor
* The parent thread actor for this frame.
*/
function FrameActor(aFrame, aThreadActor)
{
this.frame = aFrame;
this.threadActor = aThreadActor;
}
FrameActor.prototype = {
actorPrefix: "frame",
/**
* A pool that contains frame-lifetime objects, like the environment.
*/
_frameLifetimePool: null,
get frameLifetimePool() {
if (!this._frameLifetimePool) {
this._frameLifetimePool = new ActorPool(this.conn);
this.conn.addActorPool(this._frameLifetimePool);
}
return this._frameLifetimePool;
},
/**
* Finalization handler that is called when the actor is being evicted from
* the pool.
*/
disconnect: function () {
this.conn.removeActorPool(this._frameLifetimePool);
this._frameLifetimePool = null;
},
/**
* Returns a frame form for use in a protocol message.
*/
form: function () {
let threadActor = this.threadActor;
let form = { actor: this.actorID,
type: this.frame.type };
if (this.frame.type === "call") {
form.callee = createValueGrip(this.frame.callee, threadActor._pausePool,
threadActor.objectGrip);
}
if (this.frame.environment) {
let envActor = threadActor.createEnvironmentActor(
this.frame.environment,
this.frameLifetimePool
);
form.environment = envActor.form();
}
form.this = createValueGrip(this.frame.this, threadActor._pausePool,
threadActor.objectGrip);
form.arguments = this._args();
if (this.frame.script) {
var generatedLocation = this.threadActor.sources.getFrameLocation(this.frame);
form.where = {
source: generatedLocation.generatedSourceActor.form(),
line: generatedLocation.generatedLine,
column: generatedLocation.generatedColumn
};
}
if (!this.frame.older) {
form.oldest = true;
}
return form;
},
_args: function () {
if (!this.frame.arguments) {
return [];
}
return this.frame.arguments.map(arg => createValueGrip(arg,
this.threadActor._pausePool, this.threadActor.objectGrip));
},
};
/**
* Creates a BreakpointActor. BreakpointActors exist for the lifetime of their
* containing thread and are responsible for deleting breakpoints, handling

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

@ -408,7 +408,15 @@ function format(msg) {
msg.styles = [];
// Remove and get the first log (in which the specifiers are).
let firstString = msg.logs.shift();
// Note that the first string doesn't have to be specified.
// An example of a log on the server side:
// ChromePhp::log("server info: ", $_SERVER);
// ChromePhp::log($_SERVER);
let firstString = "";
if (typeof msg.logs[0] == "string") {
firstString = msg.logs.shift();
}
// All the specifiers present in the first string.
let splitLogRegExp = /(.*?)(%[oOcsdif]|$)/g;
let splitLogRegExpRes;

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

@ -1,33 +0,0 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
_("Define some functions in well defined line positions for the test");
function foo(v) { return bar(v + 1); } // line 2
function bar(v) { return baz(v + 1); } // line 3
function baz(v) { throw new Error(v + 1); } // line 4
_("Make sure lazy constructor calling/assignment works");
Cu.import("resource://services-common/utils.js");
function run_test() {
_("Make sure functions, arguments, files are pretty printed in the trace");
let trace = "";
try {
foo(0);
}
catch(ex) {
trace = CommonUtils.stackTrace(ex);
}
_("Got trace:", trace);
do_check_neq(trace, "");
let bazPos = trace.indexOf("baz@test_utils_stackTrace.js:7");
let barPos = trace.indexOf("bar@test_utils_stackTrace.js:6");
let fooPos = trace.indexOf("foo@test_utils_stackTrace.js:5");
_("String positions:", bazPos, barPos, fooPos);
_("Make sure the desired messages show up");
do_check_true(bazPos >= 0);
do_check_true(barPos > bazPos);
do_check_true(fooPos > barPos);
}

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

@ -23,7 +23,6 @@ support-files =
[test_utils_makeURI.js]
[test_utils_namedTimer.js]
[test_utils_sets.js]
[test_utils_stackTrace.js]
[test_utils_utf8.js]
[test_utils_uuid.js]

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

@ -69,9 +69,6 @@ this.CommonUtils = {
return true;
},
// Import these from Log.jsm for backward compatibility
stackTrace: Log.stackTrace,
/**
* Encode byte string as base64URL (RFC 4648).
*

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

@ -35,7 +35,6 @@ this.Utils = {
// In the ideal world, references to these would be removed.
nextTick: CommonUtils.nextTick,
namedTimer: CommonUtils.namedTimer,
stackTrace: CommonUtils.stackTrace,
makeURI: CommonUtils.makeURI,
encodeUTF8: CommonUtils.encodeUTF8,
decodeUTF8: CommonUtils.decodeUTF8,

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

@ -142,7 +142,7 @@ var TPS = {
errInfo = Log.exceptionStr(exc); // includes details and stack-trace.
} else {
// always write a stack even if no error passed.
errInfo = Utils.stackTrace(new Error());
errInfo = Log.stackTrace(new Error());
}
Logger.logError(`[phase ${this._currentPhase}] ${msg} - ${errInfo}`);
this.quit();

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

@ -31,6 +31,7 @@
"requestLongerTimeout": false,
"SimpleTest": false,
"SpecialPowers": false,
"thisTestLeaksUncaughtRejectionsAndShouldBeFixed": false,
"todo": false,
"todo_is": false,
"todo_isnot": false,

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

@ -107,13 +107,19 @@ add_task(function* testInvalidUUID() {
let uri = NetUtil.newURI("moz-extension://eb4f3be8-41c9-4970-aa6d-b84d1ecc02b2/file.css");
let stream = StringStream("Foo __MSG_xxx__ bar __MSG_yyy__ baz");
// Assert.throws raise a TypeError exception when the expected param
// is an arrow function. (See Bug 1237961 for rationale)
let expectInvalidContextException = function(e) {
return e.result === Cr.NS_ERROR_INVALID_ARG && /Invalid context/.test(e);
};
Assert.throws(() => {
convService.convert(stream, FROM_TYPE, TO_TYPE, uri);
});
}, expectInvalidContextException);
Assert.throws(() => {
let listener = { QueryInterface: XPCOMUtils.generateQI([Ci.nsIStreamListener]) };
convService.asyncConvertData(FROM_TYPE, TO_TYPE, listener, uri);
});
}, expectInvalidContextException);
});

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

@ -59,7 +59,7 @@ Structure::
// only the fact that the value has been changed is recorded
},
},
profile: { // This section is not available on Android.
profile: {
creationDate: <integer>, // integer days since UNIX epoch, e.g. 16446
resetDate: <integer>, // integer days since UNIX epoch, e.g. 16446 - optional
},

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

@ -15,6 +15,7 @@
const Cc = Components.classes;
const Cu = Components.utils;
const Ci = Components.interfaces;
const Cr = Components.results;
Cu.import("resource://gre/modules/XPCOMUtils.jsm");

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

@ -0,0 +1,30 @@
print("Define some functions in well defined line positions for the test");
function foo(v) { return bar(v + 1); } // line 2
function bar(v) { return baz(v + 1); } // line 3
function baz(v) { throw new Error(v + 1); } // line 4
print("Make sure lazy constructor calling/assignment works");
Components.utils.import("resource://gre/modules/Log.jsm");
function run_test() {
print("Make sure functions, arguments, files are pretty printed in the trace");
let trace = "";
try {
foo(0);
}
catch(ex) {
trace = Log.stackTrace(ex);
}
print(`Got trace: ${trace}`);
do_check_neq(trace, "");
let bazPos = trace.indexOf("baz@test_Log_stackTrace.js:4");
let barPos = trace.indexOf("bar@test_Log_stackTrace.js:3");
let fooPos = trace.indexOf("foo@test_Log_stackTrace.js:2");
print(`String positions: ${bazPos} ${barPos} ${fooPos}`);
print("Make sure the desired messages show up");
do_check_true(bazPos >= 0);
do_check_true(barPos > bazPos);
do_check_true(fooPos > barPos);
}

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

@ -61,3 +61,4 @@ skip-if = toolkit == 'android'
[test_web_channel_broker.js]
[test_ZipUtils.js]
skip-if = toolkit == 'android'
[test_Log_stackTrace.js]