mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 985596 Set up initial desktop conversation window. r=dmose
This commit is contained in:
parent
8711ed2ba4
commit
b1a2bb524e
@ -10,10 +10,24 @@
|
||||
<link rel="stylesheet" type="text/css" href="shared/css/conversation.css">
|
||||
</head>
|
||||
<body onload="loop.conversation.init();">
|
||||
<div id="conversation" class="conversation">
|
||||
<div class="media nested">
|
||||
<div class="remote">
|
||||
<div id="incoming"></div>
|
||||
</div>
|
||||
<div class="local">
|
||||
<div id="outgoing"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<script type="text/javascript" src="shared/libs/sdk.js"></script>
|
||||
<script type="text/javascript" src="shared/libs/jquery-2.1.0.js"></script>
|
||||
<script type="text/javascript" src="shared/libs/lodash-2.4.1.js"></script>
|
||||
<script type="text/javascript" src="shared/libs/backbone-1.1.2.js"></script>
|
||||
<script type="text/javascript" src="js/client.js"></script>
|
||||
<script type="text/javascript" src="shared/js/client.js"></script>
|
||||
<script type="text/javascript" src="shared/js/models.js"></script>
|
||||
<script type="text/javascript" src="shared/js/router.js"></script>
|
||||
<script type="text/javascript" src="shared/js/views.js"></script>
|
||||
<script type="text/javascript" src="js/conversation.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
@ -1,113 +0,0 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
/*global loop*/
|
||||
|
||||
var loop = loop || {};
|
||||
loop.Client = (function($) {
|
||||
"use strict";
|
||||
|
||||
/**
|
||||
* Loop server client.
|
||||
*
|
||||
* @param {Object} settings Settings object.
|
||||
*/
|
||||
function Client(settings) {
|
||||
settings = settings || {};
|
||||
if (!settings.hasOwnProperty("baseApiUrl")) {
|
||||
throw new Error("missing required baseApiUrl");
|
||||
}
|
||||
this.settings = settings;
|
||||
}
|
||||
|
||||
Client.prototype = {
|
||||
/**
|
||||
* Requests a call URL to the Loop server.
|
||||
*
|
||||
* @param {String} simplepushUrl a registered Simple Push URL
|
||||
* @param {string} nickname the nickname of the future caller
|
||||
* @param {Function} cb Callback(err, callUrl)
|
||||
*/
|
||||
requestCallUrl: function(nickname, cb) {
|
||||
var endpoint = this.settings.baseApiUrl + "/call-url/",
|
||||
reqData = {callerId: nickname};
|
||||
|
||||
function validate(callUrlData) {
|
||||
if (typeof callUrlData !== "object" ||
|
||||
!callUrlData.hasOwnProperty("call_url")) {
|
||||
var message = "Invalid call url data received";
|
||||
console.error(message, callUrlData);
|
||||
throw new Error(message);
|
||||
}
|
||||
return callUrlData.call_url;
|
||||
}
|
||||
|
||||
var req = $.post(endpoint, reqData, function(callUrlData) {
|
||||
try {
|
||||
cb(null, validate(callUrlData));
|
||||
} catch (err) {
|
||||
cb(err);
|
||||
}
|
||||
}, "json");
|
||||
|
||||
req.fail(function(jqXHR, testStatus, errorThrown) {
|
||||
var error = "Unknown error.";
|
||||
if (jqXHR && jqXHR.responseJSON && jqXHR.responseJSON.error) {
|
||||
error = jqXHR.responseJSON.error;
|
||||
}
|
||||
var message = "HTTP error " + jqXHR.status + ": " +
|
||||
errorThrown + "; " + error;
|
||||
console.error(message);
|
||||
cb(new Error(message));
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Requests call information from the server
|
||||
*
|
||||
* @param {Function} cb Callback(err, calls)
|
||||
*/
|
||||
requestCallsInfo: function(cb) {
|
||||
var endpoint = this.settings.baseApiUrl + "/calls";
|
||||
|
||||
// We do a basic validation here that we have an object,
|
||||
// and pass the full information back.
|
||||
function validate(callsData) {
|
||||
if (typeof callsData !== "object" ||
|
||||
!callsData.hasOwnProperty("calls")) {
|
||||
var message = "Invalid calls data received";
|
||||
console.error(message, callsData);
|
||||
throw new Error(message);
|
||||
}
|
||||
return callsData.calls;
|
||||
}
|
||||
|
||||
// XXX We'll want to figure out a way to store the version from each
|
||||
// request here. As this is typically the date, we just need to store the
|
||||
// time last requested.
|
||||
// XXX It is likely that we'll want to move some of this to whatever
|
||||
// opens the chat window.
|
||||
var req = $.get(endpoint + "?version=0", function(callsData) {
|
||||
try {
|
||||
cb(null, validate(callsData));
|
||||
} catch (err) {
|
||||
cb(err);
|
||||
}
|
||||
}, "json");
|
||||
|
||||
req.fail(function(jqXHR, testStatus, errorThrown) {
|
||||
var error = "Unknown error.";
|
||||
if (jqXHR && jqXHR.responseJSON && jqXHR.responseJSON.error) {
|
||||
error = jqXHR.responseJSON.error;
|
||||
}
|
||||
var message = "HTTP error " + jqXHR.status + ": " +
|
||||
errorThrown + "; " + error;
|
||||
console.error(message);
|
||||
cb(new Error(message));
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
return Client;
|
||||
})(jQuery);
|
@ -3,36 +3,130 @@
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
/*global loop*/
|
||||
// XXX This file needs unit testing
|
||||
|
||||
Components.utils.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
var loop = loop || {};
|
||||
loop.conversation = (function(_, __) {
|
||||
loop.conversation = (function(TB) {
|
||||
"use strict";
|
||||
|
||||
// XXX: baseApiUrl should be configurable (browser pref)
|
||||
var baseApiUrl = "http://localhost:5000";
|
||||
var baseServerUrl = Services.prefs.getCharPref("loop.server");
|
||||
|
||||
/**
|
||||
* App router.
|
||||
* @type {loop.webapp.Router}
|
||||
*/
|
||||
var router;
|
||||
|
||||
/**
|
||||
* Current conversation model instance.
|
||||
* @type {loop.webapp.ConversationModel}
|
||||
*/
|
||||
var conversation;
|
||||
|
||||
var ConversationRouter = loop.shared.router.BaseRouter.extend({
|
||||
_conversation: undefined,
|
||||
activeView: undefined,
|
||||
|
||||
routes: {
|
||||
"start/:version": "start",
|
||||
"call/ongoing": "conversation",
|
||||
"call/ended": "ended"
|
||||
},
|
||||
|
||||
/**
|
||||
* Loads and render current active view.
|
||||
*
|
||||
* @param {loop.shared.BaseView} view View.
|
||||
*/
|
||||
loadView : function(view) {
|
||||
if (this.activeView) {
|
||||
this.activeView.hide();
|
||||
}
|
||||
this.activeView = view.render().show();
|
||||
},
|
||||
|
||||
initialize: function(options) {
|
||||
options = options || {};
|
||||
if (!options.conversation) {
|
||||
throw new Error("missing required conversation");
|
||||
}
|
||||
this._conversation = options.conversation;
|
||||
|
||||
this.listenTo(this._conversation, "session:ready", this._onSessionReady);
|
||||
this.listenTo(this._conversation, "session:ended", this._onSessionEnded);
|
||||
},
|
||||
|
||||
/**
|
||||
* Navigates to conversation when the call session is ready.
|
||||
*/
|
||||
_onSessionReady: function() {
|
||||
this.navigate("call/ongoing", {trigger: true});
|
||||
},
|
||||
|
||||
/**
|
||||
* Navigates to ended state when the call has ended
|
||||
*/
|
||||
_onSessionEnded: function() {
|
||||
this.navigate("call/ended", {trigger: true});
|
||||
},
|
||||
|
||||
/**
|
||||
* start is the initial route that does any necessary prompting and set
|
||||
* up for the call.
|
||||
*
|
||||
* @param {String} loopVersion The version from the push notification, set
|
||||
* by the router from the URL.
|
||||
*/
|
||||
start: function(loopVersion) {
|
||||
// XXX For now, we just kick the conversation straight away, bug 990678
|
||||
// will implement the follow-ups.
|
||||
this._conversation.set({loopVersion: loopVersion});
|
||||
this._conversation.initiate({
|
||||
baseServerUrl: baseServerUrl,
|
||||
outgoing: false
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* conversation is the route when the conversation is active. The start
|
||||
* route should be navigated to first.
|
||||
*/
|
||||
conversation: function() {
|
||||
if (!this._conversation.isSessionReady()) {
|
||||
// XXX: notify user that something has gone wrong.
|
||||
console.error("Error: navigated to conversation route without " +
|
||||
"the start route to initialise the call first");
|
||||
return;
|
||||
}
|
||||
|
||||
this.loadView(
|
||||
new loop.shared.views.ConversationView({
|
||||
sdk: TB,
|
||||
model: this._conversation
|
||||
}));
|
||||
},
|
||||
|
||||
/**
|
||||
* ended does any necessary work to end the call.
|
||||
*/
|
||||
ended: function() {
|
||||
// XXX Later we implement the end-of call here (bug 974873)
|
||||
window.close();
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Panel initialisation.
|
||||
*/
|
||||
function init() {
|
||||
// Send a message to the server to get the call info
|
||||
this.client = new loop.Client({
|
||||
baseApiUrl: baseApiUrl
|
||||
});
|
||||
|
||||
// Get the call information
|
||||
this.client.requestCallsInfo(function(err, calls) {
|
||||
if (err) {
|
||||
console.error("Error getting call data: ", err);
|
||||
return;
|
||||
}
|
||||
|
||||
console.log("Received Calls Data: ", calls);
|
||||
});
|
||||
conversation = new loop.shared.models.ConversationModel();
|
||||
router = new ConversationRouter({conversation: conversation});
|
||||
Backbone.history.start();
|
||||
}
|
||||
|
||||
return {
|
||||
ConversationRouter: ConversationRouter,
|
||||
init: init
|
||||
};
|
||||
})(_);
|
||||
})(window.TB);
|
||||
|
@ -3,13 +3,13 @@
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
/*global loop*/
|
||||
Components.utils.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
var loop = loop || {};
|
||||
loop.panel = (function(_, __) {
|
||||
"use strict";
|
||||
|
||||
// XXX: baseApiUrl should be configurable (browser pref)
|
||||
var baseApiUrl = "http://localhost:5000",
|
||||
var baseServerUrl = Services.prefs.getCharPref("loop.server"),
|
||||
panelView;
|
||||
|
||||
/**
|
||||
@ -98,8 +98,8 @@ loop.panel = (function(_, __) {
|
||||
},
|
||||
|
||||
initialize: function() {
|
||||
this.client = new loop.Client({
|
||||
baseApiUrl: baseApiUrl
|
||||
this.client = new loop.shared.Client({
|
||||
baseServerUrl: baseServerUrl
|
||||
});
|
||||
this.notificationCollection = new NotificationCollection();
|
||||
this.notificationListView = new NotificationListView({
|
||||
|
@ -44,7 +44,7 @@
|
||||
<script type="text/javascript" src="shared/libs/jquery-2.1.0.js"></script>
|
||||
<script type="text/javascript" src="shared/libs/lodash-2.4.1.js"></script>
|
||||
<script type="text/javascript" src="shared/libs/backbone-1.1.2.js"></script>
|
||||
<script type="text/javascript" src="js/client.js"></script>
|
||||
<script type="text/javascript" src="shared/js/client.js"></script>
|
||||
<script type="text/javascript" src="js/panel.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
@ -10,11 +10,15 @@ browser.jar:
|
||||
content/browser/loop/shared/css/conversation.css (content/shared/css/conversation.css)
|
||||
content/browser/loop/shared/img/icon_32.png (content/shared/img/icon_32.png)
|
||||
content/browser/loop/shared/img/icon_64.png (content/shared/img/icon_64.png)
|
||||
content/browser/loop/shared/js/client.js (content/shared/js/client.js)
|
||||
content/browser/loop/shared/js/models.js (content/shared/js/models.js)
|
||||
content/browser/loop/shared/js/router.js (content/shared/js/router.js)
|
||||
content/browser/loop/shared/js/views.js (content/shared/js/views.js)
|
||||
content/browser/loop/shared/libs/sdk.js (content/shared/libs/sdk.js)
|
||||
content/browser/loop/shared/libs/lodash-2.4.1.js (content/shared/libs/lodash-2.4.1.js)
|
||||
content/browser/loop/shared/libs/jquery-2.1.0.js (content/shared/libs/jquery-2.1.0.js)
|
||||
content/browser/loop/shared/libs/backbone-1.1.2.js (content/shared/libs/backbone-1.1.2.js)
|
||||
content/browser/loop/libs/l10n.js (content/libs/l10n.js)
|
||||
content/browser/loop/js/fxcom.js (content/js/fxcom.js)
|
||||
content/browser/loop/js/conversation.js (content/js/conversation.js)
|
||||
content/browser/loop/js/client.js (content/js/client.js)
|
||||
content/browser/loop/js/panel.js (content/js/panel.js)
|
||||
|
@ -1,112 +0,0 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
/* global loop, sinon */
|
||||
|
||||
var expect = chai.expect;
|
||||
|
||||
describe("loop.Client", function() {
|
||||
"use strict";
|
||||
|
||||
var sandbox, fakeXHR, requests = [];
|
||||
|
||||
beforeEach(function() {
|
||||
sandbox = sinon.sandbox.create();
|
||||
fakeXHR = sandbox.useFakeXMLHttpRequest();
|
||||
requests = [];
|
||||
// https://github.com/cjohansen/Sinon.JS/issues/393
|
||||
fakeXHR.xhr.onCreate = function (xhr) {
|
||||
requests.push(xhr);
|
||||
};
|
||||
});
|
||||
|
||||
afterEach(function() {
|
||||
sandbox.restore();
|
||||
});
|
||||
|
||||
describe("loop.Client", function() {
|
||||
describe("#constructor", function() {
|
||||
it("should require a baseApiUrl setting", function() {
|
||||
expect(function() {
|
||||
new loop.Client();
|
||||
}).to.Throw(Error, /required/);
|
||||
});
|
||||
});
|
||||
|
||||
describe("#requestCallUrl", function() {
|
||||
var client;
|
||||
|
||||
beforeEach(function() {
|
||||
client = new loop.Client({baseApiUrl: "http://fake.api"});
|
||||
});
|
||||
|
||||
it("should request for a call url", function() {
|
||||
var callback = sinon.spy();
|
||||
client.requestCallUrl("foo", callback);
|
||||
|
||||
expect(requests).to.have.length.of(1);
|
||||
|
||||
requests[0].respond(200, {"Content-Type": "application/json"},
|
||||
'{"call_url": "fakeCallUrl"}');
|
||||
sinon.assert.calledWithExactly(callback, null, "fakeCallUrl");
|
||||
});
|
||||
|
||||
it("should send an error when the request fails", function() {
|
||||
var callback = sinon.spy();
|
||||
client.requestCallUrl("foo", callback);
|
||||
|
||||
expect(requests).to.have.length.of(1);
|
||||
|
||||
requests[0].respond(400, {"Content-Type": "application/json"},
|
||||
'{"error": "my error"}');
|
||||
sinon.assert.calledWithMatch(callback, sinon.match(function(err) {
|
||||
return /HTTP error 400: Bad Request; my error/.test(err.message);
|
||||
}));
|
||||
});
|
||||
});
|
||||
|
||||
describe("#requestCallsInfo", function() {
|
||||
var client;
|
||||
|
||||
beforeEach(function() {
|
||||
client = new loop.Client({baseApiUrl: "http://fake.api"});
|
||||
});
|
||||
|
||||
it("should request data for all calls", function() {
|
||||
var callback = sinon.spy();
|
||||
client.requestCallsInfo(callback);
|
||||
|
||||
expect(requests).to.have.length.of(1);
|
||||
expect(requests[0].url).to.be.equal("http://fake.api/calls?version=0");
|
||||
expect(requests[0].method).to.be.equal("GET");
|
||||
|
||||
requests[0].respond(200, {"Content-Type": "application/json"},
|
||||
'{"calls": [{"apiKey": "fake"}]}');
|
||||
sinon.assert.calledWithExactly(callback, null, [{apiKey: "fake"}]);
|
||||
});
|
||||
|
||||
it("should send an error when the request fails", function() {
|
||||
var callback = sinon.spy();
|
||||
client.requestCallsInfo(callback);
|
||||
|
||||
requests[0].respond(400, {"Content-Type": "application/json"},
|
||||
'{"error": "my error"}');
|
||||
sinon.assert.calledWithMatch(callback, sinon.match(function(err) {
|
||||
return /HTTP error 400: Bad Request; my error/.test(err.message);
|
||||
}));
|
||||
});
|
||||
|
||||
it("should send an error if the data is not valid", function() {
|
||||
var callback = sinon.spy();
|
||||
client.requestCallsInfo(callback);
|
||||
|
||||
requests[0].respond(200, {"Content-Type": "application/json"},
|
||||
'{"bad": {}}');
|
||||
sinon.assert.calledWithMatch(callback, sinon.match(function(err) {
|
||||
return /Invalid calls data received/.test(err.message);
|
||||
}));
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
140
browser/components/loop/test/desktop-local/conversation_test.js
Normal file
140
browser/components/loop/test/desktop-local/conversation_test.js
Normal file
@ -0,0 +1,140 @@
|
||||
/* 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/. */
|
||||
|
||||
/* global loop, sinon */
|
||||
|
||||
var expect = chai.expect;
|
||||
|
||||
describe("loop.conversation", function() {
|
||||
"use strict";
|
||||
|
||||
var ConversationRouter = loop.conversation.ConversationRouter,
|
||||
sandbox;
|
||||
|
||||
beforeEach(function() {
|
||||
sandbox = sinon.sandbox.create();
|
||||
});
|
||||
|
||||
afterEach(function() {
|
||||
sandbox.restore();
|
||||
});
|
||||
|
||||
describe("ConversationRouter", function() {
|
||||
var conversation;
|
||||
|
||||
beforeEach(function() {
|
||||
conversation = new loop.shared.models.ConversationModel();
|
||||
});
|
||||
|
||||
describe("#constructor", function() {
|
||||
it("should require a ConversationModel instance", function() {
|
||||
expect(function() {
|
||||
new ConversationRouter();
|
||||
}).to.Throw(Error, /missing required conversation/);
|
||||
});
|
||||
});
|
||||
|
||||
describe("Routes", function() {
|
||||
var router;
|
||||
|
||||
beforeEach(function() {
|
||||
router = new ConversationRouter({conversation: conversation});
|
||||
sandbox.stub(router, "loadView");
|
||||
});
|
||||
|
||||
describe("#start", function() {
|
||||
it("should set the loopVersion on the conversation model", function() {
|
||||
router.start("fakeVersion");
|
||||
|
||||
expect(conversation.get("loopVersion")).to.equal("fakeVersion");
|
||||
});
|
||||
|
||||
it("should initiate the conversation", function() {
|
||||
sandbox.stub(conversation, "initiate");
|
||||
|
||||
router.start("fakeVersion");
|
||||
|
||||
sinon.assert.calledOnce(conversation.initiate);
|
||||
sinon.assert.calledWithExactly(conversation.initiate, {
|
||||
baseServerUrl: "http://example.com",
|
||||
outgoing: false
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("#conversation", function() {
|
||||
it("should load the ConversationView if session is set", function() {
|
||||
sandbox.stub(loop.shared.views.ConversationView.prototype,
|
||||
"initialize");
|
||||
conversation.set("sessionId", "fakeSessionId");
|
||||
|
||||
router.conversation();
|
||||
|
||||
sinon.assert.calledOnce(router.loadView);
|
||||
sinon.assert.calledWithMatch(router.loadView, {
|
||||
$el: {selector: "#conversation"}
|
||||
});
|
||||
});
|
||||
|
||||
it("should not load the ConversationView if session is not set",
|
||||
function() {
|
||||
router.conversation();
|
||||
|
||||
sinon.assert.notCalled(router.loadView);
|
||||
});
|
||||
});
|
||||
|
||||
describe("#ended", function() {
|
||||
// XXX When the call is ended gracefully, we should check that we
|
||||
// close connections nicely
|
||||
it("should close the window", function() {
|
||||
sandbox.stub(window, "close");
|
||||
|
||||
router.ended();
|
||||
|
||||
sinon.assert.calledOnce(window.close);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("Events", function() {
|
||||
var fakeSessionData;
|
||||
|
||||
beforeEach(function() {
|
||||
fakeSessionData = {
|
||||
sessionId: "sessionId",
|
||||
sessionToken: "sessionToken",
|
||||
apiKey: "apiKey"
|
||||
};
|
||||
});
|
||||
|
||||
it("should navigate to call/ongoing once the call session is ready",
|
||||
function() {
|
||||
sandbox.stub(ConversationRouter.prototype, "navigate");
|
||||
var router = new ConversationRouter({
|
||||
conversation: conversation
|
||||
});
|
||||
|
||||
conversation.setReady(fakeSessionData);
|
||||
|
||||
sinon.assert.calledOnce(router.navigate);
|
||||
sinon.assert.calledWith(router.navigate, "call/ongoing");
|
||||
});
|
||||
|
||||
it("should navigate to call/ended when the call session ends",
|
||||
function() {
|
||||
sandbox.stub(ConversationRouter.prototype, "navigate");
|
||||
var router = new ConversationRouter({
|
||||
conversation: conversation
|
||||
});
|
||||
|
||||
conversation.trigger("session:ended");
|
||||
|
||||
sinon.assert.calledOnce(router.navigate);
|
||||
sinon.assert.calledWith(router.navigate, "call/ended");
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
});
|
@ -32,11 +32,16 @@
|
||||
return [];
|
||||
},
|
||||
};
|
||||
window.Components = {fake: true, utils: {import: function(){}}};
|
||||
window.Services = {fake: true, prefs: {getCharPref: function() {
|
||||
return "http://example.com";
|
||||
}}};
|
||||
</script>
|
||||
<script src="../../content/libs/l10n.js"></script>
|
||||
<script src="../../content/shared/libs/jquery-2.1.0.js"></script>
|
||||
<script src="../../content/shared/libs/lodash-2.4.1.js"></script>
|
||||
<script src="../../content/shared/libs/backbone-1.1.2.js"></script>
|
||||
|
||||
<!-- test dependencies -->
|
||||
<script src="../shared/vendor/mocha-1.17.1.js"></script>
|
||||
<script src="../shared/vendor/chai-1.9.0.js"></script>
|
||||
@ -45,16 +50,22 @@
|
||||
chai.Assertion.includeStack = true;
|
||||
mocha.setup('bdd');
|
||||
</script>
|
||||
|
||||
<!-- App scripts -->
|
||||
<script src="../../content/js/client.js"></script>
|
||||
<script src="../../content/shared/js/client.js"></script>
|
||||
<script src="../../content/shared/js/models.js"></script>
|
||||
<script src="../../content/shared/js/router.js"></script>
|
||||
<script src="../../content/shared/js/views.js"></script>
|
||||
<script src="../../content/js/conversation.js"></script>
|
||||
<script src="../../content/js/panel.js"></script>
|
||||
|
||||
<!-- Test scripts -->
|
||||
<script src="conversation_test.js"></script>
|
||||
<script src="panel_test.js"></script>
|
||||
<script src="client_test.js"></script>
|
||||
<script>
|
||||
mocha.run(function () {
|
||||
$("#mocha").append("<p>Complete.</p>");
|
||||
});
|
||||
</script>
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
@ -106,7 +106,7 @@ describe("loop.panel", function() {
|
||||
|
||||
describe("#getCallurl", function() {
|
||||
it("should request a call url to the server", function() {
|
||||
var requestCallUrl = sandbox.stub(loop.Client.prototype,
|
||||
var requestCallUrl = sandbox.stub(loop.shared.Client.prototype,
|
||||
"requestCallUrl");
|
||||
var view = new loop.panel.PanelView();
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user