Remove shared state between tests

Only a small subset of tests currently working with this.
This commit is contained in:
JC Brand 2016-11-02 20:19:17 +00:00
parent d3090f80bc
commit 50275cce64
6 changed files with 347 additions and 364 deletions

View File

@ -1,4 +1,3 @@
/*global converse */
(function (root, factory) { (function (root, factory) {
define([ define([
"jquery", "jquery",
@ -12,10 +11,15 @@
} (this, function ($, _, mock, test_utils) { } (this, function ($, _, mock, test_utils) {
var b64_sha1 = converse_api.env.b64_sha1; var b64_sha1 = converse_api.env.b64_sha1;
return describe("Converse", $.proxy(function(mock, test_utils) { describe("Converse", function() {
afterEach(function () {
converse_api.user.logout();
test_utils.clearBrowserStorage();
});
describe("Authentication", function () { describe("Authentication", function () {
it("needs either a bosh_service_url a websocket_url or both", function () { it("needs either a bosh_service_url a websocket_url or both", mock.initConverse(function (converse) {
var url = converse.bosh_service_url; var url = converse.bosh_service_url;
var connection = converse.connection; var connection = converse.connection;
delete converse.bosh_service_url; delete converse.bosh_service_url;
@ -24,10 +28,10 @@
new Error("initConnection: you must supply a value for either the bosh_service_url or websocket_url or both.")); new Error("initConnection: you must supply a value for either the bosh_service_url or websocket_url or both."));
converse.bosh_service_url = url; converse.bosh_service_url = url;
converse.connection = connection; converse.connection = connection;
}); }));
describe("with prebind", function () { describe("with prebind", function () {
it("needs a jid when also using keepalive", function () { it("needs a jid when also using keepalive", mock.initConverse(function (converse) {
var authentication = converse.authentication; var authentication = converse.authentication;
var jid = converse.jid; var jid = converse.jid;
delete converse.jid; delete converse.jid;
@ -38,9 +42,9 @@
converse.authentication= authentication; converse.authentication= authentication;
converse.jid = jid; converse.jid = jid;
converse.keepalive = false; converse.keepalive = false;
}); }));
it("needs jid, rid and sid values when not using keepalive", function () { it("needs jid, rid and sid values when not using keepalive", mock.initConverse(function (converse) {
var authentication = converse.authentication; var authentication = converse.authentication;
var jid = converse.jid; var jid = converse.jid;
delete converse.jid; delete converse.jid;
@ -50,13 +54,13 @@
converse.authentication= authentication; converse.authentication= authentication;
converse.bosh_service_url = undefined; converse.bosh_service_url = undefined;
converse.jid = jid; converse.jid = jid;
}); }));
}); });
}); });
describe("A chat state indication", function () { describe("A chat state indication", function () {
it("are sent out when the client becomes or stops being idle", function () { it("are sent out when the client becomes or stops being idle", mock.initConverse(function (converse) {
spyOn(converse, 'sendCSI').andCallThrough(); spyOn(converse, 'sendCSI').andCallThrough();
var sent_stanza; var sent_stanza;
spyOn(converse.connection, 'send').andCallFake(function (stanza) { spyOn(converse.connection, 'send').andCallFake(function (stanza) {
@ -85,12 +89,12 @@
// Reset values // Reset values
converse.csi_waiting_time = 0; converse.csi_waiting_time = 0;
converse.features['urn:xmpp:csi:0'] = false; converse.features['urn:xmpp:csi:0'] = false;
}); }));
}); });
describe("Automatic status change", function () { describe("Automatic status change", function () {
it("happens when the client is idle for long enough", function () { it("happens when the client is idle for long enough", mock.initConverse(function (converse) {
var i = 0; var i = 0;
// Usually initialized by registerIntervalHandler // Usually initialized by registerIntervalHandler
converse.idle_seconds = 0; converse.idle_seconds = 0;
@ -124,26 +128,21 @@
converse.auto_away = 0; converse.auto_away = 0;
converse.auto_xa = 0; converse.auto_xa = 0;
converse.auto_changed_status = false; converse.auto_changed_status = false;
}); }));
}); });
describe("The \"user\" grouping", function () { describe("The \"user\" grouping", function () {
describe("The \"status\" API", function () { describe("The \"status\" API", function () {
beforeEach(function () {
test_utils.closeAllChatBoxes();
test_utils.clearBrowserStorage();
converse.rosterview.model.reset();
});
it("has a method for getting the user's availability", function () { it("has a method for getting the user's availability", mock.initConverse(function (converse) {
converse.xmppstatus.set('status', 'online'); converse.xmppstatus.set('status', 'online');
expect(converse_api.user.status.get()).toBe('online'); expect(converse_api.user.status.get()).toBe('online');
converse.xmppstatus.set('status', 'dnd'); converse.xmppstatus.set('status', 'dnd');
expect(converse_api.user.status.get()).toBe('dnd'); expect(converse_api.user.status.get()).toBe('dnd');
}); }));
it("has a method for setting the user's availability", function () { it("has a method for setting the user's availability", mock.initConverse(function (converse) {
converse_api.user.status.set('away'); converse_api.user.status.set('away');
expect(converse.xmppstatus.get('status')).toBe('away'); expect(converse.xmppstatus.get('status')).toBe('away');
converse_api.user.status.set('dnd'); converse_api.user.status.set('dnd');
@ -155,38 +154,33 @@
expect(_.partial(converse_api.user.status.set, 'invalid')).toThrow( expect(_.partial(converse_api.user.status.set, 'invalid')).toThrow(
new Error('Invalid availability value. See https://xmpp.org/rfcs/rfc3921.html#rfc.section.2.2.2.1') new Error('Invalid availability value. See https://xmpp.org/rfcs/rfc3921.html#rfc.section.2.2.2.1')
); );
}); }));
it("allows setting the status message as well", function () { it("allows setting the status message as well", mock.initConverse(function (converse) {
converse_api.user.status.set('away', "I'm in a meeting"); converse_api.user.status.set('away', "I'm in a meeting");
expect(converse.xmppstatus.get('status')).toBe('away'); expect(converse.xmppstatus.get('status')).toBe('away');
expect(converse.xmppstatus.get('status_message')).toBe("I'm in a meeting"); expect(converse.xmppstatus.get('status_message')).toBe("I'm in a meeting");
}); }));
it("has a method for getting the user's status message", function () { it("has a method for getting the user's status message", mock.initConverse(function (converse) {
converse.xmppstatus.set('status_message', undefined); converse.xmppstatus.set('status_message', undefined);
expect(converse_api.user.status.message.get()).toBe(undefined); expect(converse_api.user.status.message.get()).toBe(undefined);
converse.xmppstatus.set('status_message', "I'm in a meeting"); converse.xmppstatus.set('status_message', "I'm in a meeting");
expect(converse_api.user.status.message.get()).toBe("I'm in a meeting"); expect(converse_api.user.status.message.get()).toBe("I'm in a meeting");
}); }));
it("has a method for setting the user's status message", function () { it("has a method for setting the user's status message", mock.initConverse(function (converse) {
converse.xmppstatus.set('status_message', undefined); converse.xmppstatus.set('status_message', undefined);
converse_api.user.status.message.set("I'm in a meeting"); converse_api.user.status.message.set("I'm in a meeting");
expect(converse.xmppstatus.get('status_message')).toBe("I'm in a meeting"); expect(converse.xmppstatus.get('status_message')).toBe("I'm in a meeting");
}); }));
}); });
}); });
describe("The \"tokens\" API", $.proxy(function () { describe("The \"tokens\" API", function () {
beforeEach(function () {
test_utils.closeAllChatBoxes();
test_utils.clearBrowserStorage();
converse.rosterview.model.reset();
test_utils.createContacts('current');
});
it("has a method for retrieving the next RID", $.proxy(function () { it("has a method for retrieving the next RID", mock.initConverse(function (converse) {
test_utils.createContacts(converse, 'current');
var old_connection = converse.connection; var old_connection = converse.connection;
converse.connection._proto.rid = '1234'; converse.connection._proto.rid = '1234';
converse.expose_rid_and_sid = false; converse.expose_rid_and_sid = false;
@ -197,9 +191,10 @@
expect(converse_api.tokens.get('rid')).toBe(null); expect(converse_api.tokens.get('rid')).toBe(null);
// Restore the connection // Restore the connection
converse.connection = old_connection; converse.connection = old_connection;
}, converse)); }));
it("has a method for retrieving the SID", $.proxy(function () { it("has a method for retrieving the SID", mock.initConverse(function (converse) {
test_utils.createContacts(converse, 'current');
var old_connection = converse.connection; var old_connection = converse.connection;
converse.connection._proto.sid = '1234'; converse.connection._proto.sid = '1234';
converse.expose_rid_and_sid = false; converse.expose_rid_and_sid = false;
@ -210,19 +205,14 @@
expect(converse_api.tokens.get('sid')).toBe(null); expect(converse_api.tokens.get('sid')).toBe(null);
// Restore the connection // Restore the connection
converse.connection = old_connection; converse.connection = old_connection;
}, converse)); }));
}, converse)); });
describe("The \"contacts\" API", $.proxy(function () { describe("The \"contacts\" API", function () {
beforeEach($.proxy(function () {
test_utils.closeAllChatBoxes();
test_utils.clearBrowserStorage();
converse.rosterview.model.reset();
test_utils.createContacts('current');
}, converse));
it("has a method 'get' which returns wrapped contacts", $.proxy(function () { it("has a method 'get' which returns wrapped contacts", mock.initConverse(function (converse) {
// Check that it returns nothing if a non-existing JID is given // Check that it returns nothing if a non-existing JID is given
test_utils.createContacts(converse, 'current');
expect(converse_api.contacts.get('non-existing@jabber.org')).toBeFalsy(); expect(converse_api.contacts.get('non-existing@jabber.org')).toBeFalsy();
// Check when a single jid is given // Check when a single jid is given
var jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@localhost'; var jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@localhost';
@ -239,28 +229,23 @@
// Check that all JIDs are returned if you call without any parameters // Check that all JIDs are returned if you call without any parameters
list = converse_api.contacts.get(); list = converse_api.contacts.get();
expect(list.length).toBe(mock.cur_names.length); expect(list.length).toBe(mock.cur_names.length);
}, converse)); }));
it("has a method 'add' with which contacts can be added", $.proxy(function () { it("has a method 'add' with which contacts can be added", mock.initConverse(function (converse) {
test_utils.createContacts(converse, 'current');
var error = new TypeError('contacts.add: invalid jid'); var error = new TypeError('contacts.add: invalid jid');
expect(converse_api.contacts.add).toThrow(error); expect(converse_api.contacts.add).toThrow(error);
expect(converse_api.contacts.add.bind(converse_api, "invalid jid")).toThrow(error); expect(converse_api.contacts.add.bind(converse_api, "invalid jid")).toThrow(error);
spyOn(converse.roster, 'addAndSubscribe'); spyOn(converse.roster, 'addAndSubscribe');
converse_api.contacts.add("newcontact@example.org"); converse_api.contacts.add("newcontact@example.org");
expect(converse.roster.addAndSubscribe).toHaveBeenCalled(); expect(converse.roster.addAndSubscribe).toHaveBeenCalled();
}, converse)); }));
});
}, converse)); describe("The \"chats\" API", function() {
describe("The \"chats\" API", $.proxy(function() { it("has a method 'get' which returns a wrapped chat box", mock.initConverse(function (converse) {
beforeEach($.proxy(function () { test_utils.createContacts(converse, 'current');
test_utils.closeAllChatBoxes();
test_utils.clearBrowserStorage();
converse.rosterview.model.reset();
test_utils.createContacts('current');
}, converse));
it("has a method 'get' which returns a wrapped chat box", function () {
// Test on chat that doesn't exist. // Test on chat that doesn't exist.
expect(converse_api.chats.get('non-existing@jabber.org')).toBeFalsy(); expect(converse_api.chats.get('non-existing@jabber.org')).toBeFalsy();
var jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@localhost'; var jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@localhost';
@ -271,7 +256,7 @@
var chatboxview = converse.chatboxviews.get(jid); var chatboxview = converse.chatboxviews.get(jid);
// Test for single JID // Test for single JID
test_utils.openChatBoxFor(jid); test_utils.openChatBoxFor(converse, jid);
box = converse_api.chats.get(jid); box = converse_api.chats.get(jid);
expect(box instanceof Object).toBeTruthy(); expect(box instanceof Object).toBeTruthy();
expect(box.get('box_id')).toBe(b64_sha1(jid)); expect(box.get('box_id')).toBe(b64_sha1(jid));
@ -279,14 +264,15 @@
expect(chatboxview.$el.is(':visible')).toBeTruthy(); expect(chatboxview.$el.is(':visible')).toBeTruthy();
// Test for multiple JIDs // Test for multiple JIDs
var jid2 = mock.cur_names[1].replace(/ /g,'.').toLowerCase() + '@localhost'; var jid2 = mock.cur_names[1].replace(/ /g,'.').toLowerCase() + '@localhost';
test_utils.openChatBoxFor(jid2); test_utils.openChatBoxFor(converse, jid2);
var list = converse_api.chats.get([jid, jid2]); var list = converse_api.chats.get([jid, jid2]);
expect(Array.isArray(list)).toBeTruthy(); expect(Array.isArray(list)).toBeTruthy();
expect(list[0].get('box_id')).toBe(b64_sha1(jid)); expect(list[0].get('box_id')).toBe(b64_sha1(jid));
expect(list[1].get('box_id')).toBe(b64_sha1(jid2)); expect(list[1].get('box_id')).toBe(b64_sha1(jid2));
}); }));
it("has a method 'open' which opens and returns a wrapped chat box", function () { it("has a method 'open' which opens and returns a wrapped chat box", mock.initConverse(function (converse) {
test_utils.createContacts(converse, 'current');
var jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@localhost'; var jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@localhost';
var chatboxview; var chatboxview;
waits('300'); // ChatBox.show() is debounced for 250ms waits('300'); // ChatBox.show() is debounced for 250ms
@ -309,18 +295,11 @@
expect(list[0].get('box_id')).toBe(b64_sha1(jid)); expect(list[0].get('box_id')).toBe(b64_sha1(jid));
expect(list[1].get('box_id')).toBe(b64_sha1(jid2)); expect(list[1].get('box_id')).toBe(b64_sha1(jid2));
}); });
}); }));
}, converse)); });
describe("The \"settings\" API", $.proxy(function() { describe("The \"settings\" API", function() {
beforeEach($.proxy(function () { it("has methods 'get' and 'set' to set configuration settings", mock.initConverse(function (converse) {
test_utils.closeAllChatBoxes();
test_utils.clearBrowserStorage();
converse.rosterview.model.reset();
test_utils.createContacts('current');
}, converse));
it("has methods 'get' and 'set' to set configuration settings", $.proxy(function () {
expect(Object.keys(converse_api.settings)).toEqual(["get", "set"]); expect(Object.keys(converse_api.settings)).toEqual(["get", "set"]);
expect(converse_api.settings.get("play_sounds")).toBe(false); expect(converse_api.settings.get("play_sounds")).toBe(false);
converse_api.settings.set("play_sounds", true); converse_api.settings.set("play_sounds", true);
@ -331,7 +310,7 @@
expect(typeof converse_api.settings.get("non_existing")).toBe("undefined"); expect(typeof converse_api.settings.get("non_existing")).toBe("undefined");
converse_api.settings.set("non_existing", true); converse_api.settings.set("non_existing", true);
expect(typeof converse_api.settings.get("non_existing")).toBe("undefined"); expect(typeof converse_api.settings.get("non_existing")).toBe("undefined");
}, converse)); }));
}, converse)); });
}, converse, mock, test_utils)); });
})); }));

View File

@ -1,4 +1,3 @@
/*global converse */
(function (root, factory) { (function (root, factory) {
define([ define([
"jquery", "jquery",
@ -16,14 +15,17 @@
// See: // See:
// https://xmpp.org/rfcs/rfc3921.html // https://xmpp.org/rfcs/rfc3921.html
describe("The Protocol", $.proxy(function (mock, test_utils) { describe("The Protocol", function () {
beforeEach(function () {
test_utils.removeControlBox(); describe("Integration of Roster Items and Presence Subscriptions", function () {
converse.roster.browserStorage._clear(); // Stub the trimChat method. It causes havoc when running with
test_utils.initConverse(); // phantomJS.
});
afterEach(function () {
converse_api.user.logout();
test_utils.clearBrowserStorage();
});
describe("Integration of Roster Items and Presence Subscriptions", $.proxy(function (mock, test_utils) {
/* Some level of integration between roster items and presence /* Some level of integration between roster items and presence
* subscriptions is normally expected by an instant messaging user * subscriptions is normally expected by an instant messaging user
* regarding the user's subscriptions to and from other contacts. This * regarding the user's subscriptions to and from other contacts. This
@ -52,26 +54,24 @@
* that session. A client MUST acknowledge each roster push with an IQ * that session. A client MUST acknowledge each roster push with an IQ
* stanza of type "result". * stanza of type "result".
*/ */
beforeEach(function () { it("Subscribe to contact, contact accepts and subscribes back", mock.initConverse(function (converse) {
test_utils.closeAllChatBoxes();
test_utils.openControlBox();
test_utils.openContactsPanel();
});
it("Subscribe to contact, contact accepts and subscribes back", $.proxy(function () {
/* The process by which a user subscribes to a contact, including /* The process by which a user subscribes to a contact, including
* the interaction between roster items and subscription states. * the interaction between roster items and subscription states.
*/ */
var contact, stanza, sent_stanza, IQ_id; var contact, stanza, sent_stanza, IQ_id;
runs($.proxy(function () { runs(function () {
var panel = this.chatboxviews.get('controlbox').contactspanel; test_utils.openControlBox(converse);
});
waits(100);
runs(function () {
var panel = converse.chatboxviews.get('controlbox').contactspanel;
spyOn(panel, "addContactFromForm").andCallThrough(); spyOn(panel, "addContactFromForm").andCallThrough();
spyOn(this.roster, "addAndSubscribe").andCallThrough(); spyOn(converse.roster, "addAndSubscribe").andCallThrough();
spyOn(this.roster, "addContact").andCallThrough(); spyOn(converse.roster, "addContact").andCallThrough();
spyOn(this.roster, "sendContactAddIQ").andCallThrough(); spyOn(converse.roster, "sendContactAddIQ").andCallThrough();
spyOn(this, "getVCard").andCallThrough(); spyOn(converse, "getVCard").andCallThrough();
var sendIQ = this.connection.sendIQ; var sendIQ = converse.connection.sendIQ;
spyOn(this.connection, 'sendIQ').andCallFake(function (iq, callback, errback) { spyOn(converse.connection, 'sendIQ').andCallFake(function (iq, callback, errback) {
sent_stanza = iq; sent_stanza = iq;
IQ_id = sendIQ.bind(this)(iq, callback, errback); IQ_id = sendIQ.bind(this)(iq, callback, errback);
}); });
@ -99,7 +99,7 @@
// The form should not be visible anymore. // The form should not be visible anymore.
expect($form.is(":visible")).toBeFalsy(); expect($form.is(":visible")).toBeFalsy();
/* This request consists of sending an IQ /* converse request consists of sending an IQ
* stanza of type='set' containing a <query/> element qualified by * stanza of type='set' containing a <query/> element qualified by
* the 'jabber:iq:roster' namespace, which in turn contains an * the 'jabber:iq:roster' namespace, which in turn contains an
* <item/> element that defines the new roster item; the <item/> * <item/> element that defines the new roster item; the <item/>
@ -127,7 +127,7 @@
); );
/* As a result, the user's server (1) MUST initiate a roster push /* As a result, the user's server (1) MUST initiate a roster push
* for the new roster item to all available resources associated * for the new roster item to all available resources associated
* with this user that have requested the roster, setting the * with converse user that have requested the roster, setting the
* 'subscription' attribute to a value of "none"; and (2) MUST * 'subscription' attribute to a value of "none"; and (2) MUST
* reply to the sending resource with an IQ result indicating the * reply to the sending resource with an IQ result indicating the
* success of the roster set: * success of the roster set:
@ -157,17 +157,17 @@
'jid': 'contact@example.org', 'jid': 'contact@example.org',
'subscription': 'none', 'subscription': 'none',
'name': 'contact@example.org'}); 'name': 'contact@example.org'});
this.connection._dataRecv(test_utils.createRequest(stanza)); converse.connection._dataRecv(test_utils.createRequest(stanza));
/* /*
* <iq type='result' id='set1'/> * <iq type='result' id='set1'/>
*/ */
stanza = $iq({'type': 'result', 'id':IQ_id}); stanza = $iq({'type': 'result', 'id':IQ_id});
this.connection._dataRecv(test_utils.createRequest(stanza)); converse.connection._dataRecv(test_utils.createRequest(stanza));
// A contact should now have been created // A contact should now have been created
expect(this.roster.get('contact@example.org') instanceof this.RosterContact).toBeTruthy(); expect(converse.roster.get('contact@example.org') instanceof converse.RosterContact).toBeTruthy();
expect(contact.get('jid')).toBe('contact@example.org'); expect(contact.get('jid')).toBe('contact@example.org');
expect(this.getVCard).toHaveBeenCalled(); expect(converse.getVCard).toHaveBeenCalled();
/* To subscribe to the contact's presence information, /* To subscribe to the contact's presence information,
* the user's client MUST send a presence stanza of * the user's client MUST send a presence stanza of
@ -184,7 +184,7 @@
/* As a result, the user's server MUST initiate a second roster /* As a result, the user's server MUST initiate a second roster
* push to all of the user's available resources that have * push to all of the user's available resources that have
* requested the roster, setting the contact to the pending * requested the roster, setting the contact to the pending
* sub-state of the 'none' subscription state; this pending * sub-state of the 'none' subscription state; converse pending
* sub-state is denoted by the inclusion of the ask='subscribe' * sub-state is denoted by the inclusion of the ask='subscribe'
* attribute in the roster item: * attribute in the roster item:
* *
@ -208,11 +208,11 @@
'subscription': 'none', 'subscription': 'none',
'ask': 'subscribe', 'ask': 'subscribe',
'name': 'contact@example.org'}); 'name': 'contact@example.org'});
this.connection._dataRecv(test_utils.createRequest(stanza)); converse.connection._dataRecv(test_utils.createRequest(stanza));
expect(converse.roster.updateContact).toHaveBeenCalled(); expect(converse.roster.updateContact).toHaveBeenCalled();
}, this)); });
waits(50); waits(50);
runs($.proxy(function () { runs(function () {
// Check that the user is now properly shown as a pending // Check that the user is now properly shown as a pending
// contact in the roster. // contact in the roster.
var $header = $('a:contains("Pending contacts")'); var $header = $('a:contains("Pending contacts")');
@ -223,46 +223,46 @@
spyOn(contact, "ackSubscribe").andCallThrough(); spyOn(contact, "ackSubscribe").andCallThrough();
/* Here we assume the "happy path" that the contact /* Here we assume the "happy path" that the contact
* approves the subscription request * approves the subscription request
* *
* <presence * <presence
* to='user@example.com' * to='user@example.com'
* from='contact@example.org' * from='contact@example.org'
* type='subscribed'/> * type='subscribed'/>
*/ */
stanza = $pres({ stanza = $pres({
'to': converse.bare_jid, 'to': converse.bare_jid,
'from': 'contact@example.org', 'from': 'contact@example.org',
'type': 'subscribed' 'type': 'subscribed'
}); });
sent_stanza = ""; // Reset sent_stanza = ""; // Reset
this.connection._dataRecv(test_utils.createRequest(stanza)); converse.connection._dataRecv(test_utils.createRequest(stanza));
/* Upon receiving the presence stanza of type "subscribed", /* Upon receiving the presence stanza of type "subscribed",
* the user SHOULD acknowledge receipt of that * the user SHOULD acknowledge receipt of that
* subscription state notification by sending a presence * subscription state notification by sending a presence
* stanza of type "subscribe". * stanza of type "subscribe".
*/ */
expect(contact.ackSubscribe).toHaveBeenCalled(); expect(contact.ackSubscribe).toHaveBeenCalled();
expect(sent_stanza.toLocaleString()).toBe( // Strophe adds the xmlns attr (although not in spec) expect(sent_stanza.toLocaleString()).toBe( // Strophe adds the xmlns attr (although not in spec)
"<presence type='subscribe' to='contact@example.org' xmlns='jabber:client'/>" "<presence type='subscribe' to='contact@example.org' xmlns='jabber:client'/>"
); );
/* The user's server MUST initiate a roster push to all of the user's /* The user's server MUST initiate a roster push to all of the user's
* available resources that have requested the roster, * available resources that have requested the roster,
* containing an updated roster item for the contact with * containing an updated roster item for the contact with
* the 'subscription' attribute set to a value of "to"; * the 'subscription' attribute set to a value of "to";
* *
* <iq type='set'> * <iq type='set'>
* <query xmlns='jabber:iq:roster'> * <query xmlns='jabber:iq:roster'>
* <item * <item
* jid='contact@example.org' * jid='contact@example.org'
* subscription='to' * subscription='to'
* name='MyContact'> * name='MyContact'>
* <group>MyBuddies</group> * <group>MyBuddies</group>
* </item> * </item>
* </query> * </query>
* </iq> * </iq>
*/ */
IQ_id = converse.connection.getUniqueId('roster'); IQ_id = converse.connection.getUniqueId('roster');
stanza = $iq({'type': 'set', 'id': IQ_id}) stanza = $iq({'type': 'set', 'id': IQ_id})
.c('query', {'xmlns': 'jabber:iq:roster'}) .c('query', {'xmlns': 'jabber:iq:roster'})
@ -270,7 +270,7 @@
'jid': 'contact@example.org', 'jid': 'contact@example.org',
'subscription': 'to', 'subscription': 'to',
'name': 'contact@example.org'}); 'name': 'contact@example.org'});
this.connection._dataRecv(test_utils.createRequest(stanza)); converse.connection._dataRecv(test_utils.createRequest(stanza));
// Check that the IQ set was acknowledged. // Check that the IQ set was acknowledged.
expect(sent_stanza.toLocaleString()).toBe( // Strophe adds the xmlns attr (although not in spec) expect(sent_stanza.toLocaleString()).toBe( // Strophe adds the xmlns attr (although not in spec)
"<iq type='result' id='"+IQ_id+"' from='dummy@localhost/resource' xmlns='jabber:client'/>" "<iq type='result' id='"+IQ_id+"' from='dummy@localhost/resource' xmlns='jabber:client'/>"
@ -292,78 +292,82 @@
expect(contact.get('chat_status')).toBe('offline'); expect(contact.get('chat_status')).toBe('offline');
/* <presence /* <presence
* from='contact@example.org/resource' * from='contact@example.org/resource'
* to='user@example.com/resource'/> * to='user@example.com/resource'/>
*/ */
stanza = $pres({'to': converse.bare_jid, 'from': 'contact@example.org/resource'}); stanza = $pres({'to': converse.bare_jid, 'from': 'contact@example.org/resource'});
this.connection._dataRecv(test_utils.createRequest(stanza)); converse.connection._dataRecv(test_utils.createRequest(stanza));
// Now the contact should also be online. // Now the contact should also be online.
expect(contact.get('chat_status')).toBe('online'); expect(contact.get('chat_status')).toBe('online');
/* Section 8.3. Creating a Mutual Subscription /* Section 8.3. Creating a Mutual Subscription
* *
* If the contact wants to create a mutual subscription, * If the contact wants to create a mutual subscription,
* the contact MUST send a subscription request to the * the contact MUST send a subscription request to the
* user. * user.
* *
* <presence from='contact@example.org' to='user@example.com' type='subscribe'/> * <presence from='contact@example.org' to='user@example.com' type='subscribe'/>
*/ */
spyOn(contact, 'authorize').andCallThrough(); spyOn(contact, 'authorize').andCallThrough();
spyOn(this.roster, 'handleIncomingSubscription').andCallThrough(); spyOn(converse.roster, 'handleIncomingSubscription').andCallThrough();
stanza = $pres({ stanza = $pres({
'to': converse.bare_jid, 'to': converse.bare_jid,
'from': 'contact@example.org/resource', 'from': 'contact@example.org/resource',
'type': 'subscribe'}); 'type': 'subscribe'});
this.connection._dataRecv(test_utils.createRequest(stanza)); converse.connection._dataRecv(test_utils.createRequest(stanza));
expect(this.roster.handleIncomingSubscription).toHaveBeenCalled(); expect(converse.roster.handleIncomingSubscription).toHaveBeenCalled();
/* The user's client MUST send a presence stanza of type /* The user's client MUST send a presence stanza of type
* "subscribed" to the contact in order to approve the * "subscribed" to the contact in order to approve the
* subscription request. * subscription request.
* *
* <presence to='contact@example.org' type='subscribed'/> * <presence to='contact@example.org' type='subscribed'/>
*/ */
expect(contact.authorize).toHaveBeenCalled(); expect(contact.authorize).toHaveBeenCalled();
expect(sent_stanza.toLocaleString()).toBe( expect(sent_stanza.toLocaleString()).toBe(
"<presence to='contact@example.org' type='subscribed' xmlns='jabber:client'/>" "<presence to='contact@example.org' type='subscribed' xmlns='jabber:client'/>"
); );
/* As a result, the user's server MUST initiate a /* As a result, the user's server MUST initiate a
* roster push containing a roster item for the * roster push containing a roster item for the
* contact with the 'subscription' attribute set to * contact with the 'subscription' attribute set to
* a value of "both". * a value of "both".
* *
* <iq type='set'> * <iq type='set'>
* <query xmlns='jabber:iq:roster'> * <query xmlns='jabber:iq:roster'>
* <item * <item
* jid='contact@example.org' * jid='contact@example.org'
* subscription='both' * subscription='both'
* name='MyContact'> * name='MyContact'>
* <group>MyBuddies</group> * <group>MyBuddies</group>
* </item> * </item>
* </query> * </query>
* </iq> * </iq>
*/ */
stanza = $iq({'type': 'set'}).c('query', {'xmlns': 'jabber:iq:roster'}) stanza = $iq({'type': 'set'}).c('query', {'xmlns': 'jabber:iq:roster'})
.c('item', { .c('item', {
'jid': 'contact@example.org', 'jid': 'contact@example.org',
'subscription': 'both', 'subscription': 'both',
'name': 'contact@example.org'}); 'name': 'contact@example.org'});
this.connection._dataRecv(test_utils.createRequest(stanza)); converse.connection._dataRecv(test_utils.createRequest(stanza));
expect(converse.roster.updateContact).toHaveBeenCalled(); expect(converse.roster.updateContact).toHaveBeenCalled();
// The class on the contact will now have switched. // The class on the contact will now have switched.
expect($contacts.hasClass('to')).toBeFalsy(); expect($contacts.hasClass('to')).toBeFalsy();
expect($contacts.hasClass('both')).toBeTruthy(); expect($contacts.hasClass('both')).toBeTruthy();
}, this)); });
}, converse)); }));
it("Alternate Flow: Contact Declines Subscription Request", $.proxy(function () { it("Alternate Flow: Contact Declines Subscription Request", mock.initConverse(function (converse) {
/* The process by which a user subscribes to a contact, including /* The process by which a user subscribes to a contact, including
* the interaction between roster items and subscription states. * the interaction between roster items and subscription states.
*/ */
var contact, stanza, sent_stanza, sent_IQ; var contact, stanza, sent_stanza, sent_IQ;
runs($.proxy(function () { runs(function () {
test_utils.openControlBox(converse);
});
waits(100);
runs(function () {
// Add a new roster contact via roster push // Add a new roster contact via roster push
stanza = $iq({'type': 'set'}).c('query', {'xmlns': 'jabber:iq:roster'}) stanza = $iq({'type': 'set'}).c('query', {'xmlns': 'jabber:iq:roster'})
.c('item', { .c('item', {
@ -371,69 +375,69 @@
'subscription': 'none', 'subscription': 'none',
'ask': 'subscribe', 'ask': 'subscribe',
'name': 'contact@example.org'}); 'name': 'contact@example.org'});
this.connection._dataRecv(test_utils.createRequest(stanza)); converse.connection._dataRecv(test_utils.createRequest(stanza));
}, this)); });
waits(50); waits(50);
runs($.proxy(function () { runs(function () {
// A pending contact should now exist. // A pending contact should now exist.
contact = this.roster.get('contact@example.org'); contact = converse.roster.get('contact@example.org');
expect(this.roster.get('contact@example.org') instanceof this.RosterContact).toBeTruthy(); expect(converse.roster.get('contact@example.org') instanceof converse.RosterContact).toBeTruthy();
spyOn(contact, "ackUnsubscribe").andCallThrough(); spyOn(contact, "ackUnsubscribe").andCallThrough();
spyOn(converse.connection, 'send').andCallFake(function (stanza) { spyOn(converse.connection, 'send').andCallFake(function (stanza) {
sent_stanza = stanza; sent_stanza = stanza;
}); });
spyOn(this.connection, 'sendIQ').andCallFake(function (iq, callback, errback) { spyOn(converse.connection, 'sendIQ').andCallFake(function (iq, callback, errback) {
sent_IQ = iq; sent_IQ = iq;
}); });
/* We now assume the contact declines the subscription /* We now assume the contact declines the subscription
* requests. * requests.
* *
/* Upon receiving the presence stanza of type "unsubscribed" /* Upon receiving the presence stanza of type "unsubscribed"
* addressed to the user, the user's server (1) MUST deliver * addressed to the user, the user's server (1) MUST deliver
* that presence stanza to the user and (2) MUST initiate a * that presence stanza to the user and (2) MUST initiate a
* roster push to all of the user's available resources that * roster push to all of the user's available resources that
* have requested the roster, containing an updated roster * have requested the roster, containing an updated roster
* item for the contact with the 'subscription' attribute * item for the contact with the 'subscription' attribute
* set to a value of "none" and with no 'ask' attribute: * set to a value of "none" and with no 'ask' attribute:
* *
* <presence * <presence
* from='contact@example.org' * from='contact@example.org'
* to='user@example.com' * to='user@example.com'
* type='unsubscribed'/> * type='unsubscribed'/>
* *
* <iq type='set'> * <iq type='set'>
* <query xmlns='jabber:iq:roster'> * <query xmlns='jabber:iq:roster'>
* <item * <item
* jid='contact@example.org' * jid='contact@example.org'
* subscription='none' * subscription='none'
* name='MyContact'> * name='MyContact'>
* <group>MyBuddies</group> * <group>MyBuddies</group>
* </item> * </item>
* </query> * </query>
* </iq> * </iq>
*/ */
// FIXME: also add the <iq> // FIXME: also add the <iq>
stanza = $pres({ stanza = $pres({
'to': converse.bare_jid, 'to': converse.bare_jid,
'from': 'contact@example.org', 'from': 'contact@example.org',
'type': 'unsubscribed' 'type': 'unsubscribed'
}); });
this.connection._dataRecv(test_utils.createRequest(stanza)); converse.connection._dataRecv(test_utils.createRequest(stanza));
/* Upon receiving the presence stanza of type "unsubscribed", /* Upon receiving the presence stanza of type "unsubscribed",
* the user SHOULD acknowledge receipt of that subscription * the user SHOULD acknowledge receipt of that subscription
* state notification through either "affirming" it by * state notification through either "affirming" it by
* sending a presence stanza of type "unsubscribe * sending a presence stanza of type "unsubscribe
*/ */
expect(contact.ackUnsubscribe).toHaveBeenCalled(); expect(contact.ackUnsubscribe).toHaveBeenCalled();
expect(sent_stanza.toLocaleString()).toBe( expect(sent_stanza.toLocaleString()).toBe(
"<presence type='unsubscribe' to='contact@example.org' xmlns='jabber:client'/>" "<presence type='unsubscribe' to='contact@example.org' xmlns='jabber:client'/>"
); );
/* Converse.js will then also automatically remove the /* Converse.js will then also automatically remove the
* contact from the user's roster. * contact from the user's roster.
*/ */
expect(sent_IQ.toLocaleString()).toBe( expect(sent_IQ.toLocaleString()).toBe(
"<iq type='set' xmlns='jabber:client'>"+ "<iq type='set' xmlns='jabber:client'>"+
"<query xmlns='jabber:iq:roster'>"+ "<query xmlns='jabber:iq:roster'>"+
@ -441,22 +445,23 @@
"</query>"+ "</query>"+
"</iq>" "</iq>"
); );
}, this)); });
}, converse)); }));
it("Unsubscribe to a contact when subscription is mutual", function () { it("Unsubscribe to a contact when subscription is mutual", mock.initConverse(function (converse) {
var sent_IQ, IQ_id, jid = 'annegreet.gomez@localhost'; var sent_IQ, IQ_id, jid = 'annegreet.gomez@localhost';
runs(function () { runs(function () {
test_utils.createContacts('current'); test_utils.openControlBox(converse);
test_utils.createContacts(converse, 'current');
}); });
waits(50); waits(50);
runs(function () { runs(function () {
spyOn(window, 'confirm').andReturn(true); spyOn(window, 'confirm').andReturn(true);
// We now have a contact we want to remove // We now have a contact we want to remove
expect(this.roster.get(jid) instanceof this.RosterContact).toBeTruthy(); expect(converse.roster.get(jid) instanceof converse.RosterContact).toBeTruthy();
var sendIQ = this.connection.sendIQ; var sendIQ = converse.connection.sendIQ;
spyOn(this.connection, 'sendIQ').andCallFake(function (iq, callback, errback) { spyOn(converse.connection, 'sendIQ').andCallFake(function (iq, callback, errback) {
sent_IQ = iq; sent_IQ = iq;
IQ_id = sendIQ.bind(this)(iq, callback, errback); IQ_id = sendIQ.bind(this)(iq, callback, errback);
}); });
@ -467,24 +472,24 @@
expect(window.confirm).toHaveBeenCalled(); expect(window.confirm).toHaveBeenCalled();
/* Section 8.6 Removing a Roster Item and Cancelling All /* Section 8.6 Removing a Roster Item and Cancelling All
* Subscriptions * Subscriptions
* *
* First the user is removed from the roster * First the user is removed from the roster
* Because there may be many steps involved in completely * Because there may be many steps involved in completely
* removing a roster item and cancelling subscriptions in * removing a roster item and cancelling subscriptions in
* both directions, the roster management protocol includes * both directions, the roster management protocol includes
* a "shortcut" method for doing so. The process may be * a "shortcut" method for doing so. The process may be
* initiated no matter what the current subscription state * initiated no matter what the current subscription state
* is by sending a roster set containing an item for the * is by sending a roster set containing an item for the
* contact with the 'subscription' attribute set to a value * contact with the 'subscription' attribute set to a value
* of "remove": * of "remove":
* *
* <iq type='set' id='remove1'> * <iq type='set' id='remove1'>
* <query xmlns='jabber:iq:roster'> * <query xmlns='jabber:iq:roster'>
* <item jid='contact@example.org' subscription='remove'/> * <item jid='contact@example.org' subscription='remove'/>
* </query> * </query>
* </iq> * </iq>
*/ */
expect(sent_IQ.toLocaleString()).toBe( expect(sent_IQ.toLocaleString()).toBe(
"<iq type='set' xmlns='jabber:client' id='"+IQ_id+"'>"+ "<iq type='set' xmlns='jabber:client' id='"+IQ_id+"'>"+
"<query xmlns='jabber:iq:roster'>"+ "<query xmlns='jabber:iq:roster'>"+
@ -495,21 +500,21 @@
// Receive confirmation from the contact's server // Receive confirmation from the contact's server
// <iq type='result' id='remove1'/> // <iq type='result' id='remove1'/>
var stanza = $iq({'type': 'result', 'id':IQ_id}); var stanza = $iq({'type': 'result', 'id':IQ_id});
this.connection._dataRecv(test_utils.createRequest(stanza)); converse.connection._dataRecv(test_utils.createRequest(stanza));
// Our contact has now been removed // Our contact has now been removed
expect(typeof this.roster.get(jid) === "undefined").toBeTruthy(); expect(typeof converse.roster.get(jid) === "undefined").toBeTruthy();
}.bind(converse)); });
}.bind(converse)); }));
it("Receiving a subscription request", function () { it("Receiving a subscription request", mock.initConverse(function (converse) {
runs(function () { runs(function () {
test_utils.createContacts('current'); // Create some contacts so that we can test positioning test_utils.openControlBox(converse);
test_utils.createContacts(converse, 'current'); // Create some contacts so that we can test positioning
}); });
waits(50); waits(50);
runs(function () { runs(function () {
spyOn(converse, "emit"); spyOn(converse, "emit");
/* /* <presence
* <presence
* from='user@example.com' * from='user@example.com'
* to='contact@example.org' * to='contact@example.org'
* type='subscribe'/> * type='subscribe'/>
@ -521,15 +526,15 @@
}).c('nick', { }).c('nick', {
'xmlns': Strophe.NS.NICK, 'xmlns': Strophe.NS.NICK,
}).t('Clint Contact'); }).t('Clint Contact');
this.connection._dataRecv(test_utils.createRequest(stanza)); converse.connection._dataRecv(test_utils.createRequest(stanza));
expect(converse.emit).toHaveBeenCalledWith('contactRequest', jasmine.any(Object)); expect(converse.emit).toHaveBeenCalledWith('contactRequest', jasmine.any(Object));
var $header = $('a:contains("Contact requests")'); var $header = $('a:contains("Contact requests")');
expect($header.length).toBe(1); expect($header.length).toBe(1);
expect($header.is(":visible")).toBeTruthy(); expect($header.is(":visible")).toBeTruthy();
var $contacts = $header.parent().nextUntil('dt', 'dd'); var $contacts = $header.parent().nextUntil('dt', 'dd');
expect($contacts.length).toBe(1); expect($contacts.length).toBe(1);
}.bind(converse)); });
}.bind(converse)); }));
}, converse, mock, test_utils)); });
}, converse, mock, test_utils)); });
})); }));

View File

@ -1950,6 +1950,15 @@
utils.merge(converse, settings); utils.merge(converse, settings);
utils.applyUserSettings(converse, settings, converse.user_settings); utils.applyUserSettings(converse, settings, converse.user_settings);
}; };
// If initialize gets called a second time (e.g. during tests), then we
// need to re-apply all plugins (for a new converse instance), and we
// therefore need to clear this array that prevents plugins from being
// initialized twice.
// If initialize is called for the first time, then this array is empty
// in any case.
converse.pluggable.initialized_plugins = [];
converse.pluggable.initializePlugins({ converse.pluggable.initializePlugins({
'updateSettings': updateSettings, 'updateSettings': updateSettings,
'converse': converse 'converse': converse

View File

@ -45,71 +45,49 @@ require([
window.localStorage.clear(); window.localStorage.clear();
window.sessionStorage.clear(); window.sessionStorage.clear();
converse.initialize({ require([
i18n: window.locales.en, "console-runner",
auto_subscribe: false, //"spec/transcripts",
bosh_service_url: 'localhost', "spec/utils",
connection: mock.mock_connection, "spec/converse",
animate: false, /*
no_trimming: true, "spec/bookmarks",
auto_login: true, "spec/headline",
jid: 'dummy@localhost', "spec/disco",
password: 'secret', */
debug: true "spec/protocol",
}).then(function (converse) { /*
window.converse = converse; "spec/mam",
window.crypto = { "spec/otr",
getRandomValues: function (buf) { "spec/eventemitter",
var i; "spec/controlbox",
for (i=0, len=buf.length; i<len; i++) { "spec/chatbox",
buf[i] = Math.floor(Math.random()*256); "spec/chatroom",
} "spec/minchats",
} "spec/notification",
}; "spec/profiling",
require([ "spec/ping",
"console-runner", "spec/register",
//"spec/transcripts", "spec/xmppstatus",
"spec/utils", */
"spec/converse", ], function () {
"spec/bookmarks", // Jasmine stuff
"spec/headline", var jasmineEnv = jasmine.getEnv();
"spec/disco", var reporter;
"spec/protocol", if (/PhantomJS/.test(navigator.userAgent)) {
"spec/mam", reporter = new jasmine.ConsoleReporter();
"spec/otr", window.console_reporter = reporter;
"spec/eventemitter", jasmineEnv.addReporter(reporter);
"spec/controlbox", jasmineEnv.updateInterval = 0;
"spec/chatbox", } else {
"spec/chatroom", reporter = new jasmine.HtmlReporter();
"spec/minchats", jasmineEnv.addReporter(reporter);
"spec/notification", jasmineEnv.specFilter = function(spec) {
"spec/profiling", return reporter.specFilter(spec);
"spec/ping", };
"spec/register", jasmineEnv.updateInterval = 0;
"spec/xmppstatus", }
], function () { jasmineEnv.execute();
// Stub the trimChat method. It causes havoc when running with
// phantomJS.
converse.ChatBoxViews.prototype.trimChat = function () {};
// Jasmine stuff
var jasmineEnv = jasmine.getEnv();
var reporter;
if (/PhantomJS/.test(navigator.userAgent)) {
reporter = new jasmine.ConsoleReporter();
window.console_reporter = reporter;
jasmineEnv.addReporter(reporter);
jasmineEnv.updateInterval = 0;
} else {
reporter = new jasmine.HtmlReporter();
jasmineEnv.addReporter(reporter);
jasmineEnv.specFilter = function(spec) {
return reporter.specFilter(spec);
};
jasmineEnv.updateInterval = 0;
}
jasmineEnv.execute();
});
}); });
} }
); );

View File

@ -1,12 +1,8 @@
(function (root, factory) { (function (root, factory) {
define("mock", define("mock", ['converse'], factory);
['converse'], }(this, function (converse_api) {
function(converse) { var Strophe = converse_api.env.Strophe;
return factory(converse); var $iq = converse_api.env.$iq;
});
}(this, function (converse) {
var Strophe = converse.env.Strophe;
var $iq = converse.env.$iq;
var mock = {}; var mock = {};
// Names from http://www.fakenamegenerator.com/ // Names from http://www.fakenamegenerator.com/
mock.req_names = [ mock.req_names = [
@ -48,33 +44,54 @@
}; };
mock.mock_connection = function () { mock.mock_connection = function () {
Strophe.Bosh.prototype._processRequest = function () {}; // Don't attempt to send out stanzas return function () {
var c = new Strophe.Connection('jasmine tests'); Strophe.Bosh.prototype._processRequest = function () {}; // Don't attempt to send out stanzas
c.vcard = { var c = new Strophe.Connection('jasmine tests');
'get': function (callback, jid) { c.vcard = {
var fullname; 'get': function (callback, jid) {
if (!jid) { var fullname;
jid = 'dummy@localhost'; if (!jid) {
fullname = 'Max Mustermann' ; jid = 'dummy@localhost';
} else { fullname = 'Max Mustermann' ;
var name = jid.split('@')[0].replace(/\./g, ' ').split(' '); } else {
var last = name.length-1; var name = jid.split('@')[0].replace(/\./g, ' ').split(' ');
name[0] = name[0].charAt(0).toUpperCase()+name[0].slice(1); var last = name.length-1;
name[last] = name[last].charAt(0).toUpperCase()+name[last].slice(1); name[0] = name[0].charAt(0).toUpperCase()+name[0].slice(1);
fullname = name.join(' '); name[last] = name[last].charAt(0).toUpperCase()+name[last].slice(1);
fullname = name.join(' ');
}
var vcard = $iq().c('vCard').c('FN').t(fullname);
callback(vcard.tree());
} }
var vcard = $iq().c('vCard').c('FN').t(fullname); };
callback(vcard.tree()); c._proto._connect = function () {
} c.authenticated = true;
c.connected = true;
c.mock = true;
c.jid = 'dummy@localhost/resource';
c._changeConnectStatus(Strophe.Status.CONNECTED);
};
return c;
}; };
c._proto._connect = function () {
c.authenticated = true;
c.connected = true;
c.mock = true;
c.jid = 'dummy@localhost/resource';
c._changeConnectStatus(Strophe.Status.CONNECTED);
};
return c;
}(); }();
mock.initConverse = function (func) {
return function () {
var converse = converse_api.initialize({
i18n: window.locales.en,
auto_subscribe: false,
bosh_service_url: 'localhost',
connection: mock.mock_connection(),
animate: false,
no_trimming: true,
auto_login: true,
jid: 'dummy@localhost',
password: 'secret',
debug: true
});
converse.ChatBoxViews.prototype.trimChat = function () {};
return func(converse);
};
};
return mock; return mock;
})); }));

View File

@ -1,12 +1,7 @@
(function (root, factory) { (function (root, factory) {
define("test_utils", [ define("test_utils", ['converse', 'mock'], factory);
'jquery', }(this, function (converse_api, mock) {
'mock' var $ = converse_api.env.jQuery;
],
function($, mock) {
return factory($, mock);
});
}(this, function ($, mock) {
var $pres = converse_api.env.$pres; var $pres = converse_api.env.$pres;
var $iq = converse_api.env.$iq; var $iq = converse_api.env.$iq;
var Strophe = converse_api.env.Strophe; var Strophe = converse_api.env.Strophe;
@ -23,7 +18,7 @@
return req; return req;
}; };
utils.closeAllChatBoxes = function () { utils.closeAllChatBoxes = function (converse) {
var i, chatbox; var i, chatbox;
for (i=converse.chatboxes.models.length-1; i>-1; i--) { for (i=converse.chatboxes.models.length-1; i>-1; i--) {
chatbox = converse.chatboxes.models[i]; chatbox = converse.chatboxes.models[i];
@ -78,7 +73,7 @@
$('#controlbox').remove(); $('#controlbox').remove();
}; };
utils.openContactsPanel = function () { utils.openContactsPanel = function (converse) {
var cbview = converse.chatboxviews.get('controlbox'); var cbview = converse.chatboxviews.get('controlbox');
var $tabs = cbview.$el.find('#controlbox-tabs'); var $tabs = cbview.$el.find('#controlbox-tabs');
$tabs.find('li').first().find('a').click(); $tabs.find('li').first().find('a').click();
@ -100,7 +95,7 @@
return views; return views;
}; };
utils.openChatBoxFor = function (jid) { utils.openChatBoxFor = function (converse, jid) {
return converse.roster.get(jid).trigger("open"); return converse.roster.get(jid).trigger("open");
}; };
@ -172,7 +167,7 @@
view.model.messages.browserStorage._clear(); view.model.messages.browserStorage._clear();
}; };
utils.createContacts = function (type, length) { utils.createContacts = function (converse, type, length) {
/* Create current (as opposed to requesting or pending) contacts /* Create current (as opposed to requesting or pending) contacts
* for the user's roster. * for the user's roster.
* *