зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1065201: introduce new sounds for Hello standalone and desktop. r=mikedeboer
This commit is contained in:
Родитель
61eeb953f5
Коммит
002e180974
|
@ -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.ToS_url", "https://hello.firefox.com/legal/terms/");
|
||||||
pref("loop.legal.privacy_url", "https://www.mozilla.org/privacy/");
|
pref("loop.legal.privacy_url", "https://www.mozilla.org/privacy/");
|
||||||
pref("loop.do_not_disturb", false);
|
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.start", 60000);
|
||||||
pref("loop.retry_delay.limit", 300000);
|
pref("loop.retry_delay.limit", 300000);
|
||||||
pref("loop.feedback.baseUrl", "https://input.mozilla.org/api/v1/feedback");
|
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.websocket", false);
|
||||||
pref("loop.debug.sdk", false);
|
pref("loop.debug.sdk", false);
|
||||||
#ifdef DEBUG
|
#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
|
#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
|
#endif
|
||||||
pref("loop.oauth.google.redirect_uri", "urn:ietf:wg:oauth:2.0:oob:auto");
|
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");
|
pref("loop.oauth.google.scope", "https://www.google.com/m8/feeds");
|
||||||
|
|
|
@ -13,6 +13,7 @@ Cu.import("resource:///modules/loop/LoopCalls.jsm");
|
||||||
Cu.import("resource:///modules/loop/MozLoopService.jsm");
|
Cu.import("resource:///modules/loop/MozLoopService.jsm");
|
||||||
Cu.import("resource:///modules/loop/LoopRooms.jsm");
|
Cu.import("resource:///modules/loop/LoopRooms.jsm");
|
||||||
Cu.import("resource:///modules/loop/LoopContacts.jsm");
|
Cu.import("resource:///modules/loop/LoopContacts.jsm");
|
||||||
|
Cu.importGlobalProperties(["Blob"]);
|
||||||
|
|
||||||
XPCOMUtils.defineLazyModuleGetter(this, "LoopContacts",
|
XPCOMUtils.defineLazyModuleGetter(this, "LoopContacts",
|
||||||
"resource:///modules/loop/LoopContacts.jsm");
|
"resource:///modules/loop/LoopContacts.jsm");
|
||||||
|
@ -685,6 +686,31 @@ function injectLoopAPI(targetWindow) {
|
||||||
return MozLoopService.generateUUID();
|
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) {
|
function onStatusChanged(aSubject, aTopic, aData) {
|
||||||
|
|
|
@ -21,7 +21,7 @@ loop.conversation = (function(mozL10n) {
|
||||||
var DesktopRoomView = loop.roomViews.DesktopRoomView;
|
var DesktopRoomView = loop.roomViews.DesktopRoomView;
|
||||||
|
|
||||||
var IncomingCallView = React.createClass({displayName: 'IncomingCallView',
|
var IncomingCallView = React.createClass({displayName: 'IncomingCallView',
|
||||||
mixins: [sharedMixins.DropdownMenuMixin],
|
mixins: [sharedMixins.DropdownMenuMixin, sharedMixins.AudioMixin],
|
||||||
|
|
||||||
propTypes: {
|
propTypes: {
|
||||||
model: React.PropTypes.object.isRequired,
|
model: React.PropTypes.object.isRequired,
|
||||||
|
@ -185,10 +185,16 @@ loop.conversation = (function(mozL10n) {
|
||||||
* incoming call views (bug 1088672).
|
* incoming call views (bug 1088672).
|
||||||
*/
|
*/
|
||||||
var GenericFailureView = React.createClass({displayName: 'GenericFailureView',
|
var GenericFailureView = React.createClass({displayName: 'GenericFailureView',
|
||||||
|
mixins: [sharedMixins.AudioMixin],
|
||||||
|
|
||||||
propTypes: {
|
propTypes: {
|
||||||
cancelCall: React.PropTypes.func.isRequired
|
cancelCall: React.PropTypes.func.isRequired
|
||||||
},
|
},
|
||||||
|
|
||||||
|
componentDidMount: function() {
|
||||||
|
this.play("failure");
|
||||||
|
},
|
||||||
|
|
||||||
render: function() {
|
render: function() {
|
||||||
document.title = mozL10n.get("generic_failure_title");
|
document.title = mozL10n.get("generic_failure_title");
|
||||||
|
|
||||||
|
|
|
@ -21,7 +21,7 @@ loop.conversation = (function(mozL10n) {
|
||||||
var DesktopRoomView = loop.roomViews.DesktopRoomView;
|
var DesktopRoomView = loop.roomViews.DesktopRoomView;
|
||||||
|
|
||||||
var IncomingCallView = React.createClass({
|
var IncomingCallView = React.createClass({
|
||||||
mixins: [sharedMixins.DropdownMenuMixin],
|
mixins: [sharedMixins.DropdownMenuMixin, sharedMixins.AudioMixin],
|
||||||
|
|
||||||
propTypes: {
|
propTypes: {
|
||||||
model: React.PropTypes.object.isRequired,
|
model: React.PropTypes.object.isRequired,
|
||||||
|
@ -185,10 +185,16 @@ loop.conversation = (function(mozL10n) {
|
||||||
* incoming call views (bug 1088672).
|
* incoming call views (bug 1088672).
|
||||||
*/
|
*/
|
||||||
var GenericFailureView = React.createClass({
|
var GenericFailureView = React.createClass({
|
||||||
|
mixins: [sharedMixins.AudioMixin],
|
||||||
|
|
||||||
propTypes: {
|
propTypes: {
|
||||||
cancelCall: React.PropTypes.func.isRequired
|
cancelCall: React.PropTypes.func.isRequired
|
||||||
},
|
},
|
||||||
|
|
||||||
|
componentDidMount: function() {
|
||||||
|
this.play("failure");
|
||||||
|
},
|
||||||
|
|
||||||
render: function() {
|
render: function() {
|
||||||
document.title = mozL10n.get("generic_failure_title");
|
document.title = mozL10n.get("generic_failure_title");
|
||||||
|
|
||||||
|
|
|
@ -14,6 +14,7 @@ loop.conversationViews = (function(mozL10n) {
|
||||||
var sharedActions = loop.shared.actions;
|
var sharedActions = loop.shared.actions;
|
||||||
var sharedUtils = loop.shared.utils;
|
var sharedUtils = loop.shared.utils;
|
||||||
var sharedViews = loop.shared.views;
|
var sharedViews = loop.shared.views;
|
||||||
|
var sharedMixins = loop.shared.mixins;
|
||||||
|
|
||||||
// This duplicates a similar function in contacts.jsx that isn't used in the
|
// 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
|
// 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.
|
* pending/ringing strings.
|
||||||
*/
|
*/
|
||||||
var PendingConversationView = React.createClass({displayName: 'PendingConversationView',
|
var PendingConversationView = React.createClass({displayName: 'PendingConversationView',
|
||||||
|
mixins: [sharedMixins.AudioMixin],
|
||||||
|
|
||||||
propTypes: {
|
propTypes: {
|
||||||
dispatcher: React.PropTypes.instanceOf(loop.Dispatcher).isRequired,
|
dispatcher: React.PropTypes.instanceOf(loop.Dispatcher).isRequired,
|
||||||
callState: React.PropTypes.string,
|
callState: React.PropTypes.string,
|
||||||
|
@ -146,6 +149,10 @@ loop.conversationViews = (function(mozL10n) {
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
|
componentDidMount: function() {
|
||||||
|
this.play("ringtone", {loop: true});
|
||||||
|
},
|
||||||
|
|
||||||
cancelCall: function() {
|
cancelCall: function() {
|
||||||
this.props.dispatcher.dispatch(new sharedActions.CancelCall());
|
this.props.dispatcher.dispatch(new sharedActions.CancelCall());
|
||||||
},
|
},
|
||||||
|
@ -186,7 +193,7 @@ loop.conversationViews = (function(mozL10n) {
|
||||||
* Call failed view. Displayed when a call fails.
|
* Call failed view. Displayed when a call fails.
|
||||||
*/
|
*/
|
||||||
var CallFailedView = React.createClass({displayName: 'CallFailedView',
|
var CallFailedView = React.createClass({displayName: 'CallFailedView',
|
||||||
mixins: [Backbone.Events],
|
mixins: [Backbone.Events, sharedMixins.AudioMixin],
|
||||||
|
|
||||||
propTypes: {
|
propTypes: {
|
||||||
dispatcher: React.PropTypes.instanceOf(loop.Dispatcher).isRequired,
|
dispatcher: React.PropTypes.instanceOf(loop.Dispatcher).isRequired,
|
||||||
|
@ -205,6 +212,7 @@ loop.conversationViews = (function(mozL10n) {
|
||||||
},
|
},
|
||||||
|
|
||||||
componentDidMount: function() {
|
componentDidMount: function() {
|
||||||
|
this.play("failure");
|
||||||
this.listenTo(this.props.store, "change:emailLink",
|
this.listenTo(this.props.store, "change:emailLink",
|
||||||
this._onEmailLinkReceived);
|
this._onEmailLinkReceived);
|
||||||
this.listenTo(this.props.store, "error:emailLink",
|
this.listenTo(this.props.store, "error:emailLink",
|
||||||
|
|
|
@ -14,6 +14,7 @@ loop.conversationViews = (function(mozL10n) {
|
||||||
var sharedActions = loop.shared.actions;
|
var sharedActions = loop.shared.actions;
|
||||||
var sharedUtils = loop.shared.utils;
|
var sharedUtils = loop.shared.utils;
|
||||||
var sharedViews = loop.shared.views;
|
var sharedViews = loop.shared.views;
|
||||||
|
var sharedMixins = loop.shared.mixins;
|
||||||
|
|
||||||
// This duplicates a similar function in contacts.jsx that isn't used in the
|
// 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
|
// 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.
|
* pending/ringing strings.
|
||||||
*/
|
*/
|
||||||
var PendingConversationView = React.createClass({
|
var PendingConversationView = React.createClass({
|
||||||
|
mixins: [sharedMixins.AudioMixin],
|
||||||
|
|
||||||
propTypes: {
|
propTypes: {
|
||||||
dispatcher: React.PropTypes.instanceOf(loop.Dispatcher).isRequired,
|
dispatcher: React.PropTypes.instanceOf(loop.Dispatcher).isRequired,
|
||||||
callState: React.PropTypes.string,
|
callState: React.PropTypes.string,
|
||||||
|
@ -146,6 +149,10 @@ loop.conversationViews = (function(mozL10n) {
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
|
componentDidMount: function() {
|
||||||
|
this.play("ringtone", {loop: true});
|
||||||
|
},
|
||||||
|
|
||||||
cancelCall: function() {
|
cancelCall: function() {
|
||||||
this.props.dispatcher.dispatch(new sharedActions.CancelCall());
|
this.props.dispatcher.dispatch(new sharedActions.CancelCall());
|
||||||
},
|
},
|
||||||
|
@ -186,7 +193,7 @@ loop.conversationViews = (function(mozL10n) {
|
||||||
* Call failed view. Displayed when a call fails.
|
* Call failed view. Displayed when a call fails.
|
||||||
*/
|
*/
|
||||||
var CallFailedView = React.createClass({
|
var CallFailedView = React.createClass({
|
||||||
mixins: [Backbone.Events],
|
mixins: [Backbone.Events, sharedMixins.AudioMixin],
|
||||||
|
|
||||||
propTypes: {
|
propTypes: {
|
||||||
dispatcher: React.PropTypes.instanceOf(loop.Dispatcher).isRequired,
|
dispatcher: React.PropTypes.instanceOf(loop.Dispatcher).isRequired,
|
||||||
|
@ -205,6 +212,7 @@ loop.conversationViews = (function(mozL10n) {
|
||||||
},
|
},
|
||||||
|
|
||||||
componentDidMount: function() {
|
componentDidMount: function() {
|
||||||
|
this.play("failure");
|
||||||
this.listenTo(this.props.store, "change:emailLink",
|
this.listenTo(this.props.store, "change:emailLink",
|
||||||
this._onEmailLinkReceived);
|
this._onEmailLinkReceived);
|
||||||
this.listenTo(this.props.store, "error:emailLink",
|
this.listenTo(this.props.store, "error:emailLink",
|
||||||
|
|
|
@ -141,6 +141,7 @@ loop.shared.mixins = (function() {
|
||||||
*/
|
*/
|
||||||
var AudioMixin = {
|
var AudioMixin = {
|
||||||
audio: null,
|
audio: null,
|
||||||
|
_audioRequest: null,
|
||||||
|
|
||||||
_isLoopDesktop: function() {
|
_isLoopDesktop: function() {
|
||||||
return typeof rootObject.navigator.mozLoop === "object";
|
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.
|
* 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) {
|
play: function(name, options) {
|
||||||
if (this._isLoopDesktop()) {
|
|
||||||
// XXX: We need navigator.mozLoop.playSound(name), see Bug 1089585.
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
options = options || {};
|
options = options || {};
|
||||||
options.loop = options.loop || false;
|
options.loop = options.loop || false;
|
||||||
|
|
||||||
this._ensureAudioStopped();
|
this._ensureAudioStopped();
|
||||||
this.audio = new Audio('shared/sounds/' + filename + ".ogg");
|
this._getAudioBlob(name, function(error, blob) {
|
||||||
this.audio.loop = options.loop;
|
if (error) {
|
||||||
this.audio.play();
|
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.
|
* Ensures audio is stopped playing, and removes the object from memory.
|
||||||
*/
|
*/
|
||||||
_ensureAudioStopped: function() {
|
_ensureAudioStopped: function() {
|
||||||
|
if (this._audioRequest) {
|
||||||
|
this._audioRequest.abort();
|
||||||
|
delete this._audioRequest;
|
||||||
|
}
|
||||||
|
|
||||||
if (this.audio) {
|
if (this.audio) {
|
||||||
this.audio.pause();
|
this.audio.pause();
|
||||||
this.audio.removeAttribute("src");
|
this.audio.removeAttribute("src");
|
||||||
|
|
|
@ -540,6 +540,8 @@ loop.shared.views = (function(_, OT, l10n) {
|
||||||
* Feedback view.
|
* Feedback view.
|
||||||
*/
|
*/
|
||||||
var FeedbackView = React.createClass({displayName: 'FeedbackView',
|
var FeedbackView = React.createClass({displayName: 'FeedbackView',
|
||||||
|
mixins: [sharedMixins.AudioMixin],
|
||||||
|
|
||||||
propTypes: {
|
propTypes: {
|
||||||
// A loop.FeedbackAPIClient instance
|
// A loop.FeedbackAPIClient instance
|
||||||
feedbackApiClient: React.PropTypes.object.isRequired,
|
feedbackApiClient: React.PropTypes.object.isRequired,
|
||||||
|
@ -556,6 +558,10 @@ loop.shared.views = (function(_, OT, l10n) {
|
||||||
return {step: "start"};
|
return {step: "start"};
|
||||||
},
|
},
|
||||||
|
|
||||||
|
componentDidMount: function() {
|
||||||
|
this.play("terminated");
|
||||||
|
},
|
||||||
|
|
||||||
reset: function() {
|
reset: function() {
|
||||||
this.setState(this.getInitialState());
|
this.setState(this.getInitialState());
|
||||||
},
|
},
|
||||||
|
|
|
@ -540,6 +540,8 @@ loop.shared.views = (function(_, OT, l10n) {
|
||||||
* Feedback view.
|
* Feedback view.
|
||||||
*/
|
*/
|
||||||
var FeedbackView = React.createClass({
|
var FeedbackView = React.createClass({
|
||||||
|
mixins: [sharedMixins.AudioMixin],
|
||||||
|
|
||||||
propTypes: {
|
propTypes: {
|
||||||
// A loop.FeedbackAPIClient instance
|
// A loop.FeedbackAPIClient instance
|
||||||
feedbackApiClient: React.PropTypes.object.isRequired,
|
feedbackApiClient: React.PropTypes.object.isRequired,
|
||||||
|
@ -556,6 +558,10 @@ loop.shared.views = (function(_, OT, l10n) {
|
||||||
return {step: "start"};
|
return {step: "start"};
|
||||||
},
|
},
|
||||||
|
|
||||||
|
componentDidMount: function() {
|
||||||
|
this.play("terminated");
|
||||||
|
},
|
||||||
|
|
||||||
reset: function() {
|
reset: function() {
|
||||||
this.setState(this.getInitialState());
|
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)
|
content/browser/loop/shared/libs/backbone-1.1.2.js (content/shared/libs/backbone-1.1.2.js)
|
||||||
|
|
||||||
# Shared sounds
|
# 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
|
# Partner SDK assets
|
||||||
content/browser/loop/libs/sdk.js (content/shared/libs/sdk.js)
|
content/browser/loop/libs/sdk.js (content/shared/libs/sdk.js)
|
||||||
|
|
|
@ -286,7 +286,7 @@ loop.webapp = (function($, _, OT, mozL10n) {
|
||||||
},
|
},
|
||||||
|
|
||||||
_handleRingingProgress: function() {
|
_handleRingingProgress: function() {
|
||||||
this.play("ringing", {loop: true});
|
this.play("ringtone", {loop: true});
|
||||||
this.setState({callState: "ringing"});
|
this.setState({callState: "ringing"});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -534,8 +534,6 @@ loop.webapp = (function($, _, OT, mozL10n) {
|
||||||
* Ended conversation view.
|
* Ended conversation view.
|
||||||
*/
|
*/
|
||||||
var EndedConversationView = React.createClass({displayName: 'EndedConversationView',
|
var EndedConversationView = React.createClass({displayName: 'EndedConversationView',
|
||||||
mixins: [sharedMixins.AudioMixin],
|
|
||||||
|
|
||||||
propTypes: {
|
propTypes: {
|
||||||
conversation: React.PropTypes.instanceOf(sharedModels.ConversationModel)
|
conversation: React.PropTypes.instanceOf(sharedModels.ConversationModel)
|
||||||
.isRequired,
|
.isRequired,
|
||||||
|
@ -544,10 +542,6 @@ loop.webapp = (function($, _, OT, mozL10n) {
|
||||||
onAfterFeedbackReceived: React.PropTypes.func.isRequired
|
onAfterFeedbackReceived: React.PropTypes.func.isRequired
|
||||||
},
|
},
|
||||||
|
|
||||||
componentDidMount: function() {
|
|
||||||
this.play("terminated");
|
|
||||||
},
|
|
||||||
|
|
||||||
render: function() {
|
render: function() {
|
||||||
document.title = mozL10n.get("standalone_title_with_status",
|
document.title = mozL10n.get("standalone_title_with_status",
|
||||||
{clientShortname: mozL10n.get("clientShortname2"),
|
{clientShortname: mozL10n.get("clientShortname2"),
|
||||||
|
|
|
@ -286,7 +286,7 @@ loop.webapp = (function($, _, OT, mozL10n) {
|
||||||
},
|
},
|
||||||
|
|
||||||
_handleRingingProgress: function() {
|
_handleRingingProgress: function() {
|
||||||
this.play("ringing", {loop: true});
|
this.play("ringtone", {loop: true});
|
||||||
this.setState({callState: "ringing"});
|
this.setState({callState: "ringing"});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -534,8 +534,6 @@ loop.webapp = (function($, _, OT, mozL10n) {
|
||||||
* Ended conversation view.
|
* Ended conversation view.
|
||||||
*/
|
*/
|
||||||
var EndedConversationView = React.createClass({
|
var EndedConversationView = React.createClass({
|
||||||
mixins: [sharedMixins.AudioMixin],
|
|
||||||
|
|
||||||
propTypes: {
|
propTypes: {
|
||||||
conversation: React.PropTypes.instanceOf(sharedModels.ConversationModel)
|
conversation: React.PropTypes.instanceOf(sharedModels.ConversationModel)
|
||||||
.isRequired,
|
.isRequired,
|
||||||
|
@ -544,10 +542,6 @@ loop.webapp = (function($, _, OT, mozL10n) {
|
||||||
onAfterFeedbackReceived: React.PropTypes.func.isRequired
|
onAfterFeedbackReceived: React.PropTypes.func.isRequired
|
||||||
},
|
},
|
||||||
|
|
||||||
componentDidMount: function() {
|
|
||||||
this.play("terminated");
|
|
||||||
},
|
|
||||||
|
|
||||||
render: function() {
|
render: function() {
|
||||||
document.title = mozL10n.get("standalone_title_with_status",
|
document.title = mozL10n.get("standalone_title_with_status",
|
||||||
{clientShortname: mozL10n.get("clientShortname2"),
|
{clientShortname: mozL10n.get("clientShortname2"),
|
||||||
|
|
|
@ -7,7 +7,7 @@ describe("loop.conversationViews", function () {
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
var sharedUtils = loop.shared.utils;
|
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;
|
var CALL_STATES = loop.store.CALL_STATES;
|
||||||
|
|
||||||
|
@ -30,11 +30,39 @@ describe("loop.conversationViews", function () {
|
||||||
pref: true
|
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() {
|
afterEach(function() {
|
||||||
document.title = oldTitle;
|
document.title = oldTitle;
|
||||||
view = undefined;
|
view = undefined;
|
||||||
|
delete navigator.mozLoop;
|
||||||
sandbox.restore();
|
sandbox.restore();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -202,7 +230,7 @@ describe("loop.conversationViews", function () {
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("CallFailedView", function() {
|
describe("CallFailedView", function() {
|
||||||
var store;
|
var store, fakeAudio;
|
||||||
|
|
||||||
function mountTestComponent(props) {
|
function mountTestComponent(props) {
|
||||||
return TestUtils.renderIntoDocument(
|
return TestUtils.renderIntoDocument(
|
||||||
|
@ -219,6 +247,12 @@ describe("loop.conversationViews", function () {
|
||||||
client: {},
|
client: {},
|
||||||
sdkDriver: {}
|
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",
|
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);
|
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() {
|
describe("OngoingConversationView", function() {
|
||||||
|
@ -412,11 +456,6 @@ describe("loop.conversationViews", function () {
|
||||||
}
|
}
|
||||||
|
|
||||||
beforeEach(function() {
|
beforeEach(function() {
|
||||||
navigator.mozLoop = {
|
|
||||||
getLoopCharPref: function() { return "fake"; },
|
|
||||||
appVersionInfo: sinon.spy()
|
|
||||||
};
|
|
||||||
|
|
||||||
store = new loop.store.ConversationStore({}, {
|
store = new loop.store.ConversationStore({}, {
|
||||||
dispatcher: dispatcher,
|
dispatcher: dispatcher,
|
||||||
client: {},
|
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'",
|
it("should render the CallFailedView when the call state is 'terminated'",
|
||||||
function() {
|
function() {
|
||||||
store.set({callState: CALL_STATES.TERMINATED});
|
store.set({callState: CALL_STATES.TERMINATED});
|
||||||
|
|
|
@ -57,7 +57,10 @@ describe("loop.conversation", function() {
|
||||||
channel: "test",
|
channel: "test",
|
||||||
platform: "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
|
// XXX These stubs should be hoisted in a common file
|
||||||
|
@ -690,8 +693,8 @@ describe("loop.conversation", function() {
|
||||||
function() {
|
function() {
|
||||||
conversation.trigger("session:network-disconnected");
|
conversation.trigger("session:network-disconnected");
|
||||||
|
|
||||||
TestUtils.findRenderedComponentWithType(icView,
|
TestUtils.findRenderedComponentWithType(icView,
|
||||||
loop.conversation.GenericFailureView);
|
loop.conversation.GenericFailureView);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should update the conversation window toolbar title",
|
it("should update the conversation window toolbar title",
|
||||||
|
@ -747,7 +750,7 @@ describe("loop.conversation", function() {
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("IncomingCallView", function() {
|
describe("IncomingCallView", function() {
|
||||||
var view, model;
|
var view, model, fakeAudio;
|
||||||
|
|
||||||
beforeEach(function() {
|
beforeEach(function() {
|
||||||
var Model = Backbone.Model.extend({
|
var Model = Backbone.Model.extend({
|
||||||
|
@ -757,6 +760,13 @@ describe("loop.conversation", function() {
|
||||||
sandbox.spy(model, "trigger");
|
sandbox.spy(model, "trigger");
|
||||||
sandbox.stub(model, "set");
|
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({
|
view = TestUtils.renderIntoDocument(loop.conversation.IncomingCallView({
|
||||||
model: model,
|
model: model,
|
||||||
video: true
|
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);
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -15,7 +15,7 @@ describe("loop.shared.views", function() {
|
||||||
var sharedModels = loop.shared.models,
|
var sharedModels = loop.shared.models,
|
||||||
sharedViews = loop.shared.views,
|
sharedViews = loop.shared.views,
|
||||||
getReactElementByClass = TestUtils.findRenderedDOMComponentWithClass,
|
getReactElementByClass = TestUtils.findRenderedDOMComponentWithClass,
|
||||||
sandbox;
|
sandbox, fakeAudioXHR;
|
||||||
|
|
||||||
beforeEach(function() {
|
beforeEach(function() {
|
||||||
sandbox = sinon.sandbox.create();
|
sandbox = sinon.sandbox.create();
|
||||||
|
@ -23,6 +23,18 @@ describe("loop.shared.views", function() {
|
||||||
sandbox.stub(l10n, "get", function(x) {
|
sandbox.stub(l10n, "get", function(x) {
|
||||||
return "translated:" + 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() {
|
afterEach(function() {
|
||||||
|
@ -368,16 +380,55 @@ describe("loop.shared.views", function() {
|
||||||
|
|
||||||
it("should play a connected sound, once, on session:connected",
|
it("should play a connected sound, once, on session:connected",
|
||||||
function() {
|
function() {
|
||||||
|
var url = "shared/sounds/connected.ogg";
|
||||||
|
sandbox.stub(window, "XMLHttpRequest").returns(fakeAudioXHR);
|
||||||
model.trigger("session:connected");
|
model.trigger("session:connected");
|
||||||
|
|
||||||
sinon.assert.calledOnce(window.Audio);
|
fakeAudioXHR.onload();
|
||||||
sinon.assert.calledWithExactly(
|
|
||||||
window.Audio, "shared/sounds/connected.ogg");
|
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);
|
expect(fakeAudio.loop).to.not.equal(true);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("for both (standalone and desktop)", function() {
|
describe("for both (standalone and desktop)", function() {
|
||||||
|
beforeEach(function() {
|
||||||
|
sandbox.stub(window, "XMLHttpRequest").returns(fakeAudioXHR);
|
||||||
|
});
|
||||||
|
|
||||||
it("should start streaming on session:connected", function() {
|
it("should start streaming on session:connected", function() {
|
||||||
model.trigger("session:connected");
|
model.trigger("session:connected");
|
||||||
|
|
||||||
|
@ -458,6 +509,7 @@ describe("loop.shared.views", function() {
|
||||||
|
|
||||||
beforeEach(function() {
|
beforeEach(function() {
|
||||||
fakeFeedbackApiClient = {send: sandbox.stub()};
|
fakeFeedbackApiClient = {send: sandbox.stub()};
|
||||||
|
sandbox.stub(window, "XMLHttpRequest").returns(fakeAudioXHR);
|
||||||
comp = TestUtils.renderIntoDocument(sharedViews.FeedbackView({
|
comp = TestUtils.renderIntoDocument(sharedViews.FeedbackView({
|
||||||
feedbackApiClient: fakeFeedbackApiClient
|
feedbackApiClient: fakeFeedbackApiClient
|
||||||
}));
|
}));
|
||||||
|
|
|
@ -18,7 +18,8 @@ describe("loop.webapp", function() {
|
||||||
sandbox,
|
sandbox,
|
||||||
notifications,
|
notifications,
|
||||||
feedbackApiClient,
|
feedbackApiClient,
|
||||||
stubGetPermsAndCacheMedia;
|
stubGetPermsAndCacheMedia,
|
||||||
|
fakeAudioXHR;
|
||||||
|
|
||||||
beforeEach(function() {
|
beforeEach(function() {
|
||||||
sandbox = sinon.sandbox.create();
|
sandbox = sinon.sandbox.create();
|
||||||
|
@ -29,6 +30,19 @@ describe("loop.webapp", function() {
|
||||||
|
|
||||||
stubGetPermsAndCacheMedia = sandbox.stub(
|
stubGetPermsAndCacheMedia = sandbox.stub(
|
||||||
loop.standaloneMedia._MultiplexGum.prototype, "getPermsAndCacheMedia");
|
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() {
|
afterEach(function() {
|
||||||
|
@ -219,6 +233,7 @@ describe("loop.webapp", function() {
|
||||||
describe("state: terminate, reason: reject", function() {
|
describe("state: terminate, reason: reject", function() {
|
||||||
beforeEach(function() {
|
beforeEach(function() {
|
||||||
sandbox.stub(notifications, "errorL10n");
|
sandbox.stub(notifications, "errorL10n");
|
||||||
|
sandbox.stub(window, "XMLHttpRequest").returns(fakeAudioXHR);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should display the FailedConversationView", function() {
|
it("should display the FailedConversationView", function() {
|
||||||
|
@ -307,6 +322,7 @@ describe("loop.webapp", function() {
|
||||||
promiseConnectStub =
|
promiseConnectStub =
|
||||||
sandbox.stub(loop.CallConnectionWebSocket.prototype, "promiseConnect");
|
sandbox.stub(loop.CallConnectionWebSocket.prototype, "promiseConnect");
|
||||||
promiseConnectStub.returns(new Promise(function(resolve, reject) {}));
|
promiseConnectStub.returns(new Promise(function(resolve, reject) {}));
|
||||||
|
sandbox.stub(window, "XMLHttpRequest").returns(fakeAudioXHR);
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("call:outgoing", function() {
|
describe("call:outgoing", function() {
|
||||||
|
@ -526,6 +542,8 @@ describe("loop.webapp", function() {
|
||||||
var view, conversation, client, fakeAudio;
|
var view, conversation, client, fakeAudio;
|
||||||
|
|
||||||
beforeEach(function() {
|
beforeEach(function() {
|
||||||
|
sandbox.stub(window, "XMLHttpRequest").returns(fakeAudioXHR);
|
||||||
|
|
||||||
fakeAudio = {
|
fakeAudio = {
|
||||||
play: sinon.spy(),
|
play: sinon.spy(),
|
||||||
pause: sinon.spy(),
|
pause: sinon.spy(),
|
||||||
|
@ -541,6 +559,7 @@ describe("loop.webapp", function() {
|
||||||
});
|
});
|
||||||
conversation.set("loopToken", "fakeToken");
|
conversation.set("loopToken", "fakeToken");
|
||||||
|
|
||||||
|
sandbox.stub(client, "requestCallUrlInfo");
|
||||||
view = React.addons.TestUtils.renderIntoDocument(
|
view = React.addons.TestUtils.renderIntoDocument(
|
||||||
loop.webapp.FailedConversationView({
|
loop.webapp.FailedConversationView({
|
||||||
conversation: conversation,
|
conversation: conversation,
|
||||||
|
@ -550,9 +569,12 @@ describe("loop.webapp", function() {
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should play a failure sound, once", function() {
|
it("should play a failure sound, once", function() {
|
||||||
sinon.assert.calledOnce(window.Audio);
|
fakeAudioXHR.onload();
|
||||||
sinon.assert.calledWithExactly(window.Audio,
|
|
||||||
"shared/sounds/failure.ogg");
|
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);
|
expect(fakeAudio.loop).to.equal(false);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -678,6 +700,7 @@ describe("loop.webapp", function() {
|
||||||
removeAttribute: sinon.spy()
|
removeAttribute: sinon.spy()
|
||||||
};
|
};
|
||||||
sandbox.stub(window, "Audio").returns(fakeAudio);
|
sandbox.stub(window, "Audio").returns(fakeAudio);
|
||||||
|
sandbox.stub(window, "XMLHttpRequest").returns(fakeAudioXHR);
|
||||||
|
|
||||||
view = React.addons.TestUtils.renderIntoDocument(
|
view = React.addons.TestUtils.renderIntoDocument(
|
||||||
loop.webapp.PendingConversationView({
|
loop.webapp.PendingConversationView({
|
||||||
|
@ -689,8 +712,12 @@ describe("loop.webapp", function() {
|
||||||
describe("#componentDidMount", function() {
|
describe("#componentDidMount", function() {
|
||||||
|
|
||||||
it("should play a looped connecting sound", function() {
|
it("should play a looped connecting sound", function() {
|
||||||
sinon.assert.calledOnce(window.Audio);
|
fakeAudioXHR.onload();
|
||||||
sinon.assert.calledWithExactly(window.Audio, "shared/sounds/connecting.ogg");
|
|
||||||
|
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);
|
expect(fakeAudio.loop).to.equal(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -727,8 +754,13 @@ describe("loop.webapp", function() {
|
||||||
|
|
||||||
it("should play a looped ringing sound", function() {
|
it("should play a looped ringing sound", function() {
|
||||||
websocket.trigger("progress:alerting");
|
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);
|
expect(fakeAudio.loop).to.equal(true);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -997,6 +1029,7 @@ describe("loop.webapp", function() {
|
||||||
conversation = new sharedModels.ConversationModel({}, {
|
conversation = new sharedModels.ConversationModel({}, {
|
||||||
sdk: {}
|
sdk: {}
|
||||||
});
|
});
|
||||||
|
sandbox.stub(window, "XMLHttpRequest").returns(fakeAudioXHR);
|
||||||
view = React.addons.TestUtils.renderIntoDocument(
|
view = React.addons.TestUtils.renderIntoDocument(
|
||||||
loop.webapp.EndedConversationView({
|
loop.webapp.EndedConversationView({
|
||||||
conversation: conversation,
|
conversation: conversation,
|
||||||
|
@ -1018,8 +1051,13 @@ describe("loop.webapp", function() {
|
||||||
describe("#componentDidMount", function() {
|
describe("#componentDidMount", function() {
|
||||||
|
|
||||||
it("should play a terminating sound, once", function() {
|
it("should play a terminating sound, once", function() {
|
||||||
sinon.assert.calledOnce(window.Audio);
|
fakeAudioXHR.onload();
|
||||||
sinon.assert.calledWithExactly(window.Audio, "shared/sounds/terminated.ogg");
|
|
||||||
|
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);
|
expect(fakeAudio.loop).to.not.equal(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
Загрузка…
Ссылка в новой задаче