зеркало из https://github.com/mozilla/gecko-dev.git
Merge m-c to b2g-inbound a=merge
This commit is contained in:
Коммит
d6ef25a0ca
2
CLOBBER
2
CLOBBER
|
@ -22,4 +22,4 @@
|
|||
# changes to stick? As of bug 928195, this shouldn't be necessary! Please
|
||||
# don't change CLOBBER for WebIDL changes any more.
|
||||
|
||||
Bug 1087560 changed a mochitest manifest without touching its moz.build.
|
||||
Bug 1095234 - Bug 1091260 stopped packaging a devtools file with EXTRA_JS_MODULES while making it require pre-processing.
|
||||
|
|
|
@ -1650,7 +1650,7 @@ pref("loop.learnMoreUrl", "https://www.firefox.com/hello/");
|
|||
pref("loop.legal.ToS_url", "https://hello.firefox.com/legal/terms/");
|
||||
pref("loop.legal.privacy_url", "https://www.mozilla.org/privacy/");
|
||||
pref("loop.do_not_disturb", false);
|
||||
pref("loop.ringtone", "chrome://browser/content/loop/shared/sounds/Firefox-Long.ogg");
|
||||
pref("loop.ringtone", "chrome://browser/content/loop/shared/sounds/ringtone.ogg");
|
||||
pref("loop.retry_delay.start", 60000);
|
||||
pref("loop.retry_delay.limit", 300000);
|
||||
pref("loop.feedback.baseUrl", "https://input.mozilla.org/api/v1/feedback");
|
||||
|
@ -1660,9 +1660,9 @@ pref("loop.debug.dispatcher", false);
|
|||
pref("loop.debug.websocket", false);
|
||||
pref("loop.debug.sdk", false);
|
||||
#ifdef DEBUG
|
||||
pref("loop.CSP", "default-src 'self' about: file: chrome: http://localhost:*; img-src 'self' data: http://www.gravatar.com/ about: file: chrome:; font-src 'none'; connect-src wss://*.tokbox.com https://*.opentok.com https://*.tokbox.com wss://*.mozilla.com https://*.mozilla.org wss://*.mozaws.net http://localhost:* ws://localhost:*");
|
||||
pref("loop.CSP", "default-src 'self' about: file: chrome: http://localhost:*; img-src 'self' data: http://www.gravatar.com/ about: file: chrome:; font-src 'none'; connect-src wss://*.tokbox.com https://*.opentok.com https://*.tokbox.com wss://*.mozilla.com https://*.mozilla.org wss://*.mozaws.net http://localhost:* ws://localhost:*; media-src blob:");
|
||||
#else
|
||||
pref("loop.CSP", "default-src 'self' about: file: chrome:; img-src 'self' data: http://www.gravatar.com/ about: file: chrome:; font-src 'none'; connect-src wss://*.tokbox.com https://*.opentok.com https://*.tokbox.com wss://*.mozilla.com https://*.mozilla.org wss://*.mozaws.net");
|
||||
pref("loop.CSP", "default-src 'self' about: file: chrome:; img-src 'self' data: http://www.gravatar.com/ about: file: chrome:; font-src 'none'; connect-src wss://*.tokbox.com https://*.opentok.com https://*.tokbox.com wss://*.mozilla.com https://*.mozilla.org wss://*.mozaws.net; media-src blob:");
|
||||
#endif
|
||||
pref("loop.oauth.google.redirect_uri", "urn:ietf:wg:oauth:2.0:oob:auto");
|
||||
pref("loop.oauth.google.scope", "https://www.google.com/m8/feeds");
|
||||
|
@ -1809,6 +1809,10 @@ pref("browser.polaris.enabled", false);
|
|||
pref("privacy.trackingprotection.ui.enabled", false);
|
||||
#endif
|
||||
|
||||
#ifdef NIGHTLY_BUILD
|
||||
pref("browser.tabs.remote.autostart.1", true);
|
||||
#endif
|
||||
|
||||
// Temporary pref to allow printing in e10s windows on some platforms.
|
||||
#ifdef UNIX_BUT_NOT_MAC
|
||||
pref("print.enable_e10s_testing", false);
|
||||
|
|
|
@ -787,9 +787,6 @@ statuspanel[inactive][previoustype=overLink] {
|
|||
max-width: 32em;
|
||||
}
|
||||
|
||||
/* highlighter */
|
||||
%include highlighter.css
|
||||
|
||||
/* gcli */
|
||||
|
||||
html|*#gcli-tooltip-frame,
|
||||
|
|
|
@ -4551,15 +4551,14 @@ function nsBrowserAccess() { }
|
|||
nsBrowserAccess.prototype = {
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsIBrowserDOMWindow, Ci.nsISupports]),
|
||||
|
||||
_openURIInNewTab: function(aURI, aOpener, aIsExternal) {
|
||||
_openURIInNewTab: function(aURI, aReferrer, aIsPrivate, aIsExternal) {
|
||||
let win, needToFocusWin;
|
||||
|
||||
// try the current window. if we're in a popup, fall back on the most recent browser window
|
||||
if (window.toolbar.visible)
|
||||
win = window;
|
||||
else {
|
||||
let isPrivate = PrivateBrowsingUtils.isWindowPrivate(aOpener || window);
|
||||
win = RecentWindow.getMostRecentBrowserWindow({private: isPrivate});
|
||||
win = RecentWindow.getMostRecentBrowserWindow({private: aIsPrivate});
|
||||
needToFocusWin = true;
|
||||
}
|
||||
|
||||
|
@ -4575,10 +4574,9 @@ nsBrowserAccess.prototype = {
|
|||
}
|
||||
|
||||
let loadInBackground = gPrefService.getBoolPref("browser.tabs.loadDivertedInBackground");
|
||||
let referrer = aOpener ? makeURI(aOpener.location.href) : null;
|
||||
|
||||
let tab = win.gBrowser.loadOneTab(aURI ? aURI.spec : "about:blank", {
|
||||
referrerURI: referrer,
|
||||
referrerURI: aReferrer,
|
||||
fromExternal: aIsExternal,
|
||||
inBackground: loadInBackground});
|
||||
let browser = win.gBrowser.getBrowserForTab(tab);
|
||||
|
@ -4615,7 +4613,9 @@ nsBrowserAccess.prototype = {
|
|||
newWindow = openDialog(getBrowserURL(), "_blank", "all,dialog=no", url, null, null, null);
|
||||
break;
|
||||
case Ci.nsIBrowserDOMWindow.OPEN_NEWTAB :
|
||||
let browser = this._openURIInNewTab(aURI, aOpener, isExternal);
|
||||
let referrer = aOpener ? makeURI(aOpener.location.href) : null;
|
||||
let isPrivate = PrivateBrowsingUtils.isWindowPrivate(aOpener || window);
|
||||
let browser = this._openURIInNewTab(aURI, referrer, isPrivate, isExternal);
|
||||
if (browser)
|
||||
newWindow = browser.contentWindow;
|
||||
break;
|
||||
|
@ -4634,14 +4634,14 @@ nsBrowserAccess.prototype = {
|
|||
return newWindow;
|
||||
},
|
||||
|
||||
openURIInFrame: function browser_openURIInFrame(aURI, aOpener, aWhere, aContext) {
|
||||
openURIInFrame: function browser_openURIInFrame(aURI, aParams, aWhere, aContext) {
|
||||
if (aWhere != Ci.nsIBrowserDOMWindow.OPEN_NEWTAB) {
|
||||
dump("Error: openURIInFrame can only open in new tabs");
|
||||
return null;
|
||||
}
|
||||
|
||||
var isExternal = (aContext == Ci.nsIBrowserDOMWindow.OPEN_EXTERNAL);
|
||||
let browser = this._openURIInNewTab(aURI, aOpener, isExternal);
|
||||
let browser = this._openURIInNewTab(aURI, aParams.referrer, aParams.isPrivate, isExternal);
|
||||
if (browser)
|
||||
return browser.QueryInterface(Ci.nsIFrameLoaderOwner);
|
||||
|
||||
|
|
|
@ -123,7 +123,7 @@ chatBrowserAccess.prototype = {
|
|||
return browser ? browser.contentWindow : null;
|
||||
},
|
||||
|
||||
openURIInFrame: function browser_openURIInFrame(aURI, aOpener, aWhere, aContext) {
|
||||
openURIInFrame: function browser_openURIInFrame(aURI, aParams, aWhere, aContext) {
|
||||
let browser = this._openURIInNewTab(aURI, aWhere);
|
||||
return browser ? browser.QueryInterface(Ci.nsIFrameLoaderOwner) : null;
|
||||
},
|
||||
|
|
|
@ -1,80 +0,0 @@
|
|||
/* 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/. */
|
||||
|
||||
.highlighter-container {
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
/*
|
||||
* Box model highlighter
|
||||
*/
|
||||
svg|svg.box-model-root[hidden],
|
||||
svg|line.box-model-guide-top[hidden],
|
||||
svg|line.box-model-guide-right[hidden],
|
||||
svg|line.box-model-guide-left[hidden],
|
||||
svg|line.box-model-guide-bottom[hidden] {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/*
|
||||
* Node Infobar
|
||||
*/
|
||||
.highlighter-nodeinfobar-container {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.highlighter-nodeinfobar-positioner {
|
||||
position: absolute;
|
||||
max-width: 95%;
|
||||
}
|
||||
|
||||
.highlighter-nodeinfobar-positioner[hidden] {
|
||||
opacity: 0;
|
||||
pointer-events: none;
|
||||
display: -moz-box;
|
||||
}
|
||||
|
||||
.highlighter-nodeinfobar-text {
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
direction: ltr;
|
||||
}
|
||||
|
||||
html|*.highlighter-nodeinfobar-id,
|
||||
html|*.highlighter-nodeinfobar-classes,
|
||||
html|*.highlighter-nodeinfobar-pseudo-classes,
|
||||
html|*.highlighter-nodeinfobar-dimensions,
|
||||
html|*.highlighter-nodeinfobar-tagname {
|
||||
-moz-user-select: text;
|
||||
-moz-user-focus: normal;
|
||||
cursor: text;
|
||||
}
|
||||
|
||||
.highlighter-nodeinfobar-arrow {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.highlighter-nodeinfobar-positioner[position="top"]:not([hide-arrow]) > .highlighter-nodeinfobar-arrow-bottom {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.highlighter-nodeinfobar-positioner[position="bottom"]:not([hide-arrow]) > .highlighter-nodeinfobar-arrow-top {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.highlighter-nodeinfobar-positioner[disabled] {
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
html|*.highlighter-nodeinfobar-tagname {
|
||||
text-transform: lowercase;
|
||||
}
|
||||
|
||||
/*
|
||||
* Css transform highlighter
|
||||
*/
|
||||
svg|svg.css-transform-root[hidden] {
|
||||
display: none;
|
||||
}
|
|
@ -74,7 +74,7 @@ Sanitizer.prototype = {
|
|||
itemsToClear.splice(openWindowsIndex, 1);
|
||||
let item = this.items.openWindows;
|
||||
|
||||
function onWindowsCleaned() {
|
||||
let ok = item.clear(() => {
|
||||
try {
|
||||
let clearedPromise = this.sanitize(itemsToClear);
|
||||
clearedPromise.then(deferred.resolve, deferred.reject);
|
||||
|
@ -83,9 +83,7 @@ Sanitizer.prototype = {
|
|||
Cu.reportError(error);
|
||||
deferred.reject(error);
|
||||
}
|
||||
}
|
||||
|
||||
let ok = item.clear(onWindowsCleaned.bind(this));
|
||||
});
|
||||
// When cancelled, reject immediately
|
||||
if (!ok) {
|
||||
deferred.reject("Sanitizer canceled closing windows");
|
||||
|
|
|
@ -2,6 +2,8 @@
|
|||
* 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/. */
|
||||
|
||||
Components.utils.import("resource://gre/modules/Promise.jsm", this);
|
||||
|
||||
let chatbar = document.getElementById("pinnedchats");
|
||||
|
||||
add_chat_task(function* testOpenCloseChat() {
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
|
||||
// Tests the focus functionality.
|
||||
|
||||
Components.utils.import("resource://gre/modules/Promise.jsm", this);
|
||||
const CHAT_URL = "https://example.com/browser/browser/base/content/test/chat/chat.html";
|
||||
|
||||
// Is the currently opened tab focused?
|
||||
|
|
|
@ -2,6 +2,8 @@
|
|||
* 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/. */
|
||||
|
||||
Components.utils.import("resource://gre/modules/Promise.jsm", this);
|
||||
|
||||
let chatbar = document.getElementById("pinnedchats");
|
||||
|
||||
function promiseNewWindowLoaded() {
|
||||
|
|
|
@ -300,11 +300,11 @@ skip-if = e10s # Bug 1093155 - tries to use context menu from browser-chrome and
|
|||
skip-if = os == 'win' || e10s # Bug 1056146 - zoom tests use FullZoomHelper and break in e10s
|
||||
[browser_bug1064280_changeUrlInPinnedTab.js]
|
||||
[browser_canonizeURL.js]
|
||||
skip-if = e10s # Bug ?????? - [JavaScript Error: "Error in AboutHome.sendAboutHomeData TypeError: target.messageManager is undefined" {file: "resource:///modules/AboutHome.jsm" line: 208}]
|
||||
skip-if = e10s # Bug 1094510 - test hits the network in e10s mode only
|
||||
[browser_contentAreaClick.js]
|
||||
skip-if = e10s
|
||||
[browser_contextSearchTabPosition.js]
|
||||
skip-if = os == "mac" || e10s # bug 967013, bug 926729
|
||||
skip-if = os == "mac" || e10s # bug 967013; e10s: bug 1094761 - test hits the network in e10s, causing next test to crash
|
||||
[browser_ctrlTab.js]
|
||||
skip-if = e10s # Bug ????? - thumbnail captures need e10s love (tabPreviews_capture fails with Argument 1 of CanvasRenderingContext2D.drawWindow does not implement interface Window.)
|
||||
[browser_customize_popupNotification.js]
|
||||
|
|
|
@ -49,6 +49,11 @@ let check_history = Task.async(function*() {
|
|||
}
|
||||
});
|
||||
|
||||
function clear_history() {
|
||||
gExpectedHistory.index = -1;
|
||||
gExpectedHistory.entries = [];
|
||||
}
|
||||
|
||||
// Waits for a load and updates the known history
|
||||
let waitForLoad = Task.async(function*(uri) {
|
||||
info("Loading " + uri);
|
||||
|
@ -63,6 +68,28 @@ let waitForLoad = Task.async(function*(uri) {
|
|||
});
|
||||
});
|
||||
|
||||
// Waits for a load and updates the known history
|
||||
let waitForLoadWithFlags = Task.async(function*(uri, flags = Ci.nsIWebNavigation.LOAD_FLAGS_NONE) {
|
||||
info("Loading " + uri + " flags = " + flags);
|
||||
gBrowser.selectedBrowser.loadURIWithFlags(uri, flags, null, null, null);
|
||||
|
||||
yield waitForDocLoadComplete();
|
||||
if (!(flags & Ci.nsIWebNavigation.LOAD_FLAGS_BYPASS_HISTORY)) {
|
||||
|
||||
if (flags & Ci.nsIWebNavigation.LOAD_FLAGS_REPLACE_HISTORY) {
|
||||
gExpectedHistory.entries.pop();
|
||||
}
|
||||
else {
|
||||
gExpectedHistory.index++;
|
||||
}
|
||||
|
||||
gExpectedHistory.entries.push({
|
||||
uri: gBrowser.currentURI.spec,
|
||||
title: gBrowser.contentTitle
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
let back = Task.async(function*() {
|
||||
info("Going back");
|
||||
gBrowser.goBack();
|
||||
|
@ -80,10 +107,7 @@ let forward = Task.async(function*() {
|
|||
// Tests that navigating from a page that should be in the remote process and
|
||||
// a page that should be in the main process works and retains history
|
||||
add_task(function* test_navigation() {
|
||||
SimpleTest.requestCompleteLog();
|
||||
|
||||
let remoting = Services.prefs.getBoolPref("browser.tabs.remote.autostart");
|
||||
let expectedRemote = remoting ? "true" : "";
|
||||
let expectedRemote = gMultiProcessBrowser ? "true" : "";
|
||||
|
||||
info("1");
|
||||
// Create a tab and load a remote page in it
|
||||
|
@ -154,13 +178,13 @@ add_task(function* test_navigation() {
|
|||
|
||||
info("11");
|
||||
gBrowser.removeCurrentTab();
|
||||
clear_history();
|
||||
});
|
||||
|
||||
// Tests that calling gBrowser.loadURI or browser.loadURI to load a page in a
|
||||
// different process updates the browser synchronously
|
||||
add_task(function* test_synchronous() {
|
||||
let remoting = Services.prefs.getBoolPref("browser.tabs.remote.autostart");
|
||||
let expectedRemote = remoting ? "true" : "";
|
||||
let expectedRemote = gMultiProcessBrowser ? "true" : "";
|
||||
|
||||
info("1");
|
||||
// Create a tab and load a remote page in it
|
||||
|
@ -194,4 +218,42 @@ add_task(function* test_synchronous() {
|
|||
|
||||
info("4");
|
||||
gBrowser.removeCurrentTab();
|
||||
clear_history();
|
||||
});
|
||||
|
||||
// Tests that load flags are correctly passed through to the child process with
|
||||
// normal loads
|
||||
add_task(function* test_loadflags() {
|
||||
let expectedRemote = gMultiProcessBrowser ? "true" : "";
|
||||
|
||||
info("1");
|
||||
// Create a tab and load a remote page in it
|
||||
gBrowser.selectedTab = gBrowser.addTab("about:blank", {skipAnimation: true});
|
||||
yield waitForLoadWithFlags("about:robots");
|
||||
is(gBrowser.selectedTab.getAttribute("remote"), "", "Remote attribute should be correct");
|
||||
yield check_history();
|
||||
|
||||
info("2");
|
||||
// Load a page in the remote process with some custom flags
|
||||
yield waitForLoadWithFlags("http://example.com/" + DUMMY_PATH, Ci.nsIWebNavigation.LOAD_FLAGS_BYPASS_HISTORY);
|
||||
is(gBrowser.selectedTab.getAttribute("remote"), expectedRemote, "Remote attribute should be correct");
|
||||
yield check_history();
|
||||
|
||||
info("3");
|
||||
// Load a non-remote page
|
||||
yield waitForLoadWithFlags("about:robots");
|
||||
is(gBrowser.selectedTab.getAttribute("remote"), "", "Remote attribute should be correct");
|
||||
yield check_history();
|
||||
|
||||
info("4");
|
||||
// Load another remote page
|
||||
yield waitForLoadWithFlags("http://example.org/" + DUMMY_PATH, Ci.nsIWebNavigation.LOAD_FLAGS_REPLACE_HISTORY);
|
||||
is(gBrowser.selectedTab.getAttribute("remote"), expectedRemote, "Remote attribute should be correct");
|
||||
yield check_history();
|
||||
|
||||
is(gExpectedHistory.entries.length, 2, "Should end with the right number of history entries");
|
||||
|
||||
info("5");
|
||||
gBrowser.removeCurrentTab();
|
||||
clear_history();
|
||||
});
|
||||
|
|
|
@ -10,11 +10,20 @@
|
|||
* ALL need to match an error in order for that error not to cause a test
|
||||
* failure. */
|
||||
const kWhitelist = [
|
||||
{sourceName: /cleopatra.*(tree|ui)\.css/i}, /* Cleopatra is imported as-is, see bug 1004421 */
|
||||
{sourceName: /codemirror\.css/i}, /* CodeMirror is imported as-is, see bug 1004423 */
|
||||
{sourceName: /web\/viewer\.css/i, errorMessage: /Unknown pseudo-class.*(fullscreen|selection)/i }, /* PDFjs is futureproofing its pseudoselectors, and those rules are dropped. */
|
||||
{sourceName: /aboutaccounts\/(main|normalize)\.css/i}, /* Tracked in bug 1004428 */
|
||||
{sourceName: /loop\/.*sdk-content\/.*\.css$/i /* TokBox SDK assets, see bug 1032469 */}
|
||||
// Cleopatra is imported as-is, see bug 1004421.
|
||||
{sourceName: /cleopatra.*(tree|ui)\.css/i},
|
||||
// CodeMirror is imported as-is, see bug 1004423.
|
||||
{sourceName: /codemirror\.css/i},
|
||||
// PDFjs is futureproofing its pseudoselectors, and those rules are dropped.
|
||||
{sourceName: /web\/viewer\.css/i,
|
||||
errorMessage: /Unknown pseudo-class.*(fullscreen|selection)/i},
|
||||
// Tracked in bug 1004428.
|
||||
{sourceName: /aboutaccounts\/(main|normalize)\.css/i},
|
||||
// TokBox SDK assets, see bug 1032469.
|
||||
{sourceName: /loop\/.*sdk-content\/.*\.css$/i},
|
||||
// Highlighter CSS uses chrome-only pseudo-class, see bug 985597.
|
||||
{sourceName: /highlighter\.css/i,
|
||||
errorMessage: /Unknown pseudo-class.*moz-native-anonymous/i}
|
||||
];
|
||||
|
||||
let moduleLocation = gTestPath.replace(/\/[^\/]*$/i, "/parsingTestHelpers.jsm");
|
||||
|
|
|
@ -27,7 +27,8 @@ add_task(function testWrapUnwrap() {
|
|||
// Creating and destroying a widget should correctly deal with panel placeholders
|
||||
add_task(function testPanelPlaceholders() {
|
||||
let panel = document.getElementById(CustomizableUI.AREA_PANEL);
|
||||
is(panel.querySelectorAll(".panel-customization-placeholder").length, isInWin8() ? 1 : 2, "The number of placeholders should be correct.");
|
||||
let expectedPlaceholders = (isInWin8() ? 1 : 2) + (isInDevEdition() ? 1 : 0);
|
||||
is(panel.querySelectorAll(".panel-customization-placeholder").length, expectedPlaceholders, "The number of placeholders should be correct.");
|
||||
CustomizableUI.createWidget({id: kTestWidget2, label: 'Pretty label', tooltiptext: 'Pretty tooltip', defaultArea: CustomizableUI.AREA_PANEL});
|
||||
let elem = document.getElementById(kTestWidget2);
|
||||
let wrapper = document.getElementById("wrapper-" + kTestWidget2);
|
||||
|
@ -35,7 +36,8 @@ add_task(function testPanelPlaceholders() {
|
|||
ok(wrapper, "There should be a wrapper");
|
||||
is(wrapper.firstChild.id, kTestWidget2, "Wrapper should have test widget");
|
||||
is(wrapper.parentNode, panel, "Wrapper should be in panel");
|
||||
is(panel.querySelectorAll(".panel-customization-placeholder").length, isInWin8() ? 3 : 1, "The number of placeholders should be correct.");
|
||||
expectedPlaceholders = (isInWin8() ? 3 : 1) + (isInDevEdition() ? 1 : 0);
|
||||
is(panel.querySelectorAll(".panel-customization-placeholder").length, expectedPlaceholders, "The number of placeholders should be correct.");
|
||||
CustomizableUI.destroyWidget(kTestWidget2);
|
||||
wrapper = document.getElementById("wrapper-" + kTestWidget2);
|
||||
ok(!wrapper, "There should be a wrapper");
|
||||
|
|
|
@ -18,6 +18,9 @@ XPCOMUtils.defineLazyGetter(this, "eventEmitter", function() {
|
|||
|
||||
this.EXPORTED_SYMBOLS = ["LoopRooms", "roomsPushNotification"];
|
||||
|
||||
// The maximum number of clients that we support currently.
|
||||
const CLIENT_MAX_SIZE = 2;
|
||||
|
||||
const roomsPushNotification = function(version, channelID) {
|
||||
return LoopRoomsInternal.onNotification(version, channelID);
|
||||
};
|
||||
|
@ -271,6 +274,81 @@ let LoopRoomsInternal = {
|
|||
}, error => callback(error)).catch(error => callback(error));
|
||||
},
|
||||
|
||||
/**
|
||||
* Internal function to handle POSTs to a room.
|
||||
*
|
||||
* @param {String} roomToken The room token.
|
||||
* @param {Object} postData The data to post to the room.
|
||||
* @param {Function} callback Function that will be invoked once the operation
|
||||
* finished. The first argument passed will be an
|
||||
* `Error` object or `null`.
|
||||
*/
|
||||
_postToRoom(roomToken, postData, callback) {
|
||||
let url = "/rooms/" + encodeURIComponent(roomToken);
|
||||
MozLoopService.hawkRequest(this.sessionType, url, "POST", postData).then(response => {
|
||||
// Delete doesn't have a body return.
|
||||
var joinData = response.body ? JSON.parse(response.body) : {};
|
||||
callback(null, joinData);
|
||||
}, error => callback(error)).catch(error => callback(error));
|
||||
},
|
||||
|
||||
/**
|
||||
* Joins a room
|
||||
*
|
||||
* @param {String} roomToken The room token.
|
||||
* @param {Function} callback Function that will be invoked once the operation
|
||||
* finished. The first argument passed will be an
|
||||
* `Error` object or `null`.
|
||||
*/
|
||||
join: function(roomToken, callback) {
|
||||
this._postToRoom(roomToken, {
|
||||
action: "join",
|
||||
displayName: MozLoopService.userProfile.email,
|
||||
clientMaxSize: CLIENT_MAX_SIZE
|
||||
}, callback);
|
||||
},
|
||||
|
||||
/**
|
||||
* Refreshes a room
|
||||
*
|
||||
* @param {String} roomToken The room token.
|
||||
* @param {String} sessionToken The session token for the session that has been
|
||||
* joined
|
||||
* @param {Function} callback Function that will be invoked once the operation
|
||||
* finished. The first argument passed will be an
|
||||
* `Error` object or `null`.
|
||||
*/
|
||||
refreshMembership: function(roomToken, sessionToken, callback) {
|
||||
this._postToRoom(roomToken, {
|
||||
action: "refresh",
|
||||
sessionToken: sessionToken
|
||||
}, callback);
|
||||
},
|
||||
|
||||
/**
|
||||
* Leaves a room. Although this is an sync function, no data is returned
|
||||
* from the server.
|
||||
*
|
||||
* @param {String} roomToken The room token.
|
||||
* @param {String} sessionToken The session token for the session that has been
|
||||
* joined
|
||||
* @param {Function} callback Optional. Function that will be invoked once the operation
|
||||
* finished. The first argument passed will be an
|
||||
* `Error` object or `null`.
|
||||
*/
|
||||
leave: function(roomToken, sessionToken, callback) {
|
||||
if (!callback) {
|
||||
callback = function(error) {
|
||||
if (error) {
|
||||
MozLoopService.log.error(error);
|
||||
}
|
||||
};
|
||||
}
|
||||
this._postToRoom(roomToken, {
|
||||
action: "leave",
|
||||
sessionToken: sessionToken
|
||||
}, callback);
|
||||
},
|
||||
|
||||
/**
|
||||
* Callback used to indicate changes to rooms data on the LoopServer.
|
||||
|
@ -322,6 +400,19 @@ this.LoopRooms = {
|
|||
return LoopRoomsInternal.delete(roomToken, callback);
|
||||
},
|
||||
|
||||
join: function(roomToken, callback) {
|
||||
return LoopRoomsInternal.join(roomToken, callback);
|
||||
},
|
||||
|
||||
refreshMembership: function(roomToken, sessionToken, callback) {
|
||||
return LoopRoomsInternal.refreshMembership(roomToken, sessionToken,
|
||||
callback);
|
||||
},
|
||||
|
||||
leave: function(roomToken, sessionToken, callback) {
|
||||
return LoopRoomsInternal.leave(roomToken, sessionToken, callback);
|
||||
},
|
||||
|
||||
promise: function(method, ...params) {
|
||||
return new Promise((resolve, reject) => {
|
||||
this[method](...params, (error, result) => {
|
||||
|
|
|
@ -13,6 +13,7 @@ Cu.import("resource:///modules/loop/LoopCalls.jsm");
|
|||
Cu.import("resource:///modules/loop/MozLoopService.jsm");
|
||||
Cu.import("resource:///modules/loop/LoopRooms.jsm");
|
||||
Cu.import("resource:///modules/loop/LoopContacts.jsm");
|
||||
Cu.importGlobalProperties(["Blob"]);
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "LoopContacts",
|
||||
"resource:///modules/loop/LoopContacts.jsm");
|
||||
|
@ -685,6 +686,31 @@ function injectLoopAPI(targetWindow) {
|
|||
return MozLoopService.generateUUID();
|
||||
}
|
||||
},
|
||||
|
||||
getAudioBlob: {
|
||||
enumerable: true,
|
||||
writable: true,
|
||||
value: function(name, callback) {
|
||||
let request = Cc["@mozilla.org/xmlextras/xmlhttprequest;1"]
|
||||
.createInstance(Ci.nsIXMLHttpRequest);
|
||||
let url = `chrome://browser/content/loop/shared/sounds/${name}.ogg`;
|
||||
|
||||
request.open("GET", url, true);
|
||||
request.responseType = "arraybuffer";
|
||||
request.onload = () => {
|
||||
if (request.status < 200 || request.status >= 300) {
|
||||
let error = new Error(request.status + " " + request.statusText);
|
||||
callback(cloneValueInto(error, targetWindow));
|
||||
return;
|
||||
}
|
||||
|
||||
let blob = new Blob([request.response], {type: "audio/ogg"});
|
||||
callback(null, cloneValueInto(blob, targetWindow));
|
||||
};
|
||||
|
||||
request.send();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
function onStatusChanged(aSubject, aTopic, aData) {
|
||||
|
|
|
@ -21,7 +21,7 @@ loop.conversation = (function(mozL10n) {
|
|||
var DesktopRoomView = loop.roomViews.DesktopRoomView;
|
||||
|
||||
var IncomingCallView = React.createClass({displayName: 'IncomingCallView',
|
||||
mixins: [sharedMixins.DropdownMenuMixin],
|
||||
mixins: [sharedMixins.DropdownMenuMixin, sharedMixins.AudioMixin],
|
||||
|
||||
propTypes: {
|
||||
model: React.PropTypes.object.isRequired,
|
||||
|
@ -185,10 +185,16 @@ loop.conversation = (function(mozL10n) {
|
|||
* incoming call views (bug 1088672).
|
||||
*/
|
||||
var GenericFailureView = React.createClass({displayName: 'GenericFailureView',
|
||||
mixins: [sharedMixins.AudioMixin],
|
||||
|
||||
propTypes: {
|
||||
cancelCall: React.PropTypes.func.isRequired
|
||||
},
|
||||
|
||||
componentDidMount: function() {
|
||||
this.play("failure");
|
||||
},
|
||||
|
||||
render: function() {
|
||||
document.title = mozL10n.get("generic_failure_title");
|
||||
|
||||
|
@ -665,7 +671,11 @@ loop.conversation = (function(mozL10n) {
|
|||
|
||||
window.addEventListener("unload", function(event) {
|
||||
// Handle direct close of dialog box via [x] control.
|
||||
// XXX Move to the conversation models, when we transition
|
||||
// incoming calls to flux (bug 1088672).
|
||||
navigator.mozLoop.calls.clearCallInProgress(windowId);
|
||||
|
||||
dispatcher.dispatch(new sharedActions.WindowUnload());
|
||||
});
|
||||
|
||||
React.renderComponent(AppControllerView({
|
||||
|
|
|
@ -21,7 +21,7 @@ loop.conversation = (function(mozL10n) {
|
|||
var DesktopRoomView = loop.roomViews.DesktopRoomView;
|
||||
|
||||
var IncomingCallView = React.createClass({
|
||||
mixins: [sharedMixins.DropdownMenuMixin],
|
||||
mixins: [sharedMixins.DropdownMenuMixin, sharedMixins.AudioMixin],
|
||||
|
||||
propTypes: {
|
||||
model: React.PropTypes.object.isRequired,
|
||||
|
@ -185,10 +185,16 @@ loop.conversation = (function(mozL10n) {
|
|||
* incoming call views (bug 1088672).
|
||||
*/
|
||||
var GenericFailureView = React.createClass({
|
||||
mixins: [sharedMixins.AudioMixin],
|
||||
|
||||
propTypes: {
|
||||
cancelCall: React.PropTypes.func.isRequired
|
||||
},
|
||||
|
||||
componentDidMount: function() {
|
||||
this.play("failure");
|
||||
},
|
||||
|
||||
render: function() {
|
||||
document.title = mozL10n.get("generic_failure_title");
|
||||
|
||||
|
@ -665,7 +671,11 @@ loop.conversation = (function(mozL10n) {
|
|||
|
||||
window.addEventListener("unload", function(event) {
|
||||
// Handle direct close of dialog box via [x] control.
|
||||
// XXX Move to the conversation models, when we transition
|
||||
// incoming calls to flux (bug 1088672).
|
||||
navigator.mozLoop.calls.clearCallInProgress(windowId);
|
||||
|
||||
dispatcher.dispatch(new sharedActions.WindowUnload());
|
||||
});
|
||||
|
||||
React.renderComponent(<AppControllerView
|
||||
|
|
|
@ -14,6 +14,7 @@ loop.conversationViews = (function(mozL10n) {
|
|||
var sharedActions = loop.shared.actions;
|
||||
var sharedUtils = loop.shared.utils;
|
||||
var sharedViews = loop.shared.views;
|
||||
var sharedMixins = loop.shared.mixins;
|
||||
|
||||
// This duplicates a similar function in contacts.jsx that isn't used in the
|
||||
// conversation window. If we get too many of these, we might want to consider
|
||||
|
@ -133,6 +134,8 @@ loop.conversationViews = (function(mozL10n) {
|
|||
* pending/ringing strings.
|
||||
*/
|
||||
var PendingConversationView = React.createClass({displayName: 'PendingConversationView',
|
||||
mixins: [sharedMixins.AudioMixin],
|
||||
|
||||
propTypes: {
|
||||
dispatcher: React.PropTypes.instanceOf(loop.Dispatcher).isRequired,
|
||||
callState: React.PropTypes.string,
|
||||
|
@ -146,6 +149,10 @@ loop.conversationViews = (function(mozL10n) {
|
|||
};
|
||||
},
|
||||
|
||||
componentDidMount: function() {
|
||||
this.play("ringtone", {loop: true});
|
||||
},
|
||||
|
||||
cancelCall: function() {
|
||||
this.props.dispatcher.dispatch(new sharedActions.CancelCall());
|
||||
},
|
||||
|
@ -186,7 +193,7 @@ loop.conversationViews = (function(mozL10n) {
|
|||
* Call failed view. Displayed when a call fails.
|
||||
*/
|
||||
var CallFailedView = React.createClass({displayName: 'CallFailedView',
|
||||
mixins: [Backbone.Events],
|
||||
mixins: [Backbone.Events, sharedMixins.AudioMixin],
|
||||
|
||||
propTypes: {
|
||||
dispatcher: React.PropTypes.instanceOf(loop.Dispatcher).isRequired,
|
||||
|
@ -205,6 +212,7 @@ loop.conversationViews = (function(mozL10n) {
|
|||
},
|
||||
|
||||
componentDidMount: function() {
|
||||
this.play("failure");
|
||||
this.listenTo(this.props.store, "change:emailLink",
|
||||
this._onEmailLinkReceived);
|
||||
this.listenTo(this.props.store, "error:emailLink",
|
||||
|
|
|
@ -14,6 +14,7 @@ loop.conversationViews = (function(mozL10n) {
|
|||
var sharedActions = loop.shared.actions;
|
||||
var sharedUtils = loop.shared.utils;
|
||||
var sharedViews = loop.shared.views;
|
||||
var sharedMixins = loop.shared.mixins;
|
||||
|
||||
// This duplicates a similar function in contacts.jsx that isn't used in the
|
||||
// conversation window. If we get too many of these, we might want to consider
|
||||
|
@ -133,6 +134,8 @@ loop.conversationViews = (function(mozL10n) {
|
|||
* pending/ringing strings.
|
||||
*/
|
||||
var PendingConversationView = React.createClass({
|
||||
mixins: [sharedMixins.AudioMixin],
|
||||
|
||||
propTypes: {
|
||||
dispatcher: React.PropTypes.instanceOf(loop.Dispatcher).isRequired,
|
||||
callState: React.PropTypes.string,
|
||||
|
@ -146,6 +149,10 @@ loop.conversationViews = (function(mozL10n) {
|
|||
};
|
||||
},
|
||||
|
||||
componentDidMount: function() {
|
||||
this.play("ringtone", {loop: true});
|
||||
},
|
||||
|
||||
cancelCall: function() {
|
||||
this.props.dispatcher.dispatch(new sharedActions.CancelCall());
|
||||
},
|
||||
|
@ -186,7 +193,7 @@ loop.conversationViews = (function(mozL10n) {
|
|||
* Call failed view. Displayed when a call fails.
|
||||
*/
|
||||
var CallFailedView = React.createClass({
|
||||
mixins: [Backbone.Events],
|
||||
mixins: [Backbone.Events, sharedMixins.AudioMixin],
|
||||
|
||||
propTypes: {
|
||||
dispatcher: React.PropTypes.instanceOf(loop.Dispatcher).isRequired,
|
||||
|
@ -205,6 +212,7 @@ loop.conversationViews = (function(mozL10n) {
|
|||
},
|
||||
|
||||
componentDidMount: function() {
|
||||
this.play("failure");
|
||||
this.listenTo(this.props.store, "change:emailLink",
|
||||
this._onEmailLinkReceived);
|
||||
this.listenTo(this.props.store, "error:emailLink",
|
||||
|
|
|
@ -10,6 +10,8 @@ var loop = loop || {};
|
|||
loop.roomViews = (function(mozL10n) {
|
||||
"use strict";
|
||||
|
||||
var ROOM_STATES = loop.store.ROOM_STATES;
|
||||
|
||||
var DesktopRoomView = React.createClass({displayName: 'DesktopRoomView',
|
||||
mixins: [Backbone.Events, loop.shared.mixins.DocumentTitleMixin],
|
||||
|
||||
|
@ -19,7 +21,7 @@ loop.roomViews = (function(mozL10n) {
|
|||
},
|
||||
|
||||
getInitialState: function() {
|
||||
return this.props.roomStore.getStoreState();
|
||||
return this.props.roomStore.getStoreState("activeRoom");
|
||||
},
|
||||
|
||||
componentWillMount: function() {
|
||||
|
@ -41,13 +43,28 @@ loop.roomViews = (function(mozL10n) {
|
|||
this.stopListening(this.props.roomStore);
|
||||
},
|
||||
|
||||
/**
|
||||
* Closes the window if the cancel button is pressed in the generic failure view.
|
||||
*/
|
||||
closeWindow: function() {
|
||||
window.close();
|
||||
},
|
||||
|
||||
render: function() {
|
||||
if (this.state.serverData && this.state.serverData.roomName) {
|
||||
this.setTitle(this.state.serverData.roomName);
|
||||
if (this.state.roomName) {
|
||||
this.setTitle(this.state.roomName);
|
||||
}
|
||||
|
||||
if (this.state.roomState === ROOM_STATES.FAILED) {
|
||||
return (loop.conversation.GenericFailureView({
|
||||
cancelCall: this.closeWindow}
|
||||
));
|
||||
}
|
||||
|
||||
return (
|
||||
React.DOM.div({className: "goat"})
|
||||
React.DOM.div(null,
|
||||
React.DOM.div(null, mozL10n.get("invite_header_text"))
|
||||
)
|
||||
);
|
||||
}
|
||||
});
|
||||
|
|
|
@ -10,6 +10,8 @@ var loop = loop || {};
|
|||
loop.roomViews = (function(mozL10n) {
|
||||
"use strict";
|
||||
|
||||
var ROOM_STATES = loop.store.ROOM_STATES;
|
||||
|
||||
var DesktopRoomView = React.createClass({
|
||||
mixins: [Backbone.Events, loop.shared.mixins.DocumentTitleMixin],
|
||||
|
||||
|
@ -19,7 +21,7 @@ loop.roomViews = (function(mozL10n) {
|
|||
},
|
||||
|
||||
getInitialState: function() {
|
||||
return this.props.roomStore.getStoreState();
|
||||
return this.props.roomStore.getStoreState("activeRoom");
|
||||
},
|
||||
|
||||
componentWillMount: function() {
|
||||
|
@ -41,13 +43,28 @@ loop.roomViews = (function(mozL10n) {
|
|||
this.stopListening(this.props.roomStore);
|
||||
},
|
||||
|
||||
/**
|
||||
* Closes the window if the cancel button is pressed in the generic failure view.
|
||||
*/
|
||||
closeWindow: function() {
|
||||
window.close();
|
||||
},
|
||||
|
||||
render: function() {
|
||||
if (this.state.serverData && this.state.serverData.roomName) {
|
||||
this.setTitle(this.state.serverData.roomName);
|
||||
if (this.state.roomName) {
|
||||
this.setTitle(this.state.roomName);
|
||||
}
|
||||
|
||||
if (this.state.roomState === ROOM_STATES.FAILED) {
|
||||
return (<loop.conversation.GenericFailureView
|
||||
cancelCall={this.closeWindow}
|
||||
/>);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="goat"/>
|
||||
<div>
|
||||
<div>{mozL10n.get("invite_header_text")}</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
|
|
@ -67,6 +67,12 @@ loop.shared.actions = (function() {
|
|||
windowType: String
|
||||
}),
|
||||
|
||||
/**
|
||||
* Used to signal when the window is being unloaded.
|
||||
*/
|
||||
WindowUnload: Action.define("windowUnload", {
|
||||
}),
|
||||
|
||||
/**
|
||||
* Fetch a new call url from the server, intended to be sent over email when
|
||||
* a contact can't be reached.
|
||||
|
@ -227,6 +233,46 @@ loop.shared.actions = (function() {
|
|||
*/
|
||||
CopyRoomUrl: Action.define("copyRoomUrl", {
|
||||
roomUrl: String
|
||||
}),
|
||||
|
||||
/**
|
||||
* XXX: should move to some roomActions module - refs bug 1079284
|
||||
*/
|
||||
RoomFailure: Action.define("roomFailure", {
|
||||
error: Object
|
||||
}),
|
||||
|
||||
/**
|
||||
* Updates the room information when it is received.
|
||||
* XXX: should move to some roomActions module - refs bug 1079284
|
||||
*
|
||||
* @see https://wiki.mozilla.org/Loop/Architecture/Rooms#GET_.2Frooms.2F.7Btoken.7D
|
||||
*/
|
||||
UpdateRoomInfo: Action.define("updateRoomInfo", {
|
||||
roomName: String,
|
||||
roomOwner: String,
|
||||
roomToken: String,
|
||||
roomUrl: String
|
||||
}),
|
||||
|
||||
/**
|
||||
* Starts the process for the user to join the room.
|
||||
* XXX: should move to some roomActions module - refs bug 1079284
|
||||
*/
|
||||
JoinRoom: Action.define("joinRoom", {
|
||||
}),
|
||||
|
||||
/**
|
||||
* Signals the user has successfully joined the room on the loop-server.
|
||||
* XXX: should move to some roomActions module - refs bug 1079284
|
||||
*
|
||||
* @see https://wiki.mozilla.org/Loop/Architecture/Rooms#Joining_a_Room
|
||||
*/
|
||||
JoinedRoom: Action.define("joinedRoom", {
|
||||
apiKey: String,
|
||||
sessionToken: String,
|
||||
sessionId: String,
|
||||
expires: Number
|
||||
})
|
||||
};
|
||||
})();
|
||||
|
|
|
@ -11,6 +11,19 @@ loop.store.ActiveRoomStore = (function() {
|
|||
|
||||
var sharedActions = loop.shared.actions;
|
||||
|
||||
var ROOM_STATES = loop.store.ROOM_STATES = {
|
||||
// The initial state of the room
|
||||
INIT: "room-init",
|
||||
// The store is gathering the room data
|
||||
GATHER: "room-gather",
|
||||
// The store has got the room data
|
||||
READY: "room-ready",
|
||||
// The room is known to be joined on the loop-server
|
||||
JOINED: "room-joined",
|
||||
// There was an issue with the room
|
||||
FAILED: "room-failed"
|
||||
};
|
||||
|
||||
/**
|
||||
* Store for things that are local to this instance (in this profile, on
|
||||
* this machine) of this roomRoom store, in addition to a mirror of some
|
||||
|
@ -29,53 +42,78 @@ loop.store.ActiveRoomStore = (function() {
|
|||
if (!options.dispatcher) {
|
||||
throw new Error("Missing option dispatcher");
|
||||
}
|
||||
this.dispatcher = options.dispatcher;
|
||||
this._dispatcher = options.dispatcher;
|
||||
|
||||
if (!options.mozLoop) {
|
||||
throw new Error("Missing option mozLoop");
|
||||
}
|
||||
this.mozLoop = options.mozLoop;
|
||||
this._mozLoop = options.mozLoop;
|
||||
|
||||
this.dispatcher.register(this, [
|
||||
"setupWindowData"
|
||||
this._dispatcher.register(this, [
|
||||
"roomFailure",
|
||||
"setupWindowData",
|
||||
"updateRoomInfo",
|
||||
"joinRoom",
|
||||
"joinedRoom",
|
||||
"windowUnload"
|
||||
]);
|
||||
}
|
||||
|
||||
ActiveRoomStore.prototype = _.extend({
|
||||
|
||||
/**
|
||||
* Stored data reflecting the local state of a given room, used to drive
|
||||
* the room's views.
|
||||
*
|
||||
* @property {Object} serverData - local cache of the data returned by
|
||||
* MozLoop.getRoomData for this room.
|
||||
* @see https://wiki.mozilla.org/Loop/Architecture/Rooms#GET_.2Frooms.2F.7Btoken.7D
|
||||
* for the main data. Additional properties below.
|
||||
*
|
||||
* @property {ROOM_STATES} roomState - the state of the room.
|
||||
* @property {Error=} error - if the room is an error state, this will be
|
||||
* set to an Error object reflecting the problem;
|
||||
* otherwise it will be unset.
|
||||
*/
|
||||
_storeState: {
|
||||
},
|
||||
this._storeState = {
|
||||
roomState: ROOM_STATES.INIT
|
||||
};
|
||||
}
|
||||
|
||||
ActiveRoomStore.prototype = _.extend({
|
||||
/**
|
||||
* The time factor to adjust the expires time to ensure that we send a refresh
|
||||
* before the expiry. Currently set as 90%.
|
||||
*/
|
||||
expiresTimeFactor: 0.9,
|
||||
|
||||
getStoreState: function() {
|
||||
return this._storeState;
|
||||
},
|
||||
|
||||
setStoreState: function(state) {
|
||||
this._storeState = state;
|
||||
setStoreState: function(newState) {
|
||||
for (var key in newState) {
|
||||
this._storeState[key] = newState[key];
|
||||
}
|
||||
this.trigger("change");
|
||||
},
|
||||
|
||||
/**
|
||||
* Execute setupWindowData event action from the dispatcher. This primes
|
||||
* the store with the roomToken, and calls MozLoop.getRoomData on that
|
||||
* ID. This will return either a reflection of state on the server, or,
|
||||
* if the createRoom call hasn't yet returned, it will have at least the
|
||||
* roomName as specified to the createRoom method.
|
||||
* Handles a room failure. Currently this prints the error to the console
|
||||
* and sets the roomState to failed.
|
||||
*
|
||||
* When the room name gets set, that will trigger the view to display
|
||||
* that name.
|
||||
* @param {sharedActions.RoomFailure} actionData
|
||||
*/
|
||||
roomFailure: function(actionData) {
|
||||
console.error("Error in state `" + this._storeState.roomState + "`:",
|
||||
actionData.error);
|
||||
|
||||
this.setStoreState({
|
||||
error: actionData.error,
|
||||
roomState: ROOM_STATES.FAILED
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Execute setupWindowData event action from the dispatcher. This gets
|
||||
* the room data from the mozLoop api, and dispatches an UpdateRoomInfo event.
|
||||
* It also dispatches JoinRoom as this action is only applicable to the desktop
|
||||
* client, and needs to auto-join.
|
||||
*
|
||||
* @param {sharedActions.SetupWindowData} actionData
|
||||
*/
|
||||
|
@ -85,14 +123,144 @@ loop.store.ActiveRoomStore = (function() {
|
|||
return;
|
||||
}
|
||||
|
||||
this.mozLoop.rooms.get(actionData.roomToken,
|
||||
this.setStoreState({
|
||||
roomState: ROOM_STATES.GATHER
|
||||
});
|
||||
|
||||
// Get the window data from the mozLoop api.
|
||||
this._mozLoop.rooms.get(actionData.roomToken,
|
||||
function(error, roomData) {
|
||||
this.setStoreState({
|
||||
error: error,
|
||||
if (error) {
|
||||
this._dispatcher.dispatch(new sharedActions.RoomFailure({
|
||||
error: error
|
||||
}));
|
||||
return;
|
||||
}
|
||||
|
||||
this._dispatcher.dispatch(
|
||||
new sharedActions.UpdateRoomInfo({
|
||||
roomToken: actionData.roomToken,
|
||||
serverData: roomData
|
||||
});
|
||||
roomName: roomData.roomName,
|
||||
roomOwner: roomData.roomOwner,
|
||||
roomUrl: roomData.roomUrl
|
||||
}));
|
||||
|
||||
// For the conversation window, we need to automatically
|
||||
// join the room.
|
||||
this._dispatcher.dispatch(new sharedActions.JoinRoom());
|
||||
}.bind(this));
|
||||
},
|
||||
|
||||
/**
|
||||
* Handles the updateRoomInfo action. Updates the room data and
|
||||
* sets the state to `READY`.
|
||||
*
|
||||
* @param {sharedActions.UpdateRoomInfo} actionData
|
||||
*/
|
||||
updateRoomInfo: function(actionData) {
|
||||
this.setStoreState({
|
||||
roomName: actionData.roomName,
|
||||
roomOwner: actionData.roomOwner,
|
||||
roomState: ROOM_STATES.READY,
|
||||
roomToken: actionData.roomToken,
|
||||
roomUrl: actionData.roomUrl
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Handles the action to join to a room.
|
||||
*/
|
||||
joinRoom: function() {
|
||||
this._mozLoop.rooms.join(this._storeState.roomToken,
|
||||
function(error, responseData) {
|
||||
if (error) {
|
||||
this._dispatcher.dispatch(
|
||||
new sharedActions.RoomFailure({error: error}));
|
||||
return;
|
||||
}
|
||||
|
||||
this._dispatcher.dispatch(new sharedActions.JoinedRoom({
|
||||
apiKey: responseData.apiKey,
|
||||
sessionToken: responseData.sessionToken,
|
||||
sessionId: responseData.sessionId,
|
||||
expires: responseData.expires
|
||||
}));
|
||||
}.bind(this));
|
||||
},
|
||||
|
||||
/**
|
||||
* Handles the data received from joining a room. It stores the relevant
|
||||
* data, and sets up the refresh timeout for ensuring membership of the room
|
||||
* is refreshed regularly.
|
||||
*
|
||||
* @param {sharedActions.JoinedRoom} actionData
|
||||
*/
|
||||
joinedRoom: function(actionData) {
|
||||
this.setStoreState({
|
||||
apiKey: actionData.apiKey,
|
||||
sessionToken: actionData.sessionToken,
|
||||
sessionId: actionData.sessionId,
|
||||
roomState: ROOM_STATES.JOINED
|
||||
});
|
||||
|
||||
this._setRefreshTimeout(actionData.expires);
|
||||
},
|
||||
|
||||
/**
|
||||
* Handles the window being unloaded. Ensures the room is left.
|
||||
*/
|
||||
windowUnload: function() {
|
||||
this._leaveRoom();
|
||||
},
|
||||
|
||||
/**
|
||||
* Handles setting of the refresh timeout callback.
|
||||
*
|
||||
* @param {Integer} expireTime The time until expiry (in seconds).
|
||||
*/
|
||||
_setRefreshTimeout: function(expireTime) {
|
||||
this._timeout = setTimeout(this._refreshMembership.bind(this),
|
||||
expireTime * this.expiresTimeFactor * 1000);
|
||||
},
|
||||
|
||||
/**
|
||||
* Refreshes the membership of the room with the server, and then
|
||||
* sets up the refresh for the next cycle.
|
||||
*/
|
||||
_refreshMembership: function() {
|
||||
this._mozLoop.rooms.refreshMembership(this._storeState.roomToken,
|
||||
this._storeState.sessionToken,
|
||||
function(error, responseData) {
|
||||
if (error) {
|
||||
this._dispatcher.dispatch(
|
||||
new sharedActions.RoomFailure({error: error}));
|
||||
return;
|
||||
}
|
||||
|
||||
this._setRefreshTimeout(responseData.expires);
|
||||
}.bind(this));
|
||||
},
|
||||
|
||||
/**
|
||||
* Handles leaving a room. Clears any membership timeouts, then
|
||||
* signals to the server the leave of the room.
|
||||
*/
|
||||
_leaveRoom: function() {
|
||||
if (this._storeState.roomState !== ROOM_STATES.JOINED) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this._timeout) {
|
||||
clearTimeout(this._timeout);
|
||||
delete this._timeout;
|
||||
}
|
||||
|
||||
this._mozLoop.rooms.leave(this._storeState.roomToken,
|
||||
this._storeState.sessionToken);
|
||||
|
||||
this.setStoreState({
|
||||
roomState: ROOM_STATES.READY
|
||||
});
|
||||
}
|
||||
|
||||
}, Backbone.Events);
|
||||
|
|
|
@ -141,6 +141,7 @@ loop.shared.mixins = (function() {
|
|||
*/
|
||||
var AudioMixin = {
|
||||
audio: null,
|
||||
_audioRequest: null,
|
||||
|
||||
_isLoopDesktop: function() {
|
||||
return typeof rootObject.navigator.mozLoop === "object";
|
||||
|
@ -149,27 +150,62 @@ loop.shared.mixins = (function() {
|
|||
/**
|
||||
* Starts playing an audio file, stopping any audio that is already in progress.
|
||||
*
|
||||
* @param {String} filename The filename to play (excluding the extension).
|
||||
* @param {String} name The filename to play (excluding the extension).
|
||||
*/
|
||||
play: function(filename, options) {
|
||||
if (this._isLoopDesktop()) {
|
||||
// XXX: We need navigator.mozLoop.playSound(name), see Bug 1089585.
|
||||
return;
|
||||
}
|
||||
|
||||
play: function(name, options) {
|
||||
options = options || {};
|
||||
options.loop = options.loop || false;
|
||||
|
||||
this._ensureAudioStopped();
|
||||
this.audio = new Audio('shared/sounds/' + filename + ".ogg");
|
||||
this.audio.loop = options.loop;
|
||||
this.audio.play();
|
||||
this._getAudioBlob(name, function(error, blob) {
|
||||
if (error) {
|
||||
console.error(error);
|
||||
return;
|
||||
}
|
||||
|
||||
var url = URL.createObjectURL(blob);
|
||||
this.audio = new Audio(url);
|
||||
this.audio.loop = options.loop;
|
||||
this.audio.play();
|
||||
}.bind(this));
|
||||
},
|
||||
|
||||
_getAudioBlob: function(name, callback) {
|
||||
if (this._isLoopDesktop()) {
|
||||
rootObject.navigator.mozLoop.getAudioBlob(name, callback);
|
||||
return;
|
||||
}
|
||||
|
||||
var url = "shared/sounds/" + name + ".ogg";
|
||||
this._audioRequest = new XMLHttpRequest();
|
||||
this._audioRequest.open("GET", url, true);
|
||||
this._audioRequest.responseType = "arraybuffer";
|
||||
this._audioRequest.onload = function() {
|
||||
var request = this._audioRequest;
|
||||
var error;
|
||||
if (request.status < 200 || request.status >= 300) {
|
||||
error = new Error(request.status + " " + request.statusText);
|
||||
callback(error);
|
||||
return;
|
||||
}
|
||||
|
||||
var type = request.getResponseHeader("Content-Type");
|
||||
var blob = new Blob([request.response], {type: type});
|
||||
callback(null, blob);
|
||||
}.bind(this);
|
||||
|
||||
this._audioRequest.send(null);
|
||||
},
|
||||
|
||||
/**
|
||||
* Ensures audio is stopped playing, and removes the object from memory.
|
||||
*/
|
||||
_ensureAudioStopped: function() {
|
||||
if (this._audioRequest) {
|
||||
this._audioRequest.abort();
|
||||
delete this._audioRequest;
|
||||
}
|
||||
|
||||
if (this.audio) {
|
||||
this.audio.pause();
|
||||
this.audio.removeAttribute("src");
|
||||
|
|
|
@ -99,10 +99,10 @@ loop.store = loop.store || {};
|
|||
maxRoomCreationSize: 2,
|
||||
|
||||
/**
|
||||
* The number of hours for which the room will exist.
|
||||
* The number of hours for which the room will exist - default 8 weeks
|
||||
* @type {Number}
|
||||
*/
|
||||
defaultExpiresIn: 5,
|
||||
defaultExpiresIn: 24 * 7 * 8,
|
||||
|
||||
/**
|
||||
* Internal store state representation.
|
||||
|
|
|
@ -540,6 +540,8 @@ loop.shared.views = (function(_, OT, l10n) {
|
|||
* Feedback view.
|
||||
*/
|
||||
var FeedbackView = React.createClass({displayName: 'FeedbackView',
|
||||
mixins: [sharedMixins.AudioMixin],
|
||||
|
||||
propTypes: {
|
||||
// A loop.FeedbackAPIClient instance
|
||||
feedbackApiClient: React.PropTypes.object.isRequired,
|
||||
|
@ -556,6 +558,10 @@ loop.shared.views = (function(_, OT, l10n) {
|
|||
return {step: "start"};
|
||||
},
|
||||
|
||||
componentDidMount: function() {
|
||||
this.play("terminated");
|
||||
},
|
||||
|
||||
reset: function() {
|
||||
this.setState(this.getInitialState());
|
||||
},
|
||||
|
|
|
@ -540,6 +540,8 @@ loop.shared.views = (function(_, OT, l10n) {
|
|||
* Feedback view.
|
||||
*/
|
||||
var FeedbackView = React.createClass({
|
||||
mixins: [sharedMixins.AudioMixin],
|
||||
|
||||
propTypes: {
|
||||
// A loop.FeedbackAPIClient instance
|
||||
feedbackApiClient: React.PropTypes.object.isRequired,
|
||||
|
@ -556,6 +558,10 @@ loop.shared.views = (function(_, OT, l10n) {
|
|||
return {step: "start"};
|
||||
},
|
||||
|
||||
componentDidMount: function() {
|
||||
this.play("terminated");
|
||||
},
|
||||
|
||||
reset: function() {
|
||||
this.setState(this.getInitialState());
|
||||
},
|
||||
|
|
Двоичные данные
browser/components/loop/content/shared/sounds/Firefox-Long.ogg
Двоичные данные
browser/components/loop/content/shared/sounds/Firefox-Long.ogg
Двоичный файл не отображается.
Двоичный файл не отображается.
|
@ -81,7 +81,11 @@ browser.jar:
|
|||
content/browser/loop/shared/libs/backbone-1.1.2.js (content/shared/libs/backbone-1.1.2.js)
|
||||
|
||||
# Shared sounds
|
||||
content/browser/loop/shared/sounds/Firefox-Long.ogg (content/shared/sounds/Firefox-Long.ogg)
|
||||
content/browser/loop/shared/sounds/ringtone.ogg (content/shared/sounds/ringtone.ogg)
|
||||
content/browser/loop/shared/sounds/connecting.ogg (content/shared/sounds/connecting.ogg)
|
||||
content/browser/loop/shared/sounds/connected.ogg (content/shared/sounds/connected.ogg)
|
||||
content/browser/loop/shared/sounds/terminated.ogg (content/shared/sounds/terminated.ogg)
|
||||
content/browser/loop/shared/sounds/failure.ogg (content/shared/sounds/failure.ogg)
|
||||
|
||||
# Partner SDK assets
|
||||
content/browser/loop/libs/sdk.js (content/shared/libs/sdk.js)
|
||||
|
|
|
@ -46,6 +46,7 @@
|
|||
<script type="text/javascript" src="shared/js/validate.js"></script>
|
||||
<script type="text/javascript" src="shared/js/dispatcher.js"></script>
|
||||
<script type="text/javascript" src="shared/js/websocket.js"></script>
|
||||
<script type="text/javascript" src="shared/js/activeRoomStore.js"></script>
|
||||
<script type="text/javascript" src="js/standaloneAppStore.js"></script>
|
||||
<script type="text/javascript" src="js/standaloneClient.js"></script>
|
||||
<script type="text/javascript" src="js/standaloneRoomViews.js"></script>
|
||||
|
|
|
@ -11,8 +11,42 @@ loop.standaloneRoomViews = (function() {
|
|||
"use strict";
|
||||
|
||||
var StandaloneRoomView = React.createClass({displayName: 'StandaloneRoomView',
|
||||
mixins: [Backbone.Events],
|
||||
|
||||
propTypes: {
|
||||
activeRoomStore:
|
||||
React.PropTypes.instanceOf(loop.store.ActiveRoomStore).isRequired
|
||||
},
|
||||
|
||||
getInitialState: function() {
|
||||
return this.props.activeRoomStore.getStoreState();
|
||||
},
|
||||
|
||||
componentWillMount: function() {
|
||||
this.listenTo(this.props.activeRoomStore, "change",
|
||||
this._onActiveRoomStateChanged);
|
||||
},
|
||||
|
||||
/**
|
||||
* Handles a "change" event on the roomStore, and updates this.state
|
||||
* to match the store.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
_onActiveRoomStateChanged: function() {
|
||||
this.setState(this.props.activeRoomStore.getStoreState());
|
||||
},
|
||||
|
||||
componentWillUnmount: function() {
|
||||
this.stopListening(this.props.activeRoomStore);
|
||||
},
|
||||
|
||||
render: function() {
|
||||
return (React.DOM.div(null, "Room"));
|
||||
return (
|
||||
React.DOM.div(null,
|
||||
React.DOM.div(null, this.state.roomState)
|
||||
)
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
@ -11,8 +11,42 @@ loop.standaloneRoomViews = (function() {
|
|||
"use strict";
|
||||
|
||||
var StandaloneRoomView = React.createClass({
|
||||
mixins: [Backbone.Events],
|
||||
|
||||
propTypes: {
|
||||
activeRoomStore:
|
||||
React.PropTypes.instanceOf(loop.store.ActiveRoomStore).isRequired
|
||||
},
|
||||
|
||||
getInitialState: function() {
|
||||
return this.props.activeRoomStore.getStoreState();
|
||||
},
|
||||
|
||||
componentWillMount: function() {
|
||||
this.listenTo(this.props.activeRoomStore, "change",
|
||||
this._onActiveRoomStateChanged);
|
||||
},
|
||||
|
||||
/**
|
||||
* Handles a "change" event on the roomStore, and updates this.state
|
||||
* to match the store.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
_onActiveRoomStateChanged: function() {
|
||||
this.setState(this.props.activeRoomStore.getStoreState());
|
||||
},
|
||||
|
||||
componentWillUnmount: function() {
|
||||
this.stopListening(this.props.activeRoomStore);
|
||||
},
|
||||
|
||||
render: function() {
|
||||
return (<div>Room</div>);
|
||||
return (
|
||||
<div>
|
||||
<div>{this.state.roomState}</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
@ -286,7 +286,7 @@ loop.webapp = (function($, _, OT, mozL10n) {
|
|||
},
|
||||
|
||||
_handleRingingProgress: function() {
|
||||
this.play("ringing", {loop: true});
|
||||
this.play("ringtone", {loop: true});
|
||||
this.setState({callState: "ringing"});
|
||||
},
|
||||
|
||||
|
@ -534,8 +534,6 @@ loop.webapp = (function($, _, OT, mozL10n) {
|
|||
* Ended conversation view.
|
||||
*/
|
||||
var EndedConversationView = React.createClass({displayName: 'EndedConversationView',
|
||||
mixins: [sharedMixins.AudioMixin],
|
||||
|
||||
propTypes: {
|
||||
conversation: React.PropTypes.instanceOf(sharedModels.ConversationModel)
|
||||
.isRequired,
|
||||
|
@ -544,10 +542,6 @@ loop.webapp = (function($, _, OT, mozL10n) {
|
|||
onAfterFeedbackReceived: React.PropTypes.func.isRequired
|
||||
},
|
||||
|
||||
componentDidMount: function() {
|
||||
this.play("terminated");
|
||||
},
|
||||
|
||||
render: function() {
|
||||
document.title = mozL10n.get("standalone_title_with_status",
|
||||
{clientShortname: mozL10n.get("clientShortname2"),
|
||||
|
@ -897,7 +891,9 @@ loop.webapp = (function($, _, OT, mozL10n) {
|
|||
|
||||
// XXX New types for flux style
|
||||
standaloneAppStore: React.PropTypes.instanceOf(
|
||||
loop.store.StandaloneAppStore).isRequired
|
||||
loop.store.StandaloneAppStore).isRequired,
|
||||
activeRoomStore: React.PropTypes.instanceOf(
|
||||
loop.store.ActiveRoomStore).isRequired
|
||||
},
|
||||
|
||||
getInitialState: function() {
|
||||
|
@ -939,7 +935,11 @@ loop.webapp = (function($, _, OT, mozL10n) {
|
|||
);
|
||||
}
|
||||
case "room": {
|
||||
return loop.standaloneRoomViews.StandaloneRoomView(null);
|
||||
return (
|
||||
loop.standaloneRoomViews.StandaloneRoomView({
|
||||
activeRoomStore: this.props.activeRoomStore}
|
||||
)
|
||||
);
|
||||
}
|
||||
case "home": {
|
||||
return HomeView(null);
|
||||
|
@ -989,6 +989,12 @@ loop.webapp = (function($, _, OT, mozL10n) {
|
|||
helper: helper,
|
||||
sdk: OT
|
||||
});
|
||||
var activeRoomStore = new loop.store.ActiveRoomStore({
|
||||
dispatcher: dispatcher,
|
||||
// XXX Bug 1074702 will introduce a mozLoop compatible object for
|
||||
// the standalone rooms.
|
||||
mozLoop: {}
|
||||
});
|
||||
|
||||
React.renderComponent(WebappRootView({
|
||||
client: client,
|
||||
|
@ -997,7 +1003,8 @@ loop.webapp = (function($, _, OT, mozL10n) {
|
|||
notifications: notifications,
|
||||
sdk: OT,
|
||||
feedbackApiClient: feedbackApiClient,
|
||||
standaloneAppStore: standaloneAppStore}
|
||||
standaloneAppStore: standaloneAppStore,
|
||||
activeRoomStore: activeRoomStore}
|
||||
), document.querySelector("#main"));
|
||||
|
||||
// Set the 'lang' and 'dir' attributes to <html> when the page is translated
|
||||
|
|
|
@ -286,7 +286,7 @@ loop.webapp = (function($, _, OT, mozL10n) {
|
|||
},
|
||||
|
||||
_handleRingingProgress: function() {
|
||||
this.play("ringing", {loop: true});
|
||||
this.play("ringtone", {loop: true});
|
||||
this.setState({callState: "ringing"});
|
||||
},
|
||||
|
||||
|
@ -534,8 +534,6 @@ loop.webapp = (function($, _, OT, mozL10n) {
|
|||
* Ended conversation view.
|
||||
*/
|
||||
var EndedConversationView = React.createClass({
|
||||
mixins: [sharedMixins.AudioMixin],
|
||||
|
||||
propTypes: {
|
||||
conversation: React.PropTypes.instanceOf(sharedModels.ConversationModel)
|
||||
.isRequired,
|
||||
|
@ -544,10 +542,6 @@ loop.webapp = (function($, _, OT, mozL10n) {
|
|||
onAfterFeedbackReceived: React.PropTypes.func.isRequired
|
||||
},
|
||||
|
||||
componentDidMount: function() {
|
||||
this.play("terminated");
|
||||
},
|
||||
|
||||
render: function() {
|
||||
document.title = mozL10n.get("standalone_title_with_status",
|
||||
{clientShortname: mozL10n.get("clientShortname2"),
|
||||
|
@ -897,7 +891,9 @@ loop.webapp = (function($, _, OT, mozL10n) {
|
|||
|
||||
// XXX New types for flux style
|
||||
standaloneAppStore: React.PropTypes.instanceOf(
|
||||
loop.store.StandaloneAppStore).isRequired
|
||||
loop.store.StandaloneAppStore).isRequired,
|
||||
activeRoomStore: React.PropTypes.instanceOf(
|
||||
loop.store.ActiveRoomStore).isRequired
|
||||
},
|
||||
|
||||
getInitialState: function() {
|
||||
|
@ -939,7 +935,11 @@ loop.webapp = (function($, _, OT, mozL10n) {
|
|||
);
|
||||
}
|
||||
case "room": {
|
||||
return <loop.standaloneRoomViews.StandaloneRoomView/>;
|
||||
return (
|
||||
<loop.standaloneRoomViews.StandaloneRoomView
|
||||
activeRoomStore={this.props.activeRoomStore}
|
||||
/>
|
||||
);
|
||||
}
|
||||
case "home": {
|
||||
return <HomeView />;
|
||||
|
@ -989,6 +989,12 @@ loop.webapp = (function($, _, OT, mozL10n) {
|
|||
helper: helper,
|
||||
sdk: OT
|
||||
});
|
||||
var activeRoomStore = new loop.store.ActiveRoomStore({
|
||||
dispatcher: dispatcher,
|
||||
// XXX Bug 1074702 will introduce a mozLoop compatible object for
|
||||
// the standalone rooms.
|
||||
mozLoop: {}
|
||||
});
|
||||
|
||||
React.renderComponent(<WebappRootView
|
||||
client={client}
|
||||
|
@ -998,6 +1004,7 @@ loop.webapp = (function($, _, OT, mozL10n) {
|
|||
sdk={OT}
|
||||
feedbackApiClient={feedbackApiClient}
|
||||
standaloneAppStore={standaloneAppStore}
|
||||
activeRoomStore={activeRoomStore}
|
||||
/>, document.querySelector("#main"));
|
||||
|
||||
// Set the 'lang' and 'dir' attributes to <html> when the page is translated
|
||||
|
|
|
@ -7,7 +7,7 @@ describe("loop.conversationViews", function () {
|
|||
"use strict";
|
||||
|
||||
var sharedUtils = loop.shared.utils;
|
||||
var sandbox, oldTitle, view, dispatcher, contact;
|
||||
var sandbox, oldTitle, view, dispatcher, contact, fakeAudioXHR;
|
||||
|
||||
var CALL_STATES = loop.store.CALL_STATES;
|
||||
|
||||
|
@ -30,11 +30,39 @@ describe("loop.conversationViews", function () {
|
|||
pref: true
|
||||
}]
|
||||
};
|
||||
fakeAudioXHR = {
|
||||
open: sinon.spy(),
|
||||
send: function() {},
|
||||
abort: function() {},
|
||||
getResponseHeader: function(header) {
|
||||
if (header === "Content-Type")
|
||||
return "audio/ogg";
|
||||
},
|
||||
responseType: null,
|
||||
response: new ArrayBuffer(10),
|
||||
onload: null
|
||||
};
|
||||
|
||||
navigator.mozLoop = {
|
||||
getLoopCharPref: sinon.stub().returns("http://fakeurl"),
|
||||
composeEmail: sinon.spy(),
|
||||
get appVersionInfo() {
|
||||
return {
|
||||
version: "42",
|
||||
channel: "test",
|
||||
platform: "test"
|
||||
};
|
||||
},
|
||||
getAudioBlob: sinon.spy(function(name, callback) {
|
||||
callback(null, new Blob([new ArrayBuffer(10)], {type: "audio/ogg"}));
|
||||
})
|
||||
};
|
||||
});
|
||||
|
||||
afterEach(function() {
|
||||
document.title = oldTitle;
|
||||
view = undefined;
|
||||
delete navigator.mozLoop;
|
||||
sandbox.restore();
|
||||
});
|
||||
|
||||
|
@ -202,7 +230,7 @@ describe("loop.conversationViews", function () {
|
|||
});
|
||||
|
||||
describe("CallFailedView", function() {
|
||||
var store;
|
||||
var store, fakeAudio;
|
||||
|
||||
function mountTestComponent(props) {
|
||||
return TestUtils.renderIntoDocument(
|
||||
|
@ -219,6 +247,12 @@ describe("loop.conversationViews", function () {
|
|||
client: {},
|
||||
sdkDriver: {}
|
||||
});
|
||||
fakeAudio = {
|
||||
play: sinon.spy(),
|
||||
pause: sinon.spy(),
|
||||
removeAttribute: sinon.spy()
|
||||
};
|
||||
sandbox.stub(window, "Audio").returns(fakeAudio);
|
||||
});
|
||||
|
||||
it("should dispatch a retryCall action when the retry button is pressed",
|
||||
|
@ -306,6 +340,16 @@ describe("loop.conversationViews", function () {
|
|||
|
||||
expect(view.getDOMNode().querySelector(".btn-email").disabled).eql(false);
|
||||
});
|
||||
|
||||
it("should play a failure sound, once", function() {
|
||||
view = mountTestComponent();
|
||||
|
||||
sinon.assert.calledOnce(navigator.mozLoop.getAudioBlob);
|
||||
sinon.assert.calledWithExactly(navigator.mozLoop.getAudioBlob,
|
||||
"failure", sinon.match.func);
|
||||
sinon.assert.calledOnce(fakeAudio.play);
|
||||
expect(fakeAudio.loop).to.equal(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe("OngoingConversationView", function() {
|
||||
|
@ -412,11 +456,6 @@ describe("loop.conversationViews", function () {
|
|||
}
|
||||
|
||||
beforeEach(function() {
|
||||
navigator.mozLoop = {
|
||||
getLoopCharPref: function() { return "fake"; },
|
||||
appVersionInfo: sinon.spy()
|
||||
};
|
||||
|
||||
store = new loop.store.ConversationStore({}, {
|
||||
dispatcher: dispatcher,
|
||||
client: {},
|
||||
|
@ -424,10 +463,6 @@ describe("loop.conversationViews", function () {
|
|||
});
|
||||
});
|
||||
|
||||
afterEach(function() {
|
||||
delete navigator.mozLoop;
|
||||
});
|
||||
|
||||
it("should render the CallFailedView when the call state is 'terminated'",
|
||||
function() {
|
||||
store.set({callState: CALL_STATES.TERMINATED});
|
||||
|
|
|
@ -57,7 +57,10 @@ describe("loop.conversation", function() {
|
|||
channel: "test",
|
||||
platform: "test"
|
||||
};
|
||||
}
|
||||
},
|
||||
getAudioBlob: sinon.spy(function(name, callback) {
|
||||
callback(null, new Blob([new ArrayBuffer(10)], {type: 'audio/ogg'}));
|
||||
})
|
||||
};
|
||||
|
||||
// XXX These stubs should be hoisted in a common file
|
||||
|
@ -690,8 +693,8 @@ describe("loop.conversation", function() {
|
|||
function() {
|
||||
conversation.trigger("session:network-disconnected");
|
||||
|
||||
TestUtils.findRenderedComponentWithType(icView,
|
||||
loop.conversation.GenericFailureView);
|
||||
TestUtils.findRenderedComponentWithType(icView,
|
||||
loop.conversation.GenericFailureView);
|
||||
});
|
||||
|
||||
it("should update the conversation window toolbar title",
|
||||
|
@ -747,7 +750,7 @@ describe("loop.conversation", function() {
|
|||
});
|
||||
|
||||
describe("IncomingCallView", function() {
|
||||
var view, model;
|
||||
var view, model, fakeAudio;
|
||||
|
||||
beforeEach(function() {
|
||||
var Model = Backbone.Model.extend({
|
||||
|
@ -757,6 +760,13 @@ describe("loop.conversation", function() {
|
|||
sandbox.spy(model, "trigger");
|
||||
sandbox.stub(model, "set");
|
||||
|
||||
fakeAudio = {
|
||||
play: sinon.spy(),
|
||||
pause: sinon.spy(),
|
||||
removeAttribute: sinon.spy()
|
||||
};
|
||||
sandbox.stub(window, "Audio").returns(fakeAudio);
|
||||
|
||||
view = TestUtils.renderIntoDocument(loop.conversation.IncomingCallView({
|
||||
model: model,
|
||||
video: true
|
||||
|
@ -896,4 +906,32 @@ describe("loop.conversation", function() {
|
|||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("GenericFailureView", function() {
|
||||
var view, fakeAudio;
|
||||
|
||||
beforeEach(function() {
|
||||
fakeAudio = {
|
||||
play: sinon.spy(),
|
||||
pause: sinon.spy(),
|
||||
removeAttribute: sinon.spy()
|
||||
};
|
||||
sandbox.stub(window, "Audio").returns(fakeAudio);
|
||||
|
||||
view = TestUtils.renderIntoDocument(
|
||||
loop.conversation.GenericFailureView({
|
||||
cancelCall: function() {}
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
it("should play a failure sound, once", function() {
|
||||
sinon.assert.calledOnce(navigator.mozLoop.getAudioBlob);
|
||||
sinon.assert.calledWithExactly(navigator.mozLoop.getAudioBlob,
|
||||
"failure", sinon.match.func);
|
||||
sinon.assert.calledOnce(fakeAudio.play);
|
||||
expect(fakeAudio.loop).to.equal(false);
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
|
|
|
@ -3,17 +3,32 @@ var expect = chai.expect;
|
|||
describe("loop.roomViews", function () {
|
||||
"use strict";
|
||||
|
||||
var sandbox, dispatcher, roomStore, activeRoomStore, fakeWindow, fakeMozLoop,
|
||||
fakeRoomId;
|
||||
var ROOM_STATES = loop.store.ROOM_STATES;
|
||||
|
||||
var sandbox, dispatcher, roomStore, activeRoomStore, fakeWindow;
|
||||
|
||||
beforeEach(function() {
|
||||
sandbox = sinon.sandbox.create();
|
||||
|
||||
dispatcher = new loop.Dispatcher();
|
||||
|
||||
fakeWindow = { document: {} };
|
||||
fakeWindow = {
|
||||
document: {},
|
||||
navigator: {
|
||||
mozLoop: {
|
||||
getAudioBlob: sinon.stub()
|
||||
}
|
||||
}
|
||||
};
|
||||
loop.shared.mixins.setRootObject(fakeWindow);
|
||||
|
||||
// XXX These stubs should be hoisted in a common file
|
||||
// Bug 1040968
|
||||
sandbox.stub(document.mozL10n, "get", function(x) {
|
||||
return x;
|
||||
});
|
||||
|
||||
|
||||
activeRoomStore = new loop.store.ActiveRoomStore({
|
||||
dispatcher: dispatcher,
|
||||
mozLoop: {}
|
||||
|
@ -26,11 +41,13 @@ describe("loop.roomViews", function () {
|
|||
});
|
||||
|
||||
afterEach(function() {
|
||||
sinon.sandbox.restore();
|
||||
sandbox.restore();
|
||||
loop.shared.mixins.setRootObject(window);
|
||||
});
|
||||
|
||||
describe("DesktopRoomView", function() {
|
||||
var view;
|
||||
|
||||
function mountTestComponent() {
|
||||
return TestUtils.renderIntoDocument(
|
||||
new loop.roomViews.DesktopRoomView({
|
||||
|
@ -43,10 +60,22 @@ describe("loop.roomViews", function () {
|
|||
it("should set document.title to store.serverData.roomName", function() {
|
||||
mountTestComponent();
|
||||
|
||||
activeRoomStore.setStoreState({serverData: {roomName: "fakeName"}});
|
||||
activeRoomStore.setStoreState({roomName: "fakeName"});
|
||||
|
||||
expect(fakeWindow.document.title).to.equal("fakeName");
|
||||
});
|
||||
|
||||
it("should render the GenericFailureView if the roomState is `FAILED`", function() {
|
||||
activeRoomStore.setStoreState({roomState: ROOM_STATES.FAILED});
|
||||
|
||||
view = mountTestComponent();
|
||||
|
||||
TestUtils.findRenderedComponentWithType(view,
|
||||
loop.conversation.GenericFailureView);
|
||||
});
|
||||
|
||||
// XXX Implement this when we do the rooms views in bug 1074686 and others.
|
||||
it("should display the main view");
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -6,6 +6,8 @@
|
|||
* effects - rather than just testing MozLoopAPI alone.
|
||||
*/
|
||||
|
||||
Components.utils.import("resource://gre/modules/Promise.jsm", this);
|
||||
|
||||
add_task(loadLoopPanel);
|
||||
|
||||
add_task(function* test_mozLoop_appVersionInfo() {
|
||||
|
|
|
@ -6,6 +6,8 @@
|
|||
* effects - rather than just testing MozLoopAPI alone.
|
||||
*/
|
||||
|
||||
Components.utils.import("resource://gre/modules/Promise.jsm", this);
|
||||
|
||||
add_task(loadLoopPanel);
|
||||
|
||||
add_task(function* test_mozLoop_doNotDisturb() {
|
||||
|
|
|
@ -6,6 +6,8 @@
|
|||
* effects - rather than just testing MozLoopAPI alone.
|
||||
*/
|
||||
|
||||
Components.utils.import("resource://gre/modules/Promise.jsm", this);
|
||||
|
||||
add_task(loadLoopPanel);
|
||||
|
||||
add_task(function* test_mozLoop_pluralStrings() {
|
||||
|
|
|
@ -6,6 +6,8 @@
|
|||
* effects - rather than just testing MozLoopAPI alone.
|
||||
*/
|
||||
|
||||
Components.utils.import("resource://gre/modules/Promise.jsm", this);
|
||||
|
||||
add_task(loadLoopPanel);
|
||||
|
||||
add_task(function* test_mozLoop_charPref() {
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
/*
|
||||
* This file contains tests for the mozLoop telemetry API.
|
||||
*/
|
||||
Components.utils.import("resource://gre/modules/Promise.jsm", this);
|
||||
|
||||
add_task(loadLoopPanel);
|
||||
|
||||
|
|
|
@ -7,6 +7,8 @@
|
|||
|
||||
"use strict";
|
||||
|
||||
Components.utils.import("resource://gre/modules/Promise.jsm", this);
|
||||
|
||||
registerCleanupFunction(function*() {
|
||||
MozLoopService.doNotDisturb = false;
|
||||
MozLoopServiceInternal.fxAOAuthProfile = null;
|
||||
|
|
|
@ -6,11 +6,27 @@ var sharedActions = loop.shared.actions;
|
|||
describe("loop.store.ActiveRoomStore", function () {
|
||||
"use strict";
|
||||
|
||||
var sandbox, dispatcher;
|
||||
var ROOM_STATES = loop.store.ROOM_STATES;
|
||||
var sandbox, dispatcher, store, fakeMozLoop;
|
||||
|
||||
beforeEach(function() {
|
||||
sandbox = sinon.sandbox.create();
|
||||
sandbox.useFakeTimers();
|
||||
|
||||
dispatcher = new loop.Dispatcher();
|
||||
sandbox.stub(dispatcher, "dispatch");
|
||||
|
||||
fakeMozLoop = {
|
||||
rooms: {
|
||||
get: sandbox.stub(),
|
||||
join: sandbox.stub(),
|
||||
refreshMembership: sandbox.stub(),
|
||||
leave: sandbox.stub()
|
||||
}
|
||||
};
|
||||
|
||||
store = new loop.store.ActiveRoomStore(
|
||||
{mozLoop: fakeMozLoop, dispatcher: dispatcher});
|
||||
});
|
||||
|
||||
afterEach(function() {
|
||||
|
@ -31,73 +47,96 @@ describe("loop.store.ActiveRoomStore", function () {
|
|||
});
|
||||
});
|
||||
|
||||
describe("#roomFailure", function() {
|
||||
var fakeError;
|
||||
|
||||
beforeEach(function() {
|
||||
sandbox.stub(console, "error");
|
||||
|
||||
fakeError = new Error("fake");
|
||||
|
||||
store.setStoreState({
|
||||
roomState: ROOM_STATES.READY
|
||||
});
|
||||
});
|
||||
|
||||
it("should log the error", function() {
|
||||
store.roomFailure({error: fakeError});
|
||||
|
||||
sinon.assert.calledOnce(console.error);
|
||||
sinon.assert.calledWith(console.error,
|
||||
sinon.match(ROOM_STATES.READY), fakeError);
|
||||
});
|
||||
|
||||
it("should set the state to `FAILED`", function() {
|
||||
store.roomFailure({error: fakeError});
|
||||
|
||||
expect(store._storeState.roomState).eql(ROOM_STATES.FAILED);
|
||||
});
|
||||
});
|
||||
|
||||
describe("#setupWindowData", function() {
|
||||
var store, fakeMozLoop, fakeToken, fakeRoomName;
|
||||
var fakeToken, fakeRoomData;
|
||||
|
||||
beforeEach(function() {
|
||||
fakeToken = "337-ff-54";
|
||||
fakeRoomName = "Monkeys";
|
||||
fakeMozLoop = {
|
||||
rooms: { get: sandbox.stub() }
|
||||
fakeRoomData = {
|
||||
roomName: "Monkeys",
|
||||
roomOwner: "Alfred",
|
||||
roomUrl: "http://invalid"
|
||||
};
|
||||
|
||||
store = new loop.store.ActiveRoomStore(
|
||||
{mozLoop: fakeMozLoop, dispatcher: dispatcher});
|
||||
fakeMozLoop.rooms.get.
|
||||
withArgs(fakeToken).
|
||||
callsArgOnWith(1, // index of callback argument
|
||||
store, // |this| to call it on
|
||||
null, // args to call the callback with...
|
||||
{roomName: fakeRoomName}
|
||||
fakeRoomData
|
||||
);
|
||||
});
|
||||
|
||||
it("should trigger a change event", function(done) {
|
||||
store.on("change", function() {
|
||||
done();
|
||||
});
|
||||
|
||||
dispatcher.dispatch(new sharedActions.SetupWindowData({
|
||||
windowId: "42",
|
||||
type: "room",
|
||||
roomToken: fakeToken
|
||||
}));
|
||||
});
|
||||
|
||||
it("should set roomToken on the store from the action data",
|
||||
function(done) {
|
||||
|
||||
store.once("change", function () {
|
||||
expect(store.getStoreState()).
|
||||
to.have.property('roomToken', fakeToken);
|
||||
done();
|
||||
});
|
||||
|
||||
dispatcher.dispatch(new sharedActions.SetupWindowData({
|
||||
it("should set the state to `GATHER`",
|
||||
function() {
|
||||
store.setupWindowData(new sharedActions.SetupWindowData({
|
||||
windowId: "42",
|
||||
type: "room",
|
||||
roomToken: fakeToken
|
||||
}));
|
||||
|
||||
expect(store.getStoreState()).
|
||||
to.have.property('roomState', ROOM_STATES.GATHER);
|
||||
});
|
||||
|
||||
it("should set serverData.roomName from the getRoomData callback",
|
||||
function(done) {
|
||||
|
||||
store.once("change", function () {
|
||||
expect(store.getStoreState()).to.have.deep.property(
|
||||
'serverData.roomName', fakeRoomName);
|
||||
done();
|
||||
});
|
||||
|
||||
dispatcher.dispatch(new sharedActions.SetupWindowData({
|
||||
it("should dispatch an UpdateRoomInfo action if the get is successful",
|
||||
function() {
|
||||
store.setupWindowData(new sharedActions.SetupWindowData({
|
||||
windowId: "42",
|
||||
type: "room",
|
||||
roomToken: fakeToken
|
||||
}));
|
||||
|
||||
sinon.assert.calledTwice(dispatcher.dispatch);
|
||||
sinon.assert.calledWithExactly(dispatcher.dispatch,
|
||||
new sharedActions.UpdateRoomInfo(_.extend({
|
||||
roomToken: fakeToken
|
||||
}, fakeRoomData)));
|
||||
});
|
||||
|
||||
it("should set error on the store when getRoomData calls back an error",
|
||||
function(done) {
|
||||
it("should dispatch a JoinRoom action if the get is successful",
|
||||
function() {
|
||||
store.setupWindowData(new sharedActions.SetupWindowData({
|
||||
windowId: "42",
|
||||
type: "room",
|
||||
roomToken: fakeToken
|
||||
}));
|
||||
|
||||
sinon.assert.calledTwice(dispatcher.dispatch);
|
||||
sinon.assert.calledWithExactly(dispatcher.dispatch,
|
||||
new sharedActions.JoinRoom());
|
||||
});
|
||||
|
||||
it("should dispatch a RoomFailure action if the get fails",
|
||||
function() {
|
||||
|
||||
var fakeError = new Error("fake error");
|
||||
fakeMozLoop.rooms.get.
|
||||
|
@ -106,17 +145,201 @@ describe("loop.store.ActiveRoomStore", function () {
|
|||
store, // |this| to call it on
|
||||
fakeError); // args to call the callback with...
|
||||
|
||||
store.once("change", function() {
|
||||
expect(this.getStoreState()).to.have.property('error', fakeError);
|
||||
done();
|
||||
});
|
||||
|
||||
dispatcher.dispatch(new sharedActions.SetupWindowData({
|
||||
store.setupWindowData(new sharedActions.SetupWindowData({
|
||||
windowId: "42",
|
||||
type: "room",
|
||||
roomToken: fakeToken
|
||||
}));
|
||||
});
|
||||
|
||||
sinon.assert.calledOnce(dispatcher.dispatch);
|
||||
sinon.assert.calledWithExactly(dispatcher.dispatch,
|
||||
new sharedActions.RoomFailure({
|
||||
error: fakeError
|
||||
}));
|
||||
});
|
||||
});
|
||||
|
||||
describe("#updateRoomInfo", function() {
|
||||
var fakeRoomInfo;
|
||||
|
||||
beforeEach(function() {
|
||||
fakeRoomInfo = {
|
||||
roomName: "Its a room",
|
||||
roomOwner: "Me",
|
||||
roomToken: "fakeToken",
|
||||
roomUrl: "http://invalid"
|
||||
};
|
||||
});
|
||||
|
||||
it("should set the state to READY", function() {
|
||||
store.updateRoomInfo(fakeRoomInfo);
|
||||
|
||||
expect(store._storeState.roomState).eql(ROOM_STATES.READY);
|
||||
});
|
||||
|
||||
it("should save the room information", function() {
|
||||
store.updateRoomInfo(fakeRoomInfo);
|
||||
|
||||
var state = store.getStoreState();
|
||||
expect(state.roomName).eql(fakeRoomInfo.roomName);
|
||||
expect(state.roomOwner).eql(fakeRoomInfo.roomOwner);
|
||||
expect(state.roomToken).eql(fakeRoomInfo.roomToken);
|
||||
expect(state.roomUrl).eql(fakeRoomInfo.roomUrl);
|
||||
});
|
||||
});
|
||||
|
||||
describe("#joinRoom", function() {
|
||||
beforeEach(function() {
|
||||
store.setStoreState({roomToken: "tokenFake"});
|
||||
});
|
||||
|
||||
it("should call rooms.join on mozLoop", function() {
|
||||
store.joinRoom();
|
||||
|
||||
sinon.assert.calledOnce(fakeMozLoop.rooms.join);
|
||||
sinon.assert.calledWith(fakeMozLoop.rooms.join, "tokenFake");
|
||||
});
|
||||
|
||||
it("should dispatch `JoinedRoom` on success", function() {
|
||||
var responseData = {
|
||||
apiKey: "keyFake",
|
||||
sessionToken: "14327659860",
|
||||
sessionId: "1357924680",
|
||||
expires: 8
|
||||
};
|
||||
|
||||
fakeMozLoop.rooms.join.callsArgWith(1, null, responseData);
|
||||
|
||||
store.joinRoom();
|
||||
|
||||
sinon.assert.calledOnce(dispatcher.dispatch);
|
||||
sinon.assert.calledWith(dispatcher.dispatch,
|
||||
new sharedActions.JoinedRoom(responseData));
|
||||
});
|
||||
|
||||
it("should dispatch `RoomFailure` on error", function() {
|
||||
var fakeError = new Error("fake");
|
||||
|
||||
fakeMozLoop.rooms.join.callsArgWith(1, fakeError);
|
||||
|
||||
store.joinRoom();
|
||||
|
||||
sinon.assert.calledOnce(dispatcher.dispatch);
|
||||
sinon.assert.calledWith(dispatcher.dispatch,
|
||||
new sharedActions.RoomFailure({error: fakeError}));
|
||||
});
|
||||
});
|
||||
|
||||
describe("#joinedRoom", function() {
|
||||
var fakeJoinedData;
|
||||
|
||||
beforeEach(function() {
|
||||
fakeJoinedData = {
|
||||
apiKey: "9876543210",
|
||||
sessionToken: "12563478",
|
||||
sessionId: "15263748",
|
||||
expires: 20
|
||||
};
|
||||
|
||||
store.setStoreState({
|
||||
roomToken: "fakeToken"
|
||||
});
|
||||
});
|
||||
|
||||
it("should set the state to `JOINED`", function() {
|
||||
store.joinedRoom(fakeJoinedData);
|
||||
|
||||
expect(store._storeState.roomState).eql(ROOM_STATES.JOINED);
|
||||
});
|
||||
|
||||
it("should store the session and api values", function() {
|
||||
store.joinedRoom(fakeJoinedData);
|
||||
|
||||
var state = store.getStoreState();
|
||||
expect(state.apiKey).eql(fakeJoinedData.apiKey);
|
||||
expect(state.sessionToken).eql(fakeJoinedData.sessionToken);
|
||||
expect(state.sessionId).eql(fakeJoinedData.sessionId);
|
||||
});
|
||||
|
||||
it("should call mozLoop.rooms.refreshMembership before the expiresTime",
|
||||
function() {
|
||||
store.joinedRoom(fakeJoinedData);
|
||||
|
||||
sandbox.clock.tick(fakeJoinedData.expires * 1000);
|
||||
|
||||
sinon.assert.calledOnce(fakeMozLoop.rooms.refreshMembership);
|
||||
sinon.assert.calledWith(fakeMozLoop.rooms.refreshMembership,
|
||||
"fakeToken", "12563478");
|
||||
});
|
||||
|
||||
it("should call mozLoop.rooms.refreshMembership before the next expiresTime",
|
||||
function() {
|
||||
fakeMozLoop.rooms.refreshMembership.callsArgWith(2,
|
||||
null, {expires: 40});
|
||||
|
||||
store.joinedRoom(fakeJoinedData);
|
||||
|
||||
// Clock tick for the first expiry time (which
|
||||
// sets up the refreshMembership).
|
||||
sandbox.clock.tick(fakeJoinedData.expires * 1000);
|
||||
|
||||
// Clock tick for expiry time in the refresh membership response.
|
||||
sandbox.clock.tick(40000);
|
||||
|
||||
sinon.assert.calledTwice(fakeMozLoop.rooms.refreshMembership);
|
||||
sinon.assert.calledWith(fakeMozLoop.rooms.refreshMembership,
|
||||
"fakeToken", "12563478");
|
||||
});
|
||||
|
||||
it("should dispatch `RoomFailure` if the refreshMembership call failed",
|
||||
function() {
|
||||
var fakeError = new Error("fake");
|
||||
fakeMozLoop.rooms.refreshMembership.callsArgWith(2, fakeError);
|
||||
|
||||
store.joinedRoom(fakeJoinedData);
|
||||
|
||||
// Clock tick for the first expiry time (which
|
||||
// sets up the refreshMembership).
|
||||
sandbox.clock.tick(fakeJoinedData.expires * 1000);
|
||||
|
||||
sinon.assert.calledOnce(dispatcher.dispatch);
|
||||
sinon.assert.calledWith(dispatcher.dispatch,
|
||||
new sharedActions.RoomFailure({
|
||||
error: fakeError
|
||||
}));
|
||||
});
|
||||
});
|
||||
|
||||
describe("#windowUnload", function() {
|
||||
beforeEach(function() {
|
||||
store.setStoreState({
|
||||
roomState: ROOM_STATES.JOINED,
|
||||
roomToken: "fakeToken",
|
||||
sessionToken: "1627384950"
|
||||
});
|
||||
});
|
||||
|
||||
it("should clear any existing timeout", function() {
|
||||
sandbox.stub(window, "clearTimeout");
|
||||
store._timeout = {};
|
||||
|
||||
store.windowUnload();
|
||||
|
||||
sinon.assert.calledOnce(clearTimeout);
|
||||
});
|
||||
|
||||
it("should call mozLoop.rooms.leave", function() {
|
||||
store.windowUnload();
|
||||
|
||||
sinon.assert.calledOnce(fakeMozLoop.rooms.leave);
|
||||
sinon.assert.calledWithExactly(fakeMozLoop.rooms.leave,
|
||||
"fakeToken", "1627384950");
|
||||
});
|
||||
|
||||
it("should set the state to ready", function() {
|
||||
store.windowUnload();
|
||||
|
||||
expect(store._storeState.roomState).eql(ROOM_STATES.READY);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -15,7 +15,7 @@ describe("loop.shared.views", function() {
|
|||
var sharedModels = loop.shared.models,
|
||||
sharedViews = loop.shared.views,
|
||||
getReactElementByClass = TestUtils.findRenderedDOMComponentWithClass,
|
||||
sandbox;
|
||||
sandbox, fakeAudioXHR;
|
||||
|
||||
beforeEach(function() {
|
||||
sandbox = sinon.sandbox.create();
|
||||
|
@ -23,6 +23,18 @@ describe("loop.shared.views", function() {
|
|||
sandbox.stub(l10n, "get", function(x) {
|
||||
return "translated:" + x;
|
||||
});
|
||||
fakeAudioXHR = {
|
||||
open: sinon.spy(),
|
||||
send: function() {},
|
||||
abort: function() {},
|
||||
getResponseHeader: function(header) {
|
||||
if (header === "Content-Type")
|
||||
return "audio/ogg";
|
||||
},
|
||||
responseType: null,
|
||||
response: new ArrayBuffer(10),
|
||||
onload: null
|
||||
};
|
||||
});
|
||||
|
||||
afterEach(function() {
|
||||
|
@ -368,16 +380,55 @@ describe("loop.shared.views", function() {
|
|||
|
||||
it("should play a connected sound, once, on session:connected",
|
||||
function() {
|
||||
var url = "shared/sounds/connected.ogg";
|
||||
sandbox.stub(window, "XMLHttpRequest").returns(fakeAudioXHR);
|
||||
model.trigger("session:connected");
|
||||
|
||||
sinon.assert.calledOnce(window.Audio);
|
||||
sinon.assert.calledWithExactly(
|
||||
window.Audio, "shared/sounds/connected.ogg");
|
||||
fakeAudioXHR.onload();
|
||||
|
||||
sinon.assert.called(fakeAudioXHR.open);
|
||||
sinon.assert.calledWithExactly(fakeAudioXHR.open, "GET", url, true);
|
||||
|
||||
sinon.assert.calledOnce(fakeAudio.play);
|
||||
expect(fakeAudio.loop).to.not.equal(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe("for desktop", function() {
|
||||
var origMozLoop;
|
||||
|
||||
beforeEach(function() {
|
||||
origMozLoop = navigator.mozLoop;
|
||||
navigator.mozLoop = {
|
||||
getAudioBlob: sinon.spy(function(name, callback) {
|
||||
var data = new ArrayBuffer(10);
|
||||
callback(null, new Blob([data], {type: "audio/ogg"}));
|
||||
})
|
||||
};
|
||||
});
|
||||
|
||||
afterEach(function() {
|
||||
navigator.mozLoop = origMozLoop;
|
||||
});
|
||||
|
||||
it("should play a connected sound, once, on session:connected",
|
||||
function() {
|
||||
var url = "chrome://browser/content/loop/shared/sounds/connected.ogg";
|
||||
model.trigger("session:connected");
|
||||
|
||||
sinon.assert.calledOnce(navigator.mozLoop.getAudioBlob);
|
||||
sinon.assert.calledWithExactly(navigator.mozLoop.getAudioBlob,
|
||||
"connected", sinon.match.func);
|
||||
sinon.assert.calledOnce(fakeAudio.play);
|
||||
expect(fakeAudio.loop).to.not.equal(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe("for both (standalone and desktop)", function() {
|
||||
beforeEach(function() {
|
||||
sandbox.stub(window, "XMLHttpRequest").returns(fakeAudioXHR);
|
||||
});
|
||||
|
||||
it("should start streaming on session:connected", function() {
|
||||
model.trigger("session:connected");
|
||||
|
||||
|
@ -458,6 +509,7 @@ describe("loop.shared.views", function() {
|
|||
|
||||
beforeEach(function() {
|
||||
fakeFeedbackApiClient = {send: sandbox.stub()};
|
||||
sandbox.stub(window, "XMLHttpRequest").returns(fakeAudioXHR);
|
||||
comp = TestUtils.renderIntoDocument(sharedViews.FeedbackView({
|
||||
feedbackApiClient: fakeFeedbackApiClient
|
||||
}));
|
||||
|
|
|
@ -40,6 +40,7 @@
|
|||
<script src="../../content/shared/js/actions.js"></script>
|
||||
<script src="../../content/shared/js/validate.js"></script>
|
||||
<script src="../../content/shared/js/dispatcher.js"></script>
|
||||
<script src="../../content/shared/js/activeRoomStore.js"></script>
|
||||
<script src="../../standalone/content/js/multiplexGum.js"></script>
|
||||
<script src="../../standalone/content/js/standaloneAppStore.js"></script>
|
||||
<script src="../../standalone/content/js/standaloneClient.js"></script>
|
||||
|
|
|
@ -18,7 +18,8 @@ describe("loop.webapp", function() {
|
|||
sandbox,
|
||||
notifications,
|
||||
feedbackApiClient,
|
||||
stubGetPermsAndCacheMedia;
|
||||
stubGetPermsAndCacheMedia,
|
||||
fakeAudioXHR;
|
||||
|
||||
beforeEach(function() {
|
||||
sandbox = sinon.sandbox.create();
|
||||
|
@ -29,6 +30,19 @@ describe("loop.webapp", function() {
|
|||
|
||||
stubGetPermsAndCacheMedia = sandbox.stub(
|
||||
loop.standaloneMedia._MultiplexGum.prototype, "getPermsAndCacheMedia");
|
||||
|
||||
fakeAudioXHR = {
|
||||
open: sinon.spy(),
|
||||
send: function() {},
|
||||
abort: function() {},
|
||||
getResponseHeader: function(header) {
|
||||
if (header === "Content-Type")
|
||||
return "audio/ogg";
|
||||
},
|
||||
responseType: null,
|
||||
response: new ArrayBuffer(10),
|
||||
onload: null
|
||||
};
|
||||
});
|
||||
|
||||
afterEach(function() {
|
||||
|
@ -219,6 +233,7 @@ describe("loop.webapp", function() {
|
|||
describe("state: terminate, reason: reject", function() {
|
||||
beforeEach(function() {
|
||||
sandbox.stub(notifications, "errorL10n");
|
||||
sandbox.stub(window, "XMLHttpRequest").returns(fakeAudioXHR);
|
||||
});
|
||||
|
||||
it("should display the FailedConversationView", function() {
|
||||
|
@ -307,6 +322,7 @@ describe("loop.webapp", function() {
|
|||
promiseConnectStub =
|
||||
sandbox.stub(loop.CallConnectionWebSocket.prototype, "promiseConnect");
|
||||
promiseConnectStub.returns(new Promise(function(resolve, reject) {}));
|
||||
sandbox.stub(window, "XMLHttpRequest").returns(fakeAudioXHR);
|
||||
});
|
||||
|
||||
describe("call:outgoing", function() {
|
||||
|
@ -526,6 +542,8 @@ describe("loop.webapp", function() {
|
|||
var view, conversation, client, fakeAudio;
|
||||
|
||||
beforeEach(function() {
|
||||
sandbox.stub(window, "XMLHttpRequest").returns(fakeAudioXHR);
|
||||
|
||||
fakeAudio = {
|
||||
play: sinon.spy(),
|
||||
pause: sinon.spy(),
|
||||
|
@ -541,6 +559,7 @@ describe("loop.webapp", function() {
|
|||
});
|
||||
conversation.set("loopToken", "fakeToken");
|
||||
|
||||
sandbox.stub(client, "requestCallUrlInfo");
|
||||
view = React.addons.TestUtils.renderIntoDocument(
|
||||
loop.webapp.FailedConversationView({
|
||||
conversation: conversation,
|
||||
|
@ -550,9 +569,12 @@ describe("loop.webapp", function() {
|
|||
});
|
||||
|
||||
it("should play a failure sound, once", function() {
|
||||
sinon.assert.calledOnce(window.Audio);
|
||||
sinon.assert.calledWithExactly(window.Audio,
|
||||
"shared/sounds/failure.ogg");
|
||||
fakeAudioXHR.onload();
|
||||
|
||||
sinon.assert.called(fakeAudioXHR.open);
|
||||
sinon.assert.calledWithExactly(
|
||||
fakeAudioXHR.open, "GET", "shared/sounds/failure.ogg", true);
|
||||
sinon.assert.calledOnce(fakeAudio.play);
|
||||
expect(fakeAudio.loop).to.equal(false);
|
||||
});
|
||||
});
|
||||
|
@ -560,7 +582,7 @@ describe("loop.webapp", function() {
|
|||
|
||||
describe("WebappRootView", function() {
|
||||
var helper, sdk, conversationModel, client, props, standaloneAppStore;
|
||||
var dispatcher;
|
||||
var dispatcher, activeRoomStore;
|
||||
|
||||
function mountTestComponent() {
|
||||
return TestUtils.renderIntoDocument(
|
||||
|
@ -571,7 +593,8 @@ describe("loop.webapp", function() {
|
|||
sdk: sdk,
|
||||
conversation: conversationModel,
|
||||
feedbackApiClient: feedbackApiClient,
|
||||
standaloneAppStore: standaloneAppStore
|
||||
standaloneAppStore: standaloneAppStore,
|
||||
activeRoomStore: activeRoomStore
|
||||
}));
|
||||
}
|
||||
|
||||
|
@ -587,6 +610,10 @@ describe("loop.webapp", function() {
|
|||
baseServerUrl: "fakeUrl"
|
||||
});
|
||||
dispatcher = new loop.Dispatcher();
|
||||
activeRoomStore = new loop.store.ActiveRoomStore({
|
||||
dispatcher: dispatcher,
|
||||
mozLoop: {}
|
||||
});
|
||||
standaloneAppStore = new loop.store.StandaloneAppStore({
|
||||
dispatcher: dispatcher,
|
||||
sdk: sdk,
|
||||
|
@ -678,6 +705,7 @@ describe("loop.webapp", function() {
|
|||
removeAttribute: sinon.spy()
|
||||
};
|
||||
sandbox.stub(window, "Audio").returns(fakeAudio);
|
||||
sandbox.stub(window, "XMLHttpRequest").returns(fakeAudioXHR);
|
||||
|
||||
view = React.addons.TestUtils.renderIntoDocument(
|
||||
loop.webapp.PendingConversationView({
|
||||
|
@ -689,8 +717,12 @@ describe("loop.webapp", function() {
|
|||
describe("#componentDidMount", function() {
|
||||
|
||||
it("should play a looped connecting sound", function() {
|
||||
sinon.assert.calledOnce(window.Audio);
|
||||
sinon.assert.calledWithExactly(window.Audio, "shared/sounds/connecting.ogg");
|
||||
fakeAudioXHR.onload();
|
||||
|
||||
sinon.assert.called(fakeAudioXHR.open);
|
||||
sinon.assert.calledWithExactly(
|
||||
fakeAudioXHR.open, "GET", "shared/sounds/connecting.ogg", true);
|
||||
sinon.assert.calledOnce(fakeAudio.play);
|
||||
expect(fakeAudio.loop).to.equal(true);
|
||||
});
|
||||
|
||||
|
@ -727,8 +759,13 @@ describe("loop.webapp", function() {
|
|||
|
||||
it("should play a looped ringing sound", function() {
|
||||
websocket.trigger("progress:alerting");
|
||||
fakeAudioXHR.onload();
|
||||
|
||||
sinon.assert.calledWithExactly(window.Audio, "shared/sounds/ringing.ogg");
|
||||
sinon.assert.called(fakeAudioXHR.open);
|
||||
sinon.assert.calledWithExactly(
|
||||
fakeAudioXHR.open, "GET", "shared/sounds/ringtone.ogg", true);
|
||||
|
||||
sinon.assert.called(fakeAudio.play);
|
||||
expect(fakeAudio.loop).to.equal(true);
|
||||
});
|
||||
});
|
||||
|
@ -997,6 +1034,7 @@ describe("loop.webapp", function() {
|
|||
conversation = new sharedModels.ConversationModel({}, {
|
||||
sdk: {}
|
||||
});
|
||||
sandbox.stub(window, "XMLHttpRequest").returns(fakeAudioXHR);
|
||||
view = React.addons.TestUtils.renderIntoDocument(
|
||||
loop.webapp.EndedConversationView({
|
||||
conversation: conversation,
|
||||
|
@ -1018,8 +1056,13 @@ describe("loop.webapp", function() {
|
|||
describe("#componentDidMount", function() {
|
||||
|
||||
it("should play a terminating sound, once", function() {
|
||||
sinon.assert.calledOnce(window.Audio);
|
||||
sinon.assert.calledWithExactly(window.Audio, "shared/sounds/terminated.ogg");
|
||||
fakeAudioXHR.onload();
|
||||
|
||||
sinon.assert.called(fakeAudioXHR.open);
|
||||
sinon.assert.calledWithExactly(
|
||||
fakeAudioXHR.open, "GET", "shared/sounds/terminated.ogg", true);
|
||||
|
||||
sinon.assert.calledOnce(fakeAudio.play);
|
||||
expect(fakeAudio.loop).to.not.equal(true);
|
||||
});
|
||||
|
||||
|
|
|
@ -212,7 +212,16 @@ add_task(function* setup_server() {
|
|||
// Add a request handler for each room in the list.
|
||||
[...kRooms.values()].forEach(function(room) {
|
||||
loopServer.registerPathHandler("/rooms/" + encodeURIComponent(room.roomToken), (req, res) => {
|
||||
returnRoomDetails(res, room.roomName);
|
||||
if (req.method == "POST") {
|
||||
let body = CommonUtils.readBytesFromInputStream(req.bodyInputStream);
|
||||
let data = JSON.parse(body);
|
||||
res.setStatusLine(null, 200, "OK");
|
||||
res.write(JSON.stringify(data));
|
||||
res.processAsync();
|
||||
res.finish();
|
||||
} else {
|
||||
returnRoomDetails(res, room.roomName);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -321,6 +330,39 @@ add_task(function* test_roomUpdates() {
|
|||
yield waitForCondition(() => Object.getOwnPropertyNames(gExpectedJoins).length === 0);
|
||||
});
|
||||
|
||||
// Test if joining a room works as expected.
|
||||
add_task(function* test_joinRoom() {
|
||||
// We need these set up for getting the email address.
|
||||
Services.prefs.setCharPref("loop.fxa_oauth.profile", JSON.stringify({
|
||||
email: "fake@invalid.com"
|
||||
}));
|
||||
Services.prefs.setCharPref("loop.fxa_oauth.tokendata", JSON.stringify({
|
||||
token_type: "bearer"
|
||||
}));
|
||||
|
||||
let roomToken = "_nxD4V4FflQ";
|
||||
let joinedData = yield LoopRooms.promise("join", roomToken);
|
||||
Assert.equal(joinedData.action, "join");
|
||||
Assert.equal(joinedData.displayName, "fake@invalid.com");
|
||||
});
|
||||
|
||||
// Test if refreshing a room works as expected.
|
||||
add_task(function* test_refreshMembership() {
|
||||
let roomToken = "_nxD4V4FflQ";
|
||||
let refreshedData = yield LoopRooms.promise("refreshMembership", roomToken,
|
||||
"fakeSessionToken");
|
||||
Assert.equal(refreshedData.action, "refresh");
|
||||
Assert.equal(refreshedData.sessionToken, "fakeSessionToken");
|
||||
});
|
||||
|
||||
// Test if leaving a room works as expected.
|
||||
add_task(function* test_leaveRoom() {
|
||||
let roomToken = "_nxD4V4FflQ";
|
||||
let leaveData = yield LoopRooms.promise("leave", roomToken, "fakeLeaveSessionToken");
|
||||
Assert.equal(leaveData.action, "leave");
|
||||
Assert.equal(leaveData.sessionToken, "fakeLeaveSessionToken");
|
||||
});
|
||||
|
||||
// Test if the event emitter implementation doesn't leak and is working as expected.
|
||||
add_task(function* () {
|
||||
Assert.strictEqual(gExpectedAdds.length, 0, "No room additions should be expected anymore");
|
||||
|
@ -339,6 +381,9 @@ function run_test() {
|
|||
// Revert original Chat.open implementation
|
||||
Chat.open = openChatOrig;
|
||||
|
||||
Services.prefs.clearUserPref("loop.fxa_oauth.profile");
|
||||
Services.prefs.clearUserPref("loop.fxa_oauth.tokendata");
|
||||
|
||||
LoopRooms.off("add", onRoomAdded);
|
||||
LoopRooms.off("update", onRoomUpdated);
|
||||
LoopRooms.off("joined", onRoomJoined);
|
||||
|
|
|
@ -2411,7 +2411,7 @@ let DefaultBrowserCheck = {
|
|||
let E10SUINotification = {
|
||||
// Increase this number each time we want to roll out an
|
||||
// e10s testing period to Nightly users.
|
||||
CURRENT_NOTICE_COUNT: 1,
|
||||
CURRENT_NOTICE_COUNT: 2,
|
||||
CURRENT_PROMPT_PREF: "browser.displayedE10SPrompt.1",
|
||||
PREVIOUS_PROMPT_PREF: "browser.displayedE10SPrompt",
|
||||
|
||||
|
@ -2514,7 +2514,7 @@ let E10SUINotification = {
|
|||
Services.prefs.setIntPref("browser.displayedE10SNotice", this.CURRENT_NOTICE_COUNT);
|
||||
|
||||
let nb = win.document.getElementById("high-priority-global-notificationbox");
|
||||
let message = "Thanks for helping to test multiprocess Firefox (e10s). Some functions might not work yet."
|
||||
let message = "You're now helping to test Process Separation (e10s)! Please report problems you find.";
|
||||
let buttons = [
|
||||
{
|
||||
label: "Learn More",
|
||||
|
|
|
@ -92,9 +92,32 @@ var gMainPane = {
|
|||
setEventListener("e10sAutoStart", "command",
|
||||
gMainPane.enableE10SChange);
|
||||
let e10sCheckbox = document.getElementById("e10sAutoStart");
|
||||
let e10sPref = document.getElementById("browser.tabs.remote.autostart");
|
||||
let e10sTempPref = document.getElementById("e10sTempPref");
|
||||
e10sCheckbox.checked = e10sPref.value || e10sTempPref.value;
|
||||
e10sCheckbox.checked = Services.appinfo.browserTabsRemoteAutostart;
|
||||
|
||||
// If e10s is blocked for some reason unrelated to prefs, we want to disable
|
||||
// the checkbox.
|
||||
if (!Services.appinfo.browserTabsRemoteAutostart) {
|
||||
let e10sBlockedReason = Cc["@mozilla.org/supports-string;1"].createInstance(Ci.nsISupportsString);
|
||||
let appinfo = Services.appinfo.QueryInterface(Ci.nsIObserver);
|
||||
appinfo.observe(e10sBlockedReason, "getE10SBlocked", "")
|
||||
if (e10sBlockedReason.data) {
|
||||
if (e10sBlockedReason.data == "Safe mode") {
|
||||
// If the only reason we're disabled is because of safe mode, then
|
||||
// we want to allow the user to un-toggle the pref.
|
||||
// We're relying on the nsAppRunner code only specifying "Safe mode"
|
||||
// as the reason if the pref is otherwise enabled, and there are no
|
||||
// other reasons to block e10s.
|
||||
// Update the checkbox to reflect the pref state.
|
||||
e10sCheckbox.checked = true;
|
||||
} else {
|
||||
e10sCheckbox.disabled = true;
|
||||
e10sCheckbox.label += " (disabled: " + e10sBlockedReason.data + ")";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If E10S is blocked because of safe mode, we want the checkbox to be
|
||||
// enabled
|
||||
#endif
|
||||
|
||||
#ifdef MOZ_DEV_EDITION
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
// This test makes sure that the URL bar is focused when entering the private window.
|
||||
|
||||
"use strict";
|
||||
Components.utils.import("resource://gre/modules/Promise.jsm", this);
|
||||
|
||||
function checkUrlbarFocus(win) {
|
||||
let urlbar = win.gURLBar;
|
||||
|
|
|
@ -198,7 +198,7 @@ ContentRestoreInternal.prototype = {
|
|||
}
|
||||
let referrer = loadArguments.referrer ?
|
||||
Utils.makeURI(loadArguments.referrer) : null;
|
||||
webNavigation.loadURI(loadArguments.uri, loadArguments.loadFlags,
|
||||
webNavigation.loadURI(loadArguments.uri, loadArguments.flags,
|
||||
referrer, null, null);
|
||||
} else if (tabData.userTypedValue && tabData.userTypedClear) {
|
||||
// If the user typed a URL into the URL bar and hit enter right before
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
Components.utils.import("resource://gre/modules/Promise.jsm", this);
|
||||
|
||||
function test() {
|
||||
waitForExplicitFinish();
|
||||
newWindowWithTabView(onTabViewWindowLoaded);
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
Components.utils.import("resource://gre/modules/Promise.jsm", this);
|
||||
|
||||
function test() {
|
||||
let cw;
|
||||
let win;
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
Components.utils.import("resource://gre/modules/Promise.jsm", this);
|
||||
|
||||
function test() {
|
||||
let cw;
|
||||
let win;
|
||||
|
|
|
@ -15,6 +15,8 @@ const TEST_URL = 'data:text/html,<script>window.onbeforeunload=' +
|
|||
let contentWindow;
|
||||
let activeGroup;
|
||||
|
||||
Components.utils.import("resource://gre/modules/Promise.jsm", this);
|
||||
|
||||
function test() {
|
||||
waitForExplicitFinish();
|
||||
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
Components.utils.import("resource://gre/modules/Promise.jsm", this);
|
||||
|
||||
function test() {
|
||||
waitForExplicitFinish();
|
||||
|
||||
|
|
|
@ -3,6 +3,8 @@
|
|||
|
||||
let cw;
|
||||
|
||||
Components.utils.import("resource://gre/modules/Promise.jsm", this);
|
||||
|
||||
function test() {
|
||||
requestLongerTimeout(2);
|
||||
waitForExplicitFinish();
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
Components.utils.import("resource://gre/modules/Promise.jsm", this);
|
||||
|
||||
function test() {
|
||||
waitForExplicitFinish();
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
Components.utils.import("resource://gre/modules/Promise.jsm", this);
|
||||
|
||||
const STATE = {
|
||||
windows: [{
|
||||
|
|
|
@ -14,28 +14,29 @@ function test() {
|
|||
|
||||
info("highlighting the body node");
|
||||
yield runCommand("highlight body", options);
|
||||
is(getHighlighters().length, 1, "The highlighter element exists for body");
|
||||
is(getHighlighterNumber(), 1, "The highlighter element exists for body");
|
||||
|
||||
info("highlighting the div node");
|
||||
yield runCommand("highlight div", options);
|
||||
is(getHighlighters().length, 1, "The highlighter element exists for div");
|
||||
is(getHighlighterNumber(), 1, "The highlighter element exists for div");
|
||||
|
||||
info("highlighting the body node again, asking to keep the div");
|
||||
yield runCommand("highlight body --keep", options);
|
||||
is(getHighlighters().length, 2, "2 highlighter elements have been created");
|
||||
is(getHighlighterNumber(), 2, "2 highlighter elements have been created");
|
||||
|
||||
info("unhighlighting all nodes");
|
||||
yield runCommand("unhighlight", options);
|
||||
is(getHighlighters().length, 0, "All highlighters have been removed");
|
||||
is(getHighlighterNumber(), 0, "All highlighters have been removed");
|
||||
|
||||
yield helpers.closeToolbar(options);
|
||||
yield helpers.closeTab(options);
|
||||
}).then(finish, helpers.handleError);
|
||||
}
|
||||
|
||||
function getHighlighters() {
|
||||
return gBrowser.selectedBrowser.parentNode
|
||||
.querySelectorAll(".highlighter-container");
|
||||
function getHighlighterNumber() {
|
||||
// Note that this only works as long as gcli tests aren't run with e10s on.
|
||||
// To make this e10s ready, execute this in a content frame script instead.
|
||||
return require("gcli/commands/highlight").highlighters.length;
|
||||
}
|
||||
|
||||
function* runCommand(cmd, options) {
|
||||
|
|
|
@ -215,6 +215,8 @@ let DebuggerController = {
|
|||
yield this._startTracingTab(traceActor);
|
||||
}
|
||||
}
|
||||
|
||||
this._hideUnsupportedFeatures();
|
||||
}),
|
||||
|
||||
/**
|
||||
|
@ -231,6 +233,16 @@ let DebuggerController = {
|
|||
this.activeThread = null;
|
||||
},
|
||||
|
||||
_hideUnsupportedFeatures: function() {
|
||||
if (this.client.mainRoot.traits.noPrettyPrinting) {
|
||||
DebuggerView.Sources.hidePrettyPrinting();
|
||||
}
|
||||
|
||||
if (this.client.mainRoot.traits.noBlackBoxing) {
|
||||
DebuggerView.Sources.hideBlackBoxing();
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Called for each location change in the debugged tab.
|
||||
*
|
||||
|
|
|
@ -546,6 +546,24 @@ SourcesView.prototype = Heritage.extend(WidgetMethods, {
|
|||
}
|
||||
},
|
||||
|
||||
hidePrettyPrinting: function() {
|
||||
this._prettyPrintButton.style.display = 'none';
|
||||
|
||||
if (this._blackBoxButton.style.display === 'none') {
|
||||
let sep = document.querySelector('#sources-toolbar .devtools-separator');
|
||||
sep.style.display = 'none';
|
||||
}
|
||||
},
|
||||
|
||||
hideBlackBoxing: function() {
|
||||
this._blackBoxButton.style.display = 'none';
|
||||
|
||||
if (this._prettyPrintButton.style.display === 'none') {
|
||||
let sep = document.querySelector('#sources-toolbar .devtools-separator');
|
||||
sep.style.display = 'none';
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Marks a breakpoint as selected in this sources container.
|
||||
*
|
||||
|
|
|
@ -134,19 +134,19 @@ skip-if = e10s
|
|||
[browser_dbg_break-on-dom-01.js]
|
||||
skip-if = e10s
|
||||
[browser_dbg_break-on-dom-02.js]
|
||||
skip-if = e10s
|
||||
skip-if = e10s && debug
|
||||
[browser_dbg_break-on-dom-03.js]
|
||||
skip-if = e10s
|
||||
skip-if = e10s && debug
|
||||
[browser_dbg_break-on-dom-04.js]
|
||||
skip-if = e10s
|
||||
skip-if = e10s && debug
|
||||
[browser_dbg_break-on-dom-05.js]
|
||||
skip-if = e10s
|
||||
skip-if = e10s && debug
|
||||
[browser_dbg_break-on-dom-06.js]
|
||||
skip-if = e10s
|
||||
skip-if = e10s && debug
|
||||
[browser_dbg_break-on-dom-07.js]
|
||||
skip-if = e10s
|
||||
skip-if = e10s && debug
|
||||
[browser_dbg_break-on-dom-08.js]
|
||||
skip-if = e10s
|
||||
skip-if = e10s && debug
|
||||
[browser_dbg_break-on-dom-event-01.js]
|
||||
skip-if = e10s || os == "mac" || e10s # Bug 895426
|
||||
[browser_dbg_break-on-dom-event-02.js]
|
||||
|
@ -235,6 +235,8 @@ skip-if = e10s
|
|||
skip-if = e10s
|
||||
[browser_dbg_globalactor.js]
|
||||
skip-if = e10s
|
||||
[browser_dbg_hide-toolbar-buttons.js]
|
||||
skip-if = e10s
|
||||
[browser_dbg_hit-counts-01.js]
|
||||
skip-if = e10s
|
||||
[browser_dbg_hit-counts-02.js]
|
||||
|
@ -308,33 +310,33 @@ skip-if = e10s
|
|||
[browser_dbg_paused-keybindings.js]
|
||||
skip-if = e10s
|
||||
[browser_dbg_pretty-print-01.js]
|
||||
skip-if = e10s
|
||||
skip-if = e10s && debug
|
||||
[browser_dbg_pretty-print-02.js]
|
||||
skip-if = e10s
|
||||
skip-if = e10s && debug
|
||||
[browser_dbg_pretty-print-03.js]
|
||||
skip-if = e10s
|
||||
skip-if = e10s && debug
|
||||
[browser_dbg_pretty-print-04.js]
|
||||
skip-if = e10s
|
||||
skip-if = e10s && debug
|
||||
[browser_dbg_pretty-print-05.js]
|
||||
skip-if = e10s
|
||||
skip-if = e10s && debug
|
||||
[browser_dbg_pretty-print-06.js]
|
||||
skip-if = e10s
|
||||
skip-if = e10s && debug
|
||||
[browser_dbg_pretty-print-07.js]
|
||||
skip-if = e10s
|
||||
skip-if = e10s && debug
|
||||
[browser_dbg_pretty-print-08.js]
|
||||
skip-if = e10s
|
||||
skip-if = e10s && debug
|
||||
[browser_dbg_pretty-print-09.js]
|
||||
skip-if = e10s
|
||||
skip-if = e10s && debug
|
||||
[browser_dbg_pretty-print-10.js]
|
||||
skip-if = e10s
|
||||
skip-if = e10s && debug
|
||||
[browser_dbg_pretty-print-11.js]
|
||||
skip-if = e10s
|
||||
skip-if = e10s && debug
|
||||
[browser_dbg_pretty-print-12.js]
|
||||
skip-if = e10s
|
||||
skip-if = e10s && debug
|
||||
[browser_dbg_pretty-print-13.js]
|
||||
skip-if = e10s
|
||||
skip-if = e10s && debug
|
||||
[browser_dbg_pretty-print-on-paused.js]
|
||||
skip-if = e10s
|
||||
skip-if = e10s && debug
|
||||
[browser_dbg_progress-listener-bug.js]
|
||||
skip-if = e10s
|
||||
[browser_dbg_reload-preferred-script-01.js]
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
const TAB_URL = EXAMPLE_URL + "doc_event-listeners-02.html";
|
||||
|
||||
function test() {
|
||||
initDebugger(TAB_URL).then(([aTab, aDebuggee, aPanel]) => {
|
||||
initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
|
||||
let gDebugger = aPanel.panelWin;
|
||||
let gView = gDebugger.DebuggerView;
|
||||
let gEvents = gView.EventListeners;
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
const TAB_URL = EXAMPLE_URL + "doc_event-listeners-02.html";
|
||||
|
||||
function test() {
|
||||
initDebugger(TAB_URL).then(([aTab, aDebuggee, aPanel]) => {
|
||||
initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
|
||||
let gDebugger = aPanel.panelWin;
|
||||
let gView = gDebugger.DebuggerView;
|
||||
let gEvents = gView.EventListeners;
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
const TAB_URL = EXAMPLE_URL + "doc_event-listeners-02.html";
|
||||
|
||||
function test() {
|
||||
initDebugger(TAB_URL).then(([aTab, aDebuggee, aPanel]) => {
|
||||
initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
|
||||
let gDebugger = aPanel.panelWin;
|
||||
let gView = gDebugger.DebuggerView;
|
||||
let gController = gDebugger.DebuggerController
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
const TAB_URL = EXAMPLE_URL + "doc_event-listeners-02.html";
|
||||
|
||||
function test() {
|
||||
initDebugger(TAB_URL).then(([aTab, aDebuggee, aPanel]) => {
|
||||
initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
|
||||
let gDebugger = aPanel.panelWin;
|
||||
let gView = gDebugger.DebuggerView;
|
||||
let gController = gDebugger.DebuggerController
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
const TAB_URL = EXAMPLE_URL + "doc_event-listeners-02.html";
|
||||
|
||||
function test() {
|
||||
initDebugger(TAB_URL).then(([aTab, aDebuggee, aPanel]) => {
|
||||
initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
|
||||
let gDebugger = aPanel.panelWin;
|
||||
let gView = gDebugger.DebuggerView;
|
||||
let gController = gDebugger.DebuggerController
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
*/
|
||||
|
||||
function test() {
|
||||
initDebugger("about:blank").then(([aTab, aDebuggee, aPanel]) => {
|
||||
initDebugger("about:blank").then(([aTab,, aPanel]) => {
|
||||
let gDebugger = aPanel.panelWin;
|
||||
let gView = gDebugger.DebuggerView;
|
||||
let gEvents = gView.EventListeners;
|
||||
|
|
|
@ -8,14 +8,15 @@
|
|||
const TAB_URL = EXAMPLE_URL + "doc_event-listeners-02.html";
|
||||
|
||||
function test() {
|
||||
initDebugger(TAB_URL).then(([aTab, aDebuggee, aPanel]) => {
|
||||
initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
|
||||
let gTab = aTab;
|
||||
let gDebugger = aPanel.panelWin;
|
||||
let gView = gDebugger.DebuggerView;
|
||||
let gEvents = gView.EventListeners;
|
||||
|
||||
Task.spawn(function() {
|
||||
yield waitForSourceShown(aPanel, ".html");
|
||||
aDebuggee.addBodyClickEventListener();
|
||||
yield callInTab(gTab, "addBodyClickEventListener");
|
||||
|
||||
let fetched = waitForDebuggerEvents(aPanel, gDebugger.EVENTS.EVENT_LISTENERS_FETCHED);
|
||||
gView.toggleInstrumentsPane({ visible: true, animated: false }, 1);
|
||||
|
@ -33,11 +34,7 @@ function test() {
|
|||
yield ensureThreadClientState(aPanel, "resumed");
|
||||
|
||||
let paused = waitForCaretAndScopes(aPanel, 48);
|
||||
// Spin the event loop before causing the debuggee to pause, to allow
|
||||
// this function to yield first.
|
||||
executeSoon(() => {
|
||||
EventUtils.sendMouseEvent({ type: "click" }, aDebuggee.document.body, aDebuggee);
|
||||
});
|
||||
sendMouseClickToTab(gTab, content.document.body);
|
||||
yield paused;
|
||||
yield ensureThreadClientState(aPanel, "paused");
|
||||
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
/**
|
||||
* Bug 1093349: Test that the pretty-printing and blackboxing buttons
|
||||
* are hidden if the server doesn't support them
|
||||
*/
|
||||
|
||||
const TAB_URL = EXAMPLE_URL + "doc_auto-pretty-print-01.html";
|
||||
|
||||
let devtools = Cu.import("resource://gre/modules/devtools/Loader.jsm", {}).devtools;
|
||||
let { RootActor } = devtools.require("devtools/server/actors/root");
|
||||
|
||||
function test() {
|
||||
let gTab, gDebuggee, gPanel, gDebugger;
|
||||
let gEditor, gSources, gBreakpoints, gBreakpointsAdded, gBreakpointsRemoving;
|
||||
|
||||
RootActor.prototype.traits.noBlackBoxing = true;
|
||||
RootActor.prototype.traits.noPrettyPrinting = true;
|
||||
|
||||
initDebugger(TAB_URL).then(([aTab, aDebuggee, aPanel]) => {
|
||||
let document = aPanel.panelWin.document;
|
||||
let ppButton = document.querySelector('#pretty-print');
|
||||
let bbButton = document.querySelector('#black-box');
|
||||
let sep = document.querySelector('#sources-toolbar .devtools-separator');
|
||||
|
||||
is(ppButton.style.display, 'none', 'The pretty-print button is hidden');
|
||||
is(bbButton.style.display, 'none', 'The blackboxing button is hidden');
|
||||
is(sep.style.display, 'none', 'The separator is hidden');
|
||||
closeDebuggerAndFinish(aPanel)
|
||||
});
|
||||
}
|
|
@ -7,13 +7,12 @@
|
|||
|
||||
const TAB_URL = EXAMPLE_URL + "doc_pretty-print.html";
|
||||
|
||||
let gTab, gDebuggee, gPanel, gDebugger;
|
||||
let gTab, gPanel, gDebugger;
|
||||
let gEditor, gSources;
|
||||
|
||||
function test() {
|
||||
initDebugger(TAB_URL).then(([aTab, aDebuggee, aPanel]) => {
|
||||
initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
|
||||
gTab = aTab;
|
||||
gDebuggee = aDebuggee;
|
||||
gPanel = aPanel;
|
||||
gDebugger = gPanel.panelWin;
|
||||
gEditor = gDebugger.DebuggerView.editor;
|
||||
|
@ -76,7 +75,6 @@ function testSourceIsStillPretty() {
|
|||
|
||||
registerCleanupFunction(function() {
|
||||
gTab = null;
|
||||
gDebuggee = null;
|
||||
gPanel = null;
|
||||
gDebugger = null;
|
||||
gEditor = null;
|
||||
|
|
|
@ -8,13 +8,12 @@
|
|||
|
||||
const TAB_URL = EXAMPLE_URL + "doc_pretty-print.html";
|
||||
|
||||
let gTab, gDebuggee, gPanel, gDebugger;
|
||||
let gTab, gPanel, gDebugger;
|
||||
let gEditor, gContextMenu;
|
||||
|
||||
function test() {
|
||||
initDebugger(TAB_URL).then(([aTab, aDebuggee, aPanel]) => {
|
||||
initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
|
||||
gTab = aTab;
|
||||
gDebuggee = aDebuggee;
|
||||
gPanel = aPanel;
|
||||
gDebugger = gPanel.panelWin;
|
||||
gEditor = gDebugger.DebuggerView.editor;
|
||||
|
@ -49,7 +48,6 @@ function testSourceIsPretty() {
|
|||
|
||||
registerCleanupFunction(function() {
|
||||
gTab = null;
|
||||
gDebuggee = null;
|
||||
gPanel = null;
|
||||
gDebugger = null;
|
||||
gEditor = null;
|
||||
|
|
|
@ -7,12 +7,11 @@
|
|||
|
||||
const TAB_URL = EXAMPLE_URL + "doc_pretty-print.html";
|
||||
|
||||
let gTab, gDebuggee, gPanel, gDebugger;
|
||||
let gTab, gPanel, gDebugger;
|
||||
|
||||
function test() {
|
||||
initDebugger(TAB_URL).then(([aTab, aDebuggee, aPanel]) => {
|
||||
initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
|
||||
gTab = aTab;
|
||||
gDebuggee = aDebuggee;
|
||||
gPanel = aPanel;
|
||||
gDebugger = gPanel.panelWin;
|
||||
|
||||
|
@ -35,8 +34,7 @@ function test() {
|
|||
function runCodeAndPause() {
|
||||
const deferred = promise.defer();
|
||||
once(gDebugger.gThreadClient, "paused").then(deferred.resolve);
|
||||
// Have to executeSoon so that we don't pause before this function returns.
|
||||
executeSoon(gDebuggee.foo);
|
||||
callInTab(gTab, "foo");
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
|
@ -46,7 +44,6 @@ function clickPrettyPrintButton() {
|
|||
|
||||
registerCleanupFunction(function() {
|
||||
gTab = null;
|
||||
gDebuggee = null;
|
||||
gPanel = null;
|
||||
gDebugger = null;
|
||||
});
|
||||
|
|
|
@ -7,13 +7,12 @@
|
|||
|
||||
const TAB_URL = EXAMPLE_URL + "doc_pretty-print.html";
|
||||
|
||||
let gTab, gDebuggee, gPanel, gDebugger;
|
||||
let gTab, gPanel, gDebugger;
|
||||
let gSearchBox;
|
||||
|
||||
function test() {
|
||||
initDebugger(TAB_URL).then(([aTab, aDebuggee, aPanel]) => {
|
||||
initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
|
||||
gTab = aTab;
|
||||
gDebuggee = aDebuggee;
|
||||
gPanel = aPanel;
|
||||
gDebugger = gPanel.panelWin;
|
||||
gSearchBox = gDebugger.DebuggerView.Filtering._searchbox;
|
||||
|
@ -65,7 +64,6 @@ function testPrettyPrintedSearch() {
|
|||
|
||||
registerCleanupFunction(function() {
|
||||
gTab = null;
|
||||
gDebuggee = null;
|
||||
gPanel = null;
|
||||
gDebugger = null;
|
||||
gSearchBox = null;
|
||||
|
|
|
@ -7,13 +7,12 @@
|
|||
|
||||
const TAB_URL = EXAMPLE_URL + "doc_included-script.html";
|
||||
|
||||
let gTab, gDebuggee, gPanel, gDebugger;
|
||||
let gTab, gPanel, gDebugger;
|
||||
let gEditor, gSources, gControllerSources;
|
||||
|
||||
function test() {
|
||||
initDebugger(TAB_URL).then(([aTab, aDebuggee, aPanel]) => {
|
||||
initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
|
||||
gTab = aTab;
|
||||
gDebuggee = aDebuggee;
|
||||
gPanel = aPanel;
|
||||
gDebugger = gPanel.panelWin;
|
||||
gEditor = gDebugger.DebuggerView.editor;
|
||||
|
@ -68,7 +67,6 @@ function prepareDebugger(aPanel) {
|
|||
|
||||
registerCleanupFunction(function() {
|
||||
gTab = null;
|
||||
gDebuggee = null;
|
||||
gPanel = null;
|
||||
gDebugger = null;
|
||||
gEditor = null;
|
||||
|
|
|
@ -8,13 +8,12 @@
|
|||
const TAB_URL = EXAMPLE_URL + "doc_included-script.html";
|
||||
const JS_URL = EXAMPLE_URL + "code_location-changes.js";
|
||||
|
||||
let gTab, gDebuggee, gPanel, gDebugger, gClient;
|
||||
let gTab, gPanel, gDebugger, gClient;
|
||||
let gEditor, gSources, gControllerSources, gPrettyPrinted;
|
||||
|
||||
function test() {
|
||||
initDebugger(TAB_URL).then(([aTab, aDebuggee, aPanel]) => {
|
||||
initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
|
||||
gTab = aTab;
|
||||
gDebuggee = aDebuggee;
|
||||
gPanel = aPanel;
|
||||
gDebugger = gPanel.panelWin;
|
||||
gClient = gDebugger.gClient;
|
||||
|
@ -83,7 +82,6 @@ function clickPrettyPrintButton() {
|
|||
|
||||
registerCleanupFunction(function() {
|
||||
gTab = null;
|
||||
gDebuggee = null;
|
||||
gPanel = null;
|
||||
gDebugger = null;
|
||||
gClient = null;
|
||||
|
|
|
@ -5,14 +5,13 @@
|
|||
// Test basic pretty printing functionality. Would be an xpcshell test, except
|
||||
// for bug 921252.
|
||||
|
||||
let gTab, gDebuggee, gPanel, gClient, gThreadClient, gSource;
|
||||
let gTab, gPanel, gClient, gThreadClient, gSource;
|
||||
|
||||
const TAB_URL = EXAMPLE_URL + "doc_pretty-print-2.html";
|
||||
|
||||
function test() {
|
||||
initDebugger(TAB_URL).then(([aTab, aDebuggee, aPanel]) => {
|
||||
initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
|
||||
gTab = aTab;
|
||||
gDebuggee = aDebuggee;
|
||||
gPanel = aPanel;
|
||||
gClient = gPanel.panelWin.gClient;
|
||||
gThreadClient = gPanel.panelWin.DebuggerController.activeThread;
|
||||
|
@ -52,5 +51,5 @@ function testUgly({ error, source }) {
|
|||
}
|
||||
|
||||
registerCleanupFunction(function() {
|
||||
gTab = gDebuggee = gPanel = gClient = gThreadClient = gSource = null;
|
||||
gTab = gPanel = gClient = gThreadClient = gSource = null;
|
||||
});
|
||||
|
|
|
@ -4,19 +4,17 @@
|
|||
|
||||
// Test stepping through pretty printed sources.
|
||||
|
||||
let gTab, gDebuggee, gPanel, gClient, gThreadClient, gSource;
|
||||
let gTab, gPanel, gClient, gThreadClient, gSource;
|
||||
|
||||
const TAB_URL = EXAMPLE_URL + "doc_pretty-print-2.html";
|
||||
|
||||
function test() {
|
||||
initDebugger(TAB_URL).then(([aTab, aDebuggee, aPanel]) => {
|
||||
initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
|
||||
gTab = aTab;
|
||||
gDebuggee = aDebuggee;
|
||||
gPanel = aPanel;
|
||||
gClient = gPanel.panelWin.gClient;
|
||||
gThreadClient = gPanel.panelWin.DebuggerController.activeThread;
|
||||
|
||||
gDebuggee.noop = x => x;
|
||||
findSource();
|
||||
});
|
||||
}
|
||||
|
@ -47,7 +45,7 @@ function prettyPrintSource(source) {
|
|||
function runCode({ error }) {
|
||||
ok(!error);
|
||||
gClient.addOneTimeListener("paused", testDbgStatement);
|
||||
gDebuggee.main3();
|
||||
callInTab(gTab, "main3");
|
||||
}
|
||||
|
||||
function testDbgStatement(event, { why, frame }) {
|
||||
|
@ -90,5 +88,5 @@ function testHitBreakpoint() {
|
|||
}
|
||||
|
||||
registerCleanupFunction(function() {
|
||||
gTab = gDebuggee = gPanel = gClient = gThreadClient = gSource = null;
|
||||
gTab = gPanel = gClient = gThreadClient = gSource = null;
|
||||
});
|
||||
|
|
|
@ -4,19 +4,17 @@
|
|||
|
||||
// Test pretty printing source mapped sources.
|
||||
|
||||
var gDebuggee;
|
||||
var gClient;
|
||||
var gThreadClient;
|
||||
var gSource;
|
||||
|
||||
let gTab, gDebuggee, gPanel, gClient, gThreadClient, gSource;
|
||||
let gTab, gPanel, gClient, gThreadClient, gSource;
|
||||
|
||||
const TAB_URL = EXAMPLE_URL + "doc_pretty-print-2.html";
|
||||
|
||||
function test() {
|
||||
initDebugger(TAB_URL).then(([aTab, aDebuggee, aPanel]) => {
|
||||
initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
|
||||
gTab = aTab;
|
||||
gDebuggee = aDebuggee;
|
||||
gPanel = aPanel;
|
||||
gClient = gPanel.panelWin.gClient;
|
||||
gThreadClient = gPanel.panelWin.DebuggerController.activeThread;
|
||||
|
@ -50,7 +48,7 @@ function prettyPrint() {
|
|||
function runCode({ error }) {
|
||||
ok(!error);
|
||||
gClient.addOneTimeListener("paused", testDbgStatement);
|
||||
gDebuggee.a();
|
||||
callInTab(gTab, "a");
|
||||
}
|
||||
|
||||
function testDbgStatement(event, { frame, why }) {
|
||||
|
@ -85,5 +83,5 @@ function testFrame({ frames: [frame] }) {
|
|||
}
|
||||
|
||||
registerCleanupFunction(function() {
|
||||
gTab = gDebuggee = gPanel = gClient = gThreadClient = null;
|
||||
gTab = gPanel = gClient = gThreadClient = null;
|
||||
});
|
||||
|
|
|
@ -8,13 +8,12 @@
|
|||
|
||||
const TAB_URL = EXAMPLE_URL + "doc_pretty-print.html";
|
||||
|
||||
let gTab, gDebuggee, gPanel, gDebugger;
|
||||
let gTab, gPanel, gDebugger;
|
||||
let gEditor, gSources;
|
||||
|
||||
function test() {
|
||||
initDebugger(TAB_URL).then(([aTab, aDebuggee, aPanel]) => {
|
||||
initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
|
||||
gTab = aTab;
|
||||
gDebuggee = aDebuggee;
|
||||
gPanel = aPanel;
|
||||
gDebugger = gPanel.panelWin;
|
||||
gEditor = gDebugger.DebuggerView.editor;
|
||||
|
@ -55,7 +54,6 @@ function testSourceIsStillUgly() {
|
|||
|
||||
registerCleanupFunction(function() {
|
||||
gTab = null;
|
||||
gDebuggee = null;
|
||||
gPanel = null;
|
||||
gDebugger = null;
|
||||
gEditor = null;
|
||||
|
|
|
@ -7,13 +7,12 @@
|
|||
|
||||
const TAB_URL = EXAMPLE_URL + "doc_pretty-print.html";
|
||||
|
||||
let gTab, gDebuggee, gPanel, gDebugger;
|
||||
let gTab, gPanel, gDebugger;
|
||||
let gEditor, gSources;
|
||||
|
||||
function test() {
|
||||
initDebugger(TAB_URL).then(([aTab, aDebuggee, aPanel]) => {
|
||||
initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
|
||||
gTab = aTab;
|
||||
gDebuggee = aDebuggee;
|
||||
gPanel = aPanel;
|
||||
gDebugger = gPanel.panelWin;
|
||||
gEditor = gDebugger.DebuggerView.editor;
|
||||
|
@ -52,7 +51,6 @@ function testSourceIsPretty() {
|
|||
|
||||
registerCleanupFunction(function() {
|
||||
gTab = null;
|
||||
gDebuggee = null;
|
||||
gPanel = null;
|
||||
gDebugger = null;
|
||||
gEditor = null;
|
||||
|
|
|
@ -8,13 +8,12 @@
|
|||
|
||||
const TAB_URL = EXAMPLE_URL + "doc_blackboxing.html";
|
||||
|
||||
let gTab, gDebuggee, gPanel, gDebugger;
|
||||
let gTab, gPanel, gDebugger;
|
||||
let gEditor, gSources;
|
||||
|
||||
function test() {
|
||||
initDebugger(TAB_URL).then(([aTab, aDebuggee, aPanel]) => {
|
||||
initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
|
||||
gTab = aTab;
|
||||
gDebuggee = aDebuggee;
|
||||
gPanel = aPanel;
|
||||
gDebugger = gPanel.panelWin;
|
||||
gEditor = gDebugger.DebuggerView.editor;
|
||||
|
@ -46,7 +45,6 @@ function testButtonIsntChecked() {
|
|||
|
||||
registerCleanupFunction(function() {
|
||||
gTab = null;
|
||||
gDebuggee = null;
|
||||
gPanel = null;
|
||||
gDebugger = null;
|
||||
gEditor = null;
|
||||
|
|
|
@ -9,13 +9,12 @@
|
|||
|
||||
const TAB_URL = EXAMPLE_URL + "doc_pretty-print-3.html";
|
||||
|
||||
let gTab, gDebuggee, gPanel, gDebugger;
|
||||
let gTab, gPanel, gDebugger;
|
||||
let gEditor, gSources;
|
||||
|
||||
function test() {
|
||||
initDebugger(TAB_URL).then(([aTab, aDebuggee, aPanel]) => {
|
||||
initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
|
||||
gTab = aTab;
|
||||
gDebuggee = aDebuggee;
|
||||
gPanel = aPanel;
|
||||
gDebugger = gPanel.panelWin;
|
||||
gEditor = gDebugger.DebuggerView.editor;
|
||||
|
@ -79,7 +78,6 @@ function testSourceIsStillPretty() {
|
|||
|
||||
registerCleanupFunction(function() {
|
||||
gTab = null;
|
||||
gDebuggee = null;
|
||||
gPanel = null;
|
||||
gDebugger = null;
|
||||
gEditor = null;
|
||||
|
|
|
@ -8,14 +8,13 @@
|
|||
|
||||
const TAB_URL = EXAMPLE_URL + "doc_pretty-print-on-paused.html";
|
||||
|
||||
let gTab, gDebuggee, gPanel, gDebugger, gThreadClient, gSources;
|
||||
let gTab, gPanel, gDebugger, gThreadClient, gSources;
|
||||
|
||||
const SECOND_SOURCE_VALUE = EXAMPLE_URL + "code_ugly-2.js";
|
||||
|
||||
function test(){
|
||||
initDebugger(TAB_URL).then(([aTab, aDebuggee, aPanel]) => {
|
||||
initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
|
||||
gTab = aTab;
|
||||
gDebuggee = aDebuggee;
|
||||
gPanel = aPanel;
|
||||
gDebugger = gPanel.panelWin;
|
||||
gThreadClient = gDebugger.gThreadClient;
|
||||
|
@ -33,9 +32,7 @@ function test(){
|
|||
yield doResume(gPanel);
|
||||
|
||||
const bpHit = waitForCaretAndScopes(gPanel, 6);
|
||||
// Get the debuggee call off this tick so that we aren't accidentally
|
||||
// blocking the yielding of bpHit which causes a deadlock.
|
||||
executeSoon(() => gDebuggee.secondCall());
|
||||
callInTab(gTab, "secondCall");
|
||||
yield bpHit;
|
||||
|
||||
info("Switch to the second source.");
|
||||
|
@ -59,7 +56,6 @@ function test(){
|
|||
|
||||
registerCleanupFunction(function() {
|
||||
gTab = null;
|
||||
gDebuggee = null;
|
||||
gPanel = null;
|
||||
gDebugger = null;
|
||||
gThreadClient = null;
|
||||
|
|
|
@ -1,9 +1,25 @@
|
|||
"use strict";
|
||||
|
||||
const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
|
||||
const { loadSubScript } = Cc['@mozilla.org/moz/jssubscript-loader;1'].
|
||||
getService(Ci.mozIJSSubScriptLoader);
|
||||
|
||||
const EventUtils = {};
|
||||
loadSubScript("chrome://marionette/content/EventUtils.js", EventUtils);
|
||||
|
||||
dump("Frame script loaded.\n");
|
||||
|
||||
addMessageListener("test:call", function (message) {
|
||||
dump("Calling function with name " + message.data + ".\n");
|
||||
|
||||
XPCNativeWrapper.unwrap(content)[message.data]();
|
||||
sendAsyncMessage("test:call");
|
||||
});
|
||||
|
||||
addMessageListener("test:click", function (message) {
|
||||
dump("Sending mouse click.\n");
|
||||
|
||||
let target = message.objects.target;
|
||||
EventUtils.synthesizeMouseAtCenter(target, {},
|
||||
target.ownerDocument.defaultView);
|
||||
});
|
||||
|
|
|
@ -8,3 +8,8 @@
|
|||
<script src="code_ugly-2.js"></script>
|
||||
<script src="code_ugly-3.js"></script>
|
||||
<script src="code_ugly-4.js"></script>
|
||||
<script>
|
||||
function noop(x) {
|
||||
return x;
|
||||
}
|
||||
</script>
|
||||
|
|
|
@ -964,4 +964,13 @@ function callInTab(tab, name) {
|
|||
info("Calling function with name " + name + " in tab.");
|
||||
|
||||
sendMessageToTab(tab, "test:call", name);
|
||||
waitForMessageFromTab(tab, "test:call");
|
||||
}
|
||||
|
||||
function sendMouseClickToTab(tab, target) {
|
||||
info("Sending mouse click to tab.");
|
||||
|
||||
sendMessageToTab(tab, "test:click", undefined, {
|
||||
target: target
|
||||
});
|
||||
}
|
||||
|
|
|
@ -2,6 +2,11 @@
|
|||
* 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/. */
|
||||
|
||||
window {
|
||||
-moz-appearance: none;
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
#doorhanger-container {
|
||||
width: 450px;
|
||||
}
|
||||
|
@ -10,7 +15,20 @@
|
|||
padding: 20px;
|
||||
background: #343c45; /* toolbars */
|
||||
color: #8fa1b2; /* body text */
|
||||
/*
|
||||
* Sloppy preprocessing since UNIX_BUT_NOT_MAC is only defined
|
||||
* in `browser/app/profile/firefox.js`, which this file cannot
|
||||
* depend on. Must style font-size to target linux.
|
||||
*/
|
||||
%ifdef XP_UNIX
|
||||
%ifndef XP_MACOSX
|
||||
font-size: 13px;
|
||||
%else
|
||||
font-size: 15px;
|
||||
%endif
|
||||
%else
|
||||
font-size: 15px;
|
||||
%endif
|
||||
line-height: 19px;
|
||||
min-height: 100px;
|
||||
}
|
||||
|
@ -60,6 +78,8 @@
|
|||
border-radius: 5px;
|
||||
height: 30px;
|
||||
width: 450px;
|
||||
/* Override embossed borders on Windows/Linux */
|
||||
border: none;
|
||||
}
|
||||
|
||||
#close {
|
||||
|
|
|
@ -1,22 +1,24 @@
|
|||
[DEFAULT]
|
||||
skip-if = e10s # Bug ?????? - devtools tests disabled with e10s
|
||||
skip-if = e10s # Bug 1074836 - inspector tests disabled with e10s
|
||||
subsuite = devtools
|
||||
support-files =
|
||||
doc_frame_script.js
|
||||
doc_inspector_breadcrumbs.html
|
||||
doc_inspector_delete-selected-node-01.html
|
||||
doc_inspector_delete-selected-node-02.html
|
||||
doc_inspector_gcli-inspect-command.html
|
||||
doc_inspector_highlight_after_transition.html
|
||||
doc_inspector_highlighter-comments.html
|
||||
doc_inspector_highlighter_csstransform.html
|
||||
doc_inspector_highlighter.html
|
||||
browser_inspector_infobar_01.html
|
||||
browser_inspector_infobar_02.html
|
||||
doc_inspector_infobar_01.html
|
||||
doc_inspector_infobar_02.html
|
||||
doc_inspector_menu.html
|
||||
doc_inspector_remove-iframe-during-load.html
|
||||
doc_inspector_search.html
|
||||
doc_inspector_search-suggestions.html
|
||||
doc_inspector_select-last-selected-01.html
|
||||
doc_inspector_select-last-selected-02.html
|
||||
browser_inspector_highlight_after_transition.html
|
||||
head.js
|
||||
|
||||
[browser_inspector_breadcrumbs.js]
|
||||
|
@ -29,11 +31,20 @@ support-files =
|
|||
[browser_inspector_highlighter-01.js]
|
||||
[browser_inspector_highlighter-02.js]
|
||||
[browser_inspector_highlighter-03.js]
|
||||
[browser_inspector_highlighter-04.js]
|
||||
[browser_inspector_highlighter-by-type.js]
|
||||
[browser_inspector_highlighter-comments.js]
|
||||
[browser_inspector_highlighter-csstransform_01.js]
|
||||
[browser_inspector_highlighter-csstransform_02.js]
|
||||
[browser_inspector_highlighter-hover_01.js]
|
||||
[browser_inspector_highlighter-hover_02.js]
|
||||
[browser_inspector_highlighter-hover_03.js]
|
||||
[browser_inspector_highlighter-iframes.js]
|
||||
[browser_inspector_highlighter-options.js]
|
||||
[browser_inspector_highlighter-selector_01.js]
|
||||
[browser_inspector_highlighter-selector_02.js]
|
||||
[browser_inspector_iframe-navigation.js]
|
||||
[browser_inspector_infobar_01.js]
|
||||
[browser_inspector_infobar_02.js]
|
||||
[browser_inspector_initialization.js]
|
||||
[browser_inspector_inspect-object-element.js]
|
||||
[browser_inspector_invalidate.js]
|
||||
|
@ -57,4 +68,3 @@ support-files =
|
|||
[browser_inspector_sidebarstate.js]
|
||||
[browser_inspector_switch-to-inspector-on-pick.js]
|
||||
[browser_inspector_update-on-navigation.js]
|
||||
|
||||
|
|
|
@ -7,70 +7,67 @@
|
|||
|
||||
const TEST_URI = TEST_URL_ROOT + "doc_inspector_breadcrumbs.html";
|
||||
const NODES = [
|
||||
{nodeId: "#i1111", result: "i1 i11 i111 i1111"},
|
||||
{nodeId: "#i22", result: "i2 i22 i221"},
|
||||
{nodeId: "#i2111", result: "i2 i21 i211 i2111"},
|
||||
{nodeId: "#i21", result: "i2 i21 i211 i2111"},
|
||||
{nodeId: "#i22211", result: "i2 i22 i222 i2221 i22211"},
|
||||
{nodeId: "#i22", result: "i2 i22 i222 i2221 i22211"},
|
||||
{selector: "#i1111", result: "i1 i11 i111 i1111"},
|
||||
{selector: "#i22", result: "i2 i22 i221"},
|
||||
{selector: "#i2111", result: "i2 i21 i211 i2111"},
|
||||
{selector: "#i21", result: "i2 i21 i211 i2111"},
|
||||
{selector: "#i22211", result: "i2 i22 i222 i2221 i22211"},
|
||||
{selector: "#i22", result: "i2 i22 i222 i2221 i22211"},
|
||||
];
|
||||
|
||||
let test = asyncTest(function*() {
|
||||
add_task(function*() {
|
||||
let { inspector } = yield openInspectorForURL(TEST_URI);
|
||||
let container = inspector.panelDoc.getElementById("inspector-breadcrumbs");
|
||||
|
||||
for (let node of NODES) {
|
||||
info("Testing node " + node.nodeId);
|
||||
|
||||
let documentNode = getNode(node.nodeId);
|
||||
info("Testing node " + node.selector);
|
||||
|
||||
info("Selecting node and waiting for breadcrumbs to update");
|
||||
let breadcrumbsUpdated = inspector.once("breadcrumbs-updated");
|
||||
let nodeSelected = selectNode(documentNode, inspector);
|
||||
yield selectNode(node.selector, inspector);
|
||||
yield breadcrumbsUpdated;
|
||||
|
||||
yield Promise.all([breadcrumbsUpdated, nodeSelected]);
|
||||
|
||||
info("Performing checks for node " + node.nodeId);
|
||||
info("Performing checks for node " + node.selector);
|
||||
let buttonsLabelIds = node.result.split(" ");
|
||||
|
||||
// html > body > …
|
||||
is(container.childNodes.length, buttonsLabelIds.length + 2,
|
||||
"Node " + node.nodeId + ": Items count");
|
||||
"Node " + node.selector + ": Items count");
|
||||
|
||||
for (let i = 2; i < container.childNodes.length; i++) {
|
||||
let expectedId = "#" + buttonsLabelIds[i - 2];
|
||||
let button = container.childNodes[i];
|
||||
let labelId = button.querySelector(".breadcrumbs-widget-item-id");
|
||||
is(labelId.textContent, expectedId,
|
||||
"Node #" + node.nodeId + ": button " + i + " matches");
|
||||
"Node #" + node.selector + ": button " + i + " matches");
|
||||
}
|
||||
|
||||
let checkedButton = container.querySelector("button[checked]");
|
||||
let labelId = checkedButton.querySelector(".breadcrumbs-widget-item-id");
|
||||
let id = inspector.selection.node.id;
|
||||
let id = inspector.selection.nodeFront.id;
|
||||
is(labelId.textContent, "#" + id,
|
||||
"Node #" + node.nodeId + ": selection matches");
|
||||
"Node #" + node.selector + ": selection matches");
|
||||
}
|
||||
|
||||
yield testPseudoElements(inspector, container);
|
||||
});
|
||||
|
||||
function *testPseudoElements(inspector, container) {
|
||||
function* testPseudoElements(inspector, container) {
|
||||
info ("Checking for pseudo elements");
|
||||
|
||||
let pseudoParent = getNodeFront(getNode("#pseudo-container"));
|
||||
let pseudoParent = yield getNodeFront("#pseudo-container", inspector);
|
||||
let children = yield inspector.walker.children(pseudoParent);
|
||||
is (children.nodes.length, 2, "Pseudo children returned from walker");
|
||||
|
||||
let beforeElement = children.nodes[0];
|
||||
let breadcrumbsUpdated = inspector.once("breadcrumbs-updated");
|
||||
let nodeSelected = selectNode(beforeElement, inspector);
|
||||
yield Promise.all([breadcrumbsUpdated, nodeSelected]);
|
||||
yield selectNode(beforeElement, inspector);
|
||||
yield breadcrumbsUpdated;
|
||||
is(container.childNodes[3].textContent, "::before", "::before shows up in breadcrumb");
|
||||
|
||||
let afterElement = children.nodes[1];
|
||||
breadcrumbsUpdated = inspector.once("breadcrumbs-updated");
|
||||
nodeSelected = selectNode(afterElement, inspector);
|
||||
yield Promise.all([breadcrumbsUpdated, nodeSelected]);
|
||||
yield selectNode(afterElement, inspector);
|
||||
yield breadcrumbsUpdated;
|
||||
is(container.childNodes[3].textContent, "::after", "::before shows up in breadcrumb");
|
||||
}
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
// Test that hovering over nodes on the breadcrumb buttons in the inspector shows the highlighter over
|
||||
// those nodes
|
||||
let test = asyncTest(function*() {
|
||||
add_task(function*() {
|
||||
info("Loading the test document and opening the inspector");
|
||||
yield addTab("data:text/html;charset=utf-8,<h1>foo</h1><span>bar</span>");
|
||||
let {toolbox, inspector} = yield openInspector();
|
||||
|
@ -18,15 +18,23 @@ let test = asyncTest(function*() {
|
|||
let button = bcButtons.childNodes[1];
|
||||
EventUtils.synthesizeMouseAtCenter(button, {type: "mousemove"}, button.ownerDocument.defaultView);
|
||||
yield onNodeHighlighted;
|
||||
ok(isHighlighting(), "The highlighter is shown on a markup container hover");
|
||||
is(getHighlitNode(), getNode("body"), "The highlighter highlights the right node");
|
||||
|
||||
let isVisible = yield isHighlighting(toolbox);
|
||||
ok(isVisible, "The highlighter is shown on a markup container hover");
|
||||
|
||||
let highlightedNode = yield getHighlitNode(toolbox);
|
||||
is(highlightedNode, getNode("body"), "The highlighter highlights the right node");
|
||||
|
||||
onNodeHighlighted = toolbox.once("node-highlight");
|
||||
button = bcButtons.childNodes[2];
|
||||
EventUtils.synthesizeMouseAtCenter(button, {type: "mousemove"}, button.ownerDocument.defaultView);
|
||||
yield onNodeHighlighted;
|
||||
ok(isHighlighting(), "The highlighter is shown on a markup container hover");
|
||||
is(getHighlitNode(), getNode("span"), "The highlighter highlights the right node");
|
||||
|
||||
isVisible = yield isHighlighting(toolbox);
|
||||
ok(isVisible, "The highlighter is shown on a markup container hover");
|
||||
|
||||
highlightedNode = yield getHighlitNode(toolbox);
|
||||
is(highlightedNode, getNode("span"), "The highlighter highlights the right node");
|
||||
|
||||
gBrowser.removeCurrentTab();
|
||||
});
|
||||
|
|
|
@ -7,22 +7,18 @@
|
|||
|
||||
const TEST_URL = TEST_URL_ROOT + "doc_inspector_delete-selected-node-01.html";
|
||||
|
||||
let test = asyncTest(function* () {
|
||||
let { inspector } = yield openInspectorForURL(TEST_URL);
|
||||
let iframe = getNode("iframe");
|
||||
let span = getNode("span", { document: iframe.contentDocument });
|
||||
add_task(function* () {
|
||||
let {inspector} = yield openInspectorForURL(TEST_URL);
|
||||
|
||||
let span = yield getNodeFrontInFrame("span", "iframe", inspector);
|
||||
yield selectNode(span, inspector);
|
||||
|
||||
info("Removing selected <span> element.");
|
||||
let parentNode = span.parentNode;
|
||||
span.remove();
|
||||
|
||||
let lh = new LayoutHelpers(window.content);
|
||||
ok(!lh.isNodeConnected(span), "Node considered as disconnected.");
|
||||
let parentNode = span.parentNode();
|
||||
yield inspector.walker.removeNode(span);
|
||||
|
||||
// Wait for the inspector to process the mutation
|
||||
yield inspector.once("inspector-updated");
|
||||
is(inspector.selection.node, parentNode,
|
||||
is(inspector.selection.nodeFront, parentNode,
|
||||
"Parent node of selected <span> got selected.");
|
||||
});
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
const TEST_PAGE = TEST_URL_ROOT +
|
||||
"doc_inspector_delete-selected-node-02.html";
|
||||
|
||||
let test = asyncTest(function* () {
|
||||
add_task(function* () {
|
||||
let { inspector } = yield openInspectorForURL(TEST_PAGE);
|
||||
|
||||
yield testManuallyDeleteSelectedNode();
|
||||
|
@ -23,11 +23,10 @@ let test = asyncTest(function* () {
|
|||
info("Selecting a node, deleting it via context menu and checking that " +
|
||||
"its parent node is selected and breadcrumbs are updated.");
|
||||
|
||||
let div = getNode("#deleteManually");
|
||||
yield selectNode(div, inspector);
|
||||
yield selectNode("#deleteManually", inspector);
|
||||
|
||||
info("Getting the node container in the markup view.");
|
||||
let container = getContainerForRawNode(inspector.markup, div);
|
||||
let container = yield getContainerForSelector("#deleteManually", inspector);
|
||||
|
||||
info("Simulating right-click on the markup view container.");
|
||||
EventUtils.synthesizeMouse(container.tagLine, 2, 2,
|
||||
|
@ -43,26 +42,24 @@ let test = asyncTest(function* () {
|
|||
yield inspector.once("inspector-updated");
|
||||
|
||||
info("Inspector updated, performing checks.");
|
||||
let parent = getNode("#deleteChildren");
|
||||
assertNodeSelectedAndPanelsUpdated(parent, "ul#deleteChildren");
|
||||
yield assertNodeSelectedAndPanelsUpdated("#deleteChildren", "ul#deleteChildren");
|
||||
}
|
||||
|
||||
function* testAutomaticallyDeleteSelectedNode() {
|
||||
info("Selecting a node, deleting it via javascript and checking that " +
|
||||
"its parent node is selected and breadcrumbs are updated.");
|
||||
|
||||
let div = getNode("#deleteAutomatically");
|
||||
let div = yield getNodeFront("#deleteAutomatically", inspector);
|
||||
yield selectNode(div, inspector);
|
||||
|
||||
info("Deleting selected node via javascript.");
|
||||
div.remove();
|
||||
yield inspector.walker.removeNode(div);
|
||||
|
||||
info("Waiting for inspector to update.");
|
||||
yield inspector.once("inspector-updated");
|
||||
|
||||
info("Inspector updated, performing checks.");
|
||||
let parent = getNode("#deleteChildren");
|
||||
assertNodeSelectedAndPanelsUpdated(parent, "ul#deleteChildren");
|
||||
yield assertNodeSelectedAndPanelsUpdated("#deleteChildren", "ul#deleteChildren");
|
||||
}
|
||||
|
||||
function* testDeleteSelectedNodeContainerFrame() {
|
||||
|
@ -71,23 +68,23 @@ let test = asyncTest(function* () {
|
|||
"breadcrumbs are updated.");
|
||||
|
||||
info("Selecting an element inside iframe.");
|
||||
let iframe = getNode("#deleteIframe");
|
||||
let div = iframe.contentDocument.getElementById("deleteInIframe");
|
||||
let iframe = yield getNodeFront("#deleteIframe", inspector);
|
||||
let div = yield getNodeFrontInFrame("#deleteInIframe", iframe, inspector);
|
||||
yield selectNode(div, inspector);
|
||||
|
||||
info("Deleting selected node via javascript.");
|
||||
iframe.remove();
|
||||
yield inspector.walker.removeNode(iframe);
|
||||
|
||||
info("Waiting for inspector to update.");
|
||||
yield inspector.once("inspector-updated");
|
||||
|
||||
info("Inspector updated, performing checks.");
|
||||
assertNodeSelectedAndPanelsUpdated(getNode("body"), "body");
|
||||
yield assertNodeSelectedAndPanelsUpdated("body", "body");
|
||||
}
|
||||
|
||||
function assertNodeSelectedAndPanelsUpdated(node, crumbLabel) {
|
||||
is(inspector.selection.nodeFront, getNodeFront(node),
|
||||
"The right node is selected");
|
||||
function* assertNodeSelectedAndPanelsUpdated(selector, crumbLabel) {
|
||||
let nodeFront = yield getNodeFront(selector, inspector);
|
||||
is(inspector.selection.nodeFront, nodeFront, "The right node is selected");
|
||||
|
||||
let breadcrumbs = inspector.panelDoc.getElementById("inspector-breadcrumbs");
|
||||
is(breadcrumbs.querySelector("button[checked=true]").textContent, crumbLabel,
|
||||
|
|
|
@ -8,19 +8,18 @@
|
|||
|
||||
const TEST_URL = TEST_URL_ROOT + "doc_inspector_delete-selected-node-01.html";
|
||||
|
||||
let test = asyncTest(function* () {
|
||||
add_task(function* () {
|
||||
let { inspector } = yield openInspectorForURL(TEST_URL);
|
||||
|
||||
let iframe = getNode("iframe");
|
||||
let node = getNode("span", { document: iframe.contentDocument });
|
||||
let iframe = yield getNodeFront("iframe", inspector);
|
||||
let node = yield getNodeFrontInFrame("span", iframe, inspector);
|
||||
yield selectNode(node, inspector);
|
||||
|
||||
info("Removing iframe.");
|
||||
iframe.remove();
|
||||
yield inspector.walker.removeNode(iframe);
|
||||
|
||||
let lh = new LayoutHelpers(window.content);
|
||||
ok(!lh.isNodeConnected(node), "Node considered as disconnected.");
|
||||
ok(!inspector.selection.isConnected(), "Selection considered as disconnected.");
|
||||
let body = yield getNodeFront("body", inspector);
|
||||
is(inspector.selection.nodeFront, body, "Selection is now the body node");
|
||||
|
||||
yield inspector.once("inspector-updated");
|
||||
});
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
const URL_1 = "data:text/plain;charset=UTF-8,abcde";
|
||||
const URL_2 = "data:text/plain;charset=UTF-8,12345";
|
||||
|
||||
let test = asyncTest(function* () {
|
||||
add_task(function* () {
|
||||
let { toolbox } = yield openInspectorForURL(URL_1);
|
||||
|
||||
info("Navigating to different URL.");
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
|
||||
const TEST_URI = TEST_URL_ROOT + "doc_inspector_gcli-inspect-command.html";
|
||||
|
||||
let test = asyncTest(function* () {
|
||||
add_task(function* () {
|
||||
return helpers.addTabWithToolbar(TEST_URI, function(options) {
|
||||
return helpers.audit(options, [
|
||||
{
|
||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче