diff --git a/spec/chatbox.js b/spec/chatbox.js
index 67a69b80a..d564510de 100644
--- a/spec/chatbox.js
+++ b/spec/chatbox.js
@@ -10,6 +10,7 @@
} (this, function ($, jasmine, utils, converse, mock, test_utils) {
"use strict";
var _ = converse.env._;
+ var $iq = converse.env.$iq;
var $msg = converse.env.$msg;
var Strophe = converse.env.Strophe;
var moment = converse.env.moment;
@@ -22,30 +23,37 @@
null, ['rosterGroupsFetched'], {},
function (done, _converse) {
- test_utils.createContacts(_converse, 'current');
- test_utils.openControlBox();
- test_utils.openContactsPanel(_converse);
- expect(_converse.chatboxes.length).toEqual(1);
- var sender_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@localhost';
- var message = '/me is tired';
- var msg = $msg({
- from: sender_jid,
- to: _converse.connection.jid,
- type: 'chat',
- id: (new Date()).getTime()
- }).c('body').t(message).up()
- .c('active', {'xmlns': 'http://jabber.org/protocol/chatstates'}).tree();
+ test_utils.waitUntilFeatureSupportConfirmed(_converse, 'vcard-temp')
+ .then(function () {
+ return test_utils.waitUntil(function () {
+ return _converse.xmppstatus.get('fullname');
+ }, 300);
+ }).then(function () {
+ test_utils.createContacts(_converse, 'current');
+ test_utils.openControlBox();
+ test_utils.openContactsPanel(_converse);
+ expect(_converse.chatboxes.length).toEqual(1);
+ var sender_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@localhost';
+ var message = '/me is tired';
+ var msg = $msg({
+ from: sender_jid,
+ to: _converse.connection.jid,
+ type: 'chat',
+ id: (new Date()).getTime()
+ }).c('body').t(message).up()
+ .c('active', {'xmlns': 'http://jabber.org/protocol/chatstates'}).tree();
- _converse.chatboxes.onMessage(msg);
- var view = _converse.chatboxviews.get(sender_jid);
- expect(_.includes(view.$el.find('.chat-msg-author').text(), '**Max Frankfurter')).toBeTruthy();
- expect(view.$el.find('.chat-msg-content').text()).toBe(' is tired');
+ _converse.chatboxes.onMessage(msg);
+ var view = _converse.chatboxviews.get(sender_jid);
+ expect(_.includes(view.$el.find('.chat-msg-author').text(), '**Max Frankfurter')).toBeTruthy();
+ expect(view.$el.find('.chat-msg-content').text()).toBe(' is tired');
- message = '/me is as well';
- test_utils.sendMessage(view, message);
- expect(_.includes(view.$el.find('.chat-msg-author:last').text(), '**Max Mustermann')).toBeTruthy();
- expect(view.$el.find('.chat-msg-content:last').text()).toBe(' is as well');
- done();
+ message = '/me is as well';
+ test_utils.sendMessage(view, message);
+ expect(_.includes(view.$el.find('.chat-msg-author:last').text(), '**Max Mustermann')).toBeTruthy();
+ expect(view.$el.find('.chat-msg-content:last').text()).toBe(' is as well');
+ done();
+ });
}));
it("is created when you click on a roster item",
@@ -527,7 +535,8 @@
describe("A Chat Message", function () {
describe("when received from someone else", function () {
- it("can be received which will open a chatbox and be displayed inside it",
+
+ it("will open a chatbox and be displayed inside it",
mock.initConverseWithPromises(
null, ['rosterGroupsFetched'], {},
function (done, _converse) {
@@ -953,47 +962,55 @@
null, ['rosterGroupsFetched'], {},
function (done, _converse) {
- test_utils.createContacts(_converse, 'current');
- test_utils.openControlBox();
- test_utils.openContactsPanel(_converse);
+ var contact, sent_stanza, IQ_id, stanza;
+ test_utils.waitUntilFeatureSupportConfirmed(_converse, 'vcard-temp')
+ .then(function () {
+ return test_utils.waitUntil(function () {
+ return _converse.xmppstatus.get('fullname');
+ }, 300);
+ }).then(function () {
+ test_utils.createContacts(_converse, 'current');
+ test_utils.openControlBox();
+ test_utils.openContactsPanel(_converse);
- // Send a message from a different resource
- spyOn(_converse, 'log');
- var msgtext = 'This is a sent carbon message';
- var recipient_jid = mock.cur_names[5].replace(/ /g,'.').toLowerCase() + '@localhost';
- var msg = $msg({
- 'from': _converse.bare_jid,
- 'id': (new Date()).getTime(),
- 'to': _converse.connection.jid,
- 'type': 'chat',
- 'xmlns': 'jabber:client'
- }).c('sent', {'xmlns': 'urn:xmpp:carbons:2'})
- .c('forwarded', {'xmlns': 'urn:xmpp:forward:0'})
- .c('message', {
- 'xmlns': 'jabber:client',
- 'from': _converse.bare_jid+'/another-resource',
- 'to': recipient_jid,
- 'type': 'chat'
- }).c('body').t(msgtext).tree();
- _converse.chatboxes.onMessage(msg);
+ // Send a message from a different resource
+ spyOn(_converse, 'log');
+ var msgtext = 'This is a sent carbon message';
+ var recipient_jid = mock.cur_names[5].replace(/ /g,'.').toLowerCase() + '@localhost';
+ var msg = $msg({
+ 'from': _converse.bare_jid,
+ 'id': (new Date()).getTime(),
+ 'to': _converse.connection.jid,
+ 'type': 'chat',
+ 'xmlns': 'jabber:client'
+ }).c('sent', {'xmlns': 'urn:xmpp:carbons:2'})
+ .c('forwarded', {'xmlns': 'urn:xmpp:forward:0'})
+ .c('message', {
+ 'xmlns': 'jabber:client',
+ 'from': _converse.bare_jid+'/another-resource',
+ 'to': recipient_jid,
+ 'type': 'chat'
+ }).c('body').t(msgtext).tree();
+ _converse.chatboxes.onMessage(msg);
- // Check that the chatbox and its view now exist
- var chatbox = _converse.chatboxes.get(recipient_jid);
- var chatboxview = _converse.chatboxviews.get(recipient_jid);
- expect(chatbox).toBeDefined();
- expect(chatboxview).toBeDefined();
- // Check that the message was received and check the message parameters
- expect(chatbox.messages.length).toEqual(1);
- var msg_obj = chatbox.messages.models[0];
- expect(msg_obj.get('message')).toEqual(msgtext);
- expect(msg_obj.get('fullname')).toEqual(_converse.xmppstatus.get('fullname'));
- expect(msg_obj.get('sender')).toEqual('me');
- expect(msg_obj.get('delayed')).toEqual(false);
- // Now check that the message appears inside the chatbox in the DOM
- var $chat_content = chatboxview.$el.find('.chat-content');
- var msg_txt = $chat_content.find('.chat-message').find('.chat-msg-content').text();
- expect(msg_txt).toEqual(msgtext);
- done();
+ // Check that the chatbox and its view now exist
+ var chatbox = _converse.chatboxes.get(recipient_jid);
+ var chatboxview = _converse.chatboxviews.get(recipient_jid);
+ expect(chatbox).toBeDefined();
+ expect(chatboxview).toBeDefined();
+ // Check that the message was received and check the message parameters
+ expect(chatbox.messages.length).toEqual(1);
+ var msg_obj = chatbox.messages.models[0];
+ expect(msg_obj.get('message')).toEqual(msgtext);
+ expect(msg_obj.get('fullname')).toEqual(_converse.xmppstatus.get('fullname'));
+ expect(msg_obj.get('sender')).toEqual('me');
+ expect(msg_obj.get('delayed')).toEqual(false);
+ // Now check that the message appears inside the chatbox in the DOM
+ var $chat_content = chatboxview.$el.find('.chat-content');
+ var msg_txt = $chat_content.find('.chat-message').find('.chat-msg-content').text();
+ expect(msg_txt).toEqual(msgtext);
+ done();
+ });
}));
it("will be discarded if it's a malicious message meant to look like a carbon copy",
@@ -1561,41 +1578,48 @@
null, ['rosterGroupsFetched'], {},
function (done, _converse) {
- test_utils.createContacts(_converse, 'current');
+ var contact, sent_stanza, IQ_id, stanza;
+ test_utils.waitUntilFeatureSupportConfirmed(_converse, 'vcard-temp')
+ .then(function () {
+ return test_utils.waitUntil(function () {
+ return _converse.xmppstatus.get('fullname');
+ }, 300);
+ }).then(function () {
+ test_utils.createContacts(_converse, 'current');
+ // Send a message from a different resource
+ spyOn(_converse, 'log');
+ var recipient_jid = mock.cur_names[5].replace(/ /g,'.').toLowerCase() + '@localhost';
+ test_utils.openChatBoxFor(_converse, recipient_jid);
+ var msg = $msg({
+ 'from': _converse.bare_jid,
+ 'id': (new Date()).getTime(),
+ 'to': _converse.connection.jid,
+ 'type': 'chat',
+ 'xmlns': 'jabber:client'
+ }).c('sent', {'xmlns': 'urn:xmpp:carbons:2'})
+ .c('forwarded', {'xmlns': 'urn:xmpp:forward:0'})
+ .c('message', {
+ 'xmlns': 'jabber:client',
+ 'from': _converse.bare_jid+'/another-resource',
+ 'to': recipient_jid,
+ 'type': 'chat'
+ }).c('composing', {'xmlns': Strophe.NS.CHATSTATES}).tree();
+ _converse.chatboxes.onMessage(msg);
- // Send a message from a different resource
- spyOn(_converse, 'log');
- var recipient_jid = mock.cur_names[5].replace(/ /g,'.').toLowerCase() + '@localhost';
- test_utils.openChatBoxFor(_converse, recipient_jid);
- var msg = $msg({
- 'from': _converse.bare_jid,
- 'id': (new Date()).getTime(),
- 'to': _converse.connection.jid,
- 'type': 'chat',
- 'xmlns': 'jabber:client'
- }).c('sent', {'xmlns': 'urn:xmpp:carbons:2'})
- .c('forwarded', {'xmlns': 'urn:xmpp:forward:0'})
- .c('message', {
- 'xmlns': 'jabber:client',
- 'from': _converse.bare_jid+'/another-resource',
- 'to': recipient_jid,
- 'type': 'chat'
- }).c('composing', {'xmlns': Strophe.NS.CHATSTATES}).tree();
- _converse.chatboxes.onMessage(msg);
-
- // Check that the chatbox and its view now exist
- var chatbox = _converse.chatboxes.get(recipient_jid);
- var chatboxview = _converse.chatboxviews.get(recipient_jid);
- // Check that the message was received and check the message parameters
- expect(chatbox.messages.length).toEqual(1);
- var msg_obj = chatbox.messages.models[0];
- expect(msg_obj.get('fullname')).toEqual(_converse.xmppstatus.get('fullname'));
- expect(msg_obj.get('sender')).toEqual('me');
- expect(msg_obj.get('delayed')).toEqual(false);
- var $chat_content = chatboxview.$el.find('.chat-content');
- var status_text = $chat_content.find('.chat-info.chat-event').text();
- expect(status_text).toBe('Typing from another device');
- done();
+ // Check that the chatbox and its view now exist
+ var chatbox = _converse.chatboxes.get(recipient_jid);
+ var chatboxview = _converse.chatboxviews.get(recipient_jid);
+ // Check that the message was received and check the message parameters
+ expect(chatbox.messages.length).toEqual(1);
+ var msg_obj = chatbox.messages.models[0];
+ expect(msg_obj.get('fullname')).toEqual(_converse.xmppstatus.get('fullname'));
+ expect(msg_obj.get('sender')).toEqual('me');
+ expect(msg_obj.get('delayed')).toEqual(false);
+ var $chat_content = chatboxview.$el.find('.chat-content');
+ var status_text = $chat_content.find('.chat-info.chat-event').text();
+ expect(status_text).toBe('Typing from another device');
+ done();
+ });
}));
});
@@ -1702,41 +1726,48 @@
null, ['rosterGroupsFetched'], {},
function (done, _converse) {
- test_utils.createContacts(_converse, 'current');
+ var contact, sent_stanza, IQ_id, stanza;
+ test_utils.waitUntilFeatureSupportConfirmed(_converse, 'vcard-temp')
+ .then(function () {
+ return test_utils.waitUntil(function () {
+ return _converse.xmppstatus.get('fullname');
+ }, 300);
+ }).then(function () {
+ test_utils.createContacts(_converse, 'current');
+ // Send a message from a different resource
+ spyOn(_converse, 'log');
+ var recipient_jid = mock.cur_names[5].replace(/ /g,'.').toLowerCase() + '@localhost';
+ test_utils.openChatBoxFor(_converse, recipient_jid);
+ var msg = $msg({
+ 'from': _converse.bare_jid,
+ 'id': (new Date()).getTime(),
+ 'to': _converse.connection.jid,
+ 'type': 'chat',
+ 'xmlns': 'jabber:client'
+ }).c('sent', {'xmlns': 'urn:xmpp:carbons:2'})
+ .c('forwarded', {'xmlns': 'urn:xmpp:forward:0'})
+ .c('message', {
+ 'xmlns': 'jabber:client',
+ 'from': _converse.bare_jid+'/another-resource',
+ 'to': recipient_jid,
+ 'type': 'chat'
+ }).c('paused', {'xmlns': Strophe.NS.CHATSTATES}).tree();
+ _converse.chatboxes.onMessage(msg);
- // Send a message from a different resource
- spyOn(_converse, 'log');
- var recipient_jid = mock.cur_names[5].replace(/ /g,'.').toLowerCase() + '@localhost';
- test_utils.openChatBoxFor(_converse, recipient_jid);
- var msg = $msg({
- 'from': _converse.bare_jid,
- 'id': (new Date()).getTime(),
- 'to': _converse.connection.jid,
- 'type': 'chat',
- 'xmlns': 'jabber:client'
- }).c('sent', {'xmlns': 'urn:xmpp:carbons:2'})
- .c('forwarded', {'xmlns': 'urn:xmpp:forward:0'})
- .c('message', {
- 'xmlns': 'jabber:client',
- 'from': _converse.bare_jid+'/another-resource',
- 'to': recipient_jid,
- 'type': 'chat'
- }).c('paused', {'xmlns': Strophe.NS.CHATSTATES}).tree();
- _converse.chatboxes.onMessage(msg);
-
- // Check that the chatbox and its view now exist
- var chatbox = _converse.chatboxes.get(recipient_jid);
- var chatboxview = _converse.chatboxviews.get(recipient_jid);
- // Check that the message was received and check the message parameters
- expect(chatbox.messages.length).toEqual(1);
- var msg_obj = chatbox.messages.models[0];
- expect(msg_obj.get('fullname')).toEqual(_converse.xmppstatus.get('fullname'));
- expect(msg_obj.get('sender')).toEqual('me');
- expect(msg_obj.get('delayed')).toEqual(false);
- var $chat_content = chatboxview.$el.find('.chat-content');
- var status_text = $chat_content.find('.chat-info.chat-event').text();
- expect(status_text).toBe('Stopped typing on the other device');
- done();
+ // Check that the chatbox and its view now exist
+ var chatbox = _converse.chatboxes.get(recipient_jid);
+ var chatboxview = _converse.chatboxviews.get(recipient_jid);
+ // Check that the message was received and check the message parameters
+ expect(chatbox.messages.length).toEqual(1);
+ var msg_obj = chatbox.messages.models[0];
+ expect(msg_obj.get('fullname')).toEqual(_converse.xmppstatus.get('fullname'));
+ expect(msg_obj.get('sender')).toEqual('me');
+ expect(msg_obj.get('delayed')).toEqual(false);
+ var $chat_content = chatboxview.$el.find('.chat-content');
+ var status_text = $chat_content.find('.chat-info.chat-event').text();
+ expect(status_text).toBe('Stopped typing on the other device');
+ done();
+ });
}));
});
diff --git a/spec/chatroom.js b/spec/chatroom.js
index 1e9b7833d..260d271cd 100644
--- a/spec/chatroom.js
+++ b/spec/chatroom.js
@@ -546,8 +546,16 @@
null, ['rosterGroupsFetched'], {},
function (done, _converse) {
- test_utils.createContacts(_converse, 'current');
- test_utils.openAndEnterChatRoom(_converse, 'lounge', 'localhost', 'dummy').then(function () {
+
+ test_utils.waitUntilFeatureSupportConfirmed(_converse, 'vcard-temp')
+ .then(function () {
+ return test_utils.waitUntil(function () {
+ return _converse.xmppstatus.get('fullname');
+ }, 300);
+ }).then(function () {
+ test_utils.createContacts(_converse, 'current');
+ return test_utils.openAndEnterChatRoom(_converse, 'lounge', 'localhost', 'dummy');
+ }).then(function () {
var view = _converse.chatboxviews.get('lounge@localhost');
if (!view.$el.find('.chat-area').length) { view.renderChatArea(); }
var message = '/me is tired';
diff --git a/spec/protocol.js b/spec/protocol.js
index a68a70ba7..fd3214e6e 100644
--- a/spec/protocol.js
+++ b/spec/protocol.js
@@ -54,178 +54,185 @@
{ roster_groups: false },
function (done, _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;
- test_utils.openControlBox(_converse);
- var panel = _converse.chatboxviews.get('controlbox').contactspanel;
- spyOn(panel, "addContactFromForm").and.callThrough();
- spyOn(_converse.roster, "addAndSubscribe").and.callThrough();
- spyOn(_converse.roster, "addContact").and.callThrough();
- spyOn(_converse.roster, "sendContactAddIQ").and.callThrough();
- spyOn(_converse.api.vcard, "get").and.callThrough();
- var sendIQ = _converse.connection.sendIQ;
- spyOn(_converse.connection, 'sendIQ').and.callFake(function (iq, callback, errback) {
- sent_stanza = iq;
- IQ_id = sendIQ.bind(this)(iq, callback, errback);
- });
- panel.delegateEvents(); // Rebind all events so that our spy gets called
+ var contact, sent_stanza, IQ_id, stanza;
+ test_utils.waitUntilFeatureSupportConfirmed(_converse, 'vcard-temp')
+ .then(function () {
+ return test_utils.waitUntil(function () {
+ return _converse.xmppstatus.get('fullname');
+ }, 300);
+ }).then(function () {
+ /* The process by which a user subscribes to a contact, including
+ * the interaction between roster items and subscription states.
+ */
+ test_utils.openControlBox(_converse);
+ var panel = _converse.chatboxviews.get('controlbox').contactspanel;
+ spyOn(panel, "addContactFromForm").and.callThrough();
+ spyOn(_converse.roster, "addAndSubscribe").and.callThrough();
+ spyOn(_converse.roster, "addContact").and.callThrough();
+ spyOn(_converse.roster, "sendContactAddIQ").and.callThrough();
+ spyOn(_converse.api.vcard, "get").and.callThrough();
- /* Add a new contact through the UI */
- var form = panel.el.querySelector('form.add-xmpp-contact');
- expect(_.isNull(form)).toBeTruthy();
+ var sendIQ = _converse.connection.sendIQ;
+ spyOn(_converse.connection, 'sendIQ').and.callFake(function (iq, callback, errback) {
+ sent_stanza = iq;
+ IQ_id = sendIQ.bind(this)(iq, callback, errback);
+ });
+ panel.delegateEvents(); // Rebind all events so that our spy gets called
- // Click the "Add a contact" link.
- panel.$('.toggle-xmpp-contact-form').click();
+ /* Add a new contact through the UI */
+ var form = panel.el.querySelector('form.add-xmpp-contact');
+ expect(_.isNull(form)).toBeTruthy();
- // Check that the form appears
- form = panel.el.querySelector('form.add-xmpp-contact');
- expect(form.parentElement.offsetHeight).not.toBe(0);
- expect(_.includes(form.parentElement.classList, 'collapsed')).toBeFalsy();
+ // Click the "Add a contact" link.
+ panel.$('.toggle-xmpp-contact-form').click();
- // Fill in the form and submit
- $(form).find('input').val('contact@example.org');
- $(form).submit();
+ // Check that the form appears
+ form = panel.el.querySelector('form.add-xmpp-contact');
+ expect(form.parentElement.offsetHeight).not.toBe(0);
+ expect(_.includes(form.parentElement.classList, 'collapsed')).toBeFalsy();
- /* In preparation for being able to render the contact in the
- * user's client interface and for the server to keep track of the
- * subscription, the user's client SHOULD perform a "roster set"
- * for the new roster item.
- */
- expect(panel.addContactFromForm).toHaveBeenCalled();
- expect(_converse.roster.addAndSubscribe).toHaveBeenCalled();
- expect(_converse.roster.addContact).toHaveBeenCalled();
+ // Fill in the form and submit
+ $(form).find('input').val('contact@example.org');
+ $(form).submit();
- // The form should not be visible anymore (by virtue of its
- // parent being collapsed)
- expect(form.parentElement.offsetHeight).toBe(0);
- expect(_.includes(form.parentElement.classList, 'collapsed')).toBeTrue;
+ /* In preparation for being able to render the contact in the
+ * user's client interface and for the server to keep track of the
+ * subscription, the user's client SHOULD perform a "roster set"
+ * for the new roster item.
+ */
+ expect(panel.addContactFromForm).toHaveBeenCalled();
+ expect(_converse.roster.addAndSubscribe).toHaveBeenCalled();
+ expect(_converse.roster.addContact).toHaveBeenCalled();
- /* _converse request consists of sending an IQ
- * stanza of type='set' containing a element qualified by
- * the 'jabber:iq:roster' namespace, which in turn contains an
- * element that defines the new roster item; the
- * element MUST possess a 'jid' attribute, MAY possess a 'name'
- * attribute, MUST NOT possess a 'subscription' attribute, and MAY
- * contain one or more child elements:
- *
- *
- *
- * -
- * MyBuddies
- *
- *
- *
- */
- expect(_converse.roster.sendContactAddIQ).toHaveBeenCalled();
- expect(sent_stanza.toLocaleString()).toBe(
- ""+
- ""+
- " "+
- ""+
- ""
- );
- /* As a result, the user's server (1) MUST initiate a roster push
- * for the new roster item to all available resources associated
- * 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:
- *
- *
- *
- * -
- * MyBuddies
- *
- *
- *
- */
- var create = _converse.roster.create;
- var sent_stanzas = [];
- spyOn(_converse.connection, 'send').and.callFake(function (stanza) {
- sent_stanza = stanza;
- sent_stanzas.push(stanza.toLocaleString());
- });
- spyOn(_converse.roster, 'create').and.callFake(function () {
- contact = create.apply(_converse.roster, arguments);
- spyOn(contact, 'subscribe').and.callThrough();
- return contact;
- });
- stanza = $iq({'type': 'set'}).c('query', {'xmlns': 'jabber:iq:roster'})
- .c('item', {
- 'jid': 'contact@example.org',
- 'subscription': 'none',
- 'name': 'contact@example.org'});
- _converse.connection._dataRecv(test_utils.createRequest(stanza));
- /*
- *
- */
- stanza = $iq({'type': 'result', 'id':IQ_id});
- _converse.connection._dataRecv(test_utils.createRequest(stanza));
+ // The form should not be visible anymore (by virtue of its
+ // parent being collapsed)
+ expect(form.parentElement.offsetHeight).toBe(0);
+ expect(_.includes(form.parentElement.classList, 'collapsed')).toBeTrue;
- // A contact should now have been created
- expect(_converse.roster.get('contact@example.org') instanceof _converse.RosterContact).toBeTruthy();
- expect(contact.get('jid')).toBe('contact@example.org');
- expect(_converse.api.vcard.get).toHaveBeenCalled();
+ /* _converse request consists of sending an IQ
+ * stanza of type='set' containing a element qualified by
+ * the 'jabber:iq:roster' namespace, which in turn contains an
+ * element that defines the new roster item; the
+ * element MUST possess a 'jid' attribute, MAY possess a 'name'
+ * attribute, MUST NOT possess a 'subscription' attribute, and MAY
+ * contain one or more child elements:
+ *
+ *
+ *
+ * -
+ * MyBuddies
+ *
+ *
+ *
+ */
+ expect(_converse.roster.sendContactAddIQ).toHaveBeenCalled();
+ expect(sent_stanza.toLocaleString()).toBe(
+ ""+
+ ""+
+ " "+
+ ""+
+ ""
+ );
+ /* As a result, the user's server (1) MUST initiate a roster push
+ * for the new roster item to all available resources associated
+ * 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:
+ *
+ *
+ *
+ * -
+ * MyBuddies
+ *
+ *
+ *
+ */
+ var create = _converse.roster.create;
+ var sent_stanzas = [];
+ spyOn(_converse.connection, 'send').and.callFake(function (stanza) {
+ sent_stanza = stanza;
+ sent_stanzas.push(stanza.toLocaleString());
+ });
+ spyOn(_converse.roster, 'create').and.callFake(function () {
+ contact = create.apply(_converse.roster, arguments);
+ spyOn(contact, 'subscribe').and.callThrough();
+ return contact;
+ });
+ stanza = $iq({'type': 'set'}).c('query', {'xmlns': 'jabber:iq:roster'})
+ .c('item', {
+ 'jid': 'contact@example.org',
+ 'subscription': 'none',
+ 'name': 'contact@example.org'});
+ _converse.connection._dataRecv(test_utils.createRequest(stanza));
+ /*
+ *
+ */
+ stanza = $iq({'type': 'result', 'id':IQ_id});
+ _converse.connection._dataRecv(test_utils.createRequest(stanza));
- /* To subscribe to the contact's presence information,
- * the user's client MUST send a presence stanza of
- * type='subscribe' to the contact:
- *
- *
- */
-
- test_utils.waitUntil(function () {
- return sent_stanzas.length == 1;
- }, 300).then(function () {
-
- expect(contact.subscribe).toHaveBeenCalled();
- expect(sent_stanza.toLocaleString()).toBe( // Strophe adds the xmlns attr (although not in spec)
- ""+
- "Max Mustermann"+
- ""
- );
- /* 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; _converse pending
- * sub-state is denoted by the inclusion of the ask='subscribe'
- * attribute in the roster item:
- *
- *
- *
- * -
- * MyBuddies
- *
- *
- *
- */
- spyOn(_converse.roster, "updateContact").and.callThrough();
- stanza = $iq({'type': 'set', 'from': 'dummy@localhost'})
- .c('query', {'xmlns': 'jabber:iq:roster'})
- .c('item', {
- 'jid': 'contact@example.org',
- 'subscription': 'none',
- 'ask': 'subscribe',
- 'name': 'contact@example.org'});
- _converse.connection._dataRecv(test_utils.createRequest(stanza));
- expect(_converse.roster.updateContact).toHaveBeenCalled();
- // Check that the user is now properly shown as a pending
- // contact in the roster.
- test_utils.waitUntil(function () {
- return $('a:contains("Pending contacts")').length;
- }, 300).then(function () {
+ // A contact should now have been created
+ expect(_converse.roster.get('contact@example.org') instanceof _converse.RosterContact).toBeTruthy();
+ expect(contact.get('jid')).toBe('contact@example.org');
+ expect(_converse.api.vcard.get).toHaveBeenCalled();
+ /* To subscribe to the contact's presence information,
+ * the user's client MUST send a presence stanza of
+ * type='subscribe' to the contact:
+ *
+ *
+ */
+ return test_utils.waitUntil(function () {
+ return sent_stanzas.length == 1;
+ }, 300);
+ }).then(function () {
+ expect(contact.subscribe).toHaveBeenCalled();
+ expect(sent_stanza.toLocaleString()).toBe( // Strophe adds the xmlns attr (although not in spec)
+ ""+
+ "Max Mustermann"+
+ ""
+ );
+ /* 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; _converse pending
+ * sub-state is denoted by the inclusion of the ask='subscribe'
+ * attribute in the roster item:
+ *
+ *
+ *
+ * -
+ * MyBuddies
+ *
+ *
+ *
+ */
+ spyOn(_converse.roster, "updateContact").and.callThrough();
+ stanza = $iq({'type': 'set', 'from': 'dummy@localhost'})
+ .c('query', {'xmlns': 'jabber:iq:roster'})
+ .c('item', {
+ 'jid': 'contact@example.org',
+ 'subscription': 'none',
+ 'ask': 'subscribe',
+ 'name': 'contact@example.org'});
+ _converse.connection._dataRecv(test_utils.createRequest(stanza));
+ expect(_converse.roster.updateContact).toHaveBeenCalled();
+ // Check that the user is now properly shown as a pending
+ // contact in the roster.
+
+ return test_utils.waitUntil(function () {
+ return $('a:contains("Pending contacts")').length;
+ }, 300);
+ }).then(function () {
var $header = $('a:contains("Pending contacts")');
expect($header.length).toBe(1);
expect($header.is(":visible")).toBeTruthy();
@@ -234,13 +241,13 @@
spyOn(contact, "ackSubscribe").and.callThrough();
/* Here we assume the "happy path" that the contact
- * approves the subscription request
- *
- *
- */
+ * approves the subscription request
+ *
+ *
+ */
stanza = $pres({
'to': _converse.bare_jid,
'from': 'contact@example.org',
@@ -249,31 +256,31 @@
sent_stanza = ""; // Reset
_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)
""
);
/* 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";
- *
- *
- *
- * -
- * MyBuddies
- *
- *
- *
- */
+ * 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";
+ *
+ *
+ *
+ * -
+ * MyBuddies
+ *
+ *
+ *
+ */
IQ_id = _converse.connection.getUniqueId('roster');
stanza = $iq({'type': 'set', 'id': IQ_id})
.c('query', {'xmlns': 'jabber:iq:roster'})
@@ -303,22 +310,22 @@
expect(contact.get('chat_status')).toBe('offline');
/*
- */
+ * from='contact@example.org/resource'
+ * to='user@example.com/resource'/>
+ */
stanza = $pres({'to': _converse.bare_jid, 'from': 'contact@example.org/resource'});
_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.
- *
- *
- */
+ *
+ * If the contact wants to create a mutual subscription,
+ * the contact MUST send a subscription request to the
+ * user.
+ *
+ *
+ */
spyOn(contact, 'authorize').and.callThrough();
spyOn(_converse.roster, 'handleIncomingSubscription').and.callThrough();
stanza = $pres({
@@ -329,32 +336,32 @@
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.
- *
- *
- */
+ * "subscribed" to the contact in order to approve the
+ * subscription request.
+ *
+ *
+ */
expect(contact.authorize).toHaveBeenCalled();
expect(sent_stanza.toLocaleString()).toBe(
""
);
/* 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".
- *
- *
- *
- * -
- * MyBuddies
- *
- *
- *
- */
+ * roster push containing a roster item for the
+ * contact with the 'subscription' attribute set to
+ * a value of "both".
+ *
+ *
+ *
+ * -
+ * MyBuddies
+ *
+ *
+ *
+ */
stanza = $iq({'type': 'set'}).c('query', {'xmlns': 'jabber:iq:roster'})
.c('item', {
'jid': 'contact@example.org',
@@ -368,7 +375,6 @@
expect($contacts.hasClass('both')).toBeTruthy();
done();
});
- });
}));
it("Alternate Flow: Contact Declines Subscription Request",
@@ -377,8 +383,8 @@
function (done, _converse) {
/* 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;
test_utils.openControlBox(_converse);
// Add a new roster contact via roster push
@@ -401,32 +407,32 @@
sent_IQ = iq;
});
/* We now assume the contact declines the subscription
- * 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:
- *
- *
- *
- *
- *
- * -
- * MyBuddies
- *
- *
- *
- */
+ * 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:
+ *
+ *
+ *
+ *
+ *
+ * -
+ * MyBuddies
+ *
+ *
+ *
+ */
// FIXME: also add the
stanza = $pres({
'to': _converse.bare_jid,
@@ -436,18 +442,18 @@
_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(
""
);
/* _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(
""+
""+
@@ -486,24 +492,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":
- *
- *
- *
- *
- *
- *
- */
+ * 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":
+ *
+ *
+ *
+ *
+ *
+ *
+ */
expect(sent_IQ.toLocaleString()).toBe(
""+
""+
diff --git a/tests/utils.js b/tests/utils.js
index 3624e2f22..46835dbd2 100644
--- a/tests/utils.js
+++ b/tests/utils.js
@@ -11,7 +11,27 @@
if (typeof window.Promise === 'undefined') {
waitUntilPromise.setPromiseImplementation(Promise);
}
- utils.waitUntil = waitUntilPromise['default'];
+ utils.waitUntil = waitUntilPromise.default;
+
+ utils.waitUntilFeatureSupportConfirmed = function (_converse, feature_name) {
+ var IQ_disco, stanza;
+ return utils.waitUntil(function () {
+ IQ_disco = _.filter(_converse.connection.IQ_stanzas, function (iq) {
+ return iq.nodeTree.querySelector('query[xmlns="http://jabber.org/protocol/disco#info"]');
+ }).pop();
+ return !_.isUndefined(IQ_disco);
+ }, 300).then(function () {
+ var info_IQ_id = IQ_disco.nodeTree.getAttribute('id');
+ stanza = $iq({
+ 'type': 'result',
+ 'from': 'localhost',
+ 'to': 'dummy@localhost/resource',
+ 'id': info_IQ_id
+ }).c('query', {'xmlns': 'http://jabber.org/protocol/disco#info'})
+ .c('feature', {'var': feature_name});
+ _converse.connection._dataRecv(utils.createRequest(stanza));
+ });
+ }
utils.createRequest = function (iq) {
iq = typeof iq.tree == "function" ? iq.tree() : iq;