(function (root, factory) {
define(["jquery", "jasmine", "mock", "test-utils" ], factory);
} (this, function ($, jasmine, mock, test_utils) {
var _ = converse.env._;
var $pres = converse.env.$pres;
var $iq = converse.env.$iq;
var $msg = converse.env.$msg;
var Strophe = converse.env.Strophe;
var Promise = converse.env.Promise;
var moment = converse.env.moment;
var sizzle = converse.env.sizzle;
var u = converse.env.utils;
return describe("ChatRooms", function () {
describe("The \"rooms\" API", function () {
it("has a method 'close' which closes rooms by JID or all rooms when called with no arguments",
mock.initConverseWithPromises(
null, ['rosterGroupsFetched'], {},
function (done, _converse) {
test_utils.openAndEnterChatRoom(_converse, 'lounge', 'localhost', 'dummy')
.then(() => test_utils.openAndEnterChatRoom(_converse, 'leisure', 'localhost', 'dummy'))
.then(() => test_utils.openAndEnterChatRoom(_converse, 'news', 'localhost', 'dummy'))
.then(() => {
expect(u.isVisible(_converse.chatboxviews.get('lounge@localhost').el)).toBeTruthy();
expect(u.isVisible(_converse.chatboxviews.get('leisure@localhost').el)).toBeTruthy();
expect(u.isVisible(_converse.chatboxviews.get('news@localhost').el)).toBeTruthy();
// XXX: bit of a cheat here. We want `cleanup()` to be
// called on the room. Either it's this or faking
// `sendPresence`.
_converse.connection.connected = false;
_converse.api.rooms.close('lounge@localhost');
expect(_converse.chatboxviews.get('lounge@localhost')).toBeUndefined();
expect(u.isVisible(_converse.chatboxviews.get('leisure@localhost').el)).toBeTruthy();
expect(u.isVisible(_converse.chatboxviews.get('news@localhost').el)).toBeTruthy();
_converse.api.rooms.close(['leisure@localhost', 'news@localhost']);
expect(_converse.chatboxviews.get('lounge@localhost')).toBeUndefined();
expect(_converse.chatboxviews.get('leisure@localhost')).toBeUndefined();
expect(_converse.chatboxviews.get('news@localhost')).toBeUndefined();
return test_utils.openAndEnterChatRoom(_converse, 'lounge', 'localhost', 'dummy');
})
.then(() => test_utils.openAndEnterChatRoom(_converse, 'leisure', 'localhost', 'dummy'))
.then(() => {
expect(u.isVisible(_converse.chatboxviews.get('lounge@localhost').el)).toBeTruthy();
expect(u.isVisible(_converse.chatboxviews.get('leisure@localhost').el)).toBeTruthy();
_converse.api.rooms.close();
expect(_converse.chatboxviews.get('lounge@localhost')).toBeUndefined();
expect(_converse.chatboxviews.get('leisure@localhost')).toBeUndefined();
done();
}).catch(_.partial(console.error, _));
}));
it("has a method 'get' which returns a wrapped groupchat (if it exists)",
mock.initConverseWithPromises(
null, ['rosterGroupsFetched'], {},
function (done, _converse) {
test_utils.createContacts(_converse, 'current');
test_utils.waitUntil(function () {
return $(_converse.rosterview.el).find('.roster-group .group-toggle').length;
}, 300).then(function () {
test_utils.openAndEnterChatRoom(_converse, 'lounge', 'localhost', 'dummy').then(function () {
var jid = 'lounge@localhost';
var room = _converse.api.rooms.get(jid);
expect(room instanceof Object).toBeTruthy();
var chatroomview = _converse.chatboxviews.get(jid);
expect(chatroomview.is_chatroom).toBeTruthy();
expect(u.isVisible(chatroomview.el)).toBeTruthy();
chatroomview.close();
// Test with mixed case
test_utils.openAndEnterChatRoom(_converse, 'Leisure', 'localhost', 'dummy').then(function () {
jid = 'Leisure@localhost';
room = _converse.api.rooms.get(jid);
expect(room instanceof Object).toBeTruthy();
chatroomview = _converse.chatboxviews.get(jid.toLowerCase());
expect(u.isVisible(chatroomview.el)).toBeTruthy();
jid = 'leisure@localhost';
room = _converse.api.rooms.get(jid);
expect(room instanceof Object).toBeTruthy();
chatroomview = _converse.chatboxviews.get(jid.toLowerCase());
expect(u.isVisible(chatroomview.el)).toBeTruthy();
jid = 'leiSure@localhost';
room = _converse.api.rooms.get(jid);
expect(room instanceof Object).toBeTruthy();
chatroomview = _converse.chatboxviews.get(jid.toLowerCase());
expect(u.isVisible(chatroomview.el)).toBeTruthy();
chatroomview.close();
// Non-existing room
jid = 'lounge2@localhost';
room = _converse.api.rooms.get(jid);
expect(typeof room === 'undefined').toBeTruthy();
done();
});
});
});
}));
it("has a method 'open' which opens (optionally configures) and returns a wrapped chat box",
mock.initConverseWithPromises(
null, ['rosterGroupsFetched'], {},
function (done, _converse) {
// Mock 'getRoomFeatures', otherwise the room won't be
// displayed as it waits first for the features to be returned
// (when it's a new room being created).
spyOn(_converse.ChatRoom.prototype, 'getRoomFeatures').and.callFake(function () {
var deferred = new $.Deferred();
deferred.resolve();
return deferred.promise();
});
test_utils.openControlBox();
test_utils.createContacts(_converse, 'current');
test_utils.waitUntil(function () {
return $(_converse.rosterview.el).find('.roster-group .group-toggle').length;
}, 300).then(function () {
var jid = 'lounge@localhost';
var room = _converse.api.rooms.open(jid);
// Test on groupchat that's not yet open
expect(room instanceof Object).toBeTruthy();
var chatroomview = _converse.chatboxviews.get(jid);
expect(chatroomview.is_chatroom).toBeTruthy();
expect(u.isVisible(chatroomview.el)).toBeTruthy();
// Test again, now that the room exists.
room = _converse.api.rooms.open(jid);
expect(room instanceof Object).toBeTruthy();
chatroomview = _converse.chatboxviews.get(jid);
expect(chatroomview.is_chatroom).toBeTruthy();
expect(u.isVisible(chatroomview.el)).toBeTruthy();
chatroomview.close();
// Test with mixed case in JID
jid = 'Leisure@localhost';
room = _converse.api.rooms.open(jid);
expect(room instanceof Object).toBeTruthy();
chatroomview = _converse.chatboxviews.get(jid.toLowerCase());
expect(u.isVisible(chatroomview.el)).toBeTruthy();
jid = 'leisure@localhost';
room = _converse.api.rooms.open(jid);
expect(room instanceof Object).toBeTruthy();
chatroomview = _converse.chatboxviews.get(jid.toLowerCase());
expect(u.isVisible(chatroomview.el)).toBeTruthy();
jid = 'leiSure@localhost';
room = _converse.api.rooms.open(jid);
expect(room instanceof Object).toBeTruthy();
chatroomview = _converse.chatboxviews.get(jid.toLowerCase());
expect(u.isVisible(chatroomview.el)).toBeTruthy();
chatroomview.close();
_converse.muc_instant_rooms = false;
var sent_IQ, IQ_id, sent_IQ_els = [];
var sendIQ = _converse.connection.sendIQ;
spyOn(_converse.connection, 'sendIQ').and.callFake(function (iq, callback, errback) {
sent_IQ = iq;
sent_IQ_els.push(iq.nodeTree);
IQ_id = sendIQ.bind(this)(iq, callback, errback);
});
// Test with configuration
_converse.api.rooms.open('room@conference.example.org', {
'nick': 'some1',
'auto_configure': true,
'roomconfig': {
'changesubject': false,
'membersonly': true,
'persistentroom': true,
'publicroom': true,
'roomdesc': 'Welcome to this groupchat',
'whois': 'anyone'
}
});
chatroomview = _converse.chatboxviews.get('room@conference.example.org');
// We pretend this is a new room, so no disco info is returned.
var features_stanza = $iq({
from: 'room@conference.example.org',
'id': IQ_id,
'to': 'dummy@localhost/desktop',
'type': 'error'
}).c('error', {'type': 'cancel'})
.c('item-not-found', {'xmlns': "urn:ietf:params:xml:ns:xmpp-stanzas"});
_converse.connection._dataRecv(test_utils.createRequest(features_stanza));
/*
*
*
*
*
*
*
*/
var presence = $pres({
from:'room@conference.example.org/some1',
to:'dummy@localhost/pda'
})
.c('x', {xmlns:'http://jabber.org/protocol/muc#user'})
.c('item', {
affiliation: 'owner',
jid: 'dummy@localhost/pda',
role: 'moderator'
}).up()
.c('status', {code:'110'}).up()
.c('status', {code:'201'});
_converse.connection._dataRecv(test_utils.createRequest(presence));
expect(_converse.connection.sendIQ).toHaveBeenCalled();
expect(sent_IQ.toLocaleString()).toBe(
""
);
var node = Strophe.xmlHtmlNode(
''+
' '+
' '+
' Configuration for room@conference.example.org'+
' Complete and submit this form to configure the room.'+
' '+
' http://jabber.org/protocol/muc#roomconfig'+
' '+
' '+
' Room'+
' '+
' '+
' '+
' 1'+
' '+
' '+
' '+
' '+
' '+
' '+
' '+
' 20'+
' '+
' '+
' ');
spyOn(chatroomview.model, 'sendConfiguration').and.callThrough();
_converse.connection._dataRecv(test_utils.createRequest(node.firstElementChild));
return test_utils.waitUntil(function () {
return chatroomview.model.sendConfiguration.calls.count() === 1;
}, 300).then(function () {
var sent_stanza = sent_IQ_els.pop();
while (sent_stanza.getAttribute('type') !== 'set') {
sent_stanza = sent_IQ_els.pop();
}
expect(sizzle('field[var="muc#roomconfig_roomname"] value', sent_stanza).pop().textContent).toBe('Room');
expect(sizzle('field[var="muc#roomconfig_roomdesc"] value', sent_stanza).pop().textContent).toBe('Welcome to this groupchat');
expect(sizzle('field[var="muc#roomconfig_persistentroom"] value', sent_stanza).pop().textContent).toBe('1');
expect(sizzle('field[var="muc#roomconfig_publicroom"] value ', sent_stanza).pop().textContent).toBe('1');
expect(sizzle('field[var="muc#roomconfig_changesubject"] value', sent_stanza).pop().textContent).toBe('0');
expect(sizzle('field[var="muc#roomconfig_whois"] value ', sent_stanza).pop().textContent).toBe('anyone');
expect(sizzle('field[var="muc#roomconfig_membersonly"] value', sent_stanza).pop().textContent).toBe('1');
expect(sizzle('field[var="muc#roomconfig_historylength"] value', sent_stanza).pop().textContent).toBe('20');
done();
});
});
}));
});
describe("An instant groupchat", function () {
it("will be created when muc_instant_rooms is set to true",
mock.initConverseWithPromises(
null, ['rosterGroupsFetched'], {},
function (done, _converse) {
var IQ_stanzas = _converse.connection.IQ_stanzas;
var sent_IQ, IQ_id;
var sendIQ = _converse.connection.sendIQ;
spyOn(_converse.connection, 'sendIQ').and.callFake(function (iq, callback, errback) {
if (iq.nodeTree.getAttribute('to') === 'lounge@localhost') {
sent_IQ = iq;
IQ_id = sendIQ.bind(this)(iq, callback, errback);
} else {
sendIQ.bind(this)(iq, callback, errback);
}
});
test_utils.openChatRoom(_converse, 'lounge', 'localhost', 'dummy');
// We pretend this is a new room, so no disco info is returned.
//
/*
*
*
*
*
*
*
*
*/
var features_stanza = $iq({
'from': 'lounge@localhost',
'id': IQ_id,
'to': 'dummy@localhost/desktop',
'type': 'error'
}).c('error', {'type': 'cancel'})
.c('item-not-found', {'xmlns': "urn:ietf:params:xml:ns:xmpp-stanzas"});
_converse.connection._dataRecv(test_utils.createRequest(features_stanza));
var view = _converse.chatboxviews.get('lounge@localhost');
spyOn(view, 'join').and.callThrough();
spyOn(view, 'submitNickname').and.callThrough();
/*
*
*
*/
test_utils.waitUntil(function () {
return _.filter(IQ_stanzas, function (iq) {
return iq.nodeTree.querySelector('query[node="x-roomuser-item"]');
}).length > 0;
}, 300).then(function () {
const iq = _.filter(IQ_stanzas, function (iq) {
return iq.nodeTree.querySelector(`query[node="x-roomuser-item"]`);
}).pop();
const id = iq.nodeTree.getAttribute('id');
expect(iq.toLocaleString()).toBe(
""+
"");
/*
*
*
*
*
*/
var stanza = $iq({
'type': 'error',
'id': id,
'from': view.model.get('jid'),
'to': _converse.connection.jid
}).c('error', {'type': 'cancel'})
.c('item-not-found', {'xmlns': "urn:ietf:params:xml:ns:xmpp-stanzas"});
_converse.connection._dataRecv(test_utils.createRequest(stanza));
var input = view.el.querySelector('input[name="nick"]');
input.value = 'nicky';
view.el.querySelector('input[type=submit]').click();
expect(view.submitNickname).toHaveBeenCalled();
expect(view.join).toHaveBeenCalled();
// The user has just entered the room (because join was called)
// and receives their own presence from the server.
// See example 24:
// http://xmpp.org/extensions/xep-0045.html#enter-pres
//
/*
*
*
*
*
*
*
*/
var presence = $pres({
to:'dummy@localhost/resource',
from:'lounge@localhost/thirdwitch',
id:'5025e055-036c-4bc5-a227-706e7e352053'
}).c('x').attrs({xmlns:'http://jabber.org/protocol/muc#user'})
.c('item').attrs({
affiliation: 'owner',
jid: 'dummy@localhost/resource',
role: 'moderator'
}).up()
.c('status').attrs({code:'110'}).up()
.c('status').attrs({code:'201'}).nodeTree;
_converse.connection._dataRecv(test_utils.createRequest(presence));
var info_text = view.el.querySelector('.chat-content .chat-info').textContent;
expect(info_text).toBe('A new groupchat has been created');
// An instant room is created by saving the default configuratoin.
//
/*
*
*
*/
expect(sent_IQ.toLocaleString()).toBe(
""+
""+
"");
done();
});
}));
});
describe("A Groupchat", function () {
it("shows join/leave messages when users enter or exit a groupchat",
mock.initConverseWithPromises(
null, ['rosterGroupsFetched'], {},
function (done, _converse) {
test_utils.openChatRoom(_converse, "coven", 'chat.shakespeare.lit', 'some1');
var view = _converse.chatboxviews.get('coven@chat.shakespeare.lit');
var $chat_content = $(view.el).find('.chat-content');
/* We don't show join/leave messages for existing occupants. We
* know about them because we receive their presences before we
* receive our own.
*/
var presence = $pres({
to: 'dummy@localhost/_converse.js-29092160',
from: 'coven@chat.shakespeare.lit/oldguy'
}).c('x', {xmlns: Strophe.NS.MUC_USER})
.c('item', {
'affiliation': 'none',
'jid': 'oldguy@localhost/_converse.js-290929789',
'role': 'participant'
});
_converse.connection._dataRecv(test_utils.createRequest(presence));
expect($chat_content[0].querySelectorAll('div.chat-info').length).toBe(0);
/*
*
*
*
*
*