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) {
define([
"jquery",
@ -12,10 +11,15 @@
} (this, function ($, _, mock, test_utils) {
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 () {
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 connection = converse.connection;
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."));
converse.bosh_service_url = url;
converse.connection = connection;
});
}));
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 jid = converse.jid;
delete converse.jid;
@ -38,9 +42,9 @@
converse.authentication= authentication;
converse.jid = jid;
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 jid = converse.jid;
delete converse.jid;
@ -50,13 +54,13 @@
converse.authentication= authentication;
converse.bosh_service_url = undefined;
converse.jid = jid;
});
}));
});
});
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();
var sent_stanza;
spyOn(converse.connection, 'send').andCallFake(function (stanza) {
@ -85,12 +89,12 @@
// Reset values
converse.csi_waiting_time = 0;
converse.features['urn:xmpp:csi:0'] = false;
});
}));
});
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;
// Usually initialized by registerIntervalHandler
converse.idle_seconds = 0;
@ -124,26 +128,21 @@
converse.auto_away = 0;
converse.auto_xa = 0;
converse.auto_changed_status = false;
});
}));
});
describe("The \"user\" grouping", 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');
expect(converse_api.user.status.get()).toBe('online');
converse.xmppstatus.set('status', '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');
expect(converse.xmppstatus.get('status')).toBe('away');
converse_api.user.status.set('dnd');
@ -155,38 +154,33 @@
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')
);
});
}));
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");
expect(converse.xmppstatus.get('status')).toBe('away');
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);
expect(converse_api.user.status.message.get()).toBe(undefined);
converse.xmppstatus.set('status_message', "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_api.user.status.message.set("I'm in a meeting");
expect(converse.xmppstatus.get('status_message')).toBe("I'm in a meeting");
});
}));
});
});
describe("The \"tokens\" API", $.proxy(function () {
beforeEach(function () {
test_utils.closeAllChatBoxes();
test_utils.clearBrowserStorage();
converse.rosterview.model.reset();
test_utils.createContacts('current');
});
describe("The \"tokens\" API", function () {
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;
converse.connection._proto.rid = '1234';
converse.expose_rid_and_sid = false;
@ -197,9 +191,10 @@
expect(converse_api.tokens.get('rid')).toBe(null);
// Restore the 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;
converse.connection._proto.sid = '1234';
converse.expose_rid_and_sid = false;
@ -210,19 +205,14 @@
expect(converse_api.tokens.get('sid')).toBe(null);
// Restore the connection
converse.connection = old_connection;
}, converse));
}, converse));
}));
});
describe("The \"contacts\" API", $.proxy(function () {
beforeEach($.proxy(function () {
test_utils.closeAllChatBoxes();
test_utils.clearBrowserStorage();
converse.rosterview.model.reset();
test_utils.createContacts('current');
}, converse));
describe("The \"contacts\" API", function () {
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
test_utils.createContacts(converse, 'current');
expect(converse_api.contacts.get('non-existing@jabber.org')).toBeFalsy();
// Check when a single jid is given
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
list = converse_api.contacts.get();
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');
expect(converse_api.contacts.add).toThrow(error);
expect(converse_api.contacts.add.bind(converse_api, "invalid jid")).toThrow(error);
spyOn(converse.roster, 'addAndSubscribe');
converse_api.contacts.add("newcontact@example.org");
expect(converse.roster.addAndSubscribe).toHaveBeenCalled();
}, converse));
}));
});
}, converse));
describe("The \"chats\" API", function() {
describe("The \"chats\" API", $.proxy(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 a wrapped chat box", function () {
it("has a method 'get' which returns a wrapped chat box", mock.initConverse(function (converse) {
test_utils.createContacts(converse, 'current');
// Test on chat that doesn't exist.
expect(converse_api.chats.get('non-existing@jabber.org')).toBeFalsy();
var jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@localhost';
@ -271,7 +256,7 @@
var chatboxview = converse.chatboxviews.get(jid);
// Test for single JID
test_utils.openChatBoxFor(jid);
test_utils.openChatBoxFor(converse, jid);
box = converse_api.chats.get(jid);
expect(box instanceof Object).toBeTruthy();
expect(box.get('box_id')).toBe(b64_sha1(jid));
@ -279,14 +264,15 @@
expect(chatboxview.$el.is(':visible')).toBeTruthy();
// Test for multiple JIDs
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]);
expect(Array.isArray(list)).toBeTruthy();
expect(list[0].get('box_id')).toBe(b64_sha1(jid));
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 chatboxview;
waits('300'); // ChatBox.show() is debounced for 250ms
@ -309,18 +295,11 @@
expect(list[0].get('box_id')).toBe(b64_sha1(jid));
expect(list[1].get('box_id')).toBe(b64_sha1(jid2));
});
});
}, converse));
}));
});
describe("The \"settings\" API", $.proxy(function() {
beforeEach($.proxy(function () {
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 () {
describe("The \"settings\" API", function() {
it("has methods 'get' and 'set' to set configuration settings", mock.initConverse(function (converse) {
expect(Object.keys(converse_api.settings)).toEqual(["get", "set"]);
expect(converse_api.settings.get("play_sounds")).toBe(false);
converse_api.settings.set("play_sounds", true);
@ -331,7 +310,7 @@
expect(typeof converse_api.settings.get("non_existing")).toBe("undefined");
converse_api.settings.set("non_existing", true);
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) {
define([
"jquery",
@ -16,14 +15,17 @@
// See:
// https://xmpp.org/rfcs/rfc3921.html
describe("The Protocol", $.proxy(function (mock, test_utils) {
beforeEach(function () {
test_utils.removeControlBox();
converse.roster.browserStorage._clear();
test_utils.initConverse();
});
describe("The Protocol", function () {
describe("Integration of Roster Items and Presence Subscriptions", function () {
// Stub the trimChat method. It causes havoc when running with
// 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
* subscriptions is normally expected by an instant messaging user
* 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
* stanza of type "result".
*/
beforeEach(function () {
test_utils.closeAllChatBoxes();
test_utils.openControlBox();
test_utils.openContactsPanel();
});
it("Subscribe to contact, contact accepts and subscribes back", $.proxy(function () {
it("Subscribe to contact, contact accepts and subscribes back", mock.initConverse(function (converse) {
/* The process by which a user subscribes to a contact, including
* the interaction between roster items and subscription states.
*/
var contact, stanza, sent_stanza, IQ_id;
runs($.proxy(function () {
var panel = this.chatboxviews.get('controlbox').contactspanel;
runs(function () {
test_utils.openControlBox(converse);
});
waits(100);
runs(function () {
var panel = converse.chatboxviews.get('controlbox').contactspanel;
spyOn(panel, "addContactFromForm").andCallThrough();
spyOn(this.roster, "addAndSubscribe").andCallThrough();
spyOn(this.roster, "addContact").andCallThrough();
spyOn(this.roster, "sendContactAddIQ").andCallThrough();
spyOn(this, "getVCard").andCallThrough();
var sendIQ = this.connection.sendIQ;
spyOn(this.connection, 'sendIQ').andCallFake(function (iq, callback, errback) {
spyOn(converse.roster, "addAndSubscribe").andCallThrough();
spyOn(converse.roster, "addContact").andCallThrough();
spyOn(converse.roster, "sendContactAddIQ").andCallThrough();
spyOn(converse, "getVCard").andCallThrough();
var sendIQ = converse.connection.sendIQ;
spyOn(converse.connection, 'sendIQ').andCallFake(function (iq, callback, errback) {
sent_stanza = iq;
IQ_id = sendIQ.bind(this)(iq, callback, errback);
});
@ -99,7 +99,7 @@
// The form should not be visible anymore.
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
* the 'jabber:iq:roster' namespace, which in turn contains an
* <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
* 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
* reply to the sending resource with an IQ result indicating the
* success of the roster set:
@ -157,17 +157,17 @@
'jid': 'contact@example.org',
'subscription': 'none',
'name': 'contact@example.org'});
this.connection._dataRecv(test_utils.createRequest(stanza));
converse.connection._dataRecv(test_utils.createRequest(stanza));
/*
* <iq type='result' id='set1'/>
*/
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
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(this.getVCard).toHaveBeenCalled();
expect(converse.getVCard).toHaveBeenCalled();
/* To subscribe to the contact's presence information,
* 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
* push to all of the user's available resources that have
* 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'
* attribute in the roster item:
*
@ -208,11 +208,11 @@
'subscription': 'none',
'ask': 'subscribe',
'name': 'contact@example.org'});
this.connection._dataRecv(test_utils.createRequest(stanza));
converse.connection._dataRecv(test_utils.createRequest(stanza));
expect(converse.roster.updateContact).toHaveBeenCalled();
}, this));
});
waits(50);
runs($.proxy(function () {
runs(function () {
// Check that the user is now properly shown as a pending
// contact in the roster.
var $header = $('a:contains("Pending contacts")');
@ -223,46 +223,46 @@
spyOn(contact, "ackSubscribe").andCallThrough();
/* Here we assume the "happy path" that the contact
* approves the subscription request
*
* <presence
* to='user@example.com'
* from='contact@example.org'
* type='subscribed'/>
*/
* approves the subscription request
*
* <presence
* to='user@example.com'
* from='contact@example.org'
* type='subscribed'/>
*/
stanza = $pres({
'to': converse.bare_jid,
'from': 'contact@example.org',
'type': 'subscribed'
});
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",
* the user SHOULD acknowledge receipt of that
* subscription state notification by sending a presence
* stanza of type "subscribe".
*/
* the user SHOULD acknowledge receipt of that
* subscription state notification by sending a presence
* stanza of type "subscribe".
*/
expect(contact.ackSubscribe).toHaveBeenCalled();
expect(sent_stanza.toLocaleString()).toBe( // Strophe adds the xmlns attr (although not in spec)
"<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
* available resources that have requested the roster,
* containing an updated roster item for the contact with
* the 'subscription' attribute set to a value of "to";
*
* <iq type='set'>
* <query xmlns='jabber:iq:roster'>
* <item
* jid='contact@example.org'
* subscription='to'
* name='MyContact'>
* <group>MyBuddies</group>
* </item>
* </query>
* </iq>
*/
* available resources that have requested the roster,
* containing an updated roster item for the contact with
* the 'subscription' attribute set to a value of "to";
*
* <iq type='set'>
* <query xmlns='jabber:iq:roster'>
* <item
* jid='contact@example.org'
* subscription='to'
* name='MyContact'>
* <group>MyBuddies</group>
* </item>
* </query>
* </iq>
*/
IQ_id = converse.connection.getUniqueId('roster');
stanza = $iq({'type': 'set', 'id': IQ_id})
.c('query', {'xmlns': 'jabber:iq:roster'})
@ -270,7 +270,7 @@
'jid': 'contact@example.org',
'subscription': 'to',
'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.
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'/>"
@ -292,78 +292,82 @@
expect(contact.get('chat_status')).toBe('offline');
/* <presence
* from='contact@example.org/resource'
* to='user@example.com/resource'/>
*/
* from='contact@example.org/resource'
* to='user@example.com/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.
expect(contact.get('chat_status')).toBe('online');
/* Section 8.3. Creating a Mutual Subscription
*
* If the contact wants to create a mutual subscription,
* the contact MUST send a subscription request to the
* user.
*
* <presence from='contact@example.org' to='user@example.com' type='subscribe'/>
*/
*
* If the contact wants to create a mutual subscription,
* the contact MUST send a subscription request to the
* user.
*
* <presence from='contact@example.org' to='user@example.com' type='subscribe'/>
*/
spyOn(contact, 'authorize').andCallThrough();
spyOn(this.roster, 'handleIncomingSubscription').andCallThrough();
spyOn(converse.roster, 'handleIncomingSubscription').andCallThrough();
stanza = $pres({
'to': converse.bare_jid,
'from': 'contact@example.org/resource',
'type': 'subscribe'});
this.connection._dataRecv(test_utils.createRequest(stanza));
expect(this.roster.handleIncomingSubscription).toHaveBeenCalled();
converse.connection._dataRecv(test_utils.createRequest(stanza));
expect(converse.roster.handleIncomingSubscription).toHaveBeenCalled();
/* The user's client MUST send a presence stanza of type
* "subscribed" to the contact in order to approve the
* subscription request.
*
* <presence to='contact@example.org' type='subscribed'/>
*/
* "subscribed" to the contact in order to approve the
* subscription request.
*
* <presence to='contact@example.org' type='subscribed'/>
*/
expect(contact.authorize).toHaveBeenCalled();
expect(sent_stanza.toLocaleString()).toBe(
"<presence to='contact@example.org' type='subscribed' xmlns='jabber:client'/>"
);
/* As a result, the user's server MUST initiate a
* roster push containing a roster item for the
* contact with the 'subscription' attribute set to
* a value of "both".
*
* <iq type='set'>
* <query xmlns='jabber:iq:roster'>
* <item
* jid='contact@example.org'
* subscription='both'
* name='MyContact'>
* <group>MyBuddies</group>
* </item>
* </query>
* </iq>
*/
* roster push containing a roster item for the
* contact with the 'subscription' attribute set to
* a value of "both".
*
* <iq type='set'>
* <query xmlns='jabber:iq:roster'>
* <item
* jid='contact@example.org'
* subscription='both'
* name='MyContact'>
* <group>MyBuddies</group>
* </item>
* </query>
* </iq>
*/
stanza = $iq({'type': 'set'}).c('query', {'xmlns': 'jabber:iq:roster'})
.c('item', {
'jid': 'contact@example.org',
'subscription': 'both',
'name': 'contact@example.org'});
this.connection._dataRecv(test_utils.createRequest(stanza));
converse.connection._dataRecv(test_utils.createRequest(stanza));
expect(converse.roster.updateContact).toHaveBeenCalled();
// The class on the contact will now have switched.
expect($contacts.hasClass('to')).toBeFalsy();
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 interaction between roster items and subscription states.
*/
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
stanza = $iq({'type': 'set'}).c('query', {'xmlns': 'jabber:iq:roster'})
.c('item', {
@ -371,69 +375,69 @@
'subscription': 'none',
'ask': 'subscribe',
'name': 'contact@example.org'});
this.connection._dataRecv(test_utils.createRequest(stanza));
}, this));
converse.connection._dataRecv(test_utils.createRequest(stanza));
});
waits(50);
runs($.proxy(function () {
runs(function () {
// A pending contact should now exist.
contact = this.roster.get('contact@example.org');
expect(this.roster.get('contact@example.org') instanceof this.RosterContact).toBeTruthy();
contact = converse.roster.get('contact@example.org');
expect(converse.roster.get('contact@example.org') instanceof converse.RosterContact).toBeTruthy();
spyOn(contact, "ackUnsubscribe").andCallThrough();
spyOn(converse.connection, 'send').andCallFake(function (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;
});
/* We now assume the contact declines the subscription
* requests.
*
* requests.
*
/* Upon receiving the presence stanza of type "unsubscribed"
* addressed to the user, the user's server (1) MUST deliver
* that presence stanza to the user and (2) MUST initiate a
* roster push to all of the user's available resources that
* have requested the roster, containing an updated roster
* item for the contact with the 'subscription' attribute
* set to a value of "none" and with no 'ask' attribute:
*
* <presence
* from='contact@example.org'
* to='user@example.com'
* type='unsubscribed'/>
*
* <iq type='set'>
* <query xmlns='jabber:iq:roster'>
* <item
* jid='contact@example.org'
* subscription='none'
* name='MyContact'>
* <group>MyBuddies</group>
* </item>
* </query>
* </iq>
*/
* addressed to the user, the user's server (1) MUST deliver
* that presence stanza to the user and (2) MUST initiate a
* roster push to all of the user's available resources that
* have requested the roster, containing an updated roster
* item for the contact with the 'subscription' attribute
* set to a value of "none" and with no 'ask' attribute:
*
* <presence
* from='contact@example.org'
* to='user@example.com'
* type='unsubscribed'/>
*
* <iq type='set'>
* <query xmlns='jabber:iq:roster'>
* <item
* jid='contact@example.org'
* subscription='none'
* name='MyContact'>
* <group>MyBuddies</group>
* </item>
* </query>
* </iq>
*/
// FIXME: also add the <iq>
stanza = $pres({
'to': converse.bare_jid,
'from': 'contact@example.org',
'type': 'unsubscribed'
});
this.connection._dataRecv(test_utils.createRequest(stanza));
converse.connection._dataRecv(test_utils.createRequest(stanza));
/* Upon receiving the presence stanza of type "unsubscribed",
* the user SHOULD acknowledge receipt of that subscription
* state notification through either "affirming" it by
* sending a presence stanza of type "unsubscribe
*/
* the user SHOULD acknowledge receipt of that subscription
* state notification through either "affirming" it by
* sending a presence stanza of type "unsubscribe
*/
expect(contact.ackUnsubscribe).toHaveBeenCalled();
expect(sent_stanza.toLocaleString()).toBe(
"<presence type='unsubscribe' to='contact@example.org' xmlns='jabber:client'/>"
);
/* 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(
"<iq type='set' xmlns='jabber:client'>"+
"<query xmlns='jabber:iq:roster'>"+
@ -441,22 +445,23 @@
"</query>"+
"</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';
runs(function () {
test_utils.createContacts('current');
test_utils.openControlBox(converse);
test_utils.createContacts(converse, 'current');
});
waits(50);
runs(function () {
spyOn(window, 'confirm').andReturn(true);
// 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;
spyOn(this.connection, 'sendIQ').andCallFake(function (iq, callback, errback) {
var sendIQ = converse.connection.sendIQ;
spyOn(converse.connection, 'sendIQ').andCallFake(function (iq, callback, errback) {
sent_IQ = iq;
IQ_id = sendIQ.bind(this)(iq, callback, errback);
});
@ -467,24 +472,24 @@
expect(window.confirm).toHaveBeenCalled();
/* Section 8.6 Removing a Roster Item and Cancelling All
* Subscriptions
*
* First the user is removed from the roster
* Because there may be many steps involved in completely
* removing a roster item and cancelling subscriptions in
* both directions, the roster management protocol includes
* a "shortcut" method for doing so. The process may be
* initiated no matter what the current subscription state
* is by sending a roster set containing an item for the
* contact with the 'subscription' attribute set to a value
* of "remove":
*
* <iq type='set' id='remove1'>
* <query xmlns='jabber:iq:roster'>
* <item jid='contact@example.org' subscription='remove'/>
* </query>
* </iq>
*/
* Subscriptions
*
* First the user is removed from the roster
* Because there may be many steps involved in completely
* removing a roster item and cancelling subscriptions in
* both directions, the roster management protocol includes
* a "shortcut" method for doing so. The process may be
* initiated no matter what the current subscription state
* is by sending a roster set containing an item for the
* contact with the 'subscription' attribute set to a value
* of "remove":
*
* <iq type='set' id='remove1'>
* <query xmlns='jabber:iq:roster'>
* <item jid='contact@example.org' subscription='remove'/>
* </query>
* </iq>
*/
expect(sent_IQ.toLocaleString()).toBe(
"<iq type='set' xmlns='jabber:client' id='"+IQ_id+"'>"+
"<query xmlns='jabber:iq:roster'>"+
@ -495,21 +500,21 @@
// Receive confirmation from the contact's server
// <iq type='result' id='remove1'/>
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
expect(typeof this.roster.get(jid) === "undefined").toBeTruthy();
}.bind(converse));
}.bind(converse));
expect(typeof converse.roster.get(jid) === "undefined").toBeTruthy();
});
}));
it("Receiving a subscription request", function () {
it("Receiving a subscription request", mock.initConverse(function (converse) {
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);
runs(function () {
spyOn(converse, "emit");
/*
* <presence
/* <presence
* from='user@example.com'
* to='contact@example.org'
* type='subscribe'/>
@ -521,15 +526,15 @@
}).c('nick', {
'xmlns': Strophe.NS.NICK,
}).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));
var $header = $('a:contains("Contact requests")');
expect($header.length).toBe(1);
expect($header.is(":visible")).toBeTruthy();
var $contacts = $header.parent().nextUntil('dt', 'dd');
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.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({
'updateSettings': updateSettings,
'converse': converse

View File

@ -45,71 +45,49 @@ require([
window.localStorage.clear();
window.sessionStorage.clear();
converse.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
}).then(function (converse) {
window.converse = converse;
window.crypto = {
getRandomValues: function (buf) {
var i;
for (i=0, len=buf.length; i<len; i++) {
buf[i] = Math.floor(Math.random()*256);
}
}
};
require([
"console-runner",
//"spec/transcripts",
"spec/utils",
"spec/converse",
"spec/bookmarks",
"spec/headline",
"spec/disco",
"spec/protocol",
"spec/mam",
"spec/otr",
"spec/eventemitter",
"spec/controlbox",
"spec/chatbox",
"spec/chatroom",
"spec/minchats",
"spec/notification",
"spec/profiling",
"spec/ping",
"spec/register",
"spec/xmppstatus",
], function () {
// 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();
});
require([
"console-runner",
//"spec/transcripts",
"spec/utils",
"spec/converse",
/*
"spec/bookmarks",
"spec/headline",
"spec/disco",
*/
"spec/protocol",
/*
"spec/mam",
"spec/otr",
"spec/eventemitter",
"spec/controlbox",
"spec/chatbox",
"spec/chatroom",
"spec/minchats",
"spec/notification",
"spec/profiling",
"spec/ping",
"spec/register",
"spec/xmppstatus",
*/
], 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) {
define("mock",
['converse'],
function(converse) {
return factory(converse);
});
}(this, function (converse) {
var Strophe = converse.env.Strophe;
var $iq = converse.env.$iq;
define("mock", ['converse'], factory);
}(this, function (converse_api) {
var Strophe = converse_api.env.Strophe;
var $iq = converse_api.env.$iq;
var mock = {};
// Names from http://www.fakenamegenerator.com/
mock.req_names = [
@ -48,33 +44,54 @@
};
mock.mock_connection = function () {
Strophe.Bosh.prototype._processRequest = function () {}; // Don't attempt to send out stanzas
var c = new Strophe.Connection('jasmine tests');
c.vcard = {
'get': function (callback, jid) {
var fullname;
if (!jid) {
jid = 'dummy@localhost';
fullname = 'Max Mustermann' ;
} else {
var name = jid.split('@')[0].replace(/\./g, ' ').split(' ');
var last = name.length-1;
name[0] = name[0].charAt(0).toUpperCase()+name[0].slice(1);
name[last] = name[last].charAt(0).toUpperCase()+name[last].slice(1);
fullname = name.join(' ');
return function () {
Strophe.Bosh.prototype._processRequest = function () {}; // Don't attempt to send out stanzas
var c = new Strophe.Connection('jasmine tests');
c.vcard = {
'get': function (callback, jid) {
var fullname;
if (!jid) {
jid = 'dummy@localhost';
fullname = 'Max Mustermann' ;
} else {
var name = jid.split('@')[0].replace(/\./g, ' ').split(' ');
var last = name.length-1;
name[0] = name[0].charAt(0).toUpperCase()+name[0].slice(1);
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;
}));

View File

@ -1,12 +1,7 @@
(function (root, factory) {
define("test_utils", [
'jquery',
'mock'
],
function($, mock) {
return factory($, mock);
});
}(this, function ($, mock) {
define("test_utils", ['converse', 'mock'], factory);
}(this, function (converse_api, mock) {
var $ = converse_api.env.jQuery;
var $pres = converse_api.env.$pres;
var $iq = converse_api.env.$iq;
var Strophe = converse_api.env.Strophe;
@ -23,7 +18,7 @@
return req;
};
utils.closeAllChatBoxes = function () {
utils.closeAllChatBoxes = function (converse) {
var i, chatbox;
for (i=converse.chatboxes.models.length-1; i>-1; i--) {
chatbox = converse.chatboxes.models[i];
@ -78,7 +73,7 @@
$('#controlbox').remove();
};
utils.openContactsPanel = function () {
utils.openContactsPanel = function (converse) {
var cbview = converse.chatboxviews.get('controlbox');
var $tabs = cbview.$el.find('#controlbox-tabs');
$tabs.find('li').first().find('a').click();
@ -100,7 +95,7 @@
return views;
};
utils.openChatBoxFor = function (jid) {
utils.openChatBoxFor = function (converse, jid) {
return converse.roster.get(jid).trigger("open");
};
@ -172,7 +167,7 @@
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
* for the user's roster.
*