mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 1072323: Hook up the contact menus to be able to start outgoing calls. r=mikedeboer
This commit is contained in:
parent
21e19674e9
commit
86712e23bc
@ -592,11 +592,26 @@ function injectLoopAPI(targetWindow) {
|
||||
return MozLoopService.generateUUID();
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Starts a direct call to the contact addresses.
|
||||
*
|
||||
* @param {Object} contact The contact to call
|
||||
* @param {String} callType The type of call, e.g. "audio-video" or "audio-only"
|
||||
* @return true if the call is opened, false if it is not opened (i.e. busy)
|
||||
*/
|
||||
startDirectCall: {
|
||||
enumerable: true,
|
||||
writable: true,
|
||||
value: function(contact, callType) {
|
||||
MozLoopService.startDirectCall(contact, callType);
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
function onStatusChanged(aSubject, aTopic, aData) {
|
||||
let event = new targetWindow.CustomEvent("LoopStatusChanged");
|
||||
targetWindow.dispatchEvent(event)
|
||||
targetWindow.dispatchEvent(event);
|
||||
};
|
||||
|
||||
function onDOMWindowDestroyed(aSubject, aTopic, aData) {
|
||||
|
@ -719,13 +719,8 @@ let MozLoopServiceInternal = {
|
||||
if (respData.calls && Array.isArray(respData.calls)) {
|
||||
respData.calls.forEach((callData) => {
|
||||
if (!this.callsData.inUse) {
|
||||
this.callsData.inUse = true;
|
||||
callData.sessionType = sessionType;
|
||||
this.callsData.data = callData;
|
||||
this.openChatWindow(
|
||||
null,
|
||||
this.localizedStrings["incoming_call_title2"].textContent,
|
||||
"about:loopconversation#incoming/" + callData.callId);
|
||||
this._startCall(callData, "incoming");
|
||||
} else {
|
||||
this._returnBusy(callData);
|
||||
}
|
||||
@ -738,6 +733,44 @@ let MozLoopServiceInternal = {
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Starts a call, saves the call data, and opens a chat window.
|
||||
*
|
||||
* @param {Object} callData The data associated with the call including an id.
|
||||
* @param {Boolean} conversationType Whether or not the call is "incoming"
|
||||
* or "outgoing"
|
||||
*/
|
||||
_startCall: function(callData, conversationType) {
|
||||
this.callsData.inUse = true;
|
||||
this.callsData.data = callData;
|
||||
this.openChatWindow(
|
||||
null,
|
||||
// No title, let the page set that, to avoid flickering.
|
||||
"",
|
||||
"about:loopconversation#" + conversationType + "/" + callData.callId);
|
||||
},
|
||||
|
||||
/**
|
||||
* Starts a direct call to the contact addresses.
|
||||
*
|
||||
* @param {Object} contact The contact to call
|
||||
* @param {String} callType The type of call, e.g. "audio-video" or "audio-only"
|
||||
* @return true if the call is opened, false if it is not opened (i.e. busy)
|
||||
*/
|
||||
startDirectCall: function(contact, callType) {
|
||||
if (this.callsData.inUse)
|
||||
return false;
|
||||
|
||||
var callData = {
|
||||
contact: contact,
|
||||
callType: callType,
|
||||
callId: Math.floor((Math.random() * 10))
|
||||
};
|
||||
|
||||
this._startCall(callData, "outgoing");
|
||||
return true;
|
||||
},
|
||||
|
||||
/**
|
||||
* Open call progress websocket and terminate with a reason of busy
|
||||
* the server.
|
||||
@ -1505,4 +1538,15 @@ this.MozLoopService = {
|
||||
return MozLoopServiceInternal.hawkRequest(sessionType, path, method, payloadObj).catch(
|
||||
error => {MozLoopServiceInternal._hawkRequestError(error);});
|
||||
},
|
||||
|
||||
/**
|
||||
* Starts a direct call to the contact addresses.
|
||||
*
|
||||
* @param {Object} contact The contact to call
|
||||
* @param {String} callType The type of call, e.g. "audio-video" or "audio-only"
|
||||
* @return true if the call is opened, false if it is not opened (i.e. busy)
|
||||
*/
|
||||
startDirectCall: function(contact, callType) {
|
||||
MozLoopServiceInternal.startDirectCall(contact, callType);
|
||||
},
|
||||
};
|
||||
|
@ -13,6 +13,7 @@ loop.contacts = (function(_, mozL10n) {
|
||||
|
||||
const Button = loop.shared.views.Button;
|
||||
const ButtonGroup = loop.shared.views.ButtonGroup;
|
||||
const CALL_TYPES = loop.shared.utils.CALL_TYPES;
|
||||
|
||||
// Number of contacts to add to the list at the same time.
|
||||
const CONTACTS_CHUNK_SIZE = 100;
|
||||
@ -85,14 +86,12 @@ loop.contacts = (function(_, mozL10n) {
|
||||
return (
|
||||
React.DOM.ul({className: cx({ "dropdown-menu": true,
|
||||
"dropdown-menu-up": this.state.openDirUp })},
|
||||
React.DOM.li({className: cx({ "dropdown-menu-item": true,
|
||||
"disabled": true }),
|
||||
React.DOM.li({className: cx({ "dropdown-menu-item": true }),
|
||||
onClick: this.onItemClick, 'data-action': "video-call"},
|
||||
React.DOM.i({className: "icon icon-video-call"}),
|
||||
mozL10n.get("video_call_menu_button")
|
||||
),
|
||||
React.DOM.li({className: cx({ "dropdown-menu-item": true,
|
||||
"disabled": true }),
|
||||
React.DOM.li({className: cx({ "dropdown-menu-item": true }),
|
||||
onClick: this.onItemClick, 'data-action': "audio-call"},
|
||||
React.DOM.i({className: "icon icon-audio-call"}),
|
||||
mozL10n.get("audio_call_menu_button")
|
||||
@ -160,7 +159,8 @@ loop.contacts = (function(_, mozL10n) {
|
||||
return (
|
||||
currContact.name[0] !== nextContact.name[0] ||
|
||||
currContact.blocked !== nextContact.blocked ||
|
||||
getPreferredEmail(currContact).value !== getPreferredEmail(nextContact).value
|
||||
getPreferredEmail(currContact).value !==
|
||||
getPreferredEmail(nextContact).value
|
||||
);
|
||||
},
|
||||
|
||||
@ -316,6 +316,12 @@ loop.contacts = (function(_, mozL10n) {
|
||||
}
|
||||
});
|
||||
break;
|
||||
case "video-call":
|
||||
navigator.mozLoop.startDirectCall(contact, CALL_TYPES.AUDIO_VIDEO);
|
||||
break;
|
||||
case "audio-call":
|
||||
navigator.mozLoop.startDirectCall(contact, CALL_TYPES.AUDIO_ONLY);
|
||||
break;
|
||||
default:
|
||||
console.error("Unrecognized action: " + actionName);
|
||||
break;
|
||||
|
@ -13,6 +13,7 @@ loop.contacts = (function(_, mozL10n) {
|
||||
|
||||
const Button = loop.shared.views.Button;
|
||||
const ButtonGroup = loop.shared.views.ButtonGroup;
|
||||
const CALL_TYPES = loop.shared.utils.CALL_TYPES;
|
||||
|
||||
// Number of contacts to add to the list at the same time.
|
||||
const CONTACTS_CHUNK_SIZE = 100;
|
||||
@ -85,14 +86,12 @@ loop.contacts = (function(_, mozL10n) {
|
||||
return (
|
||||
<ul className={cx({ "dropdown-menu": true,
|
||||
"dropdown-menu-up": this.state.openDirUp })}>
|
||||
<li className={cx({ "dropdown-menu-item": true,
|
||||
"disabled": true })}
|
||||
<li className={cx({ "dropdown-menu-item": true })}
|
||||
onClick={this.onItemClick} data-action="video-call">
|
||||
<i className="icon icon-video-call" />
|
||||
{mozL10n.get("video_call_menu_button")}
|
||||
</li>
|
||||
<li className={cx({ "dropdown-menu-item": true,
|
||||
"disabled": true })}
|
||||
<li className={cx({ "dropdown-menu-item": true })}
|
||||
onClick={this.onItemClick} data-action="audio-call">
|
||||
<i className="icon icon-audio-call" />
|
||||
{mozL10n.get("audio_call_menu_button")}
|
||||
@ -160,7 +159,8 @@ loop.contacts = (function(_, mozL10n) {
|
||||
return (
|
||||
currContact.name[0] !== nextContact.name[0] ||
|
||||
currContact.blocked !== nextContact.blocked ||
|
||||
getPreferredEmail(currContact).value !== getPreferredEmail(nextContact).value
|
||||
getPreferredEmail(currContact).value !==
|
||||
getPreferredEmail(nextContact).value
|
||||
);
|
||||
},
|
||||
|
||||
@ -316,6 +316,12 @@ loop.contacts = (function(_, mozL10n) {
|
||||
}
|
||||
});
|
||||
break;
|
||||
case "video-call":
|
||||
navigator.mozLoop.startDirectCall(contact, CALL_TYPES.AUDIO_VIDEO);
|
||||
break;
|
||||
case "audio-call":
|
||||
navigator.mozLoop.startDirectCall(contact, CALL_TYPES.AUDIO_ONLY);
|
||||
break;
|
||||
default:
|
||||
console.error("Unrecognized action: " + actionName);
|
||||
break;
|
||||
|
@ -551,10 +551,6 @@ loop.conversation = (function(mozL10n) {
|
||||
sdkDriver: sdkDriver
|
||||
});
|
||||
|
||||
// XXX For now key this on the pref, but this should really be
|
||||
// set by the information from the mozLoop API when we can get it (bug 1072323).
|
||||
var outgoingEmail = navigator.mozLoop.getLoopCharPref("outgoingemail");
|
||||
|
||||
// XXX Old class creation for the incoming conversation view, whilst
|
||||
// we transition across (bug 1072323).
|
||||
var conversation = new sharedModels.ConversationModel(
|
||||
@ -566,14 +562,25 @@ loop.conversation = (function(mozL10n) {
|
||||
var helper = new loop.shared.utils.Helper();
|
||||
var locationHash = helper.locationHash();
|
||||
var callId;
|
||||
if (locationHash) {
|
||||
callId = locationHash.match(/\#incoming\/(.*)/)[1]
|
||||
conversation.set("callId", callId);
|
||||
var outgoing;
|
||||
|
||||
var hash = locationHash.match(/\#incoming\/(.*)/);
|
||||
if (hash) {
|
||||
callId = hash[1];
|
||||
outgoing = false;
|
||||
} else {
|
||||
hash = locationHash.match(/\#outgoing\/(.*)/);
|
||||
if (hash) {
|
||||
callId = hash[1];
|
||||
outgoing = true;
|
||||
}
|
||||
}
|
||||
|
||||
conversation.set({callId: callId});
|
||||
|
||||
window.addEventListener("unload", function(event) {
|
||||
// Handle direct close of dialog box via [x] control.
|
||||
navigator.mozLoop.releaseCallData(conversation.get("callId"));
|
||||
navigator.mozLoop.releaseCallData(callId);
|
||||
});
|
||||
|
||||
document.body.classList.add(loop.shared.utils.getTargetPlatform());
|
||||
@ -588,7 +595,7 @@ loop.conversation = (function(mozL10n) {
|
||||
|
||||
dispatcher.dispatch(new loop.shared.actions.GatherCallData({
|
||||
callId: callId,
|
||||
calleeId: outgoingEmail
|
||||
outgoing: outgoing
|
||||
}));
|
||||
}
|
||||
|
||||
|
@ -551,10 +551,6 @@ loop.conversation = (function(mozL10n) {
|
||||
sdkDriver: sdkDriver
|
||||
});
|
||||
|
||||
// XXX For now key this on the pref, but this should really be
|
||||
// set by the information from the mozLoop API when we can get it (bug 1072323).
|
||||
var outgoingEmail = navigator.mozLoop.getLoopCharPref("outgoingemail");
|
||||
|
||||
// XXX Old class creation for the incoming conversation view, whilst
|
||||
// we transition across (bug 1072323).
|
||||
var conversation = new sharedModels.ConversationModel(
|
||||
@ -566,14 +562,25 @@ loop.conversation = (function(mozL10n) {
|
||||
var helper = new loop.shared.utils.Helper();
|
||||
var locationHash = helper.locationHash();
|
||||
var callId;
|
||||
if (locationHash) {
|
||||
callId = locationHash.match(/\#incoming\/(.*)/)[1]
|
||||
conversation.set("callId", callId);
|
||||
var outgoing;
|
||||
|
||||
var hash = locationHash.match(/\#incoming\/(.*)/);
|
||||
if (hash) {
|
||||
callId = hash[1];
|
||||
outgoing = false;
|
||||
} else {
|
||||
hash = locationHash.match(/\#outgoing\/(.*)/);
|
||||
if (hash) {
|
||||
callId = hash[1];
|
||||
outgoing = true;
|
||||
}
|
||||
}
|
||||
|
||||
conversation.set({callId: callId});
|
||||
|
||||
window.addEventListener("unload", function(event) {
|
||||
// Handle direct close of dialog box via [x] control.
|
||||
navigator.mozLoop.releaseCallData(conversation.get("callId"));
|
||||
navigator.mozLoop.releaseCallData(callId);
|
||||
});
|
||||
|
||||
document.body.classList.add(loop.shared.utils.getTargetPlatform());
|
||||
@ -588,7 +595,7 @@ loop.conversation = (function(mozL10n) {
|
||||
|
||||
dispatcher.dispatch(new loop.shared.actions.GatherCallData({
|
||||
callId: callId,
|
||||
calleeId: outgoingEmail
|
||||
outgoing: outgoing
|
||||
}));
|
||||
}
|
||||
|
||||
|
@ -23,15 +23,35 @@ loop.conversationViews = (function(mozL10n) {
|
||||
*/
|
||||
var ConversationDetailView = React.createClass({displayName: 'ConversationDetailView',
|
||||
propTypes: {
|
||||
calleeId: React.PropTypes.string,
|
||||
contact: React.PropTypes.object
|
||||
},
|
||||
|
||||
// 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
|
||||
// finding a logical place for them to be shared.
|
||||
_getPreferredEmail: function(contact) {
|
||||
// A contact may not contain email addresses, but only a phone number.
|
||||
if (!contact.email || contact.email.length == 0) {
|
||||
return { value: "" };
|
||||
}
|
||||
return contact.email.find(e => e.pref) || contact.email[0];
|
||||
},
|
||||
|
||||
render: function() {
|
||||
document.title = this.props.calleeId;
|
||||
var contactName;
|
||||
|
||||
if (this.props.contact.name &&
|
||||
this.props.contact.name[0]) {
|
||||
contactName = this.props.contact.name[0];
|
||||
} else {
|
||||
contactName = this._getPreferredEmail(this.props.contact).value;
|
||||
}
|
||||
|
||||
document.title = contactName;
|
||||
|
||||
return (
|
||||
React.DOM.div({className: "call-window"},
|
||||
React.DOM.h2(null, this.props.calleeId),
|
||||
React.DOM.h2(null, contactName),
|
||||
React.DOM.div(null, this.props.children)
|
||||
)
|
||||
);
|
||||
@ -46,7 +66,7 @@ loop.conversationViews = (function(mozL10n) {
|
||||
propTypes: {
|
||||
dispatcher: React.PropTypes.instanceOf(loop.Dispatcher).isRequired,
|
||||
callState: React.PropTypes.string,
|
||||
calleeId: React.PropTypes.string,
|
||||
contact: React.PropTypes.object,
|
||||
enableCancelButton: React.PropTypes.bool
|
||||
},
|
||||
|
||||
@ -76,7 +96,7 @@ loop.conversationViews = (function(mozL10n) {
|
||||
});
|
||||
|
||||
return (
|
||||
ConversationDetailView({calleeId: this.props.calleeId},
|
||||
ConversationDetailView({contact: this.props.contact},
|
||||
|
||||
React.DOM.p({className: "btn-label"}, pendingStateString),
|
||||
|
||||
@ -340,8 +360,8 @@ loop.conversationViews = (function(mozL10n) {
|
||||
case CALL_STATES.ONGOING: {
|
||||
return (OngoingConversationView({
|
||||
dispatcher: this.props.dispatcher,
|
||||
video: {enabled: this.state.videoMuted},
|
||||
audio: {enabled: this.state.audioMuted}}
|
||||
video: {enabled: !this.state.videoMuted},
|
||||
audio: {enabled: !this.state.audioMuted}}
|
||||
)
|
||||
);
|
||||
}
|
||||
@ -352,7 +372,7 @@ loop.conversationViews = (function(mozL10n) {
|
||||
return (PendingConversationView({
|
||||
dispatcher: this.props.dispatcher,
|
||||
callState: this.state.callState,
|
||||
calleeId: this.state.calleeId,
|
||||
contact: this.state.contact,
|
||||
enableCancelButton: this._isCancellable()}
|
||||
))
|
||||
}
|
||||
|
@ -23,15 +23,35 @@ loop.conversationViews = (function(mozL10n) {
|
||||
*/
|
||||
var ConversationDetailView = React.createClass({
|
||||
propTypes: {
|
||||
calleeId: React.PropTypes.string,
|
||||
contact: React.PropTypes.object
|
||||
},
|
||||
|
||||
// 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
|
||||
// finding a logical place for them to be shared.
|
||||
_getPreferredEmail: function(contact) {
|
||||
// A contact may not contain email addresses, but only a phone number.
|
||||
if (!contact.email || contact.email.length == 0) {
|
||||
return { value: "" };
|
||||
}
|
||||
return contact.email.find(e => e.pref) || contact.email[0];
|
||||
},
|
||||
|
||||
render: function() {
|
||||
document.title = this.props.calleeId;
|
||||
var contactName;
|
||||
|
||||
if (this.props.contact.name &&
|
||||
this.props.contact.name[0]) {
|
||||
contactName = this.props.contact.name[0];
|
||||
} else {
|
||||
contactName = this._getPreferredEmail(this.props.contact).value;
|
||||
}
|
||||
|
||||
document.title = contactName;
|
||||
|
||||
return (
|
||||
<div className="call-window">
|
||||
<h2>{this.props.calleeId}</h2>
|
||||
<h2>{contactName}</h2>
|
||||
<div>{this.props.children}</div>
|
||||
</div>
|
||||
);
|
||||
@ -46,7 +66,7 @@ loop.conversationViews = (function(mozL10n) {
|
||||
propTypes: {
|
||||
dispatcher: React.PropTypes.instanceOf(loop.Dispatcher).isRequired,
|
||||
callState: React.PropTypes.string,
|
||||
calleeId: React.PropTypes.string,
|
||||
contact: React.PropTypes.object,
|
||||
enableCancelButton: React.PropTypes.bool
|
||||
},
|
||||
|
||||
@ -76,7 +96,7 @@ loop.conversationViews = (function(mozL10n) {
|
||||
});
|
||||
|
||||
return (
|
||||
<ConversationDetailView calleeId={this.props.calleeId}>
|
||||
<ConversationDetailView contact={this.props.contact}>
|
||||
|
||||
<p className="btn-label">{pendingStateString}</p>
|
||||
|
||||
@ -340,8 +360,8 @@ loop.conversationViews = (function(mozL10n) {
|
||||
case CALL_STATES.ONGOING: {
|
||||
return (<OngoingConversationView
|
||||
dispatcher={this.props.dispatcher}
|
||||
video={{enabled: this.state.videoMuted}}
|
||||
audio={{enabled: this.state.audioMuted}}
|
||||
video={{enabled: !this.state.videoMuted}}
|
||||
audio={{enabled: !this.state.audioMuted}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
@ -352,7 +372,7 @@ loop.conversationViews = (function(mozL10n) {
|
||||
return (<PendingConversationView
|
||||
dispatcher={this.props.dispatcher}
|
||||
callState={this.state.callState}
|
||||
calleeId={this.state.calleeId}
|
||||
contact={this.state.contact}
|
||||
enableCancelButton={this._isCancellable()}
|
||||
/>)
|
||||
}
|
||||
|
@ -34,11 +34,9 @@ loop.shared.actions = (function() {
|
||||
* Used to trigger gathering of initial call data.
|
||||
*/
|
||||
GatherCallData: Action.define("gatherCallData", {
|
||||
// XXX This may change when bug 1072323 is implemented.
|
||||
// Optional: Specify the calleeId for an outgoing call
|
||||
calleeId: [String, null],
|
||||
// Specify the callId for an incoming call.
|
||||
callId: [String, null]
|
||||
callId: [String, null],
|
||||
outgoing: Boolean
|
||||
}),
|
||||
|
||||
/**
|
||||
|
@ -63,8 +63,8 @@ loop.store = (function() {
|
||||
error: undefined,
|
||||
// True if the call is outgoing, false if not, undefined if unknown
|
||||
outgoing: undefined,
|
||||
// The id of the person being called for outgoing calls
|
||||
calleeId: undefined,
|
||||
// The contact being called for outgoing calls
|
||||
contact: undefined,
|
||||
// The call type for the call.
|
||||
// XXX Don't hard-code, this comes from the data in bug 1072323
|
||||
callType: CALL_TYPES.AUDIO_VIDEO,
|
||||
@ -83,9 +83,9 @@ loop.store = (function() {
|
||||
// SDK session token
|
||||
sessionToken: undefined,
|
||||
// If the audio is muted
|
||||
audioMuted: true,
|
||||
audioMuted: false,
|
||||
// If the video is muted
|
||||
videoMuted: true
|
||||
videoMuted: false
|
||||
},
|
||||
|
||||
/**
|
||||
@ -192,14 +192,29 @@ loop.store = (function() {
|
||||
* @param {sharedActions.GatherCallData} actionData The action data.
|
||||
*/
|
||||
gatherCallData: function(actionData) {
|
||||
if (!actionData.outgoing) {
|
||||
// XXX Other types aren't supported yet, but set the state for the
|
||||
// view selection.
|
||||
this.set({outgoing: false});
|
||||
return;
|
||||
}
|
||||
|
||||
var callData = navigator.mozLoop.getCallData(actionData.callId);
|
||||
if (!callData) {
|
||||
console.error("Failed to get the call data");
|
||||
this.set({callState: CALL_STATES.TERMINATED});
|
||||
return;
|
||||
}
|
||||
|
||||
this.set({
|
||||
calleeId: actionData.calleeId,
|
||||
outgoing: !!actionData.calleeId,
|
||||
contact: callData.contact,
|
||||
outgoing: actionData.outgoing,
|
||||
callId: actionData.callId,
|
||||
callType: callData.callType,
|
||||
callState: CALL_STATES.GATHER
|
||||
});
|
||||
|
||||
this.videoMuted = this.get("callType") !== CALL_TYPES.AUDIO_VIDEO;
|
||||
this.set({videoMuted: this.get("callType") === CALL_TYPES.AUDIO_ONLY});
|
||||
|
||||
if (this.get("outgoing")) {
|
||||
this._setupOutgoingCall();
|
||||
@ -285,7 +300,7 @@ loop.store = (function() {
|
||||
*/
|
||||
setMute: function(actionData) {
|
||||
var muteType = actionData.type + "Muted";
|
||||
this.set(muteType, actionData.enabled);
|
||||
this.set(muteType, !actionData.enabled);
|
||||
},
|
||||
|
||||
/**
|
||||
@ -293,8 +308,13 @@ loop.store = (function() {
|
||||
* result.
|
||||
*/
|
||||
_setupOutgoingCall: function() {
|
||||
// XXX For now, we only have one calleeId, so just wrap that in an array.
|
||||
this.client.setupOutgoingCall([this.get("calleeId")],
|
||||
var contactAddresses = [];
|
||||
|
||||
this.get("contact").email.forEach(function(address) {
|
||||
contactAddresses.push(address.value);
|
||||
});
|
||||
|
||||
this.client.setupOutgoingCall(contactAddresses,
|
||||
this.get("callType"),
|
||||
function(err, result) {
|
||||
if (err) {
|
||||
|
@ -4,7 +4,7 @@
|
||||
var expect = chai.expect;
|
||||
|
||||
describe("loop.conversationViews", function () {
|
||||
var sandbox, oldTitle, view, dispatcher;
|
||||
var sandbox, oldTitle, view, dispatcher, contact;
|
||||
|
||||
var CALL_STATES = loop.store.CALL_STATES;
|
||||
|
||||
@ -18,6 +18,15 @@ describe("loop.conversationViews", function () {
|
||||
|
||||
dispatcher = new loop.Dispatcher();
|
||||
sandbox.stub(dispatcher, "dispatch");
|
||||
|
||||
contact = {
|
||||
name: [ "mrsmith" ],
|
||||
email: [{
|
||||
type: "home",
|
||||
value: "fakeEmail",
|
||||
pref: true
|
||||
}]
|
||||
};
|
||||
});
|
||||
|
||||
afterEach(function() {
|
||||
@ -33,17 +42,28 @@ describe("loop.conversationViews", function () {
|
||||
}
|
||||
|
||||
it("should set the document title to the calledId", function() {
|
||||
mountTestComponent({calleeId: "mrsmith"});
|
||||
mountTestComponent({contact: contact});
|
||||
|
||||
expect(document.title).eql("mrsmith");
|
||||
});
|
||||
|
||||
it("should set display the calledId", function() {
|
||||
view = mountTestComponent({calleeId: "mrsmith"});
|
||||
view = mountTestComponent({contact: contact});
|
||||
|
||||
expect(TestUtils.findRenderedDOMComponentWithTag(
|
||||
view, "h2").props.children).eql("mrsmith");
|
||||
});
|
||||
|
||||
it("should fallback to the email if the contact name is not defined",
|
||||
function() {
|
||||
delete contact.name;
|
||||
|
||||
view = mountTestComponent({contact: contact});
|
||||
|
||||
expect(TestUtils.findRenderedDOMComponentWithTag(
|
||||
view, "h2").props.children).eql("fakeEmail");
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
describe("PendingConversationView", function() {
|
||||
@ -56,7 +76,7 @@ describe("loop.conversationViews", function () {
|
||||
function() {
|
||||
view = mountTestComponent({
|
||||
callState: CALL_STATES.CONNECTING,
|
||||
calleeId: "mrsmith",
|
||||
contact: contact,
|
||||
dispatcher: dispatcher
|
||||
});
|
||||
|
||||
@ -70,7 +90,7 @@ describe("loop.conversationViews", function () {
|
||||
function() {
|
||||
view = mountTestComponent({
|
||||
callState: CALL_STATES.ALERTING,
|
||||
calleeId: "mrsmith",
|
||||
contact: contact,
|
||||
dispatcher: dispatcher
|
||||
});
|
||||
|
||||
@ -84,7 +104,7 @@ describe("loop.conversationViews", function () {
|
||||
function() {
|
||||
view = mountTestComponent({
|
||||
callState: CALL_STATES.CONNECTING,
|
||||
calleeId: "mrsmith",
|
||||
contact: contact,
|
||||
dispatcher: dispatcher,
|
||||
enableCancelButton: false
|
||||
});
|
||||
@ -98,7 +118,7 @@ describe("loop.conversationViews", function () {
|
||||
function() {
|
||||
view = mountTestComponent({
|
||||
callState: CALL_STATES.CONNECTING,
|
||||
calleeId: "mrsmith",
|
||||
contact: contact,
|
||||
dispatcher: dispatcher,
|
||||
enableCancelButton: true
|
||||
});
|
||||
@ -112,7 +132,7 @@ describe("loop.conversationViews", function () {
|
||||
function() {
|
||||
view = mountTestComponent({
|
||||
callState: CALL_STATES.CONNECTING,
|
||||
calleeId: "mrsmith",
|
||||
contact: contact,
|
||||
dispatcher: dispatcher
|
||||
});
|
||||
|
||||
@ -293,7 +313,10 @@ describe("loop.conversationViews", function () {
|
||||
|
||||
it("should render the PendingConversationView when the call state is 'init'",
|
||||
function() {
|
||||
store.set({callState: CALL_STATES.INIT});
|
||||
store.set({
|
||||
callState: CALL_STATES.INIT,
|
||||
contact: contact
|
||||
});
|
||||
|
||||
view = mountTestComponent();
|
||||
|
||||
@ -323,7 +346,10 @@ describe("loop.conversationViews", function () {
|
||||
|
||||
it("should update the rendered views when the state is changed.",
|
||||
function() {
|
||||
store.set({callState: CALL_STATES.INIT});
|
||||
store.set({
|
||||
callState: CALL_STATES.INIT,
|
||||
contact: contact
|
||||
});
|
||||
|
||||
view = mountTestComponent();
|
||||
|
||||
|
@ -115,10 +115,24 @@ describe("loop.conversation", function() {
|
||||
sinon.assert.calledOnce(loop.Dispatcher.prototype.dispatch);
|
||||
sinon.assert.calledWithExactly(loop.Dispatcher.prototype.dispatch,
|
||||
new loop.shared.actions.GatherCallData({
|
||||
calleeId: null,
|
||||
callId: "42"
|
||||
callId: "42",
|
||||
outgoing: false
|
||||
}));
|
||||
});
|
||||
|
||||
it("should trigger an outgoing gatherCallData action for outgoing calls",
|
||||
function() {
|
||||
loop.shared.utils.Helper.prototype.locationHash.returns("#outgoing/24");
|
||||
|
||||
loop.conversation.init();
|
||||
|
||||
sinon.assert.calledOnce(loop.Dispatcher.prototype.dispatch);
|
||||
sinon.assert.calledWithExactly(loop.Dispatcher.prototype.dispatch,
|
||||
new loop.shared.actions.GatherCallData({
|
||||
callId: "24",
|
||||
outgoing: true
|
||||
}));
|
||||
});
|
||||
});
|
||||
|
||||
describe("ConversationControllerView", function() {
|
||||
@ -141,7 +155,16 @@ describe("loop.conversation", function() {
|
||||
sdk: {}
|
||||
});
|
||||
dispatcher = new loop.Dispatcher();
|
||||
store = new loop.store.ConversationStore({}, {
|
||||
store = new loop.store.ConversationStore({
|
||||
contact: {
|
||||
name: [ "Mr Smith" ],
|
||||
email: [{
|
||||
type: "home",
|
||||
value: "fakeEmail",
|
||||
pref: true
|
||||
}]
|
||||
}
|
||||
}, {
|
||||
client: client,
|
||||
dispatcher: dispatcher,
|
||||
sdkDriver: {}
|
||||
|
@ -11,6 +11,7 @@ describe("loop.ConversationStore", function () {
|
||||
var sharedActions = loop.shared.actions;
|
||||
var sharedUtils = loop.shared.utils;
|
||||
var sandbox, dispatcher, client, store, fakeSessionData, sdkDriver;
|
||||
var contact;
|
||||
var connectPromise, resolveConnectPromise, rejectConnectPromise;
|
||||
var wsCancelSpy, wsCloseSpy, wsMediaUpSpy, fakeWebsocket;
|
||||
|
||||
@ -26,6 +27,15 @@ describe("loop.ConversationStore", function () {
|
||||
beforeEach(function() {
|
||||
sandbox = sinon.sandbox.create();
|
||||
|
||||
contact = {
|
||||
name: [ "Mr Smith" ],
|
||||
email: [{
|
||||
type: "home",
|
||||
value: "fakeEmail",
|
||||
pref: true
|
||||
}]
|
||||
};
|
||||
|
||||
dispatcher = new loop.Dispatcher();
|
||||
client = {
|
||||
setupOutgoingCall: sinon.stub()
|
||||
@ -199,13 +209,26 @@ describe("loop.ConversationStore", function () {
|
||||
describe("#gatherCallData", function() {
|
||||
beforeEach(function() {
|
||||
store.set({callState: CALL_STATES.INIT});
|
||||
|
||||
navigator.mozLoop = {
|
||||
getCallData: function() {
|
||||
return {
|
||||
contact: contact,
|
||||
callType: sharedUtils.CALL_TYPES.AUDIO_VIDEO
|
||||
};
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
afterEach(function() {
|
||||
delete navigator.mozLoop;
|
||||
});
|
||||
|
||||
it("should set the state to 'gather'", function() {
|
||||
dispatcher.dispatch(
|
||||
new sharedActions.GatherCallData({
|
||||
calleeId: "",
|
||||
callId: "76543218"
|
||||
callId: "76543218",
|
||||
outgoing: true
|
||||
}));
|
||||
|
||||
expect(store.get("callState")).eql(CALL_STATES.GATHER);
|
||||
@ -214,22 +237,32 @@ describe("loop.ConversationStore", function () {
|
||||
it("should save the basic call information", function() {
|
||||
dispatcher.dispatch(
|
||||
new sharedActions.GatherCallData({
|
||||
calleeId: "fake",
|
||||
callId: "123456"
|
||||
callId: "123456",
|
||||
outgoing: true
|
||||
}));
|
||||
|
||||
expect(store.get("calleeId")).eql("fake");
|
||||
expect(store.get("callId")).eql("123456");
|
||||
expect(store.get("outgoing")).eql(true);
|
||||
});
|
||||
|
||||
it("should save the basic information from the mozLoop api", function() {
|
||||
dispatcher.dispatch(
|
||||
new sharedActions.GatherCallData({
|
||||
callId: "123456",
|
||||
outgoing: true
|
||||
}));
|
||||
|
||||
expect(store.get("contact")).eql(contact);
|
||||
expect(store.get("callType")).eql(sharedUtils.CALL_TYPES.AUDIO_VIDEO);
|
||||
});
|
||||
|
||||
describe("outgoing calls", function() {
|
||||
var outgoingCallData;
|
||||
|
||||
beforeEach(function() {
|
||||
outgoingCallData = {
|
||||
calleeId: "fake",
|
||||
callId: "135246"
|
||||
callId: "123456",
|
||||
outgoing: true
|
||||
};
|
||||
});
|
||||
|
||||
@ -239,7 +272,7 @@ describe("loop.ConversationStore", function () {
|
||||
|
||||
sinon.assert.calledOnce(client.setupOutgoingCall);
|
||||
sinon.assert.calledWith(client.setupOutgoingCall,
|
||||
["fake"], sharedUtils.CALL_TYPES.AUDIO_VIDEO);
|
||||
["fakeEmail"], sharedUtils.CALL_TYPES.AUDIO_VIDEO);
|
||||
});
|
||||
|
||||
describe("server response handling", function() {
|
||||
@ -488,14 +521,14 @@ describe("loop.ConversationStore", function () {
|
||||
callState: CALL_STATES.TERMINATED,
|
||||
outgoing: true,
|
||||
callType: sharedUtils.CALL_TYPES.AUDIO_VIDEO,
|
||||
calleeId: "fake"
|
||||
contact: contact
|
||||
});
|
||||
|
||||
dispatcher.dispatch(new sharedActions.RetryCall());
|
||||
|
||||
sinon.assert.calledOnce(client.setupOutgoingCall);
|
||||
sinon.assert.calledWith(client.setupOutgoingCall,
|
||||
["fake"], sharedUtils.CALL_TYPES.AUDIO_VIDEO);
|
||||
["fakeEmail"], sharedUtils.CALL_TYPES.AUDIO_VIDEO);
|
||||
});
|
||||
});
|
||||
|
||||
@ -518,7 +551,7 @@ describe("loop.ConversationStore", function () {
|
||||
enabled: true
|
||||
}));
|
||||
|
||||
expect(store.get("audioMuted")).eql(true);
|
||||
expect(store.get("audioMuted")).eql(false);
|
||||
});
|
||||
|
||||
it("should save the mute state for the video stream", function() {
|
||||
@ -529,7 +562,7 @@ describe("loop.ConversationStore", function () {
|
||||
enabled: false
|
||||
}));
|
||||
|
||||
expect(store.get("videoMuted")).eql(false);
|
||||
expect(store.get("videoMuted")).eql(true);
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -46,7 +46,7 @@ describe("loop.Dispatcher", function () {
|
||||
beforeEach(function() {
|
||||
gatherAction = new sharedActions.GatherCallData({
|
||||
callId: "42",
|
||||
calleeId: null
|
||||
outgoing: false
|
||||
});
|
||||
|
||||
cancelAction = new sharedActions.CancelCall();
|
||||
|
@ -0,0 +1,59 @@
|
||||
/* 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/. */
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "Chat",
|
||||
"resource:///modules/Chat.jsm");
|
||||
let openChatOrig = Chat.open;
|
||||
|
||||
const contact = {
|
||||
name: [ "Mr Smith" ],
|
||||
email: [{
|
||||
type: "home",
|
||||
value: "fakeEmail",
|
||||
pref: true
|
||||
}]
|
||||
};
|
||||
|
||||
add_task(function test_startDirectCall_opens_window() {
|
||||
let openedUrl;
|
||||
Chat.open = function(contentWindow, origin, title, url) {
|
||||
openedUrl = url;
|
||||
};
|
||||
|
||||
MozLoopService.startDirectCall(contact, "audio-video");
|
||||
|
||||
do_check_true(!!openedUrl, "should open a chat window");
|
||||
|
||||
// Stop the busy kicking in for following tests.
|
||||
let callId = openedUrl.match(/about:loopconversation\#outgoing\/(.*)/)[1];
|
||||
MozLoopService.releaseCallData(callId);
|
||||
});
|
||||
|
||||
add_task(function test_startDirectCall_getCallData() {
|
||||
let openedUrl;
|
||||
Chat.open = function(contentWindow, origin, title, url) {
|
||||
openedUrl = url;
|
||||
};
|
||||
|
||||
MozLoopService.startDirectCall(contact, "audio-video");
|
||||
|
||||
let callId = openedUrl.match(/about:loopconversation\#outgoing\/(.*)/)[1];
|
||||
|
||||
let callData = MozLoopService.getCallData(callId);
|
||||
|
||||
do_check_eq(callData.callType, "audio-video", "should have the correct call type");
|
||||
do_check_eq(callData.contact, contact, "should have the contact details");
|
||||
|
||||
// Stop the busy kicking in for following tests.
|
||||
MozLoopService.releaseCallData(callId);
|
||||
});
|
||||
|
||||
function run_test() {
|
||||
do_register_cleanup(function() {
|
||||
// Revert original Chat.open implementation
|
||||
Chat.open = openChatOrig;
|
||||
});
|
||||
|
||||
run_next_test();
|
||||
}
|
@ -5,6 +5,7 @@ firefox-appdir = browser
|
||||
|
||||
[test_loopapi_hawk_request.js]
|
||||
[test_looppush_initialize.js]
|
||||
[test_loopservice_directcall.js]
|
||||
[test_loopservice_dnd.js]
|
||||
[test_loopservice_expiry.js]
|
||||
[test_loopservice_hawk_errors.js]
|
||||
@ -17,4 +18,4 @@ firefox-appdir = browser
|
||||
[test_loopservice_token_save.js]
|
||||
[test_loopservice_token_send.js]
|
||||
[test_loopservice_token_validation.js]
|
||||
[test_loopservice_busy.js]
|
||||
[test_loopservice_busy.js]
|
||||
|
Loading…
Reference in New Issue
Block a user