Bug 1227539: Part 1 - close a chat window properly, including stopping all sharing and leaving the room. r=Standard8

This commit is contained in:
Mike de Boer 2015-12-23 13:37:57 +01:00
Родитель 8a4b8f794c
Коммит 7cdcdcde53
17 изменённых файлов: 249 добавлений и 110 удалений

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

@ -718,7 +718,7 @@ var LoopRoomsInternal = {
eventEmitter.emit("open", roomToken);
MozLoopService.openChatWindow(windowData, () => {
return MozLoopService.openChatWindow(windowData, () => {
eventEmitter.emit("close");
});
},

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

@ -123,7 +123,7 @@ const updateSocialProvidersCache = function() {
};
var gAppVersionInfo = null;
var gBrowserSharingListenerCount = 0;
var gBrowserSharingListeners = new Set();
var gBrowserSharingWindows = new Set();
var gPageListeners = null;
var gOriginalPageListeners = null;
@ -141,10 +141,12 @@ const kMessageHandlers = {
/**
* Start browser sharing, which basically means to start listening for tab
* switches and passing the new window ID to the sender whenever that happens.
*
*
* @param {Object} message Message meant for the handler function, containing
* the following parameters in its `data` property:
* [ ]
* [
* {Number} windowId The window ID of the chat window
* ]
* @param {Function} reply Callback function, invoked with the result of this
* message handler. The result will be sent back to
* the senders' channel.
@ -169,10 +171,13 @@ const kMessageHandlers = {
return;
}
let [windowId] = message.data;
win.LoopUI.startBrowserSharing();
gBrowserSharingWindows.add(Cu.getWeakReference(win));
++gBrowserSharingListenerCount;
gBrowserSharingListeners.add(windowId);
reply();
},
/**
@ -233,13 +238,14 @@ const kMessageHandlers = {
* message handler. The result will be sent back to
* the senders' channel.
*/
ComposeEmail: function(message) {
ComposeEmail: function(message, reply) {
let [subject, body, recipient] = message.data;
recipient = recipient || "";
let mailtoURL = "mailto:" + encodeURIComponent(recipient) +
"?subject=" + encodeURIComponent(subject) +
"&body=" + encodeURIComponent(body);
extProtocolSvc.loadURI(CommonUtils.makeURI(mailtoURL));
reply();
},
/**
@ -363,6 +369,7 @@ const kMessageHandlers = {
TWO_WAY_MEDIA_CONN_LENGTH: TWO_WAY_MEDIA_CONN_LENGTH
});
},
/**
* Returns the app version information for use during feedback.
*
@ -686,9 +693,43 @@ const kMessageHandlers = {
/**
* Hangup and close all chat windows that are open.
*
* @param {Object} message Message meant for the handler function, containing
* the following parameters in its `data` property:
* [ ]
* @param {Function} reply Callback function, invoked with the result of this
* message handler. The result will be sent back to
* the senders' channel.
*/
HangupAllChatWindows: function() {
HangupAllChatWindows: function(message, reply) {
MozLoopService.hangupAllChatWindows();
reply();
},
/**
* Hangup a specific chay window or room, by leaving a room, resetting the
* screensharing state and removing any active browser switch listeners.
*
* @param {Object} message Message meant for the handler function, containing
* the following parameters in its `data` property:
* [
* {String} roomToken The token of the room to leave
* {Number} windowId The window ID of the chat window
* ]
* @param {Function} reply Callback function, invoked with the result of this
* message handler. The result will be sent back to
* the senders' channel.
*/
HangupNow: function(message, reply) {
let [roomToken, windowId] = message.data;
LoopRooms.leave(roomToken);
MozLoopService.setScreenShareState(windowId, false);
LoopAPI.sendMessageToHandler({
name: "RemoveBrowserSharingListener",
data: [windowId]
});
reply();
},
/**
@ -815,6 +856,7 @@ const kMessageHandlers = {
let win = Services.wm.getMostRecentWindow("navigator:browser");
let url = message.data[0] ? message.data[0] : "about:home";
win.openDialog("chrome://browser/content/", "_blank", "chrome,all,dialog=no,non-remote", url);
reply();
},
/**
@ -837,14 +879,27 @@ const kMessageHandlers = {
/**
* Removes a listener that was previously added.
*
* @param {Object} message Message meant for the handler function, containing
* the following parameters in its `data` property:
* [
* {Number} windowId The window ID of the chat
* ]
* @param {Function} reply Callback function, invoked with the result of this
* message handler. The result will be sent back to
* the senders' channel.
*/
RemoveBrowserSharingListener: function() {
if (!gBrowserSharingListenerCount) {
RemoveBrowserSharingListener: function(message, reply) {
if (!gBrowserSharingListeners.size) {
reply();
return;
}
if (--gBrowserSharingListenerCount > 0) {
let [windowId] = message.data;
gBrowserSharingListeners.delete(windowId);
if (gBrowserSharingListeners.size > 0) {
// There are still clients listening in, so keep on listening...
reply();
return;
}
@ -857,6 +912,7 @@ const kMessageHandlers = {
}
gBrowserSharingWindows.clear();
reply();
},
"Rooms:*": function(action, message, reply) {
@ -942,9 +998,10 @@ const kMessageHandlers = {
* message handler. The result will be sent back to
* the senders' channel.
*/
SetScreenShareState: function(message) {
SetScreenShareState: function(message, reply) {
let [windowId, active] = message.data;
MozLoopService.setScreenShareState(windowId, active);
reply();
},
/**
@ -1314,6 +1371,46 @@ this.LoopAPI = Object.freeze({
destroy: function() {
LoopAPIInternal.destroy();
},
/**
* Gateway for chrome scripts to send a message to a message handler, when
* using the RemotePageManager module is not an option.
*
* @param {Object} message Message meant for the handler function, containing
* the following properties:
* - {String} name Name of handler to send this
* message to. See `kMessageHandlers`
* for the available names.
* - {String} [action] Optional action name of the
* function to call on a sub-API.
* - {Array} data List of arguments that the
* handler can use.
* @param {Function} [reply] Callback function, invoked with the result of this
* message handler. Optional.
*/
sendMessageToHandler: function(message, reply) {
reply = reply || function() {};
let handlerName = message.name;
let handler = kMessageHandlers[handlerName];
if (gStubbedMessageHandlers && gStubbedMessageHandlers[handlerName]) {
handler = gStubbedMessageHandlers[handlerName];
}
if (!handler) {
let msg = "Ouch, no message handler available for '" + handlerName + "'";
MozLoopService.log.error(msg);
reply(cloneableError(msg));
return;
}
if (!message.data) {
message.data = [];
}
if (handlerName.endsWith("*")) {
handler(message.action, message, reply);
} else {
handler(message, reply);
}
},
// The following functions are only used in unit tests.
inspect: function() {
return [Object.create(LoopAPIInternal), Object.create(kMessageHandlers),

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

@ -953,7 +953,10 @@ var MozLoopServiceInternal = {
// NOTE: if you add something here, please also consider if something
// needs to be done on the content side as well (e.g.
// activeRoomStore#windowUnload).
LoopRooms.leave(conversationWindowData.roomToken);
LoopAPI.sendMessageToHandler({
name: "HangupNow",
data: [conversationWindowData.roomToken, windowId]
});
}
}
}
@ -1204,7 +1207,7 @@ var gServiceInitialized = false;
*/
this.MozLoopService = {
_DNSService: gDNSService,
_activeScreenShares: [],
_activeScreenShares: new Set(),
get channelIDs() {
// Channel ids that will be registered with the PushServer for notifications
@ -1922,11 +1925,10 @@ this.MozLoopService = {
*/
setScreenShareState: function(windowId, active) {
if (active) {
this._activeScreenShares.push(windowId);
this._activeScreenShares.add(windowId);
} else {
var index = this._activeScreenShares.indexOf(windowId);
if (index != -1) {
this._activeScreenShares.splice(index, 1);
if (this._activeScreenShares.has(windowId)) {
this._activeScreenShares.delete(windowId);
}
}
@ -1937,6 +1939,6 @@ this.MozLoopService = {
* Returns true if screen sharing is active in at least one window.
*/
get screenShareActive() {
return this._activeScreenShares.length > 0;
return this._activeScreenShares.size > 0;
}
};

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

@ -819,7 +819,7 @@ loop.panel = (function(_, mozL10n) {
loop.request("GetSelectedTabMetadata").then(function(metadata) {
// Bail out when the component is not mounted (anymore).
// This occurs during test runs. See bug 1174611 for more info.
if (!this.isMounted()) {
if (!this.isMounted() || !metadata) {
return;
}

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

@ -819,7 +819,7 @@ loop.panel = (function(_, mozL10n) {
loop.request("GetSelectedTabMetadata").then(function(metadata) {
// Bail out when the component is not mounted (anymore).
// This occurs during test runs. See bug 1174611 for more info.
if (!this.isMounted()) {
if (!this.isMounted() || !metadata) {
return;
}

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

@ -979,7 +979,7 @@ loop.store.ActiveRoomStore = (function() {
endScreenShare: function() {
if (this._browserSharingListener) {
// Remove the browser sharing listener as we don't need it now.
loop.request("RemoveBrowserSharingListener");
loop.request("RemoveBrowserSharingListener", this.getStoreState().windowId);
loop.unsubscribe("BrowserSwitch", this._browserSharingListener);
this._browserSharingListener = null;
}
@ -1117,13 +1117,8 @@ loop.store.ActiveRoomStore = (function() {
loop.standaloneMedia.multiplexGum.reset();
}
var requests = [
["SetScreenShareState", this.getStoreState().windowId, false]
];
if (this._browserSharingListener) {
// Remove the browser sharing listener as we don't need it now.
requests.push(["RemoveBrowserSharingListener"]);
loop.unsubscribe("BrowserSwitch", this._browserSharingListener);
this._browserSharingListener = null;
}
@ -1145,17 +1140,15 @@ loop.store.ActiveRoomStore = (function() {
delete this._timeout;
}
if (!failedJoinRequest &&
(this._storeState.roomState === ROOM_STATES.JOINING ||
this._storeState.roomState === ROOM_STATES.JOINED ||
this._storeState.roomState === ROOM_STATES.SESSION_CONNECTED ||
this._storeState.roomState === ROOM_STATES.HAS_PARTICIPANTS)) {
requests.push(["Rooms:Leave", this._storeState.roomToken,
this._storeState.sessionToken]);
// If we're not going to close the window, we can hangup the call ourselves.
// NOTE: when the window _is_ closed, hanging up the call is performed by
// MozLoopService, because we can't get a message across to LoopAPI
// in time whilst a window is closing.
if (nextState === ROOM_STATES.FAILED && !failedJoinRequest) {
loop.request("HangupNow", this._storeState.roomToken,
this._storeState.windowId);
}
loop.requestMulti.apply(null, requests);
this.setStoreState({ roomState: nextState });
},

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

@ -393,6 +393,9 @@ loop.shared.mixins = (function() {
console.error(error);
return;
}
if (!blob) {
return;
}
var url = URL.createObjectURL(blob);
this.audio = new Audio(url);
@ -411,7 +414,7 @@ loop.shared.mixins = (function() {
if (this._isLoopDesktop()) {
loop.request("GetAudioBlob", name).then(function(result) {
if (result.isError) {
if (result && result.isError) {
callback(result);
return;
}

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

@ -8,7 +8,6 @@
"use strict";
const BASE_URL = Services.prefs.getCharPref("loop.server");
const { LoopAPI } = Cu.import("chrome://loop/content/modules/MozLoopAPI.jsm", {});
function* checkFxA401() {
let err = MozLoopService.errors.get("login");

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

@ -2,7 +2,6 @@
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
const { LoopAPI } = Cu.import("chrome://loop/content/modules/MozLoopAPI.jsm", {});
var [, gHandlers] = LoopAPI.inspect();
add_task(function* test_mozLoop_appVersionInfo() {

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

@ -18,22 +18,17 @@ add_task(function* test_mozLoop_nochat() {
});
add_task(function* test_mozLoop_openchat() {
let windowData = {
roomToken: "fake1234",
type: "room"
};
LoopRooms.open(windowData);
let windowId = LoopRooms.open("fake1234");
Assert.ok(isAnyLoopChatOpen(), "chat window should have been opened");
let chatboxesForRoom = [...Chat.chatboxes].filter(chatbox => {
return chatbox.src == MozLoopServiceInternal.getChatURL(windowId);
});
Assert.strictEqual(chatboxesForRoom.length, 1, "Only one chatbox should be open");
});
add_task(function* test_mozLoop_hangupAllChatWindows() {
let windowData = {
roomToken: "fake2345",
type: "room"
};
LoopRooms.open(windowData);
LoopRooms.open("fake2345");
yield promiseWaitForCondition(() => {
MozLoopService.hangupAllChatWindows();
@ -42,3 +37,30 @@ add_task(function* test_mozLoop_hangupAllChatWindows() {
Assert.ok(!isAnyLoopChatOpen(), "chat window should have been closed");
});
add_task(function* test_mozLoop_hangupOnClose() {
let roomToken = "fake1234";
let hangupNowCalls = [];
LoopAPI.stubMessageHandlers({
HangupNow: function(message, reply) {
hangupNowCalls.push(message);
reply();
}
});
let windowId = LoopRooms.open(roomToken);
yield promiseWaitForCondition(() => {
MozLoopService.hangupAllChatWindows();
return !isAnyLoopChatOpen();
});
Assert.strictEqual(hangupNowCalls.length, 1, "HangupNow handler should be called once");
Assert.deepEqual(hangupNowCalls.pop(), {
name: "HangupNow",
data: [roomToken, windowId]
}, "Messages should be the same");
LoopAPI.restore();
});

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

@ -7,7 +7,6 @@
*/
"use strict";
const { LoopAPI } = Cu.import("chrome://loop/content/modules/MozLoopAPI.jsm", {});
var [, gHandlers] = LoopAPI.inspect();
function promiseGetMetadata() {

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

@ -6,13 +6,15 @@
*/
"use strict";
const { LoopAPI } = Cu.import("chrome://loop/content/modules/MozLoopAPI.jsm", {});
var [, gHandlers] = LoopAPI.inspect();
var handlers = [
{ windowId: null }, { windowId: null }
];
var listenerCount = 41;
var listenerIds = [];
function promiseWindowId() {
return new Promise(resolve => {
LoopAPI.stub([{
@ -24,7 +26,8 @@ function promiseWindowId() {
}
}
}]);
gHandlers.AddBrowserSharingListener({}, () => {});
listenerIds.push(++listenerCount);
gHandlers.AddBrowserSharingListener({ data: [listenerCount] }, () => {});
});
}
@ -78,7 +81,7 @@ add_task(function* test_singleListener() {
Assert.notEqual(initialWindowId, newWindowId, "Tab contentWindow IDs shouldn't be the same");
// Now remove the listener.
gHandlers.RemoveBrowserSharingListener();
gHandlers.RemoveBrowserSharingListener({ data: [listenerIds.pop()] }, function() {});
yield removeTabs();
});
@ -108,7 +111,7 @@ add_task(function* test_multipleListener() {
Assert.notEqual(initialWindowId0, newWindowId0, "Tab contentWindow IDs shouldn't be the same");
// Now remove the first listener.
gHandlers.RemoveBrowserSharingListener();
gHandlers.RemoveBrowserSharingListener({ data: [listenerIds.pop()] }, function() {});
// Check that a new tab updates the window id.
yield promiseWindowIdReceivedNewTab([handlers[1]]);
@ -121,7 +124,7 @@ add_task(function* test_multipleListener() {
Assert.notEqual(newWindowId1, nextWindowId1, "Second listener should have updated");
// Cleanup.
gHandlers.RemoveBrowserSharingListener();
gHandlers.RemoveBrowserSharingListener({ data: [listenerIds.pop()] }, function() {});
yield removeTabs();
});
@ -178,7 +181,9 @@ add_task(function* test_infoBar() {
Assert.equal(getInfoBar(), null, "The notification should still be hidden");
// Cleanup.
gHandlers.RemoveBrowserSharingListener();
for (let listenerId of listenerIds) {
gHandlers.RemoveBrowserSharingListener({ data: [listenerId] }, function() {});
}
yield removeTabs();
Services.prefs.clearUserPref(kPrefBrowserSharingInfoBar);
});

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

@ -4,7 +4,6 @@
Cu.import("resource://gre/modules/Promise.jsm");
const { SocialService } = Cu.import("resource://gre/modules/SocialService.jsm", {});
const { LoopAPI } = Cu.import("chrome://loop/content/modules/MozLoopAPI.jsm", {});
var [, gHandlers] = LoopAPI.inspect();

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

@ -7,7 +7,6 @@
"use strict";
const { LoopAPI } = Cu.import("chrome://loop/content/modules/MozLoopAPI.jsm", {});
var [, gHandlers] = LoopAPI.inspect();
var gConstants;
gHandlers.GetAllConstants({}, constants => gConstants = constants);

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

@ -9,6 +9,7 @@ const {
MozLoopServiceInternal,
MozLoopService
} = Cu.import("chrome://loop/content/modules/MozLoopService.jsm", {});
const { LoopAPI } = Cu.import("chrome://loop/content/modules/MozLoopAPI.jsm", {});
const { LoopRooms } = Cu.import("chrome://loop/content/modules/LoopRooms.jsm", {});
// Cache this value only once, at the beginning of a
@ -68,7 +69,7 @@ function promisePanelLoaded() {
function waitForCondition(condition, nextTest, errorMsg) {
var tries = 0;
var interval = setInterval(function() {
if (tries >= 30) {
if (tries >= 100) {
ok(false, errorMsg);
moveOn();
}

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

@ -27,13 +27,13 @@ describe("loop.store.ActiveRoomStore", function() {
SetLoopPref: sinon.stub(),
AddConversationContext: sinon.stub(),
AddBrowserSharingListener: sinon.stub().returns(42),
HangupNow: sinon.stub(),
RemoveBrowserSharingListener: sinon.stub(),
"Rooms:Get": sinon.stub().returns({
roomUrl: "http://invalid"
}),
"Rooms:Join": sinon.stub().returns({}),
"Rooms:RefreshMembership": sinon.stub().returns({ expires: 42 }),
"Rooms:Leave": sinon.stub(),
"Rooms:SendConnectionStatus": sinon.stub(),
"Rooms:PushSubscription": sinon.stub(),
SetScreenShareState: sinon.stub(),
@ -95,7 +95,8 @@ describe("loop.store.ActiveRoomStore", function() {
store.setStoreState({
roomState: ROOM_STATES.JOINED,
roomToken: "fakeToken",
sessionToken: "1627384950"
sessionToken: "1627384950",
windowId: "42"
});
});
@ -178,18 +179,6 @@ describe("loop.store.ActiveRoomStore", function() {
sinon.assert.calledOnce(fakeMultiplexGum.reset);
});
it("should set screen sharing inactive", function() {
store.setStoreState({ windowId: "1234" });
store.roomFailure(new sharedActions.RoomFailure({
error: fakeError,
failedJoinRequest: false
}));
sinon.assert.calledOnce(requestStubs.SetScreenShareState);
sinon.assert.calledWithExactly(requestStubs.SetScreenShareState, "1234", false);
});
it("should disconnect from the servers via the sdk", function() {
store.roomFailure(new sharedActions.RoomFailure({
error: fakeError,
@ -212,6 +201,8 @@ describe("loop.store.ActiveRoomStore", function() {
});
it("should remove the sharing listener", function() {
sandbox.stub(loop, "unsubscribe");
// Setup the listener.
store.startBrowserShare(new sharedActions.StartBrowserShare());
@ -221,27 +212,28 @@ describe("loop.store.ActiveRoomStore", function() {
failedJoinRequest: false
}));
sinon.assert.calledOnce(requestStubs.RemoveBrowserSharingListener);
sinon.assert.calledOnce(loop.unsubscribe);
sinon.assert.calledWith(loop.unsubscribe, "BrowserSwitch");
});
it("should call mozLoop.rooms.leave", function() {
it("should call 'HangupNow' Loop API", function() {
store.roomFailure(new sharedActions.RoomFailure({
error: fakeError,
failedJoinRequest: false
}));
sinon.assert.calledOnce(requestStubs["Rooms:Leave"]);
sinon.assert.calledWithExactly(requestStubs["Rooms:Leave"],
"fakeToken", "1627384950");
sinon.assert.calledOnce(requestStubs["HangupNow"]);
sinon.assert.calledWithExactly(requestStubs["HangupNow"],
"fakeToken", "42");
});
it("should not call mozLoop.rooms.leave if failedJoinRequest is true", function() {
it("should not call 'HangupNow' Loop API if failedJoinRequest is true", function() {
store.roomFailure(new sharedActions.RoomFailure({
error: fakeError,
failedJoinRequest: true
}));
sinon.assert.notCalled(requestStubs["Rooms:Leave"]);
sinon.assert.notCalled(requestStubs["HangupNow"]);
});
});
@ -1215,7 +1207,8 @@ describe("loop.store.ActiveRoomStore", function() {
store.setStoreState({
roomState: ROOM_STATES.JOINED,
roomToken: "fakeToken",
sessionToken: "1627384950"
sessionToken: "1627384950",
windowId: "42"
});
connectionFailureAction = new sharedActions.ConnectionFailure({
@ -1235,15 +1228,6 @@ describe("loop.store.ActiveRoomStore", function() {
sinon.assert.calledOnce(fakeMultiplexGum.reset);
});
it("should set screen sharing inactive", function() {
store.setStoreState({ windowId: "1234" });
store.connectionFailure(connectionFailureAction);
sinon.assert.calledOnce(requestStubs.SetScreenShareState);
sinon.assert.calledWithExactly(requestStubs.SetScreenShareState, "1234", false);
});
it("should disconnect from the servers via the sdk", function() {
store.connectionFailure(connectionFailureAction);
@ -1259,22 +1243,25 @@ describe("loop.store.ActiveRoomStore", function() {
sinon.assert.calledOnce(clearTimeout);
});
it("should call mozLoop.rooms.leave", function() {
it("should call 'HangupNow' Loop API", function() {
store.connectionFailure(connectionFailureAction);
sinon.assert.calledOnce(requestStubs["Rooms:Leave"]);
sinon.assert.calledWithExactly(requestStubs["Rooms:Leave"],
"fakeToken", "1627384950");
sinon.assert.calledOnce(requestStubs["HangupNow"]);
sinon.assert.calledWithExactly(requestStubs["HangupNow"],
"fakeToken", "42");
});
it("should remove the sharing listener", function() {
sandbox.stub(loop, "unsubscribe");
// Setup the listener.
store.startBrowserShare(new sharedActions.StartBrowserShare());
// Now simulate connection failure.
store.connectionFailure(connectionFailureAction);
sinon.assert.calledOnce(requestStubs.RemoveBrowserSharingListener);
sinon.assert.calledOnce(loop.unsubscribe);
sinon.assert.calledWith(loop.unsubscribe, "BrowserSwitch");
});
it("should set the state to `FAILED`", function() {
@ -1820,33 +1807,32 @@ describe("loop.store.ActiveRoomStore", function() {
sinon.assert.calledOnce(clearTimeout);
});
it("should call mozLoop.rooms.leave", function() {
it("should not call 'HangupNow' Loop API", function() {
store.windowUnload();
sinon.assert.calledOnce(requestStubs["Rooms:Leave"]);
sinon.assert.calledWithExactly(requestStubs["Rooms:Leave"],
"fakeToken", "1627384950");
sinon.assert.notCalled(requestStubs["HangupNow"]);
});
it("should call mozLoop.rooms.leave if the room state is JOINING",
it("should call not call 'HangupNow' Loop API if the room state is JOINING",
function() {
store.setStoreState({ roomState: ROOM_STATES.JOINING });
store.windowUnload();
sinon.assert.calledOnce(requestStubs["Rooms:Leave"]);
sinon.assert.calledWithExactly(requestStubs["Rooms:Leave"],
"fakeToken", "1627384950");
sinon.assert.notCalled(requestStubs["HangupNow"]);
});
it("should remove the sharing listener", function() {
sandbox.stub(loop, "unsubscribe");
// Setup the listener.
store.startBrowserShare(new sharedActions.StartBrowserShare());
// Now unload the window.
store.windowUnload();
sinon.assert.calledOnce(requestStubs.RemoveBrowserSharingListener);
sinon.assert.calledOnce(loop.unsubscribe);
sinon.assert.calledWith(loop.unsubscribe, "BrowserSwitch");
});
it("should set the state to CLOSING", function() {
@ -1886,22 +1872,23 @@ describe("loop.store.ActiveRoomStore", function() {
sinon.assert.calledOnce(clearTimeout);
});
it("should call mozLoop.rooms.leave", function() {
it("should not call 'HangupNow' Loop API", function() {
store.leaveRoom();
sinon.assert.calledOnce(requestStubs["Rooms:Leave"]);
sinon.assert.calledWithExactly(requestStubs["Rooms:Leave"],
"fakeToken", "1627384950");
sinon.assert.notCalled(requestStubs["HangupNow"]);
});
it("should remove the sharing listener", function() {
sandbox.stub(loop, "unsubscribe");
// Setup the listener.
store.startBrowserShare(new sharedActions.StartBrowserShare());
// Now leave the room.
store.leaveRoom();
sinon.assert.calledOnce(requestStubs.RemoveBrowserSharingListener);
sinon.assert.calledOnce(loop.unsubscribe);
sinon.assert.calledWith(loop.unsubscribe, "BrowserSwitch");
});
it("should set the state to ENDED", function() {

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

@ -60,6 +60,40 @@ add_test(function test_handleMessage() {
run_next_test();
});
add_test(function test_sendMessageToHandler() {
// Testing error branches.
LoopAPI.sendMessageToHandler({
name: "WellThisDoesNotExist"
}, err => {
Assert.ok(err.isError, "An error should be returned");
Assert.strictEqual(err.message,
"Ouch, no message handler available for 'WellThisDoesNotExist'",
"Error messages should match");
});
// Testing correct flow branches.
let hangupNowCalls = [];
LoopAPI.stubMessageHandlers({
HangupNow: function(message, reply) {
hangupNowCalls.push(message);
reply();
}
});
let message = {
name: "HangupNow",
data: ["fakeToken", 42]
};
LoopAPI.sendMessageToHandler(message);
Assert.strictEqual(hangupNowCalls.length, 1, "HangupNow handler should be called once");
Assert.deepEqual(hangupNowCalls.pop(), message, "Messages should be the same");
LoopAPI.restore();
run_next_test();
});
function run_test() {
do_register_cleanup(function() {
LoopAPI.destroy();