Commit 506aa331 authored by JC Brand's avatar JC Brand

Wait for promises before opening chats in API methods

parent cb118b9c
......@@ -39,6 +39,9 @@
- New API method `_converse.api.vcard.update`.
- The `contactStatusChanged` event has been renamed to `contactPresenceChanged`
and a event `presenceChanged` is now also triggered on the contact.
- `_converse.api.chats.open` and `_converse.api.rooms.open` now returns a
`Presence` which resolves with the `Backbone.Model` representing the chat
object.
## UI changes
......
......@@ -76149,17 +76149,7 @@ var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_
this.model.on('show', this.show, this);
this.model.occupants.on('add', this.showJoinNotification, this);
this.model.occupants.on('remove', this.showLeaveNotification, this);
this.model.occupants.on('change:show', occupant => {
if (!occupant.isMember() || _.includes(occupant.get('states'), '303')) {
return;
}
if (occupant.get('show') === 'offline') {
this.showLeaveNotification(occupant);
} else if (occupant.get('show') === 'online') {
this.showJoinNotification(occupant);
}
});
this.model.occupants.on('change:show', this.showJoinOrLeaveNotification, this);
this.createEmojiPicker();
this.createOccupantsView();
this.render().insertIntoDOM();
......@@ -76169,8 +76159,7 @@ var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_
const handler = () => {
if (!u.isPersistableModel(this.model)) {
// Happens during tests, nothing to do if this
// is a hanging chatbox (i.e. not in the
// collection anymore).
// is a hanging chatbox (i.e. not in the collection anymore).
return;
}
......@@ -77047,6 +77036,18 @@ var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_
}
},
showJoinOrLeaveNotification(occupant) {
if (!occupant.isMember() || _.includes(occupant.get('states'), '303')) {
return;
}
if (occupant.get('show') === 'offline') {
this.showLeaveNotification(occupant);
} else if (occupant.get('show') === 'online') {
this.showJoinNotification(occupant);
}
},
showJoinNotification(occupant) {
if (this.model.get('connection_status') !== converse.ROOMSTATUS.ENTERED) {
return;
......@@ -77094,10 +77095,9 @@ var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_
showLeaveNotification(occupant) {
const nick = occupant.get('nick'),
stat = occupant.get('status'),
last_el = this.content.lastElementChild,
last_msg_date = last_el.getAttribute('data-isodate');
last_el = this.content.lastElementChild;
if (_.includes(_.get(last_el, 'classList', []), 'chat-info') && moment(last_msg_date).isSame(new Date(), "day") && _.get(last_el, 'dataset', {}).join === `"${nick}"`) {
if (last_el && _.includes(_.get(last_el, 'classList', []), 'chat-info') && moment(last_el.getAttribute('data-isodate')).isSame(new Date(), "day") && _.get(last_el, 'dataset', {}).join === `"${nick}"`) {
let message;
if (_.isNil(stat)) {
......@@ -77128,7 +77128,7 @@ var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_
'data': `data-leave="${nick}"`
};
if (_.includes(_.get(last_el, 'classList', []), 'chat-info') && _.get(last_el, 'dataset', {}).leavejoin === `"${nick}"`) {
if (last_el && _.includes(_.get(last_el, 'classList', []), 'chat-info') && _.get(last_el, 'dataset', {}).leavejoin === `"${nick}"`) {
last_el.outerHTML = tpl_info(data);
} else {
const el = u.stringToElement(tpl_info(data));
......@@ -83843,8 +83843,13 @@ var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_
xhr.onload = function () {
if (xhr.status >= 200 && xhr.status < 400) {
jed_instance = new Jed(window.JSON.parse(xhr.responseText));
resolve();
try {
const data = window.JSON.parse(xhr.responseText);
jed_instance = new Jed(data);
resolve();
} catch (e) {
xhr.onerror(e);
}
} else {
xhr.onerror();
}
......@@ -34,24 +34,24 @@
});
spyOn(_converse.connection, 'getUniqueId').and.callThrough();
test_utils.openChatRoom(_converse, 'theplay', 'conference.shakespeare.lit', 'JC');
var jid = 'theplay@conference.shakespeare.lit';
var view = _converse.chatboxviews.get(jid);
spyOn(view, 'renderBookmarkForm').and.callThrough();
spyOn(view, 'closeForm').and.callThrough();
test_utils.waitUntil(function () {
return !_.isNull(view.el.querySelector('.toggle-bookmark'));
}, 300).then(function () {
var $bookmark = $(view.el).find('.toggle-bookmark');
$bookmark[0].click();
let view;
test_utils.openChatRoom(_converse, 'theplay', 'conference.shakespeare.lit', 'JC')
.then(() => {
var jid = 'theplay@conference.shakespeare.lit';
view = _converse.chatboxviews.get(jid);
spyOn(view, 'renderBookmarkForm').and.callThrough();
spyOn(view, 'closeForm').and.callThrough();
return test_utils.waitUntil(() => !_.isNull(view.el.querySelector('.toggle-bookmark')));
}).then(() => {
var bookmark = view.el.querySelector('.toggle-bookmark');
bookmark.click();
expect(view.renderBookmarkForm).toHaveBeenCalled();
view.el.querySelector('.button-cancel').click();
expect(view.closeForm).toHaveBeenCalled();
expect($bookmark.hasClass('on-button'), false);
expect(u.hasClass('on-button', bookmark), false);
$bookmark[0].click();
bookmark.click();
expect(view.renderBookmarkForm).toHaveBeenCalled();
/* Client uploads data:
......@@ -93,7 +93,7 @@
view.el.querySelector('.btn-primary').click();
expect(view.model.get('bookmarked')).toBeTruthy();
expect($bookmark.hasClass('on-button'), true);
expect(u.hasClass('on-button', bookmark), true);
expect(sent_stanza.toLocaleString()).toBe(
"<iq type='set' from='dummy@localhost/resource' xmlns='jabber:client' id='"+IQ_id+"'>"+
......@@ -175,100 +175,96 @@
it("displays that it's bookmarked through its bookmark icon", mock.initConverseWithPromises(
null, ['rosterGroupsFetched'], {}, function (done, _converse) {
let view;
test_utils.waitUntilDiscoConfirmed(
_converse, _converse.bare_jid,
[{'category': 'pubsub', 'type': 'pep'}],
['http://jabber.org/protocol/pubsub#publish-options']
).then(function () {
test_utils.openChatRoom(_converse, 'lounge', 'localhost', 'dummy');
var view = _converse.chatboxviews.get('lounge@localhost');
test_utils.waitUntil(function () {
return !_.isNull(view.el.querySelector('.toggle-bookmark'));
}, 300).then(function () {
var bookmark_icon = view.el.querySelector('.toggle-bookmark');
expect(_.includes(bookmark_icon.classList, 'button-on')).toBeFalsy();
view.model.set('bookmarked', true);
expect(_.includes(bookmark_icon.classList, 'button-on')).toBeTruthy();
view.model.set('bookmarked', false);
expect(_.includes(bookmark_icon.classList, 'button-on')).toBeFalsy();
done();
});
).then(() => test_utils.openChatRoom(_converse, 'lounge', 'localhost', 'dummy'))
.then(() => {
view = _converse.chatboxviews.get('lounge@localhost');
return test_utils.waitUntil(() => !_.isNull(view.el.querySelector('.toggle-bookmark')))
}).then(function () {
var bookmark_icon = view.el.querySelector('.toggle-bookmark');
expect(_.includes(bookmark_icon.classList, 'button-on')).toBeFalsy();
view.model.set('bookmarked', true);
expect(_.includes(bookmark_icon.classList, 'button-on')).toBeTruthy();
view.model.set('bookmarked', false);
expect(_.includes(bookmark_icon.classList, 'button-on')).toBeFalsy();
done();
});
}));
it("can be unbookmarked", mock.initConverseWithPromises(
null, ['rosterGroupsFetched'], {}, function (done, _converse) {
let sent_stanza, IQ_id, view, sendIQ;
test_utils.waitUntilDiscoConfirmed(
_converse, _converse.bare_jid,
[{'category': 'pubsub', 'type': 'pep'}],
['http://jabber.org/protocol/pubsub#publish-options']
).then(function () {
var sent_stanza, IQ_id;
var sendIQ = _converse.connection.sendIQ;
test_utils.openChatRoom(_converse, 'theplay', 'conference.shakespeare.lit', 'JC');
).then(() => {
sendIQ = _converse.connection.sendIQ;
return test_utils.openChatRoom(_converse, 'theplay', 'conference.shakespeare.lit', 'JC');
}).then(() => {
var jid = 'theplay@conference.shakespeare.lit';
var view = _converse.chatboxviews.get(jid);
view = _converse.chatboxviews.get(jid);
return test_utils.waitUntil(() => !_.isNull(view.el.querySelector('.toggle-bookmark')));
}).then(function () {
spyOn(view, 'toggleBookmark').and.callThrough();
spyOn(_converse.bookmarks, 'sendBookmarkStanza').and.callThrough();
view.delegateEvents();
test_utils.waitUntil(function () {
return !_.isNull(view.el.querySelector('.toggle-bookmark'));
}, 300).then(function () {
spyOn(view, 'toggleBookmark').and.callThrough();
spyOn(_converse.bookmarks, 'sendBookmarkStanza').and.callThrough();
view.delegateEvents();
_converse.bookmarks.create({
'jid': view.model.get('jid'),
'autojoin': false,
'name': 'The Play',
'nick': ' Othello'
});
expect(_converse.bookmarks.length).toBe(1);
expect(view.model.get('bookmarked')).toBeTruthy();
var $bookmark_icon = $(view.el.querySelector('.toggle-bookmark'));
expect($bookmark_icon.hasClass('button-on')).toBeTruthy();
spyOn(_converse.connection, 'sendIQ').and.callFake(function (iq, callback, errback) {
sent_stanza = iq;
IQ_id = sendIQ.bind(this)(iq, callback, errback);
});
spyOn(_converse.connection, 'getUniqueId').and.callThrough();
$bookmark_icon[0].click();
expect(view.toggleBookmark).toHaveBeenCalled();
expect($bookmark_icon.hasClass('button-on')).toBeFalsy();
expect(_converse.bookmarks.length).toBe(0);
// Check that an IQ stanza is sent out, containing no
// conferences to bookmark (since we removed the one and
// only bookmark).
expect(sent_stanza.toLocaleString()).toBe(
"<iq type='set' from='dummy@localhost/resource' xmlns='jabber:client' id='"+IQ_id+"'>"+
"<pubsub xmlns='http://jabber.org/protocol/pubsub'>"+
"<publish node='storage:bookmarks'>"+
"<item id='current'>"+
"<storage xmlns='storage:bookmarks'/>"+
"</item>"+
"</publish>"+
"<publish-options>"+
"<x xmlns='jabber:x:data' type='submit'>"+
"<field var='FORM_TYPE' type='hidden'>"+
"<value>http://jabber.org/protocol/pubsub#publish-options</value>"+
"</field>"+
"<field var='pubsub#persist_items'>"+
"<value>true</value>"+
"</field>"+
"<field var='pubsub#access_model'>"+
"<value>whitelist</value>"+
"</field>"+
"</x>"+
"</publish-options>"+
"</pubsub>"+
"</iq>"
);
done();
_converse.bookmarks.create({
'jid': view.model.get('jid'),
'autojoin': false,
'name': 'The Play',
'nick': ' Othello'
});
expect(_converse.bookmarks.length).toBe(1);
expect(view.model.get('bookmarked')).toBeTruthy();
var bookmark_icon = view.el.querySelector('.toggle-bookmark');
expect(u.hasClass('button-on', bookmark_icon)).toBeTruthy();
spyOn(_converse.connection, 'sendIQ').and.callFake(function (iq, callback, errback) {
sent_stanza = iq;
IQ_id = sendIQ.bind(this)(iq, callback, errback);
});
spyOn(_converse.connection, 'getUniqueId').and.callThrough();
bookmark_icon.click();
expect(view.toggleBookmark).toHaveBeenCalled();
expect(u.hasClass('button-on', bookmark_icon)).toBeFalsy();
expect(_converse.bookmarks.length).toBe(0);
// Check that an IQ stanza is sent out, containing no
// conferences to bookmark (since we removed the one and
// only bookmark).
expect(sent_stanza.toLocaleString()).toBe(
"<iq type='set' from='dummy@localhost/resource' xmlns='jabber:client' id='"+IQ_id+"'>"+
"<pubsub xmlns='http://jabber.org/protocol/pubsub'>"+
"<publish node='storage:bookmarks'>"+
"<item id='current'>"+
"<storage xmlns='storage:bookmarks'/>"+
"</item>"+
"</publish>"+
"<publish-options>"+
"<x xmlns='jabber:x:data' type='submit'>"+
"<field var='FORM_TYPE' type='hidden'>"+
"<value>http://jabber.org/protocol/pubsub#publish-options</value>"+
"</field>"+
"<field var='pubsub#persist_items'>"+
"<value>true</value>"+
"</field>"+
"<field var='pubsub#access_model'>"+
"<value>whitelist</value>"+
"</field>"+
"</x>"+
"</publish-options>"+
"</pubsub>"+
"</iq>"
);
done();
});
}));
});
......@@ -585,9 +581,8 @@
'name': 'The Play',
'nick': ''
});
test_utils.waitUntil(function () {
return $('#chatrooms .bookmarks.rooms-list .room-item:visible').length;
}, 300).then(function () {
test_utils.waitUntil(() => $('#chatrooms .bookmarks.rooms-list .room-item:visible').length
).then(function () {
expect($('#chatrooms .bookmarks.rooms-list').hasClass('collapsed')).toBeFalsy();
expect($('#chatrooms .bookmarks.rooms-list .room-item:visible').length).toBe(1);
expect(_converse.bookmarksview.list_model.get('toggle-state')).toBe(_converse.OPENED);
......@@ -612,6 +607,7 @@
{ hide_open_bookmarks: true },
function (done, _converse) {
const jid = 'room@conference.example.org';
test_utils.waitUntilDiscoConfirmed(
_converse, _converse.bare_jid,
[{'category': 'pubsub', 'type': 'pep'}],
......@@ -625,14 +621,12 @@
_converse.emit('bookmarksInitialized');
// Check that it's there
var jid = 'room@conference.example.org';
_converse.bookmarks.create({
'jid': jid,
'autojoin': false,
'name': 'The Play',
'nick': ' Othello'
});
expect(_converse.bookmarks.length).toBe(1);
var room_els = _converse.bookmarksview.el.querySelectorAll(".open-room");
expect(room_els.length).toBe(1);
......@@ -640,9 +634,11 @@
// Check that it disappears once the room is opened
var bookmark = _converse.bookmarksview.el.querySelector(".open-room");
bookmark.click();
return test_utils.waitUntil(() => _converse.chatboxviews.get(jid));
}).then(() => {
expect(u.hasClass('hidden', _converse.bookmarksview.el.querySelector(".available-chatroom"))).toBeTruthy();
// Check that it reappears once the room is closed
var view = _converse.chatboxviews.get(jid);
const view = _converse.chatboxviews.get(jid);
view.close();
expect(u.hasClass('hidden', _converse.bookmarksview.el.querySelector(".available-chatroom"))).toBeFalsy();
done();
......
......@@ -7,11 +7,12 @@
], factory);
} (this, function ($, jasmine, mock, test_utils) {
"use strict";
var _ = converse.env._;
var $iq = converse.env.$iq;
var $msg = converse.env.$msg;
var Strophe = converse.env.Strophe;
var u = converse.env.utils;
const _ = converse.env._;
const $iq = converse.env.$iq;
const $msg = converse.env.$msg;
const Strophe = converse.env.Strophe;
const u = converse.env.utils;
const sizzle = converse.env.sizzle;
return describe("Chatboxes", function () {
......@@ -158,45 +159,50 @@
}));
it("can be trimmed to conserve space",
mock.initConverseWithPromises(
null, ['rosterGroupsFetched'], {},
function (done, _converse) {
mock.initConverseWithPromises(null, ['rosterGroupsFetched'], {}, function (done, _converse) {
spyOn(_converse.chatboxviews, 'trimChats');
const trimmed_chatboxes = _converse.minimized_chats;
spyOn(trimmed_chatboxes, 'addChat').and.callThrough();
spyOn(trimmed_chatboxes, 'removeChat').and.callThrough();
test_utils.createContacts(_converse, 'current');
_converse.emit('rosterContactsFetched');
test_utils.openControlBox();
var i, $el, jid, chatbox, chatboxview, trimmedview;
let online_contacts;
var i, jid, chatbox, chatboxview, trimmedview;
// openControlBox was called earlier, so the controlbox is
// visible, but no other chat boxes have been created.
var trimmed_chatboxes = _converse.minimized_chats;
expect(_converse.chatboxes.length).toEqual(1);
spyOn(_converse.chatboxviews, 'trimChats');
spyOn(trimmed_chatboxes, 'addChat').and.callThrough();
spyOn(trimmed_chatboxes, 'removeChat').and.callThrough();
expect($("#conversejs .chatbox").length).toBe(1); // Controlbox is open
expect(document.querySelectorAll("#conversejs .chatbox").length).toBe(1); // Controlbox is open
_converse.rosterview.update(); // XXX: Hack to make sure $roster element is attached.
test_utils.waitUntil(function () {
return $(_converse.rosterview.el).find('.roster-group li').length;
}, 700).then(function () {
test_utils.waitUntil(() => _converse.rosterview.el.querySelectorAll('.roster-group li').length)
.then(() => {
// Test that they can be maximized again
var online_contacts = $(_converse.rosterview.el).find('.roster-group .current-xmpp-contact a.open-chat');
online_contacts = _converse.rosterview.el.querySelectorAll('.roster-group .current-xmpp-contact a.open-chat');
expect(online_contacts.length).toBe(15);
for (i=0; i<online_contacts.length; i++) {
$el = $(online_contacts[i]);
jid = _.trim($el.text().trim()).replace(/ /g,'.').toLowerCase() + '@localhost';
$el[0].click();
expect(_converse.chatboxviews.trimChats).toHaveBeenCalled();
const el = online_contacts[i];
el.click();
}
return test_utils.waitUntil(() => _converse.chatboxes.length == 16)
}).then(() => {
expect(_converse.chatboxviews.trimChats.calls.count()).toBe(16);
for (i=0; i<online_contacts.length; i++) {
const el = online_contacts[i];
jid = _.trim(el.textContent.trim()).replace(/ /g,'.').toLowerCase() + '@localhost';
chatboxview = _converse.chatboxviews.get(jid);
spyOn(chatboxview, 'minimize').and.callThrough();
chatboxview.model.set({'minimized': true});
expect(trimmed_chatboxes.addChat).toHaveBeenCalled();
expect(chatboxview.minimize).toHaveBeenCalled();
}
return test_utils.waitUntil(function () {
return _converse.chatboxviews.keys().length > 1;
}, 500);
return test_utils.waitUntil(() => _converse.chatboxviews.keys().length);
}).then(function () {
var key = _converse.chatboxviews.keys()[1];
trimmedview = trimmed_chatboxes.get(key);
......@@ -208,10 +214,9 @@
expect(trimmedview.restore).toHaveBeenCalled();
expect(chatbox.maximize).toHaveBeenCalled();
expect(_converse.chatboxviews.trimChats).toHaveBeenCalled();
expect(_converse.chatboxviews.trimChats.calls.count()).toBe(17);
done();
});
done();
}));
it("can be opened in minimized mode initially",
......@@ -237,29 +242,26 @@
it("is focused if its already open and you click on its corresponding roster item",
mock.initConverseWithPromises(
null, ['rosterGroupsFetched'], {},
function (done, _converse) {
mock.initConverseWithPromises(null, ['rosterGroupsFetched', 'chatBoxesFetched'], {}, function (done, _converse) {
test_utils.createContacts(_converse, 'current');
_converse.rosterview.update(); // XXX: Hack to make sure $roster element is attaced.
_converse.emit('rosterContactsFetched');
test_utils.openControlBox();
var contact_jid = mock.cur_names[2].replace(/ /g,'.').toLowerCase() + '@localhost';
var $el, jid, chatbox;
const contact_jid = mock.cur_names[2].replace(/ /g,'.').toLowerCase() + '@localhost';
let el, jid;
// openControlBox was called earlier, so the controlbox is
// visible, but no other chat boxes have been created.
expect(_converse.chatboxes.length).toEqual(1);
chatbox = test_utils.openChatBoxFor(_converse, contact_jid);
$el = $(_converse.rosterview.el).find('a.open-chat:contains("'+chatbox.getDisplayName()+'")');
jid = $el.text().replace(/ /g,'.').toLowerCase() + '@localhost';
spyOn(_converse, 'emit');
$el[0].click();
test_utils.waitUntil(function () {
return _converse.emit.calls.count();
}, 300).then(function () {
test_utils.openChatBoxFor(_converse, contact_jid)
.then((view) => {
el = sizzle('a.open-chat:contains("'+view.model.getDisplayName()+'")', _converse.rosterview.el).pop();
jid = el.textContent.replace(/ /g,'.').toLowerCase() + '@localhost';
spyOn(_converse, 'emit');
el.click();
return test_utils.waitUntil(() => _converse.emit.calls.count(), 500);
}).then(() => {
expect(_converse.chatboxes.length).toEqual(2);
expect(_converse.emit).toHaveBeenCalledWith('chatBoxFocused', jasmine.any(Object));
done();
......@@ -268,10 +270,11 @@
it("can be saved to, and retrieved from, browserStorage",
mock.initConverseWithPromises(
null, ['rosterGroupsFetched'], {},
null, ['rosterGroupsFetched', 'chatBoxesFetched',], {},
function (done, _converse) {
test_utils.createContacts(_converse, 'current');
_converse.emit('rosterContactsFetched');
test_utils.openControlBox();
spyOn(_converse, 'emit');
......@@ -279,41 +282,46 @@
test_utils.openControlBox();
test_utils.openChatBoxes(_converse, 6);
expect(_converse.chatboxviews.trimChats).toHaveBeenCalled();
// We instantiate a new ChatBoxes collection, which by default
// will be empty.
var newchatboxes = new _converse.ChatBoxes();
expect(newchatboxes.length).toEqual(0);
// The chatboxes will then be fetched from browserStorage inside the
// onConnected method
newchatboxes.onConnected();
expect(newchatboxes.length).toEqual(7);
// Check that the chatboxes items retrieved from browserStorage
// have the same attributes values as the original ones.
var attrs = ['id', 'box_id', 'visible'];
var new_attrs, old_attrs;
for (var i=0; i<attrs.length; i++) {
new_attrs = _.map(_.map(newchatboxes.models, 'attributes'), attrs[i]);
old_attrs = _.map(_.map(_converse.chatboxes.models, 'attributes'), attrs[i]);
expect(_.isEqual(new_attrs, old_attrs)).toEqual(true);
}
_converse.rosterview.render();
done();
return test_utils.waitUntil(() => _converse.chatboxes.length == 7).then(() => {
expect(_converse.chatboxviews.trimChats).toHaveBeenCalled();
// We instantiate a new ChatBoxes collection, which by default
// will be empty.
const newchatboxes = new _converse.ChatBoxes();
expect(newchatboxes.length).toEqual(0);
// The chatboxes will then be fetched from browserStorage inside the
// onConnected method
newchatboxes.onConnected();
expect(newchatboxes.length).toEqual(7);
// Check that the chatboxes items retrieved from browserStorage
// have the same attributes values as the original ones.
const attrs = ['id', 'box_id', 'visible'];
let new_attrs, old_attrs;
for (var i=0; i<attrs.length; i++) {
new_attrs = _.map(_.map(newchatboxes.models, 'attributes'), attrs[i]);
old_attrs = _.map(_.map(_converse.chatboxes.models, 'attributes'), attrs[i]);
expect(_.isEqual(new_attrs, old_attrs)).toEqual(true);
}
_converse.rosterview.render();
done();
}).catch(_.partial(_converse.log, _, Strophe.LogLevel.FATAL));
}));
it("can be closed by clicking a DOM element with class 'close-chatbox-button'",
mock.initConverseWithPromises(
null, ['rosterGroupsFetched'], {},
null, ['rosterGroupsFetched', 'chatBoxesFetched'], {},
function (done, _converse) {
test_utils.createContacts(_converse, 'current');
_converse.emit('rosterContactsFetched');
test_utils.openControlBox();
test_utils.waitUntil(function () {
return $(_converse.rosterview.el).find('.roster-group').length;
}, 300).then(function () {
var chatbox = test_utils.openChatBoxes(_converse, 1)[0],
controlview = _converse.chatboxviews.get('controlbox'), // The controlbox is currently open
chatview = _converse.chatboxviews.get(chatbox.get('jid'));
const contact_jid = mock.cur_names[7].replace(/ /g,'.').toLowerCase() + '@localhost';
test_utils.waitUntil(() => _converse.rosterview.el.querySelectorAll('.roster-group').length)
.then(() => test_utils.openChatBoxFor(_converse, contact_jid))
.then(() => {
var controlview = _converse.chatboxviews.get('controlbox'), // The controlbox is currently open
chatview = _converse.chatboxviews.get(contact_jid);
spyOn(chatview, 'close').and.callThrough();
spyOn(controlview, 'close').and.callThrough();
spyOn(_converse, 'emit');
......@@ -338,20 +346,22 @@
it("can be minimized by clicking a DOM element with class 'toggle-chatbox-button'",
mock.initConverseWithPromises(
null, ['rosterGroupsFetched'], {},
null, ['rosterGroupsFetched', 'chatBoxesFetched'], {},
function (done, _converse) {
var chatview;
let chatview;
test_utils.createContacts(_converse, 'current');
_converse.emit('rosterContactsFetched');
test_utils.openControlBox();
test_utils.waitUntil(function () {
return $(_converse.rosterview.el).find('.roster-group').length;
}, 300)
.then(function () {
var chatbox = test_utils.openChatBoxes(_converse, 1)[0],
trimmed_chatboxes = _converse.minimized_chats,
const contact_jid = mock.cur_names[7].replace(/ /g,'.').toLowerCase() + '@localhost';
test_utils.waitUntil(() => _converse.rosterview.el.querySelectorAll('.roster-group').length)
.then(() => test_utils.openChatBoxFor(_converse, contact_jid))
.then(() => {
var trimmed_chatboxes = _converse.minimized_chats,
trimmedview;
chatview = _converse.chatboxviews.get(chatbox.get('jid'));
chatview = _converse.chatboxviews.get(contact_jid);
spyOn(chatview, 'minimize').and.callThrough();
spyOn(_converse, 'emit');
// We need to rebind all events otherwise our spy won't be called
......@@ -372,9 +382,7 @@
expect(trimmedview.restore).toHaveBeenCalled();
expect(_converse.emit).toHaveBeenCalledWith('chatBoxMaximized', jasmine.any(Object));
return test_utils.waitUntil(function () {
return $(chatview.el).find('.chat-body').is(':visible');
}, 500);
return test_utils.waitUntil(() => u.isVisible(chatview.el.querySelector('.chat-body')), 500);
}).then(function () {
expect($(chatview.el).find('.toggle-chatbox-button').hasClass('fa-minus')).toBeTruthy();
expect($(chatview.el).find('.toggle-chatbox-button').hasClass('fa-plus')).toBeFalsy();
......@@ -385,14 +393,14 @@
it("will be removed from browserStorage when closed",
mock.initConverseWithPromises(
null, ['rosterGroupsFetched'], {},
null, ['rosterGroupsFetched', 'chatBoxesFetched'], {},
function (done, _converse) {
test_utils.createContacts(_converse, 'current');
_converse.emit('rosterContactsFetched');
test_utils.openControlBox();
test_utils.waitUntil(function () {
return $(_converse.rosterview.el).find('.roster-group').length;
}, 300).then(function () {
test_utils.waitUntil(() => _converse.rosterview.el.querySelectorAll('.roster-group').length)
.then(() => {
spyOn(_converse, 'emit');
spyOn(_converse.chatboxviews, 'trimChats');
_converse.chatboxes.browserStorage._clear();
......@@ -403,6 +411,8 @@
expect(_converse.chatboxes.length).toEqual(1);
expect(_converse.chatboxes.pluck('id')).toEqual(['controlbox']);
test_utils.openChatBoxes(_converse, 6);
return test_utils.waitUntil(() => _converse.chatboxes.length == 7)
}).then(() => {
expect(_converse.chatboxviews.trimChats).toHaveBeenCalled();
expect(_converse.chatboxes.length).toEqual(7);
expect(_converse.emit).toHaveBeenCalledWith('chatBoxOpened', jasmine.any(Object));
......@@ -428,77 +438,70 @@
it("can be found on each chat box",
mock.initConverseWithPromises(
null, ['rosterGroupsFetched'], {},
null, ['rosterGroupsFetched', 'chatBoxesFetched'], {},
function (done, _converse) {
test_utils.createContacts(_converse, 'current');
_converse.emit('rosterContactsFetched');
test_utils.openControlBox();
var contact_jid = mock.cur_names[2].replace(/ /g,'.').toLowerCase() + '@localhost';
test_utils.openChatBoxFor(_converse, contact_jid);
var chatbox = _converse.chatboxes.get(contact_jid);
var view = _converse.chatboxviews.get(contact_jid);
expect(chatbox).toBeDefined();
expect(view).toBeDefined();
var toolbar = view.el.querySelector('ul.chat-toolbar');
expect(_.isElement(toolbar)).toBe(true);
expect(toolbar.querySelectorAll(':scope > li').length).toBe(1);
done();
test_utils.openChatBoxFor(_converse, contact_jid)
.then(() => {
var chatbox = _converse.chatboxes.get(contact_jid);
var view = _converse.chatboxviews.get(contact_jid);
expect(chatbox).toBeDefined();
expect(view).toBeDefined();
var toolbar = view.el.querySelector('ul.chat-toolbar');
expect(_.isElement(toolbar)).toBe(true);
expect(toolbar.querySelectorAll(':scope > li').length).toBe(1);
done();
});
}));
it("contains a button for inserting emojis",
mock.initConverseWithPromises(
null, ['rosterGroupsFetched'], {},
null, ['rosterGroupsFetched', 'chatBoxesFetched'], {},
function (done, _converse) {
test_utils.createContacts(_converse, 'current');
_converse.emit('rosterContactsFetched');
test_utils.openControlBox();
var contact_jid = mock.cur_names[2].replace(/ /g,'.').toLowerCase() + '@localhost';
test_utils.openChatBoxFor(_converse, contact_jid);
var view = _converse.chatboxviews.get(contact_jid);
var toolbar = view.el.querySelector('ul.chat-toolbar');
expect(toolbar.querySelectorAll('li.toggle-smiley').length).toBe(1);
// Register spies
spyOn(view, 'toggleEmojiMenu').and.callThrough();
spyOn(view, 'insertEmoji').and.callThrough();
view.delegateEvents(); // We need to rebind all events otherwise our spy won't be called
toolbar.querySelector('li.toggle-smiley').click();
var timeout = false;
let timeout = false, view, toolbar;
const contact_jid = mock.cur_names[2].replace(/ /g,'.').toLowerCase() + '@localhost';
test_utils.openChatBoxFor(_converse, contact_jid)
.then(() => {
view = _converse.chatboxviews.get(contact_jid);
toolbar = view.el.querySelector('ul.chat-toolbar');
expect(toolbar.querySelectorAll('li.toggle-smiley').length).toBe(1);
// Register spies
spyOn(view, 'toggleEmojiMenu').and.callThrough();
spyOn(view, 'insertEmoji').and.callThrough();
view.delegateEvents(); // We need to rebind all events otherwise our spy won't be called
toolbar.querySelector('li.toggle-smiley').click();
test_utils.waitUntil(function () {
return u.isVisible(view.el.querySelector('.toggle-smiley .emoji-picker-container'));
}, 500).then(function () {
return test_utils.waitUntil(() => u.isVisible(view.el.querySelector('.toggle-smiley .emoji-picker-container'), 500));
}).then(() => {
var picker = view.el.querySelector('.toggle-smiley .emoji-picker-container');
var items = picker.querySelectorAll('.emoji-picker li');
items[0].click()
expect(view.insertEmoji).toHaveBeenCalled();
setTimeout(function () { timeout = true; }, 100);
return test_utils.waitUntil(function () {
return timeout;
}, 500);
}).then(function () {
return test_utils.waitUntil(() => timeout, 500);
}).then(() => {
timeout = false;
toolbar.querySelector('li.toggle-smiley').click(); // Close the panel again
return test_utils.waitUntil(function () {
return !view.el.querySelector('.toggle-smiley .toolbar-menu').offsetHeight;
}, 500);
}).then(function () {
return test_utils.waitUntil(() => !view.el.querySelector('.toggle-smiley .toolbar-menu').offsetHeight, 500);
}).then(() => {
setTimeout(function () { timeout = true; }, 100);
return test_utils.waitUntil(function () {
return timeout;
}, 500);
}).then(function () {
return test_utils.waitUntil(() => timeout, 500);
}).then(() => {
toolbar.querySelector('li.toggle-smiley').click();
expect(view.toggleEmojiMenu).toHaveBeenCalled();
return test_utils.waitUntil(function () {
var $picker = $(view.el).find('.toggle-smiley .emoji-picker-container');
return u.isVisible($picker[0]);
}, 500);
}).then(function () {
return test_utils.waitUntil(() => u.isVisible(view.el.querySelector('.toggle-smiley .emoji-picker-container')), 500);
}).then(() => {
var nodes = view.el.querySelectorAll('.toggle-smiley ul li');
nodes[nodes.length-1].click();
expect(view.el.querySelector('textarea.chat-textarea').value).toBe(':grinning: ');
......@@ -509,34 +512,38 @@
it("can contain a button for starting a call",
mock.initConverseWithPromises(
null, ['rosterGroupsFetched'], {},
null, ['rosterGroupsFetched', 'chatBoxesFetched'], {},
function (done, _converse) {
test_utils.createContacts(_converse, 'current');
_converse.emit('rosterContactsFetched');
test_utils.openControlBox();
var view;
var contact_jid = mock.cur_names[2].replace(/ /g,'.').toLowerCase() + '@localhost';
let view, toolbar, call_button;
const contact_jid = mock.cur_names[2].replace(/ /g,'.').toLowerCase() + '@localhost';
spyOn(_converse, 'emit');
// First check that the button doesn't show if it's not enabled
// via "visible_toolbar_buttons"
_converse.visible_toolbar_buttons.call = false;
test_utils.openChatBoxFor(_converse, contact_jid);
view = _converse.chatboxviews.get(contact_jid);
var toolbar = view.el.querySelector('ul.chat-toolbar');
var call_button = toolbar.querySelector('.toggle-call');
expect(_.isNull(call_button)).toBeTruthy();
view.close();
// Now check that it's shown if enabled and that it emits
// callButtonClicked
_converse.visible_toolbar_buttons.call = true; // enable the button
test_utils.openChatBoxFor(_converse, contact_jid);
view = _converse.chatboxviews.get(contact_jid);
toolbar = view.el.querySelector('ul.chat-toolbar');
call_button = toolbar.querySelector('.toggle-call');
call_button.click();
expect(_converse.emit).toHaveBeenCalledWith('callButtonClicked', jasmine.any(Object));
done();
test_utils.openChatBoxFor(_converse, contact_jid)
.then(() => {
view = _converse.chatboxviews.get(contact_jid);
toolbar = view.el.querySelector('ul.chat-toolbar');
call_button = toolbar.querySelector('.toggle-call');
expect(_.isNull(call_button)).toBeTruthy();
view.close();
// Now check that it's shown if enabled and that it emits
// callButtonClicked
_converse.visible_toolbar_buttons.call = true; // enable the button
return test_utils.openChatBoxFor(_converse, contact_jid);
}).then(() => {
view = _converse.chatboxviews.get(contact_jid);
toolbar = view.el.querySelector('ul.chat-toolbar');
call_button = toolbar.querySelector('.toggle-call');
call_button.click();
expect(_converse.emit).toHaveBeenCalledWith('callButtonClicked', jasmine.any(Object));
done();
});
}));
});
......@@ -568,17 +575,19 @@
it("is sent when the user opens a chat box",
mock.initConverseWithPromises(
null, ['rosterGroupsFetched'], {},
null, ['rosterGroupsFetched', 'chatBoxesFetched'], {},
function (done, _converse) {
test_utils.createContacts(_converse, 'current');
_converse.emit('rosterContactsFetched');
const contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@localhost';
test_utils.openControlBox();
test_utils.waitUntil(function () {
return $(_converse.rosterview.el).find('.roster-group').length;
}, 300).then(function () {
spyOn(_converse.connection, 'send');
var contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@localhost';
test_utils.openChatBoxFor(_converse, contact_jid);
return test_utils.openChatBoxFor(_converse, contact_jid);
}).then(() => {
var view = _converse.chatboxviews.get(contact_jid);
expect(view.model.get('chat_state')).toBe('active');
expect(_converse.connection.send).toHaveBeenCalled();
......@@ -593,26 +602,24 @@
}));
it("is sent when the user maximizes a minimized a chat box", mock.initConverseWithPromises(
null, ['rosterGroupsFetched'], {},
null, ['rosterGroupsFetched', 'chatBoxesFetched'], {},
function (done, _converse) {
test_utils.createContacts(_converse, 'current');
_converse.emit('rosterContactsFetched');
test_utils.openControlBox();
var contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@localhost';
test_utils.waitUntil(function () {
return $(_converse.rosterview.el).find('.roster-group').length;
}, 500).then(function () {
test_utils.openChatBoxFor(_converse, contact_jid);
test_utils.waitUntil(() => _converse.rosterview.el.querySelectorAll('.roster-group').length)
.then(() => test_utils.openChatBoxFor(_converse, contact_jid))
.then(() => {
var view = _converse.chatboxviews.get(contact_jid);
view.model.minimize();
expect(view.model.get('chat_state')).toBe('inactive');
spyOn(_converse.connection, 'send');
view.model.maximize();
return test_utils.waitUntil(function () {
return view.model.get('chat_state') === 'active';
}, 700);
}).then(function () {
return test_utils.waitUntil(() => view.model.get('chat_state') === 'active', 700);
}).then(() => {
expect(_converse.connection.send).toHaveBeenCalled();
var calls = _.filter(_converse.connection.send.calls.all(), function (call) {
return call.args[0] instanceof Strophe.Builder;
......@@ -633,16 +640,17 @@
it("is sent as soon as the user starts typing a message which is not a command",
mock.initConverseWithPromises(
null, ['rosterGroupsFetched'], {},
null, ['rosterGroupsFetched', 'chatBoxesFetched'], {},
function (done, _converse) {
test_utils.createContacts(_converse, 'current');
_converse.emit('rosterContactsFetched');
test_utils.openControlBox();
test_utils.waitUntil(function () {
return $(_converse.rosterview.el).find('.roster-group').length;
}, 300).then(function () {
var contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@localhost';
test_utils.openChatBoxFor(_converse, contact_jid);
const contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@localhost';
test_utils.waitUntil(() => _converse.rosterview.el.querySelectorAll('.roster-group').length)
.then(() => test_utils.openChatBoxFor(_converse, contact_jid))
.then(() => {
var view = _converse.chatboxviews.get(contact_jid);
expect(view.model.get('chat_state')).toBe('active');
spyOn(_converse.connection, 'send');
......@@ -720,21 +728,20 @@
it("can be a composing carbon message that this user sent from a different client",
mock.initConverseWithPromises(
null, ['rosterGroupsFetched'], {},
null, ['rosterGroupsFetched', 'chatBoxesFetched'], {},
function (done, _converse) {
var contact, sent_stanza, IQ_id, stanza;
let contact, sent_stanza, IQ_id, stanza, recipient_jid;
test_utils.waitUntilDiscoConfirmed(_converse, 'localhost', [], ['vcard-temp'])
.then(() => test_utils.waitUntil(() => _converse.xmppstatus.vcard.get('fullname')))
.then(function () {
return test_utils.waitUntil(function () {
return _converse.xmppstatus.vcard.get('fullname');
}, 300);
}).then(function () {
test_utils.createContacts(_converse, 'current');
_converse.emit('rosterContactsFetched');
// 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);
recipient_jid = mock.cur_names[5].replace(/ /g,'.').toLowerCase() + '@localhost';
return test_utils.openChatBoxFor(_converse, recipient_jid);
}).then(() => {
var msg = $msg({
'from': _converse.bare_jid,
'id': (new Date()).getTime(),
......@@ -771,19 +778,19 @@
it("is sent if the user has stopped typing since 30 seconds",
mock.initConverseWithPromises(
null, ['rosterGroupsFetched'], {},
null, ['rosterGroupsFetched', 'chatBoxesFetched'], {},
function (done, _converse) {
var view, contact_jid;
let view;
test_utils.createContacts(_converse, 'current');
_converse.emit('rosterContactsFetched');
const contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@localhost';
test_utils.openControlBox();
test_utils.waitUntil(function () {
return $(_converse.rosterview.el).find('.roster-group li').length;
}, 700).then(function () {
test_utils.waitUntil(() => _converse.rosterview.el.querySelectorAll('.roster-group li').length, 700)
.then(() => {
_converse.TIMEOUTS.PAUSED = 200; // Make the timeout shorter so that we can test
contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@localhost';
test_utils.openChatBoxFor(_converse, contact_jid);
return test_utils.openChatBoxFor(_converse, contact_jid);
}).then(() => {
view = _converse.chatboxviews.get(contact_jid);
spyOn(_converse.connection, 'send');
spyOn(view, 'setChatState').and.callThrough();
......@@ -796,10 +803,8 @@
expect(_converse.connection.send).toHaveBeenCalled();
var $stanza = $(_converse.connection.send.calls.argsFor(0)[0].tree());
expect($stanza.children().get(0).tagName).toBe('composing');
return test_utils.waitUntil(function () {
return view.model.get('chat_state') === 'paused';
}, 500);
}).then(function () {
return test_utils.waitUntil(() => view.model.get('chat_state') === 'paused', 500);
}).then(() => {
expect(_converse.connection.send).toHaveBeenCalled();
var calls = _.filter(_converse.connection.send.calls.all(), function (call) {
return call.args[0] instanceof Strophe.Builder;
......@@ -828,7 +833,7 @@
});
expect(view.model.get('chat_state')).toBe('composing');
done();
});
}).catch(_.partial(_converse.log, _, Strophe.LogLevel.FATAL))
}));
it("will be shown if received",
......@@ -868,21 +873,20 @@
it("can be a paused carbon message that this user sent from a different client",
mock.initConverseWithPromises(
null, ['rosterGroupsFetched'], {},
null, ['rosterGroupsFetched', 'chatBoxesFetched'], {},
function (done, _converse) {
var contact, sent_stanza, IQ_id, stanza;
let contact, sent_stanza, IQ_id, stanza, recipient_jid;
test_utils.waitUntilDiscoConfirmed(_converse, 'localhost', [], ['vcard-temp'])
.then(function () {
return test_utils.waitUntil(function () {
return _converse.xmppstatus.vcard.get('fullname');
}, 300);
}).then(function () {
.then(() => test_utils.waitUntil(() => _converse.xmppstatus.vcard.get('fullname')))
.then(() => {
test_utils.createContacts(_converse, 'current');
_converse.emit('rosterContactsFetched');
// 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);
recipient_jid = mock.cur_names[5].replace(/ /g,'.').toLowerCase() + '@localhost';
return test_utils.openChatBoxFor(_converse, recipient_jid);
}).then(() => {
var msg = $msg({
'from': _converse.bare_jid,
'id': (new Date()).getTime(),
......@@ -979,38 +983,40 @@
it("is sent when the user a minimizes a chat box",
mock.initConverseWithPromises(
null, ['rosterGroupsFetched'], {},
null, ['rosterGroupsFetched', 'chatBoxesFetched'], {},
function (done, _converse) {
test_utils.createContacts(_converse, 'current');
_converse.emit('rosterContactsFetched');
test_utils.openControlBox();
var contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@localhost';
test_utils.openChatBoxFor(_converse, contact_jid);
var view = _converse.chatboxviews.get(contact_jid);
spyOn(_converse.connection, 'send');
view.minimize();
expect(view.model.get('chat_state')).toBe('inactive');
expect(_converse.connection.send).toHaveBeenCalled();
var $stanza = $(_converse.connection.send.calls.argsFor(0)[0].tree());
expect($stanza.attr('to')).toBe(contact_jid);
expect($stanza.children().get(0).tagName).toBe('inactive');
done();
test_utils.openChatBoxFor(_converse, contact_jid)
.then(() => {
var view = _converse.chatboxviews.get(contact_jid);
spyOn(_converse.connection, 'send');
view.minimize();
expect(view.model.get('chat_state')).toBe('inactive');
expect(_converse.connection.send).toHaveBeenCalled();
var $stanza = $(_converse.connection.send.calls.argsFor(0)[0].tree());
expect($stanza.attr('to')).toBe(contact_jid);
expect($stanza.children().get(0).tagName).toBe('inactive');
done();
});
}));
it("is sent if the user closes a chat box",
mock.initConverseWithPromises(
null, ['rosterGroupsFetched'], {},
null, ['rosterGroupsFetched', 'chatBoxesFetched'], {},
function (done, _converse) {
test_utils.createContacts(_converse, 'current');
_converse.emit('rosterContactsFetched');
const contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@localhost';
test_utils.openControlBox();
test_utils.waitUntil(function () {
return $(_converse.rosterview.el).find('.roster-group').length;
}, 300).then(function () {
var contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@localhost';
test_utils.openChatBoxFor(_converse, contact_jid);
var view = _converse.chatboxviews.get(contact_jid);
test_utils.waitUntil(() => _converse.rosterview.el.querySelectorAll('.roster-group').length)
.then(() => test_utils.openChatBoxFor(_converse, contact_jid))
.then((view) => {
expect(view.model.get('chat_state')).toBe('active');
spyOn(_converse.connection, 'send');
view.close();
......@@ -1028,40 +1034,43 @@
it("will clear any other chat status notifications",
mock.initConverseWithPromises(
null, ['rosterGroupsFetched'], {},
null, ['rosterGroupsFetched', 'chatBoxesFetched'], {},
function (done, _converse) {
test_utils.createContacts(_converse, 'current');
_converse.emit('rosterContactsFetched');
test_utils.openControlBox();
const sender_jid = mock.cur_names[1].replace(/ /g,'.').toLowerCase() + '@localhost';
// See XEP-0085 http://xmpp.org/extensions/xep-0085.html#definitions
spyOn(_converse, 'emit');
var sender_jid = mock.cur_names[1].replace(/ /g,'.').toLowerCase() + '@localhost';
test_utils.openChatBoxFor(_converse, sender_jid);
var view = _converse.chatboxviews.get(sender_jid);
expect(view.el.querySelectorAll('.chat-event').length).toBe(0);
// Insert <composing> message, to also check that
// text messages are inserted correctly with
// temporary chat events in the chat contents.
var msg = $msg({
'to': _converse.bare_jid,
'xmlns': 'jabber:client',
'from': sender_jid,
'type': 'chat'})
.c('composing', {'xmlns': Strophe.NS.CHATSTATES}).up()
.tree();
_converse.chatboxes.onMessage(msg);
expect(view.el.querySelectorAll('.chat-state-notification').length).toBe(1);
msg = $msg({
from: sender_jid,
to: _converse.connection.jid,
type: 'chat',
id: (new Date()).getTime()
}).c('body').c('inactive', {'xmlns': Strophe.NS.CHATSTATES}).tree();
_converse.chatboxes.onMessage(msg);
expect(_converse.emit).toHaveBeenCalledWith('message', jasmine.any(Object));
expect($(view.el).find('.chat-state-notification').length).toBe(0);
done();
test_utils.openChatBoxFor(_converse, sender_jid)
.then(() => {
var view = _converse.chatboxviews.get(sender_jid);
expect(view.el.querySelectorAll('.chat-event').length).toBe(0);
// Insert <composing> message, to also check that
// text messages are inserted correctly with
// temporary chat events in the chat contents.
var msg = $msg({
'to': _converse.bare_jid,
'xmlns': 'jabber:client',
'from': sender_jid,
'type': 'chat'})
.c('composing', {'xmlns': Strophe.NS.CHATSTATES}).up()
.tree();
_converse.chatboxes.onMessage(msg);
expect(view.el.querySelectorAll('.chat-state-notification').length).toBe(1);
msg = $msg({
from: sender_jid,
to: _converse.connection.jid,
type: 'chat',
id: (new Date()).getTime()
}).c('body').c('inactive', {'xmlns': Strophe.NS.CHATSTATES}).tree();
_converse.chatboxes.onMessage(msg);
expect(_converse.emit).toHaveBeenCalledWith('message', jasmine.any(Object));
expect($(view.el).find('.chat-state-notification').length).toBe(0);
done();
});
}));
});
......@@ -1103,39 +1112,42 @@
it("'/clear' can be used to clear messages in a conversation",
mock.initConverseWithPromises(
null, ['rosterGroupsFetched'], {},
null, ['rosterGroupsFetched', 'chatBoxesFetched'], {},
function (done, _converse) {
test_utils.createContacts(_converse, 'current');
_converse.emit('rosterContactsFetched');
test_utils.openControlBox();
const contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@localhost';
spyOn(_converse, 'emit');
var contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@localhost';
test_utils.openChatBoxFor(_converse, contact_jid);
var view = _converse.chatboxviews.get(contact_jid);
var message = 'This message is another sent from this chatbox';
// Lets make sure there is at least one message already
// (e.g for when this test is run on its own).
test_utils.sendMessage(view, message);
expect(view.model.messages.length > 0).toBeTruthy();
expect(view.model.messages.browserStorage.records.length > 0).toBeTruthy();
expect(_converse.emit).toHaveBeenCalledWith('messageSend', message);
message = '/clear';
spyOn(view, 'onMessageSubmitted').and.callThrough();
spyOn(view, 'clearMessages').and.callThrough();
spyOn(window, 'confirm').and.callFake(function () {
return true;
test_utils.openChatBoxFor(_converse, contact_jid)
.then(() => {
var view = _converse.chatboxviews.get(contact_jid);
var message = 'This message is another sent from this chatbox';
// Lets make sure there is at least one message already
// (e.g for when this test is run on its own).
test_utils.sendMessage(view, message);
expect(view.model.messages.length > 0).toBeTruthy();
expect(view.model.messages.browserStorage.records.length > 0).toBeTruthy();
expect(_converse.emit).toHaveBeenCalledWith('messageSend', message);
message = '/clear';
spyOn(view, 'onMessageSubmitted').and.callThrough();
spyOn(view, 'clearMessages').and.callThrough();
spyOn(window, 'confirm').and.callFake(function () {
return true;
});
test_utils.sendMessage(view, message);
expect(view.onMessageSubmitted).toHaveBeenCalled();
expect(view.clearMessages).toHaveBeenCalled();
expect(window.confirm).toHaveBeenCalled();
expect(view.model.messages.length, 0); // The messages must be removed from the chatbox
expect(view.model.messages.browserStorage.records.length, 0); // And also from browserStorage
expect(_converse.emit.calls.count(), 1);
expect(_converse.emit.calls.mostRecent().args, ['messageSend', message]);
done();
});
test_utils.sendMessage(view, message);
expect(view.onMessageSubmitted).toHaveBeenCalled();
expect(view.clearMessages).toHaveBeenCalled();
expect(window.confirm).toHaveBeenCalled();
expect(view.model.messages.length, 0); // The messages must be removed from the chatbox
expect(view.model.messages.browserStorage.records.length, 0); // And also from browserStorage
expect(_converse.emit.calls.count(), 1);
expect(_converse.emit.calls.mostRecent().args, ['messageSend', message]);
done();
}));
});
......@@ -1267,133 +1279,133 @@
it("is incremented when the message is received and ChatBoxView is scrolled up",
mock.initConverseWithPromises(
null, ['rosterGroupsFetched'], {},
null, ['rosterGroupsFetched', 'chatBoxesFetched'], {},
function (done, _converse) {
test_utils.createContacts(_converse, 'current');
_converse.emit('rosterContactsFetched');
var sender_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@localhost',
msg = test_utils.createChatMessage(_converse, sender_jid, 'This message will be unread');
test_utils.openChatBoxFor(_converse, sender_jid);
var chatbox = _converse.chatboxes.get(sender_jid);
chatbox.save('scrolled', true);
const sender_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@localhost',
msg = test_utils.createChatMessage(_converse, sender_jid, 'This message will be unread');
_converse.chatboxes.onMessage(msg);
expect(chatbox.get('num_unread')).toBe(1);
done();
test_utils.openChatBoxFor(_converse, sender_jid)
.then((view) => {
view.model.save('scrolled', true);
_converse.chatboxes.onMessage(msg);
expect(view.model.get('num_unread')).toBe(1);
done();
});
}));
it("is not incremented when the message is received and ChatBoxView is scrolled down",
mock.initConverseWithPromises(
null, ['rosterGroupsFetched'], {},
null, ['rosterGroupsFetched', 'chatBoxesFetched'], {},
function (done, _converse) {
test_utils.createContacts(_converse, 'current');
_converse.emit('rosterContactsFetched');
var sender_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@localhost',
msg = test_utils.createChatMessage(_converse, sender_jid, 'This message will be read');
test_utils.openChatBoxFor(_converse, sender_jid);
var chatbox = _converse.chatboxes.get(sender_jid);
const sender_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@localhost',
msg = test_utils.createChatMessage(_converse, sender_jid, 'This message will be read');
_converse.chatboxes.onMessage(msg);
expect(chatbox.get('num_unread')).toBe(0);
done();
test_utils.openChatBoxFor(_converse, sender_jid)
.then(() => {
var chatbox = _converse.chatboxes.get(sender_jid);
_converse.chatboxes.onMessage(msg);
expect(chatbox.get('num_unread')).toBe(0);
done();
});
}));
it("is incremeted when message is received, chatbox is scrolled down and the window is not focused",
mock.initConverseWithPromises(
null, ['rosterGroupsFetched'], {},
function (done, _converse) {
mock.initConverseWithPromises(null, ['rosterGroupsFetched', 'chatBoxesFetched'], {}, function (done, _converse) {
test_utils.createContacts(_converse, 'current');
_converse.emit('rosterContactsFetched');
var sender_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@localhost';
var msgFactory = function () {
return test_utils.createChatMessage(_converse, sender_jid, 'This message will be unread');
};
test_utils.openChatBoxFor(_converse, sender_jid);
var chatbox = _converse.chatboxes.get(sender_jid);
_converse.windowState = 'hidden';
_converse.chatboxes.onMessage(msgFactory());
expect(chatbox.get('num_unread')).toBe(1);
done();
test_utils.openChatBoxFor(_converse, sender_jid)
.then(() => {
var chatbox = _converse.chatboxes.get(sender_jid);
_converse.windowState = 'hidden';
_converse.chatboxes.onMessage(msgFactory());
expect(chatbox.get('num_unread')).toBe(1);
done();
});
}));
it("is incremeted when message is received, chatbox is scrolled up and the window is not focused",
mock.initConverseWithPromises(
null, ['rosterGroupsFetched'], {},
function (done, _converse) {
mock.initConverseWithPromises(
null, ['rosterGroupsFetched', 'chatBoxesFetched'], {},
function (done, _converse) {
test_utils.createContacts(_converse, 'current');
_converse.emit('rosterContactsFetched');
var sender_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@localhost';
var msgFactory = function () {
return test_utils.createChatMessage(_converse, sender_jid, 'This message will be unread');
};
test_utils.openChatBoxFor(_converse, sender_jid);
var chatbox = _converse.chatboxes.get(sender_jid);
chatbox.save('scrolled', true);
_converse.windowState = 'hidden';
_converse.chatboxes.onMessage(msgFactory());
expect(chatbox.get('num_unread')).toBe(1);
done();
test_utils.openChatBoxFor(_converse, sender_jid)
.then(() => {
var chatbox = _converse.chatboxes.get(sender_jid);
chatbox.save('scrolled', true);
_converse.windowState = 'hidden';
_converse.chatboxes.onMessage(msgFactory());
expect(chatbox.get('num_unread')).toBe(1);
done();
});
}));
it("is cleared when ChatBoxView was scrolled down and the window become focused",
mock.initConverseWithPromises(
null, ['rosterGroupsFetched'], {},
function (done, _converse) {
mock.initConverseWithPromises(
null, ['rosterGroupsFetched', 'chatBoxesFetched'], {},
function (done, _converse) {
test_utils.createContacts(_converse, 'current');
_converse.emit('rosterContactsFetched');
var sender_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@localhost';
const sender_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@localhost';
var msgFactory = function () {
return test_utils.createChatMessage(_converse, sender_jid, 'This message will be unread');
};
test_utils.openChatBoxFor(_converse, sender_jid);
var chatbox = _converse.chatboxes.get(sender_jid);
_converse.windowState = 'hidden';
_converse.chatboxes.onMessage(msgFactory());
expect(chatbox.get('num_unread')).toBe(1);
_converse.saveWindowState(null, 'focus');
expect(chatbox.get('num_unread')).toBe(0);
done();
test_utils.openChatBoxFor(_converse, sender_jid)
.then(() => {
const chatbox = _converse.chatboxes.get(sender_jid);
_converse.windowState = 'hidden';
_converse.chatboxes.onMessage(msgFactory());
expect(chatbox.get('num_unread')).toBe(1);
_converse.saveWindowState(null, 'focus');
expect(chatbox.get('num_unread')).toBe(0);
done();
});
}));
it("is not cleared when ChatBoxView was scrolled up and the windows become focused",
mock.initConverseWithPromises(
null, ['rosterGroupsFetched'], {},
function (done, _converse) {
mock.initConverseWithPromises(
null, ['rosterGroupsFetched', 'chatBoxesFetched'], {},
function (done, _converse) {
test_utils.createContacts(_converse, 'current');
_converse.emit('rosterContactsFetched');
var sender_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@localhost';
var msgFactory = function () {
return test_utils.createChatMessage(_converse, sender_jid, 'This message will be unread');
};
test_utils.openChatBoxFor(_converse, sender_jid);
var chatbox = _converse.chatboxes.get(sender_jid);
chatbox.save('scrolled', true);
_converse.windowState = 'hidden';
_converse.chatboxes.onMessage(msgFactory());
expect(chatbox.get('num_unread')).toBe(1);
_converse.saveWindowState(null, 'focus');
expect(chatbox.get('num_unread')).toBe(1);
done();
test_utils.openChatBoxFor(_converse, sender_jid)
.then(() => {
var chatbox = _converse.chatboxes.get(sender_jid);
chatbox.save('scrolled', true);
_converse.windowState = 'hidden';
_converse.chatboxes.onMessage(msgFactory());
expect(chatbox.get('num_unread')).toBe(1);
_converse.saveWindowState(null, 'focus');
expect(chatbox.get('num_unread')).toBe(1);
done();
});
}));
});
......@@ -1401,16 +1413,16 @@
it("is updated when message is received and chatbox is scrolled up",
mock.initConverseWithPromises(
null, ['rosterGroupsFetched'], {},
null, ['rosterGroupsFetched', 'chatBoxesFetched'], {},
function (done, _converse) {
test_utils.createContacts(_converse, 'current');
test_utils.waitUntil(function () {
return $(_converse.rosterview.el).find('.roster-group').length;
}, 500)
.then(function () {
var sender_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@localhost';
test_utils.openChatBoxFor(_converse, sender_jid);
_converse.emit('rosterContactsFetched');
const sender_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@localhost';
test_utils.waitUntil(() => _converse.rosterview.el.querySelectorAll('.roster-group').length, 500)
.then(() => test_utils.openChatBoxFor(_converse, sender_jid))
.then(() => {
var chatbox = _converse.chatboxes.get(sender_jid);
chatbox.save('scrolled', true);
......@@ -1433,16 +1445,16 @@
it("is updated when message is received and chatbox is minimized",
mock.initConverseWithPromises(
null, ['rosterGroupsFetched'], {},
null, ['rosterGroupsFetched', 'chatBoxesFetched'], {},
function (done, _converse) {
test_utils.createContacts(_converse, 'current');
test_utils.waitUntil(function () {
return $(_converse.rosterview.el).find('.roster-group').length;
}, 500)
.then(function () {
var sender_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@localhost';
test_utils.openChatBoxFor(_converse, sender_jid);
_converse.emit('rosterContactsFetched');
const sender_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@localhost';
test_utils.waitUntil(() => _converse.rosterview.el.querySelectorAll('.roster-group').length, 500)
.then(() => test_utils.openChatBoxFor(_converse, sender_jid))
.then(() => {
var chatbox = _converse.chatboxes.get(sender_jid);
var chatboxview = _converse.chatboxviews.get(sender_jid);
chatboxview.minimize();
......@@ -1466,16 +1478,16 @@
it("is cleared when chatbox is maximzied after receiving messages in minimized mode",
mock.initConverseWithPromises(
null, ['rosterGroupsFetched'], {},
null, ['rosterGroupsFetched', 'chatBoxesFetched'], {},
function (done, _converse) {
test_utils.createContacts(_converse, 'current');
test_utils.waitUntil(function () {
return $(_converse.rosterview.el).find('.roster-group').length;
}, 500)
.then(function () {
var sender_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@localhost';
test_utils.openChatBoxFor(_converse, sender_jid);
_converse.emit('rosterContactsFetched');
const sender_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@localhost';
test_utils.waitUntil(() => _converse.rosterview.el.querySelectorAll('.roster-group').length, 500)
.then(() => test_utils.openChatBoxFor(_converse, sender_jid))
.then(() => {
var chatbox = _converse.chatboxes.get(sender_jid);
var chatboxview = _converse.chatboxviews.get(sender_jid);
var msgsIndicatorSelector = 'a.open-chat:contains("' + chatbox.get('fullname') + '") .msgs-indicator';
......@@ -1483,7 +1495,6 @@
var msgFactory = function () {
return test_utils.createChatMessage(_converse, sender_jid, 'This message will be received as unread, but eventually will be read');
};
chatboxview.minimize();
_converse.chatboxes.onMessage(msgFactory());
......@@ -1500,16 +1511,16 @@
it("is cleared when unread messages are viewed which were received in scrolled-up chatbox",
mock.initConverseWithPromises(
null, ['rosterGroupsFetched'], {},
null, ['rosterGroupsFetched', 'chatBoxesFetched'], {},
function (done, _converse) {
test_utils.createContacts(_converse, 'current');
test_utils.waitUntil(function () {
return $(_converse.rosterview.el).find('.roster-group').length;
}, 500)
.then(function () {
var sender_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@localhost';
test_utils.openChatBoxFor(_converse, sender_jid);
_converse.emit('rosterContactsFetched');
const sender_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@localhost';
test_utils.waitUntil(() => _converse.rosterview.el.querySelectorAll('.roster-group').length, 500)
.then(() => test_utils.openChatBoxFor(_converse, sender_jid))
.then(() => {
var chatbox = _converse.chatboxes.get(sender_jid);
var chatboxview = _converse.chatboxviews.get(sender_jid);
var msgFactory = function () {
......@@ -1532,16 +1543,16 @@
it("is not cleared after user clicks on roster view when chatbox is already opened and scrolled up",
mock.initConverseWithPromises(
null, ['rosterGroupsFetched'], {},
null, ['rosterGroupsFetched', 'chatBoxesFetched'], {},
function (done, _converse) {
test_utils.createContacts(_converse, 'current');
test_utils.waitUntil(function () {
return $(_converse.rosterview.el).find('.roster-group').length;
}, 500)
.then(function () {
var sender_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@localhost';
test_utils.openChatBoxFor(_converse, sender_jid);
_converse.emit('rosterContactsFetched');
const sender_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@localhost';
test_utils.waitUntil(() => _converse.rosterview.el.querySelectorAll('.roster-group').length, 500)
.then(() => test_utils.openChatBoxFor(_converse, sender_jid))
.then(() => {
var chatbox = _converse.chatboxes.get(sender_jid);
var chatboxview = _converse.chatboxviews.get(sender_jid);
var msgFactory = function () {
......@@ -1565,89 +1576,100 @@
describe("A Minimized ChatBoxView's Unread Message Count", function () {
it("is displayed when scrolled up chatbox is minimized after receiving unread messages",
mock.initConverseWithPromises(
null, ['rosterGroupsFetched'], {},
function (done, _converse) {
mock.initConverseWithPromises(
null, ['rosterGroupsFetched', 'chatBoxesFetched'], {},
function (done, _converse) {
test_utils.createContacts(_converse, 'current');
_converse.emit('rosterContactsFetched');
const sender_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@localhost';
var sender_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@localhost';
test_utils.openChatBoxFor(_converse, sender_jid);
var msgFactory = function () {
return test_utils.createChatMessage(_converse, sender_jid, 'This message will be received as unread, but eventually will be read');
};
var selectUnreadMsgCount = function () {
var minimizedChatBoxView = _converse.minimized_chats.get(sender_jid);
return $(minimizedChatBoxView.el).find('.message-count');
};
test_utils.openChatBoxFor(_converse, sender_jid)
.then(() => {
const msgFactory = function () {
return test_utils.createChatMessage(_converse, sender_jid, 'This message will be received as unread, but eventually will be read');
};
const selectUnreadMsgCount = function () {
const minimizedChatBoxView = _converse.minimized_chats.get(sender_jid);
return $(minimizedChatBoxView.el).find('.message-count');
};
var chatbox = _converse.chatboxes.get(sender_jid);
chatbox.save('scrolled', true);
_converse.chatboxes.onMessage(msgFactory());
const chatbox = _converse.chatboxes.get(sender_jid);
chatbox.save('scrolled', true);
_converse.chatboxes.onMessage(msgFactory());
var chatboxview = _converse.chatboxviews.get(sender_jid);
chatboxview.minimize();
const chatboxview = _converse.chatboxviews.get(sender_jid);
chatboxview.minimize();
var $unreadMsgCount = selectUnreadMsgCount();
expect(u.isVisible($unreadMsgCount[0])).toBeTruthy();
expect($unreadMsgCount.html()).toBe('1');
done();
const $unreadMsgCount = selectUnreadMsgCount();
expect(u.isVisible($unreadMsgCount[0])).toBeTruthy();
expect($unreadMsgCount.html()).toBe('1');
done();
});
}));
it("is incremented when message is received and windows is not focused",
mock.initConverseWithPromises(
null, ['rosterGroupsFetched'], {},
function (done, _converse) {
mock.initConverseWithPromises(
null, ['rosterGroupsFetched', 'chatBoxesFetched'], {},
function (done, _converse) {
test_utils.createContacts(_converse, 'current');
_converse.emit('rosterContactsFetched');
const sender_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@localhost';
var sender_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@localhost';
test_utils.openChatBoxFor(_converse, sender_jid);
var msgFactory = function () {
return test_utils.createChatMessage(_converse, sender_jid, 'This message will be received as unread, but eventually will be read');
};
var selectUnreadMsgCount = function () {
var minimizedChatBoxView = _converse.minimized_chats.get(sender_jid);
return $(minimizedChatBoxView.el).find('.message-count');
};
test_utils.openChatBoxFor(_converse, sender_jid)
.then(() => {
const msgFactory = function () {
return test_utils.createChatMessage(_converse, sender_jid,
'This message will be received as unread, but eventually will be read');
};
const selectUnreadMsgCount = function () {
const minimizedChatBoxView = _converse.minimized_chats.get(sender_jid);
return $(minimizedChatBoxView.el).find('.message-count');
};
var chatboxview = _converse.chatboxviews.get(sender_jid);
chatboxview.minimize();
const chatboxview = _converse.chatboxviews.get(sender_jid);
chatboxview.minimize();
_converse.chatboxes.onMessage(msgFactory());
_converse.chatboxes.onMessage(msgFactory());
var $unreadMsgCount = selectUnreadMsgCount();
expect(u.isVisible($unreadMsgCount[0])).toBeTruthy();
expect($unreadMsgCount.html()).toBe('1');
done();
const $unreadMsgCount = selectUnreadMsgCount();
expect(u.isVisible($unreadMsgCount[0])).toBeTruthy();
expect($unreadMsgCount.html()).toBe('1');
done();
});
}));
it("will render Openstreetmap-URL from geo-URI",
mock.initConverseWithPromises(
null, ['rosterGroupsFetched'], {},
function (done, _converse) {
mock.initConverseWithPromises(
null, ['rosterGroupsFetched', 'chatBoxesFetched'], {},
function (done, _converse) {
test_utils.createContacts(_converse, 'current');
var base_url = document.URL.split(window.location.pathname)[0];
var message = "geo:37.786971,-122.399677";
var contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@localhost';
test_utils.openChatBoxFor(_converse, contact_jid);
var view = _converse.chatboxviews.get(contact_jid);
test_utils.createContacts(_converse, 'current');
_converse.emit('rosterContactsFetched');
let view;
const base_url = document.URL.split(window.location.pathname)[0],
message = "geo:37.786971,-122.399677",
contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@localhost';
test_utils.openChatBoxFor(_converse, contact_jid)
.then(() => {
view = _converse.chatboxviews.get(contact_jid);
spyOn(view.model, 'sendMessage').and.callThrough();
test_utils.sendMessage(view, message);
test_utils.waitUntil(function () {
return $(view.el).find('.chat-content').find('.chat-msg').length;
}, 1000).then(function () {
expect(view.model.sendMessage).toHaveBeenCalled();
var msg = $(view.el).find('.chat-content').find('.chat-msg').last().find('.chat-msg__text');
expect(msg.html()).toEqual(
'<a target="_blank" rel="noopener" href="https://www.openstreetmap.org/?mlat=37.786971&amp;'+
'mlon=-122.399677#map=18/37.786971/-122.399677">https://www.openstreetmap.org/?mlat=37.7869'+
'71&amp;mlon=-122.399677#map=18/37.786971/-122.399677</a>');
done();
});
}));
return test_utils.waitUntil(() => view.el.querySelectorAll('.chat-content .chat-msg').length, 1000);
}).then(() => {
expect(view.model.sendMessage).toHaveBeenCalled();
var msg = $(view.el).find('.chat-content').find('.chat-msg').last().find('.chat-msg__text');
expect(msg.html()).toEqual(
'<a target="_blank" rel="noopener" href="https://www.openstreetmap.org/?mlat=37.786971&amp;'+
'mlon=-122.399677#map=18/37.786971/-122.399677">https://www.openstreetmap.org/?mlat=37.7869'+
'71&amp;mlon=-122.399677#map=18/37.786971/-122.399677</a>');
done();
});
}));
});
});
}));
This source diff could not be displayed because it is too large. You can view the blob instead.
......@@ -225,25 +225,28 @@
[{'category': 'server', 'type':'IM'}],
['http://jabber.org/protocol/disco#items'], [], 'info').then(function () {
test_utils.waitUntilDiscoConfirmed(_converse, _converse.domain, [], [], ['upload.localhost'], 'items').then(function () {
test_utils.waitUntilDiscoConfirmed(_converse, 'upload.localhost', [], [Strophe.NS.HTTPUPLOAD], []).then(function () {
test_utils.createContacts(_converse, 'current');
var contact_jid = mock.cur_names[2].replace(/ /g,'.').toLowerCase() + '@localhost';
test_utils.openChatBoxFor(_converse, contact_jid);
var view = _converse.chatboxviews.get(contact_jid);
test_utils.waitUntil(function () {
return view.el.querySelector('.upload-file');
}, 150).then(function () {
expect(view.el.querySelector('.chat-toolbar .upload-file')).not.toBe(null);
done();
});
});
let contact_jid, view;
test_utils.waitUntilDiscoConfirmed(_converse, _converse.domain, [], [], ['upload.localhost'], 'items')
.then(() => test_utils.waitUntilDiscoConfirmed(_converse, 'upload.localhost', [], [Strophe.NS.HTTPUPLOAD], []))
.then(() => {
test_utils.createContacts(_converse, 'current', 3);
_converse.emit('rosterContactsFetched');
contact_jid = mock.cur_names[2].replace(/ /g,'.').toLowerCase() + '@localhost';
return test_utils.openChatBoxFor(_converse, contact_jid);
}).then(() => {
view = _converse.chatboxviews.get(contact_jid);
test_utils.waitUntil(() => view.el.querySelector('.upload-file'));
}).then(() => {
expect(view.el.querySelector('.chat-toolbar .upload-file')).not.toBe(null);
done();
});
});
}));
it("appears in MUC chats", mock.initConverseWithPromises(
null, ['rosterGroupsFetched'], {},
null, ['rosterGroupsFetched', 'chatBoxesFetched'], {},
function (done, _converse) {
test_utils.waitUntilDiscoConfirmed(
......@@ -251,19 +254,15 @@
[{'category': 'server', 'type':'IM'}],
['http://jabber.org/protocol/disco#items'], [], 'info').then(function () {
test_utils.waitUntilDiscoConfirmed(_converse, _converse.domain, [], [], ['upload.localhost'], 'items').then(function () {
test_utils.waitUntilDiscoConfirmed(_converse, 'upload.localhost', [], [Strophe.NS.HTTPUPLOAD], []).then(function () {
test_utils.openAndEnterChatRoom(_converse, 'lounge', 'localhost', 'dummy').then(function () {
var view = _converse.chatboxviews.get('lounge@localhost');
test_utils.waitUntil(function () {
return view.el.querySelector('.upload-file');
}).then(function () {
expect(view.el.querySelector('.chat-toolbar .upload-file')).not.toBe(null);
done();
});
});
});
});
test_utils.waitUntilDiscoConfirmed(_converse, _converse.domain, [], [], ['upload.localhost'], 'items')
.then(() => test_utils.waitUntilDiscoConfirmed(_converse, 'upload.localhost', [], [Strophe.NS.HTTPUPLOAD], []))
.then(() => test_utils.openAndEnterChatRoom(_converse, 'lounge', 'localhost', 'dummy'))
.then(() => test_utils.waitUntil(() => _converse.chatboxviews.get('lounge@localhost').el.querySelector('.upload-file')))
.then(() => {
const view = _converse.chatboxviews.get('lounge@localhost');
expect(view.el.querySelector('.chat-toolbar .upload-file')).not.toBe(null);
done();
}).catch(_.partial(_converse.log, _, Strophe.LogLevel.FATAL));
});
}));
......@@ -277,101 +276,104 @@
var send_backup = XMLHttpRequest.prototype.send;
var IQ_stanzas = _converse.connection.IQ_stanzas;
let contact_jid;
test_utils.waitUntilDiscoConfirmed(_converse, _converse.domain, [], [], ['upload.montague.tld'], 'items').then(function () {
test_utils.waitUntilDiscoConfirmed(_converse, 'upload.montague.tld', [], [Strophe.NS.HTTPUPLOAD], []).then(function () {
test_utils.createContacts(_converse, 'current');
var contact_jid = mock.cur_names[2].replace(/ /g,'.').toLowerCase() + '@localhost';
test_utils.openChatBoxFor(_converse, contact_jid);
var view = _converse.chatboxviews.get(contact_jid);
var file = {
'type': 'image/jpeg',
'size': '23456' ,
'lastModifiedDate': "",
'name': "my-juliet.jpg"
};
view.model.sendFiles([file]);
return test_utils.waitUntil(function () {
return _.filter(IQ_stanzas, function (iq) {
return iq.nodeTree.querySelector('iq[to="upload.montague.tld"] request');
}).length > 0;
}).then(function () {
var iq = IQ_stanzas.pop();
expect(iq.toLocaleString()).toBe(
"<iq from='dummy@localhost/resource' "+
"to='upload.montague.tld' "+
"type='get' "+
"xmlns='jabber:client' "+
"id='"+iq.nodeTree.getAttribute('id')+"'>"+
"<request xmlns='urn:xmpp:http:upload:0' "+
"filename='my-juliet.jpg' "+
"size='23456' "+
"content-type='image/jpeg'/>"+
"</iq>");
var base_url = document.URL.split(window.location.pathname)[0];
var message = base_url+"/logo/conversejs-filled.svg";
var stanza = Strophe.xmlHtmlNode(
"<iq from='upload.montague.tld'"+
" id='"+iq.nodeTree.getAttribute('id')+"'"+
" to='dummy@localhost/resource'"+
" type='result'>"+
"<slot xmlns='urn:xmpp:http:upload:0'>"+
" <put url='https://upload.montague.tld/4a771ac1-f0b2-4a4a-9700-f2a26fa2bb67/my-juliet.jpg'>"+
" <header name='Authorization'>Basic Base64String==</header>"+
" <header name='Cookie'>foo=bar; user=romeo</header>"+
" </put>"+
" <get url='"+message+"' />"+
"</slot>"+
"</iq>").firstElementChild;
spyOn(XMLHttpRequest.prototype, 'send').and.callFake(function () {
const message = view.model.messages.at(0);
expect(view.el.querySelector('.chat-content progress').getAttribute('value')).toBe('0');
message.set('progress', 0.5);
expect(view.el.querySelector('.chat-content progress').getAttribute('value')).toBe('0.5');
message.set('progress', 1);
expect(view.el.querySelector('.chat-content progress').getAttribute('value')).toBe('1');
message.save({
'upload': _converse.SUCCESS,
'oob_url': message.get('get'),
'message': message.get('get')
});
});
var sent_stanza;
spyOn(_converse.connection, 'send').and.callFake(function (stanza) {
sent_stanza = stanza;
test_utils.waitUntilDiscoConfirmed(_converse, _converse.domain, [], [], ['upload.montague.tld'], 'items')
.then(() => test_utils.waitUntilDiscoConfirmed(_converse, 'upload.montague.tld', [], [Strophe.NS.HTTPUPLOAD], []))
.then(() => {
test_utils.createContacts(_converse, 'current');
_converse.emit('rosterContactsFetched');
contact_jid = mock.cur_names[2].replace(/ /g,'.').toLowerCase() + '@localhost';
return test_utils.openChatBoxFor(_converse, contact_jid);
}).then(() => {
var view = _converse.chatboxviews.get(contact_jid);
var file = {
'type': 'image/jpeg',
'size': '23456' ,
'lastModifiedDate': "",
'name': "my-juliet.jpg"
};
view.model.sendFiles([file]);
return test_utils.waitUntil(function () {
return _.filter(IQ_stanzas, function (iq) {
return iq.nodeTree.querySelector('iq[to="upload.montague.tld"] request');
}).length > 0;
}).then(function () {
var iq = IQ_stanzas.pop();
expect(iq.toLocaleString()).toBe(
"<iq from='dummy@localhost/resource' "+
"to='upload.montague.tld' "+
"type='get' "+
"xmlns='jabber:client' "+
"id='"+iq.nodeTree.getAttribute('id')+"'>"+
"<request xmlns='urn:xmpp:http:upload:0' "+
"filename='my-juliet.jpg' "+
"size='23456' "+
"content-type='image/jpeg'/>"+
"</iq>");
var base_url = document.URL.split(window.location.pathname)[0];
var message = base_url+"/logo/conversejs-filled.svg";
var stanza = Strophe.xmlHtmlNode(
"<iq from='upload.montague.tld'"+
" id='"+iq.nodeTree.getAttribute('id')+"'"+
" to='dummy@localhost/resource'"+
" type='result'>"+
"<slot xmlns='urn:xmpp:http:upload:0'>"+
" <put url='https://upload.montague.tld/4a771ac1-f0b2-4a4a-9700-f2a26fa2bb67/my-juliet.jpg'>"+
" <header name='Authorization'>Basic Base64String==</header>"+
" <header name='Cookie'>foo=bar; user=romeo</header>"+
" </put>"+
" <get url='"+message+"' />"+
"</slot>"+
"</iq>").firstElementChild;
spyOn(XMLHttpRequest.prototype, 'send').and.callFake(function () {
const message = view.model.messages.at(0);
expect(view.el.querySelector('.chat-content progress').getAttribute('value')).toBe('0');
message.set('progress', 0.5);
expect(view.el.querySelector('.chat-content progress').getAttribute('value')).toBe('0.5');
message.set('progress', 1);
expect(view.el.querySelector('.chat-content progress').getAttribute('value')).toBe('1');
message.save({
'upload': _converse.SUCCESS,
'oob_url': message.get('get'),
'message': message.get('get')
});
_converse.connection._dataRecv(test_utils.createRequest(stanza));
});
var sent_stanza;
spyOn(_converse.connection, 'send').and.callFake(function (stanza) {
sent_stanza = stanza;
});
_converse.connection._dataRecv(test_utils.createRequest(stanza));
return test_utils.waitUntil(function () {
return sent_stanza;
}, 1000).then(function () {
expect(sent_stanza.toLocaleString()).toBe(
"<message from='dummy@localhost/resource' "+
"to='irini.vlastuin@localhost' "+
"type='chat' "+
"id='"+sent_stanza.nodeTree.getAttribute('id')+"' xmlns='jabber:client'>"+
"<body>"+message+"</body>"+
"<active xmlns='http://jabber.org/protocol/chatstates'/>"+
"<x xmlns='jabber:x:oob'>"+
"<url>"+message+"</url>"+
"</x>"+
"</message>");
return test_utils.waitUntil(function () {
return sent_stanza;
}, 1000).then(function () {
expect(sent_stanza.toLocaleString()).toBe(
"<message from='dummy@localhost/resource' "+
"to='irini.vlastuin@localhost' "+
"type='chat' "+
"id='"+sent_stanza.nodeTree.getAttribute('id')+"' xmlns='jabber:client'>"+
"<body>"+message+"</body>"+
"<active xmlns='http://jabber.org/protocol/chatstates'/>"+
"<x xmlns='jabber:x:oob'>"+
"<url>"+message+"</url>"+
"</x>"+
"</message>");
return test_utils.waitUntil(function () {
return view.el.querySelector('.chat-image');
}, 1000);
}).then(function () {
// Check that the image renders
expect(view.el.querySelector('.chat-msg .chat-msg__media').innerHTML.trim()).toEqual(
`<!-- src/templates/image.html -->\n`+
`<a href="${window.location.origin}/logo/conversejs-filled.svg" target="_blank" rel="noopener">`+
`<img class="chat-image img-thumbnail" src="${window.location.origin}/logo/conversejs-filled.svg">`+
`</a>`);
XMLHttpRequest.prototype.send = send_backup;
done();
});
return view.el.querySelector('.chat-image');
}, 1000);
}).then(function () {
// Check that the image renders
expect(view.el.querySelector('.chat-msg .chat-msg__media').innerHTML.trim()).toEqual(
`<!-- src/templates/image.html -->\n`+
`<a href="${window.location.origin}/logo/conversejs-filled.svg" target="_blank" rel="noopener">`+
`<img class="chat-image img-thumbnail" src="${window.location.origin}/logo/conversejs-filled.svg">`+
`</a>`);
XMLHttpRequest.prototype.send = send_backup;
done();
});
});
});
......@@ -487,56 +489,53 @@
});
}));
it("shows and error message if the file is too large", mock.initConverseWithAsync(function (done, _converse) {
var IQ_stanzas = _converse.connection.IQ_stanzas;
var IQ_ids = _converse.connection.IQ_ids;
var send_backup = XMLHttpRequest.prototype.send;
it("shows an error message if the file is too large", mock.initConverseWithAsync(function (done, _converse) {
const IQ_stanzas = _converse.connection.IQ_stanzas;
const IQ_ids = _converse.connection.IQ_ids;
const send_backup = XMLHttpRequest.prototype.send;
let view, contact_jid;
test_utils.waitUntilDiscoConfirmed(_converse, _converse.bare_jid, [], [])
.then(() => test_utils.waitUntil(() => _.filter(
IQ_stanzas, (iq) => iq.nodeTree.querySelector('iq[to="localhost"] query[xmlns="http://jabber.org/protocol/disco#info"]')).length
)).then(() => {
var stanza = _.find(IQ_stanzas, function (iq) {
return iq.nodeTree.querySelector(
'iq[to="localhost"] query[xmlns="http://jabber.org/protocol/disco#info"]');
});
var info_IQ_id = IQ_ids[IQ_stanzas.indexOf(stanza)];
test_utils.waitUntilDiscoConfirmed(_converse, _converse.bare_jid, [], []).then(function () {
test_utils.waitUntil(function () {
stanza = $iq({
'type': 'result',
'from': 'localhost',
'to': 'dummy@localhost/resource',
'id': info_IQ_id
}).c('query', {'xmlns': 'http://jabber.org/protocol/disco#info'})
.c('identity', {
'category': 'server',
'type': 'im'}).up()
.c('feature', {
'var': 'http://jabber.org/protocol/disco#info'}).up()
.c('feature', {
'var': 'http://jabber.org/protocol/disco#items'});
_converse.connection._dataRecv(test_utils.createRequest(stanza));
return _converse.api.disco.entities.get();
}).then(function (entities) {
expect(entities.length).toBe(2);
expect(_.includes(entities.pluck('jid'), 'localhost')).toBe(true);
expect(_.includes(entities.pluck('jid'), 'dummy@localhost')).toBe(true);
expect(entities.get(_converse.domain).features.length).toBe(2);
expect(entities.get(_converse.domain).identities.length).toBe(1);
return test_utils.waitUntil(function () {
// Converse.js sees that the entity has a disco#items feature,
// so it will make a query for it.
return _.filter(IQ_stanzas, function (iq) {
return iq.nodeTree.querySelector(
'iq[to="localhost"] query[xmlns="http://jabber.org/protocol/disco#info"]');
return iq.nodeTree.querySelector('iq[to="localhost"] query[xmlns="http://jabber.org/protocol/disco#items"]');
}).length > 0;
}, 300).then(function () {
var stanza = _.find(IQ_stanzas, function (iq) {
return iq.nodeTree.querySelector(
'iq[to="localhost"] query[xmlns="http://jabber.org/protocol/disco#info"]');
});
var info_IQ_id = IQ_ids[IQ_stanzas.indexOf(stanza)];
stanza = $iq({
'type': 'result',
'from': 'localhost',
'to': 'dummy@localhost/resource',
'id': info_IQ_id
}).c('query', {'xmlns': 'http://jabber.org/protocol/disco#info'})
.c('identity', {
'category': 'server',
'type': 'im'}).up()
.c('feature', {
'var': 'http://jabber.org/protocol/disco#info'}).up()
.c('feature', {
'var': 'http://jabber.org/protocol/disco#items'});
_converse.connection._dataRecv(test_utils.createRequest(stanza));
_converse.api.disco.entities.get().then(function(entities) {
expect(entities.length).toBe(2);
expect(_.includes(entities.pluck('jid'), 'localhost')).toBe(true);
expect(_.includes(entities.pluck('jid'), 'dummy@localhost')).toBe(true);
expect(entities.get(_converse.domain).features.length).toBe(2);
expect(entities.get(_converse.domain).identities.length).toBe(1);
return test_utils.waitUntil(function () {
// Converse.js sees that the entity has a disco#items feature,
// so it will make a query for it.
return _.filter(IQ_stanzas, function (iq) {
return iq.nodeTree.querySelector('iq[to="localhost"] query[xmlns="http://jabber.org/protocol/disco#items"]');
}).length > 0;
}, 300);
});
}).then(function () {
}, 300);
}).then(function () {
var stanza = _.find(IQ_stanzas, function (iq) {
return iq.nodeTree.querySelector('iq[to="localhost"] query[xmlns="http://jabber.org/protocol/disco#items"]');
});
......@@ -550,77 +549,77 @@
.c('item', {
'jid': 'upload.localhost',
'name': 'HTTP File Upload'});
_converse.connection._dataRecv(test_utils.createRequest(stanza));
_converse.api.disco.entities.get().then(function (entities) {
expect(entities.length).toBe(2);
expect(entities.get('localhost').items.length).toBe(1);
return test_utils.waitUntil(function () {
// Converse.js sees that the entity has a disco#info feature,
// so it will make a query for it.
return _.filter(IQ_stanzas, function (iq) {
return iq.nodeTree.querySelector('iq[to="upload.localhost"] query[xmlns="http://jabber.org/protocol/disco#info"]');
}).length > 0;
}, 300);
});
}).then(function () {
var stanza = _.find(IQ_stanzas, function (iq) {
return iq.nodeTree.querySelector('iq[to="upload.localhost"] query[xmlns="http://jabber.org/protocol/disco#info"]');
});
var IQ_id = IQ_ids[IQ_stanzas.indexOf(stanza)];
expect(stanza.toLocaleString()).toBe(
"<iq from='dummy@localhost/resource' to='upload.localhost' type='get' xmlns='jabber:client' id='"+IQ_id+"'>"+
"<query xmlns='http://jabber.org/protocol/disco#info'/>"+
"</iq>");
// Upload service responds and reports a maximum file size of 5MiB
stanza = $iq({'type': 'result', 'to': 'dummy@localhost/resource', 'id': IQ_id, 'from': 'upload.localhost'})
.c('query', {'xmlns': 'http://jabber.org/protocol/disco#info'})
.c('identity', {'category':'store', 'type':'file', 'name':'HTTP File Upload'}).up()
.c('feature', {'var':'urn:xmpp:http:upload:0'}).up()
.c('x', {'type':'result', 'xmlns':'jabber:x:data'})
.c('field', {'var':'FORM_TYPE', 'type':'hidden'})
.c('value').t('urn:xmpp:http:upload:0').up().up()
.c('field', {'var':'max-file-size'})
.c('value').t('5242880');
_converse.connection._dataRecv(test_utils.createRequest(stanza));
_converse.api.disco.entities.get().then(function (entities) {
expect(entities.get('localhost').items.get('upload.localhost').identities.where({'category': 'store'}).length).toBe(1);
_converse.api.disco.supports(Strophe.NS.HTTPUPLOAD, _converse.domain).then(
function (result) {
test_utils.createContacts(_converse, 'current');
var contact_jid = mock.cur_names[2].replace(/ /g,'.').toLowerCase() + '@localhost';
test_utils.openChatBoxFor(_converse, contact_jid);
var view = _converse.chatboxviews.get(contact_jid);
var file = {
'type': 'image/jpeg',
'size': '5242881',
'lastModifiedDate': "",
'name': "my-juliet.jpg"
};
view.model.sendFiles([file]);
return test_utils.waitUntil(function () {
return view.el.querySelectorAll('.message').length;
}).then(function () {
const messages = view.el.querySelectorAll('.message.chat-error');
expect(messages.length).toBe(1);
expect(messages[0].textContent).toBe(
'The size of your file, my-juliet.jpg, exceeds the maximum allowed by your server, which is 5 MB.');
done();
});
}
);
}).catch(_.partial(_converse.log, _, Strophe.LogLevel.FATAL));
})
});
_converse.connection._dataRecv(test_utils.createRequest(stanza));
_converse.api.disco.entities.get().then(function (entities) {
expect(entities.length).toBe(2);
expect(entities.get('localhost').items.length).toBe(1);
return test_utils.waitUntil(function () {
// Converse.js sees that the entity has a disco#info feature,
// so it will make a query for it.
return _.filter(IQ_stanzas, function (iq) {
return iq.nodeTree.querySelector('iq[to="upload.localhost"] query[xmlns="http://jabber.org/protocol/disco#info"]');
}).length > 0;
}, 300);
});
}).then(function () {
var stanza = _.find(IQ_stanzas, function (iq) {
return iq.nodeTree.querySelector('iq[to="upload.localhost"] query[xmlns="http://jabber.org/protocol/disco#info"]');
});
var IQ_id = IQ_ids[IQ_stanzas.indexOf(stanza)];
expect(stanza.toLocaleString()).toBe(
"<iq from='dummy@localhost/resource' to='upload.localhost' type='get' xmlns='jabber:client' id='"+IQ_id+"'>"+
"<query xmlns='http://jabber.org/protocol/disco#info'/>"+
"</iq>");
// Upload service responds and reports a maximum file size of 5MiB
stanza = $iq({'type': 'result', 'to': 'dummy@localhost/resource', 'id': IQ_id, 'from': 'upload.localhost'})
.c('query', {'xmlns': 'http://jabber.org/protocol/disco#info'})
.c('identity', {'category':'store', 'type':'file', 'name':'HTTP File Upload'}).up()
.c('feature', {'var':'urn:xmpp:http:upload:0'}).up()
.c('x', {'type':'result', 'xmlns':'jabber:x:data'})
.c('field', {'var':'FORM_TYPE', 'type':'hidden'})
.c('value').t('urn:xmpp:http:upload:0').up().up()
.c('field', {'var':'max-file-size'})
.c('value').t('5242880');
_converse.connection._dataRecv(test_utils.createRequest(stanza));
return _converse.api.disco.entities.get();
}).then(function (entities) {
expect(entities.get('localhost').items.get('upload.localhost').identities.where({'category': 'store'}).length).toBe(1);
return _converse.api.disco.supports(Strophe.NS.HTTPUPLOAD, _converse.domain);
}).then(function (result) {
test_utils.createContacts(_converse, 'current');
_converse.emit('rosterContactsFetched');
contact_jid = mock.cur_names[2].replace(/ /g,'.').toLowerCase() + '@localhost';
return test_utils.openChatBoxFor(_converse, contact_jid);
}).then(() => {
view = _converse.chatboxviews.get(contact_jid);
var file = {
'type': 'image/jpeg',
'size': '5242881',
'lastModifiedDate': "",
'name': "my-juliet.jpg"
};
view.model.sendFiles([file]);
return test_utils.waitUntil(() => view.el.querySelectorAll('.message').length)
}).then(function () {
const messages = view.el.querySelectorAll('.message.chat-error');
expect(messages.length).toBe(1);
expect(messages[0].textContent).toBe(
'The size of your file, my-juliet.jpg, exceeds the maximum allowed by your server, which is 5 MB.');
done();
}).catch(_.partial(_converse.log, _, Strophe.LogLevel.FATAL))
}));
});
});
describe("While a file is being uploaded", function () {
it("shows a progress bar", mock.initConverseWithAsync(function (done, _converse) {
it("shows a progress bar", mock.initConverseWithPromises(
null, ['rosterGroupsFetched', 'chatBoxesFetched'], {}, function (done, _converse) {
test_utils.waitUntilDiscoConfirmed(
_converse, _converse.domain,
[{'category': 'server', 'type':'IM'}],
......@@ -628,77 +627,74 @@
var send_backup = XMLHttpRequest.prototype.send;
var IQ_stanzas = _converse.connection.IQ_stanzas;
test_utils.waitUntilDiscoConfirmed(_converse, _converse.domain, [], [], ['upload.montague.tld'], 'items').then(function () {
test_utils.waitUntilDiscoConfirmed(_converse, 'upload.montague.tld', [], [Strophe.NS.HTTPUPLOAD], []).then(function () {
test_utils.createContacts(_converse, 'current');
var contact_jid = mock.cur_names[2].replace(/ /g,'.').toLowerCase() + '@localhost';
test_utils.openChatBoxFor(_converse, contact_jid);
var view = _converse.chatboxviews.get(contact_jid);
var file = {
'type': 'image/jpeg',
'size': '23456' ,
'lastModifiedDate': "",
'name': "my-juliet.jpg"
};
view.model.sendFiles([file]);
return test_utils.waitUntil(function () {
return _.filter(IQ_stanzas, function (iq) {
return iq.nodeTree.querySelector('iq[to="upload.montague.tld"] request');
}).length > 0;
}).then(function () {
var iq = IQ_stanzas.pop();
expect(iq.toLocaleString()).toBe(
"<iq from='dummy@localhost/resource' "+
"to='upload.montague.tld' "+
"type='get' "+
"xmlns='jabber:client' "+
"id='"+iq.nodeTree.getAttribute('id')+"'>"+
"<request xmlns='urn:xmpp:http:upload:0' "+
"filename='my-juliet.jpg' "+
"size='23456' "+
"content-type='image/jpeg'/>"+
"</iq>");
var base_url = document.URL.split(window.location.pathname)[0];
var message = base_url+"/logo/conversejs-filled.svg";
var stanza = Strophe.xmlHtmlNode(
"<iq from='upload.montague.tld'"+
" id='"+iq.nodeTree.getAttribute('id')+"'"+
" to='dummy@localhost/resource'"+
" type='result'>"+
"<slot xmlns='urn:xmpp:http:upload:0'>"+
" <put url='https://upload.montague.tld/4a771ac1-f0b2-4a4a-9700-f2a26fa2bb67/my-juliet.jpg'>"+
" <header name='Authorization'>Basic Base64String==</header>"+
" <header name='Cookie'>foo=bar; user=romeo</header>"+
" </put>"+
" <get url='"+message+"' />"+
"</slot>"+
"</iq>").firstElementChild;
spyOn(XMLHttpRequest.prototype, 'send').and.callFake(function () {
const message = view.model.messages.at(0);
expect(view.el.querySelector('.chat-content progress').getAttribute('value')).toBe('0');
message.set('progress', 0.5);
expect(view.el.querySelector('.chat-content progress').getAttribute('value')).toBe('0.5');
message.set('progress', 1);
expect(view.el.querySelector('.chat-content progress').getAttribute('value')).toBe('1');
expect(view.el.querySelector('.chat-content .chat-msg__text').textContent).toBe('Uploading file: my-juliet.jpg, 22.91 KB');
done();
});
var sent_stanza;
spyOn(_converse.connection, 'send').and.callFake(function (stanza) {
sent_stanza = stanza;
});
_converse.connection._dataRecv(test_utils.createRequest(stanza));
});
let view, contact_jid;
test_utils.waitUntilDiscoConfirmed(_converse, _converse.domain, [], [], ['upload.montague.tld'], 'items')
.then(() => test_utils.waitUntilDiscoConfirmed(_converse, 'upload.montague.tld', [], [Strophe.NS.HTTPUPLOAD], []))
.then(() => {
test_utils.createContacts(_converse, 'current');
_converse.emit('rosterContactsFetched');
contact_jid = mock.cur_names[2].replace(/ /g,'.').toLowerCase() + '@localhost';
return test_utils.openChatBoxFor(_converse, contact_jid);
}).then(() => {
view = _converse.chatboxviews.get(contact_jid);
const file = {
'type': 'image/jpeg',
'size': '23456' ,
'lastModifiedDate': "",
'name': "my-juliet.jpg"
};
view.model.sendFiles([file]);
return test_utils.waitUntil(() => _.filter(IQ_stanzas, (iq) => iq.nodeTree.querySelector('iq[to="upload.montague.tld"] request')).length)
}).then(function () {
const iq = IQ_stanzas.pop();
expect(iq.toLocaleString()).toBe(
"<iq from='dummy@localhost/resource' "+
"to='upload.montague.tld' "+
"type='get' "+
"xmlns='jabber:client' "+
"id='"+iq.nodeTree.getAttribute('id')+"'>"+
"<request xmlns='urn:xmpp:http:upload:0' "+
"filename='my-juliet.jpg' "+
"size='23456' "+
"content-type='image/jpeg'/>"+
"</iq>");
const base_url = document.URL.split(window.location.pathname)[0];
const message = base_url+"/logo/conversejs-filled.svg";
const stanza = Strophe.xmlHtmlNode(
"<iq from='upload.montague.tld'"+
" id='"+iq.nodeTree.getAttribute('id')+"'"+
" to='dummy@localhost/resource'"+
" type='result'>"+
"<slot xmlns='urn:xmpp:http:upload:0'>"+
" <put url='https://upload.montague.tld/4a771ac1-f0b2-4a4a-9700-f2a26fa2bb67/my-juliet.jpg'>"+
" <header name='Authorization'>Basic Base64String==</header>"+
" <header name='Cookie'>foo=bar; user=romeo</header>"+
" </put>"+
" <get url='"+message+"' />"+
"</slot>"+
"</iq>").firstElementChild;
spyOn(XMLHttpRequest.prototype, 'send').and.callFake(function () {
const message = view.model.messages.at(0);
expect(view.el.querySelector('.chat-content progress').getAttribute('value')).toBe('0');
message.set('progress', 0.5);
expect(view.el.querySelector('.chat-content progress').getAttribute('value')).toBe('0.5');
message.set('progress', 1);
expect(view.el.querySelector('.chat-content progress').getAttribute('value')).toBe('1');
expect(view.el.querySelector('.chat-content .chat-msg__text').textContent).toBe('Uploading file: my-juliet.jpg, 22.91 KB');
done();
});
var sent_stanza;
spyOn(_converse.connection, 'send').and.callFake(function (stanza) {
sent_stanza = stanza;
});
_converse.connection._dataRecv(test_utils.createRequest(stanza));
});
});
}));
});
});
});
}));
......@@ -21,247 +21,251 @@
it("can be sent as a correction by clicking the pencil icon",
mock.initConverseWithPromises(
null, ['rosterGroupsFetched'], {},
null, ['rosterGroupsFetched', 'chatBoxesFetched'], {},
function (done, _converse) {
test_utils.createContacts(_converse, 'current', 1);
_converse.emit('rosterContactsFetched');
test_utils.openControlBox();
const contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@localhost';
test_utils.openChatBoxFor(_converse, contact_jid);
test_utils.openChatBoxFor(_converse, contact_jid)
.then(() => {
const view = _converse.chatboxviews.get(contact_jid);
const textarea = view.el.querySelector('textarea.chat-textarea');
const view = _converse.chatboxviews.get(contact_jid);
const textarea = view.el.querySelector('textarea.chat-textarea');
textarea.value = 'But soft, what light through yonder airlock breaks?';
view.keyPressed({
target: textarea,
preventDefault: _.noop,
keyCode: 13 // Enter
});
expect(view.el.querySelectorAll('.chat-msg').length).toBe(1);
expect(view.el.querySelector('.chat-msg__text').textContent)
.toBe('But soft, what light through yonder airlock breaks?');
expect(textarea.value).toBe('');
textarea.value = 'But soft, what light through yonder airlock breaks?';
view.keyPressed({
target: textarea,
preventDefault: _.noop,
keyCode: 13 // Enter
});
expect(view.el.querySelectorAll('.chat-msg').length).toBe(1);
expect(view.el.querySelector('.chat-msg__text').textContent)
.toBe('But soft, what light through yonder airlock breaks?');
expect(textarea.value).toBe('');
const first_msg = view.model.messages.findWhere({'message': 'But soft, what light through yonder airlock breaks?'});
expect(view.el.querySelectorAll('.chat-msg .chat-msg__action').length).toBe(1);
let action = view.el.querySelector('.chat-msg .chat-msg__action');
expect(action.getAttribute('title')).toBe('Edit this message');
action.style.opacity = 1;
action.click();
expect(textarea.value).toBe('But soft, what light through yonder airlock breaks?');
expect(view.model.messages.at(0).get('correcting')).toBe(true);
expect(view.el.querySelectorAll('.chat-msg').length).toBe(1);
expect(u.hasClass('correcting', view.el.querySelector('.chat-msg'))).toBe(true);
spyOn(_converse.connection, 'send');
textarea.value = 'But soft, what light through yonder window breaks?';
view.keyPressed({
target: textarea,
preventDefault: _.noop,
keyCode: 13 // Enter
const first_msg = view.model.messages.findWhere({'message': 'But soft, what light through yonder airlock breaks?'});
expect(view.el.querySelectorAll('.chat-msg .chat-msg__action').length).toBe(1);
let action = view.el.querySelector('.chat-msg .chat-msg__action');
expect(action.getAttribute('title')).toBe('Edit this message');
action.style.opacity = 1;
action.click();
expect(textarea.value).toBe('But soft, what light through yonder airlock breaks?');
expect(view.model.messages.at(0).get('correcting')).toBe(true);
expect(view.el.querySelectorAll('.chat-msg').length).toBe(1);
expect(u.hasClass('correcting', view.el.querySelector('.chat-msg'))).toBe(true);
spyOn(_converse.connection, 'send');
textarea.value = 'But soft, what light through yonder window breaks?';
view.keyPressed({
target: textarea,
preventDefault: _.noop,
keyCode: 13 // Enter
});
expect(_converse.connection.send).toHaveBeenCalled();
const msg = _converse.connection.send.calls.all()[0].args[0];
expect(msg.toLocaleString())
.toBe(`<message from='dummy@localhost/resource' `+
`to='max.frankfurter@localhost' type='chat' id='${msg.nodeTree.getAttribute('id')}' `+
`xmlns='jabber:client'>`+
`<body>But soft, what light through yonder window breaks?</body>`+
`<active xmlns='http://jabber.org/protocol/chatstates'/>`+
`<replace xmlns='urn:xmpp:message-correct:0' id='${first_msg.get('msgid')}'/>`+
`</message>`);
expect(view.model.messages.models.length).toBe(1);
const corrected_message = view.model.messages.at(0);
expect(corrected_message.get('msgid')).toBe(first_msg.get('msgid'));
expect(corrected_message.get('correcting')).toBe(false);
expect(corrected_message.get('older_versions').length).toBe(1);
expect(corrected_message.get('older_versions')[0]).toBe('But soft, what light through yonder airlock breaks?');
expect(view.el.querySelectorAll('.chat-msg').length).toBe(1);
expect(u.hasClass('correcting', view.el.querySelector('.chat-msg'))).toBe(false);
// Test that clicking the pencil icon a second time cancels editing.
action = view.el.querySelector('.chat-msg .chat-msg__action');
action.style.opacity = 1;
action.click();
expect(textarea.value).toBe('But soft, what light through yonder window breaks?');
expect(view.model.messages.at(0).get('correcting')).toBe(true);
expect(view.el.querySelectorAll('.chat-msg').length).toBe(1);
expect(u.hasClass('correcting', view.el.querySelector('.chat-msg'))).toBe(true);
action = view.el.querySelector('.chat-msg .chat-msg__action');
action.style.opacity = 1;
action.click();
expect(textarea.value).toBe('');
expect(view.model.messages.at(0).get('correcting')).toBe(false);
expect(view.el.querySelectorAll('.chat-msg').length).toBe(1);
expect(u.hasClass('correcting', view.el.querySelector('.chat-msg'))).toBe(false);
// Test that messages from other users don't have the pencil icon
_converse.chatboxes.onMessage(
$msg({
'from': contact_jid,
'to': _converse.connection.jid,
'type': 'chat',
'id': (new Date()).getTime()
}).c('body').t('Hello').up()
.c('active', {'xmlns': 'http://jabber.org/protocol/chatstates'}).tree()
);
expect(view.el.querySelectorAll('.chat-msg .chat-msg__action').length).toBe(1);
done();
});
expect(_converse.connection.send).toHaveBeenCalled();
const msg = _converse.connection.send.calls.all()[0].args[0];
expect(msg.toLocaleString())
.toBe(`<message from='dummy@localhost/resource' `+
`to='max.frankfurter@localhost' type='chat' id='${msg.nodeTree.getAttribute('id')}' `+
`xmlns='jabber:client'>`+
`<body>But soft, what light through yonder window breaks?</body>`+
`<active xmlns='http://jabber.org/protocol/chatstates'/>`+
`<replace xmlns='urn:xmpp:message-correct:0' id='${first_msg.get('msgid')}'/>`+
`</message>`);
expect(view.model.messages.models.length).toBe(1);
const corrected_message = view.model.messages.at(0);
expect(corrected_message.get('msgid')).toBe(first_msg.get('msgid'));
expect(corrected_message.get('correcting')).toBe(false);
expect(corrected_message.get('older_versions').length).toBe(1);
expect(corrected_message.get('older_versions')[0]).toBe('But soft, what light through yonder airlock breaks?');
expect(view.el.querySelectorAll('.chat-msg').length).toBe(1);
expect(u.hasClass('correcting', view.el.querySelector('.chat-msg'))).toBe(false);
// Test that clicking the pencil icon a second time cancels editing.
action = view.el.querySelector('.chat-msg .chat-msg__action');
action.style.opacity = 1;
action.click();
expect(textarea.value).toBe('But soft, what light through yonder window breaks?');
expect(view.model.messages.at(0).get('correcting')).toBe(true);
expect(view.el.querySelectorAll('.chat-msg').length).toBe(1);
expect(u.hasClass('correcting', view.el.querySelector('.chat-msg'))).toBe(true);
action = view.el.querySelector('.chat-msg .chat-msg__action');
action.style.opacity = 1;
action.click();
expect(textarea.value).toBe('');
expect(view.model.messages.at(0).get('correcting')).toBe(false);
expect(view.el.querySelectorAll('.chat-msg').length).toBe(1);
expect(u.hasClass('correcting', view.el.querySelector('.chat-msg'))).toBe(false);
// Test that messages from other users don't have the pencil icon
_converse.chatboxes.onMessage(
$msg({
'from': contact_jid,
'to': _converse.connection.jid,
'type': 'chat',
'id': (new Date()).getTime()
}).c('body').t('Hello').up()
.c('active', {'xmlns': 'http://jabber.org/protocol/chatstates'}).tree()
);
expect(view.el.querySelectorAll('.chat-msg .chat-msg__action').length).toBe(1);
done();
}));
it("can be sent as a correction by using the up arrow",
mock.initConverseWithPromises(
null, ['rosterGroupsFetched'], {},
null, ['rosterGroupsFetched', 'chatBoxesFetched'], {},
function (done, _converse) {
test_utils.createContacts(_converse, 'current', 1);
_converse.emit('rosterContactsFetched');
test_utils.openControlBox();
const contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@localhost';
test_utils.openChatBoxFor(_converse, contact_jid);
test_utils.openChatBoxFor(_converse, contact_jid)
.then(() => {
const view = _converse.chatboxviews.get(contact_jid);
const textarea = view.el.querySelector('textarea.chat-textarea');
expect(textarea.value).toBe('');
view.keyPressed({
target: textarea,
keyCode: 38 // Up arrow
});
expect(textarea.value).toBe('');
const view = _converse.chatboxviews.get(contact_jid);
const textarea = view.el.querySelector('textarea.chat-textarea');
expect(textarea.value).toBe('');
view.keyPressed({
target: textarea,
keyCode: 38 // Up arrow
});
expect(textarea.value).toBe('');
textarea.value = 'But soft, what light through yonder airlock breaks?';
view.keyPressed({
target: textarea,
preventDefault: _.noop,
keyCode: 13 // Enter
});
expect(view.el.querySelectorAll('.chat-msg').length).toBe(1);
expect(view.el.querySelector('.chat-msg__text').textContent)
.toBe('But soft, what light through yonder airlock breaks?');
textarea.value = 'But soft, what light through yonder airlock breaks?';
view.keyPressed({
target: textarea,
preventDefault: _.noop,
keyCode: 13 // Enter
});
expect(view.el.querySelectorAll('.chat-msg').length).toBe(1);
expect(view.el.querySelector('.chat-msg__text').textContent)
.toBe('But soft, what light through yonder airlock breaks?');
const first_msg = view.model.messages.findWhere({'message': 'But soft, what light through yonder airlock breaks?'});
expect(textarea.value).toBe('');
view.keyPressed({
target: textarea,
keyCode: 38 // Up arrow
});
expect(textarea.value).toBe('But soft, what light through yonder airlock breaks?');
expect(view.model.messages.at(0).get('correcting')).toBe(true);
expect(view.el.querySelectorAll('.chat-msg').length).toBe(1);
expect(u.hasClass('correcting', view.el.querySelector('.chat-msg'))).toBe(true);
spyOn(_converse.connection, 'send');
textarea.value = 'But soft, what light through yonder window breaks?';
view.keyPressed({
target: textarea,
preventDefault: _.noop,
keyCode: 13 // Enter
});
expect(_converse.connection.send).toHaveBeenCalled();
const msg = _converse.connection.send.calls.all()[0].args[0];
expect(msg.toLocaleString())
.toBe(`<message from='dummy@localhost/resource' `+
`to='max.frankfurter@localhost' type='chat' id='${msg.nodeTree.getAttribute('id')}' `+
`xmlns='jabber:client'>`+
`<body>But soft, what light through yonder window breaks?</body>`+
`<active xmlns='http://jabber.org/protocol/chatstates'/>`+
`<replace xmlns='urn:xmpp:message-correct:0' id='${first_msg.get('msgid')}'/>`+
`</message>`);
expect(view.model.messages.models.length).toBe(1);
const corrected_message = view.model.messages.at(0);
expect(corrected_message.get('msgid')).toBe(first_msg.get('msgid'));
expect(corrected_message.get('correcting')).toBe(false);
expect(corrected_message.get('older_versions').length).toBe(1);
expect(corrected_message.get('older_versions')[0]).toBe('But soft, what light through yonder airlock breaks?');
expect(view.el.querySelectorAll('.chat-msg').length).toBe(1);
expect(u.hasClass('correcting', view.el.querySelector('.chat-msg'))).toBe(false);
// Test that pressing the down arrow cancels message correction
expect(textarea.value).toBe('');
view.keyPressed({
target: textarea,
keyCode: 38 // Up arrow
});
expect(textarea.value).toBe('But soft, what light through yonder window breaks?');
expect(view.model.messages.at(0).get('correcting')).toBe(true);
expect(view.el.querySelectorAll('.chat-msg').length).toBe(1);
expect(u.hasClass('correcting', view.el.querySelector('.chat-msg'))).toBe(true);
expect(textarea.value).toBe('But soft, what light through yonder window breaks?');
view.keyPressed({
target: textarea,
keyCode: 40 // Down arrow
});
expect(textarea.value).toBe('');
expect(view.model.messages.at(0).get('correcting')).toBe(false);
expect(view.el.querySelectorAll('.chat-msg').length).toBe(1);
expect(u.hasClass('correcting', view.el.querySelector('.chat-msg'))).toBe(false);
textarea.value = 'It is the east, and Juliet is the one.';
view.keyPressed({
target: textarea,
preventDefault: _.noop,
keyCode: 13 // Enter
});
expect(view.el.querySelectorAll('.chat-msg').length).toBe(2);
const first_msg = view.model.messages.findWhere({'message': 'But soft, what light through yonder airlock breaks?'});
expect(textarea.value).toBe('');
view.keyPressed({
target: textarea,
keyCode: 38 // Up arrow
});
expect(textarea.value).toBe('But soft, what light through yonder airlock breaks?');
expect(view.model.messages.at(0).get('correcting')).toBe(true);
expect(view.el.querySelectorAll('.chat-msg').length).toBe(1);
expect(u.hasClass('correcting', view.el.querySelector('.chat-msg'))).toBe(true);
textarea.value = 'Arise, fair sun, and kill the envious moon';
view.keyPressed({
target: textarea,
preventDefault: _.noop,
keyCode: 13 // Enter
});
expect(view.el.querySelectorAll('.chat-msg').length).toBe(3);
spyOn(_converse.connection, 'send');
textarea.value = 'But soft, what light through yonder window breaks?';
view.keyPressed({
target: textarea,
preventDefault: _.noop,
keyCode: 13 // Enter
});
expect(_converse.connection.send).toHaveBeenCalled();
view.keyPressed({
target: textarea,
keyCode: 38 // Up arrow
});
expect(textarea.value).toBe('Arise, fair sun, and kill the envious moon');
expect(view.model.messages.at(0).get('correcting')).toBeFalsy();
expect(view.model.messages.at(1).get('correcting')).toBeFalsy();
expect(view.model.messages.at(2).get('correcting')).toBe(true);
textarea.selectionEnd = 0; // Happens by pressing up,
// but for some reason not in tests, so we set it manually.
view.keyPressed({
target: textarea,
keyCode: 38 // Up arrow
});
expect(textarea.value).toBe('It is the east, and Juliet is the one.');
expect(view.model.messages.at(0).get('correcting')).toBeFalsy();
expect(view.model.messages.at(1).get('correcting')).toBe(true);
expect(view.model.messages.at(2).get('correcting')).toBeFalsy();
textarea.value = 'It is the east, and Juliet is the sun.';
view.keyPressed({
target: textarea,
preventDefault: _.noop,
keyCode: 13 // Enter
const msg = _converse.connection.send.calls.all()[0].args[0];
expect(msg.toLocaleString())
.toBe(`<message from='dummy@localhost/resource' `+
`to='max.frankfurter@localhost' type='chat' id='${msg.nodeTree.getAttribute('id')}' `+
`xmlns='jabber:client'>`+
`<body>But soft, what light through yonder window breaks?</body>`+
`<active xmlns='http://jabber.org/protocol/chatstates'/>`+
`<replace xmlns='urn:xmpp:message-correct:0' id='${first_msg.get('msgid')}'/>`+
`</message>`);
expect(view.model.messages.models.length).toBe(1);
const corrected_message = view.model.messages.at(0);
expect(corrected_message.get('msgid')).toBe(first_msg.get('msgid'));
expect(corrected_message.get('correcting')).toBe(false);
expect(corrected_message.get('older_versions').length).toBe(1);
expect(corrected_message.get('older_versions')[0]).toBe('But soft, what light through yonder airlock breaks?');
expect(view.el.querySelectorAll('.chat-msg').length).toBe(1);
expect(u.hasClass('correcting', view.el.querySelector('.chat-msg'))).toBe(false);
// Test that pressing the down arrow cancels message correction
expect(textarea.value).toBe('');
view.keyPressed({
target: textarea,
keyCode: 38 // Up arrow
});
expect(textarea.value).toBe('But soft, what light through yonder window breaks?');
expect(view.model.messages.at(0).get('correcting')).toBe(true);
expect(view.el.querySelectorAll('.chat-msg').length).toBe(1);
expect(u.hasClass('correcting', view.el.querySelector('.chat-msg'))).toBe(true);
expect(textarea.value).toBe('But soft, what light through yonder window breaks?');
view.keyPressed({
target: textarea,
keyCode: 40 // Down arrow
});
expect(textarea.value).toBe('');
expect(view.model.messages.at(0).get('correcting')).toBe(false);
expect(view.el.querySelectorAll('.chat-msg').length).toBe(1);
expect(u.hasClass('correcting', view.el.querySelector('.chat-msg'))).toBe(false);
textarea.value = 'It is the east, and Juliet is the one.';
view.keyPressed({
target: textarea,
preventDefault: _.noop,
keyCode: 13 // Enter
});
expect(view.el.querySelectorAll('.chat-msg').length).toBe(2);
textarea.value = 'Arise, fair sun, and kill the envious moon';
view.keyPressed({
target: textarea,
preventDefault: _.noop,
keyCode: 13 // Enter
});
expect(view.el.querySelectorAll('.chat-msg').length).toBe(3);
view.keyPressed({
target: textarea,
keyCode: 38 // Up arrow
});
expect(textarea.value).toBe('Arise, fair sun, and kill the envious moon');
expect(view.model.messages.at(0).get('correcting')).toBeFalsy();
expect(view.model.messages.at(1).get('correcting')).toBeFalsy();
expect(view.model.messages.at(2).get('correcting')).toBe(true);
textarea.selectionEnd = 0; // Happens by pressing up,
// but for some reason not in tests, so we set it manually.
view.keyPressed({
target: textarea,
keyCode: 38 // Up arrow
});
expect(textarea.value).toBe('It is the east, and Juliet is the one.');
expect(view.model.messages.at(0).get('correcting')).toBeFalsy();
expect(view.model.messages.at(1).get('correcting')).toBe(true);
expect(view.model.messages.at(2).get('correcting')).toBeFalsy();
textarea.value = 'It is the east, and Juliet is the sun.';
view.keyPressed({
target: textarea,
preventDefault: _.noop,
keyCode: 13 // Enter
});
expect(textarea.value).toBe('');
const messages = view.el.querySelectorAll('.chat-msg');
expect(messages.length).toBe(3);
expect(messages[0].querySelector('.chat-msg__text').textContent)
.toBe('But soft, what light through yonder window breaks?');
expect(messages[1].querySelector('.chat-msg__text').textContent)
.toBe('It is the east, and Juliet is the sun.');
expect(messages[2].querySelector('.chat-msg__text').textContent)
.toBe('Arise, fair sun, and kill the envious moon');
expect(view.model.messages.at(0).get('correcting')).toBeFalsy();
expect(view.model.messages.at(1).get('correcting')).toBeFalsy();
expect(view.model.messages.at(2).get('correcting')).toBeFalsy();
done();
});
expect(textarea.value).toBe('');
const messages = view.el.querySelectorAll('.chat-msg');
expect(messages.length).toBe(3);
expect(messages[0].querySelector('.chat-msg__text').textContent)
.toBe('But soft, what light through yonder window breaks?');
expect(messages[1].querySelector('.chat-msg__text').textContent)
.toBe('It is the east, and Juliet is the sun.');
expect(messages[2].querySelector('.chat-msg__text').textContent)
.toBe('Arise, fair sun, and kill the envious moon');
expect(view.model.messages.at(0).get('correcting')).toBeFalsy();
expect(view.model.messages.at(1).get('correcting')).toBeFalsy();
expect(view.model.messages.at(2).get('correcting')).toBeFalsy();
done();
}));
......@@ -321,65 +325,67 @@
it("can be replaced with a correction",
mock.initConverseWithPromises(
null, ['rosterGroupsFetched'], {},
null, ['rosterGroupsFetched', 'chatBoxesFetched'], {},
function (done, _converse) {
test_utils.createContacts(_converse, 'current', 1);
_converse.emit('rosterContactsFetched');
test_utils.openControlBox();
const message = 'This is a received message';
const sender_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@localhost';
test_utils.openChatBoxFor(_converse, sender_jid);
const msg_id = u.getUniqueId();
_converse.chatboxes.onMessage($msg({
'from': sender_jid,
'to': _converse.connection.jid,
'type': 'chat',
'id': msg_id,
}).c('body').t('But soft, what light through yonder airlock breaks?').tree());
var chatboxview = _converse.chatboxviews.get(sender_jid);
expect(chatboxview.el.querySelectorAll('.chat-msg').length).toBe(1);
expect(chatboxview.el.querySelector('.chat-msg__text').textContent)
.toBe('But soft, what light through yonder airlock breaks?');
_converse.chatboxes.onMessage($msg({
'from': sender_jid,
'to': _converse.connection.jid,
'type': 'chat',
'id': u.getUniqueId(),
}).c('body').t('But soft, what light through yonder chimney breaks?').up()
.c('replace', {'id': msg_id, 'xmlns': 'urn:xmpp:message-correct:0'}).tree());
test_utils.waitUntil(() => chatboxview.el.querySelector('.chat-msg__text').textContent ===
'But soft, what light through yonder chimney breaks?').then(() => {
test_utils.openChatBoxFor(_converse, sender_jid)
.then(() => {
const msg_id = u.getUniqueId();
_converse.chatboxes.onMessage($msg({
'from': sender_jid,
'to': _converse.connection.jid,
'type': 'chat',
'id': msg_id,
}).c('body').t('But soft, what light through yonder airlock breaks?').tree());
var chatboxview = _converse.chatboxviews.get(sender_jid);
expect(chatboxview.el.querySelectorAll('.chat-msg').length).toBe(1);
expect(chatboxview.el.querySelectorAll('.chat-msg__content .fa-edit').length).toBe(1);
expect(chatboxview.el.querySelector('.chat-msg__text').textContent)
.toBe('But soft, what light through yonder airlock breaks?');
_converse.chatboxes.onMessage($msg({
'from': sender_jid,
'to': _converse.connection.jid,
'type': 'chat',
'id': u.getUniqueId(),
}).c('body').t('But soft, what light through yonder window breaks?').up()
}).c('body').t('But soft, what light through yonder chimney breaks?').up()
.c('replace', {'id': msg_id, 'xmlns': 'urn:xmpp:message-correct:0'}).tree());
return test_utils.waitUntil(() => chatboxview.el.querySelector('.chat-msg__text').textContent ===
'But soft, what light through yonder window breaks?');
}).then(() => {
expect(chatboxview.el.querySelectorAll('.chat-msg').length).toBe(1);
expect(chatboxview.el.querySelectorAll('.chat-msg__content .fa-edit').length).toBe(1);
chatboxview.el.querySelector('.chat-msg__content .fa-edit').click();
const modal = chatboxview.model.messages.at(0).message_versions_modal;
return test_utils.waitUntil(() => u.isVisible(modal.el), 1000);
}).then(() => {
const modal = chatboxview.model.messages.at(0).message_versions_modal;
const older_msgs = modal.el.querySelectorAll('.older-msg');
expect(older_msgs.length).toBe(2);
expect(older_msgs[0].textContent).toBe('But soft, what light through yonder airlock breaks?');
expect(older_msgs[1].textContent).toBe('But soft, what light through yonder chimney breaks?');
done();
test_utils.waitUntil(() => chatboxview.el.querySelector('.chat-msg__text').textContent ===
'But soft, what light through yonder chimney breaks?').then(() => {
expect(chatboxview.el.querySelectorAll('.chat-msg').length).toBe(1);
expect(chatboxview.el.querySelectorAll('.chat-msg__content .fa-edit').length).toBe(1);
_converse.chatboxes.onMessage($msg({
'from': sender_jid,
'to': _converse.connection.jid,
'type': 'chat',
'id': u.getUniqueId(),
}).c('body').t('But soft, what light through yonder window breaks?').up()
.c('replace', {'id': msg_id, 'xmlns': 'urn:xmpp:message-correct:0'}).tree());
return test_utils.waitUntil(() => chatboxview.el.querySelector('.chat-msg__text').textContent ===
'But soft, what light through yonder window breaks?');
}).then(() => {
expect(chatboxview.el.querySelectorAll('.chat-msg').length).toBe(1);
expect(chatboxview.el.querySelectorAll('.chat-msg__content .fa-edit').length).toBe(1);
chatboxview.el.querySelector('.chat-msg__content .fa-edit').click();
const modal = chatboxview.model.messages.at(0).message_versions_modal;
return test_utils.waitUntil(() => u.isVisible(modal.el), 1000);
}).then(() => {
const modal = chatboxview.model.messages.at(0).message_versions_modal;
const older_msgs = modal.el.querySelectorAll('.older-msg');
expect(older_msgs.length).toBe(2);
expect(older_msgs[0].textContent).toBe('But soft, what light through yonder airlock breaks?');
expect(older_msgs[1].textContent).toBe('But soft, what light through yonder chimney breaks?');
done();
});
});
}));
......@@ -500,10 +506,11 @@
it("will have the error message displayed after itself",
mock.initConverseWithPromises(
null, ['rosterGroupsFetched'], {},
null, ['rosterGroupsFetched', 'chatBoxesFetched'], {},
function (done, _converse) {
test_utils.createContacts(_converse, 'current');
_converse.emit('rosterContactsFetched');
test_utils.openControlBox();
// TODO: what could still be done for error
......@@ -513,154 +520,152 @@
// that.
/* <message from="scotty@enterprise.com/_converse.js-84843526"
* to="kirk@enterprise.com.com"
* type="chat"
* id="82bc02ce-9651-4336-baf0-fa04762ed8d2"
* xmlns="jabber:client">
* <body>yo</body>
* <active xmlns="http://jabber.org/protocol/chatstates"/>
* </message>
*/
* to="kirk@enterprise.com.com"
* type="chat"
* id="82bc02ce-9651-4336-baf0-fa04762ed8d2"
* xmlns="jabber:client">
* <body>yo</body>
* <active xmlns="http://jabber.org/protocol/chatstates"/>
* </message>
*/
var sender_jid = mock.cur_names[5].replace(/ /g,'.').toLowerCase() + '@localhost';
var fullname = _converse.xmppstatus.get('fullname');
fullname = _.isEmpty(fullname)? _converse.bare_jid: fullname;
_converse.api.chats.open(sender_jid);
var msg_text = 'This message will not be sent, due to an error';
var view = _converse.chatboxviews.get(sender_jid);
var message = view.model.messages.create({
'msgid': '82bc02ce-9651-4336-baf0-fa04762ed8d2',
'fullname': fullname,
'sender': 'me',
'time': moment().format(),
'message': msg_text
});
view.model.sendMessage(message);
var $chat_content = $(view.el).find('.chat-content');
var msg_txt = $chat_content.find('.chat-msg:last').find('.chat-msg__text').text();
expect(msg_txt).toEqual(msg_text);
// We send another message, for which an error will
// not be received, to test that errors appear
// after the relevant message.
msg_text = 'This message will be sent, and also receive an error';
message = view.model.messages.create({
'msgid': '6fcdeee3-000f-4ce8-a17e-9ce28f0ae104',
'fullname': fullname,
'sender': 'me',
'time': moment().format(),
'message': msg_text
_converse.api.chats.open(sender_jid)
.then(() => {
var msg_text = 'This message will not be sent, due to an error';
var view = _converse.chatboxviews.get(sender_jid);
var message = view.model.messages.create({
'msgid': '82bc02ce-9651-4336-baf0-fa04762ed8d2',
'fullname': fullname,
'sender': 'me',
'time': moment().format(),
'message': msg_text
});
view.model.sendMessage(message);
var $chat_content = $(view.el).find('.chat-content');
var msg_txt = $chat_content.find('.chat-msg:last').find('.chat-msg__text').text();
expect(msg_txt).toEqual(msg_text);
// We send another message, for which an error will
// not be received, to test that errors appear
// after the relevant message.
msg_text = 'This message will be sent, and also receive an error';
message = view.model.messages.create({
'msgid': '6fcdeee3-000f-4ce8-a17e-9ce28f0ae104',
'fullname': fullname,
'sender': 'me',
'time': moment().format(),
'message': msg_text
});
view.model.sendMessage(message);
msg_txt = $chat_content.find('.chat-msg:last').find('.chat-msg__text').text();
expect(msg_txt).toEqual(msg_text);
/* <message xmlns="jabber:client"
* to="scotty@enterprise.com/_converse.js-84843526"
* type="error"
* id="82bc02ce-9651-4336-baf0-fa04762ed8d2"
* from="kirk@enterprise.com.com">
* <error type="cancel">
* <remote-server-not-found xmlns="urn:ietf:params:xml:ns:xmpp-stanzas"/>
* <text xmlns="urn:ietf:params:xml:ns:xmpp-stanzas">Server-to-server connection failed: Connecting failed: connection timeout</text>
* </error>
* </message>
*/
var error_txt = 'Server-to-server connection failed: Connecting failed: connection timeout';
var stanza = $msg({
'to': _converse.connection.jid,
'type':'error',
'id':'82bc02ce-9651-4336-baf0-fa04762ed8d2',
'from': sender_jid
})
.c('error', {'type': 'cancel'})
.c('remote-server-not-found', { 'xmlns': "urn:ietf:params:xml:ns:xmpp-stanzas" }).up()
.c('text', { 'xmlns': "urn:ietf:params:xml:ns:xmpp-stanzas" })
.t('Server-to-server connection failed: Connecting failed: connection timeout');
_converse.connection._dataRecv(test_utils.createRequest(stanza));
expect($chat_content.find('.chat-error').text()).toEqual(error_txt);
stanza = $msg({
'to': _converse.connection.jid,
'type':'error',
'id':'some-other-unused-id',
'from': sender_jid
})
.c('error', {'type': 'cancel'})
.c('remote-server-not-found', { 'xmlns': "urn:ietf:params:xml:ns:xmpp-stanzas" }).up()
.c('text', { 'xmlns': "urn:ietf:params:xml:ns:xmpp-stanzas" })
.t('Server-to-server connection failed: Connecting failed: connection timeout');
_converse.connection._dataRecv(test_utils.createRequest(stanza));
expect($chat_content.find('.chat-error').length).toEqual(2);
// If the last message is already an error message,
// then we don't render it another time.
stanza = $msg({
'to': _converse.connection.jid,
'type':'error',
'id':'another-unused-id',
'from': sender_jid
})
.c('error', {'type': 'cancel'})
.c('remote-server-not-found', { 'xmlns': "urn:ietf:params:xml:ns:xmpp-stanzas" }).up()
.c('text', { 'xmlns': "urn:ietf:params:xml:ns:xmpp-stanzas" })
.t('Server-to-server connection failed: Connecting failed: connection timeout');
_converse.connection._dataRecv(test_utils.createRequest(stanza));
expect($chat_content.find('.chat-error').length).toEqual(2);
// A different error message will however render
stanza = $msg({
'to': _converse.connection.jid,
'type':'error',
'id':'another-id',
'from': sender_jid
})
.c('error', {'type': 'cancel'})
.c('remote-server-not-found', { 'xmlns': "urn:ietf:params:xml:ns:xmpp-stanzas" }).up()
.c('text', { 'xmlns': "urn:ietf:params:xml:ns:xmpp-stanzas" })
.t('Something else went wrong as well');
_converse.connection._dataRecv(test_utils.createRequest(stanza));
expect($chat_content.find('.chat-error').length).toEqual(3);
done();
});
view.model.sendMessage(message);
msg_txt = $chat_content.find('.chat-msg:last').find('.chat-msg__text').text();
expect(msg_txt).toEqual(msg_text);
/* <message xmlns="jabber:client"
* to="scotty@enterprise.com/_converse.js-84843526"
* type="error"
* id="82bc02ce-9651-4336-baf0-fa04762ed8d2"
* from="kirk@enterprise.com.com">
* <error type="cancel">
* <remote-server-not-found xmlns="urn:ietf:params:xml:ns:xmpp-stanzas"/>
* <text xmlns="urn:ietf:params:xml:ns:xmpp-stanzas">Server-to-server connection failed: Connecting failed: connection timeout</text>
* </error>
* </message>
*/
var error_txt = 'Server-to-server connection failed: Connecting failed: connection timeout';
var stanza = $msg({
'to': _converse.connection.jid,
'type':'error',
'id':'82bc02ce-9651-4336-baf0-fa04762ed8d2',
'from': sender_jid
})
.c('error', {'type': 'cancel'})
.c('remote-server-not-found', { 'xmlns': "urn:ietf:params:xml:ns:xmpp-stanzas" }).up()
.c('text', { 'xmlns': "urn:ietf:params:xml:ns:xmpp-stanzas" })
.t('Server-to-server connection failed: Connecting failed: connection timeout');
_converse.connection._dataRecv(test_utils.createRequest(stanza));
expect($chat_content.find('.chat-error').text()).toEqual(error_txt);
stanza = $msg({
'to': _converse.connection.jid,
'type':'error',
'id':'some-other-unused-id',
'from': sender_jid
})
.c('error', {'type': 'cancel'})
.c('remote-server-not-found', { 'xmlns': "urn:ietf:params:xml:ns:xmpp-stanzas" }).up()
.c('text', { 'xmlns': "urn:ietf:params:xml:ns:xmpp-stanzas" })
.t('Server-to-server connection failed: Connecting failed: connection timeout');
_converse.connection._dataRecv(test_utils.createRequest(stanza));
expect($chat_content.find('.chat-error').length).toEqual(2);
// If the last message is already an error message,
// then we don't render it another time.
stanza = $msg({
'to': _converse.connection.jid,
'type':'error',
'id':'another-unused-id',
'from': sender_jid
})
.c('error', {'type': 'cancel'})
.c('remote-server-not-found', { 'xmlns': "urn:ietf:params:xml:ns:xmpp-stanzas" }).up()
.c('text', { 'xmlns': "urn:ietf:params:xml:ns:xmpp-stanzas" })
.t('Server-to-server connection failed: Connecting failed: connection timeout');
_converse.connection._dataRecv(test_utils.createRequest(stanza));
expect($chat_content.find('.chat-error').length).toEqual(2);
// A different error message will however render
stanza = $msg({
'to': _converse.connection.jid,
'type':'error',
'id':'another-id',
'from': sender_jid
})
.c('error', {'type': 'cancel'})
.c('remote-server-not-found', { 'xmlns': "urn:ietf:params:xml:ns:xmpp-stanzas" }).up()
.c('text', { 'xmlns': "urn:ietf:params:xml:ns:xmpp-stanzas" })
.t('Something else went wrong as well');
_converse.connection._dataRecv(test_utils.createRequest(stanza));
expect($chat_content.find('.chat-error').length).toEqual(3);
done();
}));
});
it("will cause the chat area to be scrolled down only if it was at the bottom originally",
mock.initConverseWithPromises(
null, ['rosterGroupsFetched'], {},
null, ['rosterGroupsFetched', 'chatBoxesFetched'], {},
function (done, _converse) {
test_utils.createContacts(_converse, 'current');
_converse.emit('rosterContactsFetched');
test_utils.openControlBox();
var sender_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@localhost';
test_utils.openChatBoxFor(_converse, sender_jid);
var chatboxview = _converse.chatboxviews.get(sender_jid);
spyOn(chatboxview, 'onScrolledDown').and.callThrough();
// Create enough messages so that there's a scrollbar.
var message = 'This message is received while the chat area is scrolled up';
for (var i=0; i<20; i++) {
_converse.chatboxes.onMessage($msg({
from: sender_jid,
to: _converse.connection.jid,
type: 'chat',
id: (new Date()).getTime()
}).c('body').t('Message: '+i).up()
.c('active', {'xmlns': 'http://jabber.org/protocol/chatstates'}).tree());
}
return test_utils.waitUntil(function () {
return chatboxview.content.scrollTop;
}, 1000).then(function () {
return test_utils.waitUntil(function () {
return !chatboxview.model.get('auto_scrolled');
}, 500);
}).then(function () {
let chatboxview;
const sender_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@localhost';
const message = 'This message is received while the chat area is scrolled up';
test_utils.openChatBoxFor(_converse, sender_jid)
.then(() => {
chatboxview = _converse.chatboxviews.get(sender_jid);
spyOn(chatboxview, 'onScrolledDown').and.callThrough();
// Create enough messages so that there's a scrollbar.
for (var i=0; i<20; i++) {
_converse.chatboxes.onMessage($msg({
from: sender_jid,
to: _converse.connection.jid,
type: 'chat',
id: (new Date()).getTime()
}).c('body').t('Message: '+i).up()
.c('active', {'xmlns': 'http://jabber.org/protocol/chatstates'}).tree());
}
return test_utils.waitUntil(() => chatboxview.content.scrollTop, 1000)
.then(() => test_utils.waitUntil(() => !chatboxview.model.get('auto_scrolled'), 500))
}).then(() => {
chatboxview.content.scrollTop = 0;
return test_utils.waitUntil(function () {
return chatboxview.model.get('scrolled');
}, 900);
}).then(function () {
return test_utils.waitUntil(() => chatboxview.model.get('scrolled'), 900);
}).then(() => {
_converse.chatboxes.onMessage($msg({
from: sender_jid,
to: _converse.connection.jid,
......@@ -1109,23 +1114,22 @@
it("received for a minimized chat box will increment a counter on its header",
mock.initConverseWithPromises(
null, ['rosterGroupsFetched'], {},
null, ['rosterGroupsFetched', 'chatBoxesFetched'], {},
function (done, _converse) {
if (_converse.view_mode === 'fullscreen') {
return done();
}
test_utils.createContacts(_converse, 'current');
_converse.emit('rosterContactsFetched');
const contact_name = mock.cur_names[0];
const contact_jid = contact_name.replace(/ /g,'.').toLowerCase() + '@localhost';
test_utils.openControlBox();
test_utils.waitUntil(function () {
return $(_converse.rosterview.el).find('.roster-group').length;
}, 300)
.then(function () {
var contact_name = mock.cur_names[0];
var contact_jid = contact_name.replace(/ /g,'.').toLowerCase() + '@localhost';
spyOn(_converse, 'emit').and.callThrough();
spyOn(_converse, 'emit').and.callThrough();
test_utils.openChatBoxFor(_converse, contact_jid);
test_utils.waitUntil(() => _converse.rosterview.el.querySelectorAll('.roster-group').length)
.then(() => test_utils.openChatBoxFor(_converse, contact_jid))
.then(() => {
var chatview = _converse.chatboxviews.get(contact_jid);
expect(u.isVisible(chatview.el)).toBeTruthy();
expect(chatview.model.get('minimized')).toBeFalsy();
......@@ -1171,19 +1175,18 @@
it("will indicate when it has a time difference of more than a day between it and its predecessor",
mock.initConverseWithPromises(
null, ['rosterGroupsFetched'], {},
null, ['rosterGroupsFetched', 'chatBoxesFetched'], {},
function (done, _converse) {
test_utils.createContacts(_converse, 'current');
_converse.emit('rosterContactsFetched');
test_utils.openControlBox();
test_utils.waitUntil(function () {
return $(_converse.rosterview.el).find('.roster-group').length;
}, 300)
.then(function () {
spyOn(_converse, 'emit');
var contact_name = mock.cur_names[1];
var contact_jid = contact_name.replace(/ /g,'.').toLowerCase() + '@localhost';
test_utils.openChatBoxFor(_converse, contact_jid);
spyOn(_converse, 'emit');
const contact_name = mock.cur_names[1];
const contact_jid = contact_name.replace(/ /g,'.').toLowerCase() + '@localhost';
test_utils.waitUntil(() => _converse.rosterview.el.querySelectorAll('.roster-group').length)
.then(() => test_utils.openChatBoxFor(_converse, contact_jid))
.then(() => {
test_utils.clearChatBoxMessages(_converse, contact_jid);
var one_day_ago = moment();
one_day_ago.subtract('days', 1);
......@@ -1269,117 +1272,132 @@
}));
it("can be sent from a chatbox, and will appear inside it",
mock.initConverseWithPromises(
null, ['rosterGroupsFetched'], {},
function (done, _converse) {
mock.initConverseWithPromises(
null, ['rosterGroupsFetched', 'chatBoxesFetched'], {},
function (done, _converse) {
test_utils.createContacts(_converse, 'current');
_converse.emit('rosterContactsFetched');
test_utils.openControlBox();
spyOn(_converse, 'emit');
var contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@localhost';
test_utils.openChatBoxFor(_converse, contact_jid);
expect(_converse.emit).toHaveBeenCalledWith('chatBoxFocused', jasmine.any(Object));
var view = _converse.chatboxviews.get(contact_jid);
var message = 'This message is sent from this chatbox';
spyOn(view.model, 'sendMessage').and.callThrough();
test_utils.sendMessage(view, message);
expect(view.model.sendMessage).toHaveBeenCalled();
expect(view.model.messages.length, 2);
expect(_converse.emit.calls.mostRecent().args, ['messageSend', message]);
expect($(view.el).find('.chat-content').find('.chat-msg').last().find('.chat-msg__text').text()).toEqual(message);
done();
const contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@localhost';
test_utils.openChatBoxFor(_converse, contact_jid)
.then(() => {
expect(_converse.emit).toHaveBeenCalledWith('chatBoxFocused', jasmine.any(Object));
const view = _converse.chatboxviews.get(contact_jid);
const message = 'This message is sent from this chatbox';
spyOn(view.model, 'sendMessage').and.callThrough();
test_utils.sendMessage(view, message);
expect(view.model.sendMessage).toHaveBeenCalled();
expect(view.model.messages.length, 2);
expect(_converse.emit.calls.mostRecent().args, ['messageSend', message]);
expect($(view.el).find('.chat-content').find('.chat-msg').last().find('.chat-msg__text').text()).toEqual(message);
done();
});
}));
it("is sanitized to prevent Javascript injection attacks",
mock.initConverseWithPromises(
null, ['rosterGroupsFetched'], {},
null, ['rosterGroupsFetched', 'chatBoxesFetched'], {},
function (done, _converse) {
test_utils.createContacts(_converse, 'current');
_converse.emit('rosterContactsFetched');
test_utils.openControlBox();
var contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@localhost';
test_utils.openChatBoxFor(_converse, contact_jid);
var view = _converse.chatboxviews.get(contact_jid);
var message = '<p>This message contains <em>some</em> <b>markup</b></p>';
spyOn(view.model, 'sendMessage').and.callThrough();
test_utils.sendMessage(view, message);
expect(view.model.sendMessage).toHaveBeenCalled();
var msg = $(view.el).find('.chat-content').find('.chat-msg').last().find('.chat-msg__text');
expect(msg.text()).toEqual(message);
expect(msg.html()).toEqual('&lt;p&gt;This message contains &lt;em&gt;some&lt;/em&gt; &lt;b&gt;markup&lt;/b&gt;&lt;/p&gt;');
done();
const contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@localhost';
test_utils.openChatBoxFor(_converse, contact_jid)
.then(() => {
const view = _converse.chatboxviews.get(contact_jid);
const message = '<p>This message contains <em>some</em> <b>markup</b></p>';
spyOn(view.model, 'sendMessage').and.callThrough();
test_utils.sendMessage(view, message);
expect(view.model.sendMessage).toHaveBeenCalled();
const msg = $(view.el).find('.chat-content').find('.chat-msg').last().find('.chat-msg__text');
expect(msg.text()).toEqual(message);
expect(msg.html()).toEqual('&lt;p&gt;This message contains &lt;em&gt;some&lt;/em&gt; &lt;b&gt;markup&lt;/b&gt;&lt;/p&gt;');
done();
});
}));
it("can contain hyperlinks, which will be clickable",
mock.initConverseWithPromises(
null, ['rosterGroupsFetched'], {},
null, ['rosterGroupsFetched', 'chatBoxesFetched'], {},
function (done, _converse) {
test_utils.createContacts(_converse, 'current');
_converse.emit('rosterContactsFetched');
test_utils.openControlBox();
var contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@localhost';
test_utils.openChatBoxFor(_converse, contact_jid);
var view = _converse.chatboxviews.get(contact_jid);
var message = 'This message contains a hyperlink: www.opkode.com';
spyOn(view.model, 'sendMessage').and.callThrough();
test_utils.sendMessage(view, message);
expect(view.model.sendMessage).toHaveBeenCalled();
var msg = $(view.el).find('.chat-content').find('.chat-msg').last().find('.chat-msg__text');
expect(msg.text()).toEqual(message);
expect(msg.html()).toEqual('This message contains a hyperlink: <a target="_blank" rel="noopener" href="http://www.opkode.com">www.opkode.com</a>');
done();
const contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@localhost';
test_utils.openChatBoxFor(_converse, contact_jid)
.then(() => {
const view = _converse.chatboxviews.get(contact_jid);
const message = 'This message contains a hyperlink: www.opkode.com';
spyOn(view.model, 'sendMessage').and.callThrough();
test_utils.sendMessage(view, message);
expect(view.model.sendMessage).toHaveBeenCalled();
const msg = $(view.el).find('.chat-content').find('.chat-msg').last().find('.chat-msg__text');
expect(msg.text()).toEqual(message);
expect(msg.html()).toEqual('This message contains a hyperlink: <a target="_blank" rel="noopener" href="http://www.opkode.com">www.opkode.com</a>');
done();
});
}));
it("will have properly escaped URLs",
mock.initConverseWithPromises(
null, ['rosterGroupsFetched'], {},
function (done, _converse) {
mock.initConverseWithPromises(
null, ['rosterGroupsFetched', 'chatBoxesFetched'], {},
function (done, _converse) {
test_utils.createContacts(_converse, 'current');
_converse.emit('rosterContactsFetched');
test_utils.openControlBox();
var message, msg;
var contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@localhost';
test_utils.openChatBoxFor(_converse, contact_jid);
var view = _converse.chatboxviews.get(contact_jid);
spyOn(view.model, 'sendMessage').and.callThrough();
message = "http://www.opkode.com/'onmouseover='alert(1)'whatever";
test_utils.sendMessage(view, message);
expect(view.model.sendMessage).toHaveBeenCalled();
msg = $(view.el).find('.chat-content').find('.chat-msg').last().find('.chat-msg__text');
expect(msg.text()).toEqual(message);
expect(msg.html()).toEqual('<a target="_blank" rel="noopener" href="http://www.opkode.com/%27onmouseover=%27alert%281%29%27whatever">http://www.opkode.com/\'onmouseover=\'alert(1)\'whatever</a>');
message = 'http://www.opkode.com/"onmouseover="alert(1)"whatever';
test_utils.sendMessage(view, message);
expect(view.model.sendMessage).toHaveBeenCalled();
msg = $(view.el).find('.chat-content').find('.chat-msg').last().find('.chat-msg__text');
expect(msg.text()).toEqual(message);
expect(msg.html()).toEqual('<a target="_blank" rel="noopener" href="http://www.opkode.com/%22onmouseover=%22alert%281%29%22whatever">http://www.opkode.com/"onmouseover="alert(1)"whatever</a>');
message = "https://en.wikipedia.org/wiki/Ender's_Game";
test_utils.sendMessage(view, message);
expect(view.model.sendMessage).toHaveBeenCalled();
msg = $(view.el).find('.chat-content').find('.chat-msg').last().find('.chat-msg__text');
expect(msg.text()).toEqual(message);
expect(msg.html()).toEqual('<a target="_blank" rel="noopener" href="https://en.wikipedia.org/wiki/Ender%27s_Game">'+message+'</a>');
message = "https://en.wikipedia.org/wiki/Ender's_Game";
test_utils.sendMessage(view, message);
expect(view.model.sendMessage).toHaveBeenCalled();
msg = $(view.el).find('.chat-content').find('.chat-msg').last().find('.chat-msg__text');
expect(msg.text()).toEqual(message);
expect(msg.html()).toEqual('<a target="_blank" rel="noopener" href="https://en.wikipedia.org/wiki/Ender%27s_Game">'+message+'</a>');
done();
let message, msg;
const contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@localhost';
test_utils.openChatBoxFor(_converse, contact_jid)
.then(() => {
var view = _converse.chatboxviews.get(contact_jid);
spyOn(view.model, 'sendMessage').and.callThrough();
message = "http://www.opkode.com/'onmouseover='alert(1)'whatever";
test_utils.sendMessage(view, message);
expect(view.model.sendMessage).toHaveBeenCalled();
msg = $(view.el).find('.chat-content').find('.chat-msg').last().find('.chat-msg__text');
expect(msg.text()).toEqual(message);
expect(msg.html()).toEqual('<a target="_blank" rel="noopener" href="http://www.opkode.com/%27onmouseover=%27alert%281%29%27whatever">http://www.opkode.com/\'onmouseover=\'alert(1)\'whatever</a>');
message = 'http://www.opkode.com/"onmouseover="alert(1)"whatever';
test_utils.sendMessage(view, message);
expect(view.model.sendMessage).toHaveBeenCalled();
msg = $(view.el).find('.chat-content').find('.chat-msg').last().find('.chat-msg__text');
expect(msg.text()).toEqual(message);
expect(msg.html()).toEqual('<a target="_blank" rel="noopener" href="http://www.opkode.com/%22onmouseover=%22alert%281%29%22whatever">http://www.opkode.com/"onmouseover="alert(1)"whatever</a>');
message = "https://en.wikipedia.org/wiki/Ender's_Game";
test_utils.sendMessage(view, message);
expect(view.model.sendMessage).toHaveBeenCalled();
msg = $(view.el).find('.chat-content').find('.chat-msg').last().find('.chat-msg__text');
expect(msg.text()).toEqual(message);
expect(msg.html()).toEqual('<a target="_blank" rel="noopener" href="https://en.wikipedia.org/wiki/Ender%27s_Game">'+message+'</a>');
message = "https://en.wikipedia.org/wiki/Ender's_Game";
test_utils.sendMessage(view, message);
expect(view.model.sendMessage).toHaveBeenCalled();
msg = $(view.el).find('.chat-content').find('.chat-msg').last().find('.chat-msg__text');
expect(msg.text()).toEqual(message);
expect(msg.html()).toEqual('<a target="_blank" rel="noopener" href="https://en.wikipedia.org/wiki/Ender%27s_Game">'+message+'</a>');
done();
});
}));
it("will render newlines", mock.initConverseWithPromises(null, ['rosterGroupsFetched'], {}, function (done, _converse) {
it("will render newlines",
mock.initConverseWithPromises(null, ['rosterGroupsFetched', 'chatBoxesFetched'], {}, function (done, _converse) {
test_utils.createContacts(_converse, 'current');
_converse.emit('rosterContactsFetched');
const contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@localhost';
test_utils.openChatBoxFor(_converse, contact_jid);
......@@ -1416,20 +1434,23 @@
}));
it("will render images from their URLs",
mock.initConverseWithPromises(
null, ['rosterGroupsFetched'], {},
function (done, _converse) {
mock.initConverseWithPromises(
null, ['rosterGroupsFetched', 'chatBoxesFetched'], {},
function (done, _converse) {
test_utils.createContacts(_converse, 'current', 1);
_converse.emit('rosterContactsFetched');
const base_url = document.URL.split(window.location.pathname)[0];
let message = base_url+"/logo/conversejs-filled.svg";
const contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@localhost';
test_utils.openChatBoxFor(_converse, contact_jid);
const view = _converse.chatboxviews.get(contact_jid);
spyOn(view.model, 'sendMessage').and.callThrough();
test_utils.sendMessage(view, message);
test_utils.waitUntil(() => view.el.querySelectorAll('.chat-content .chat-image').length, 1000).then(() => {
let view;
test_utils.openChatBoxFor(_converse, contact_jid)
.then(() => {
view = _converse.chatboxviews.get(contact_jid);
spyOn(view.model, 'sendMessage').and.callThrough();
test_utils.sendMessage(view, message);
return test_utils.waitUntil(() => view.el.querySelectorAll('.chat-content .chat-image').length, 1000)
}).then(() => {
expect(view.model.sendMessage).toHaveBeenCalled();
const msg = $(view.el).find('.chat-content .chat-msg').last().find('.chat-msg__text');
expect(msg.html().trim()).toEqual(
......@@ -1461,30 +1482,33 @@
}));
it("will render the message time as configured",
mock.initConverseWithPromises(
null, ['rosterGroupsFetched'], {},
function (done, _converse) {
mock.initConverseWithPromises(
null, ['rosterGroupsFetched', 'chatBoxesFetched'],
{}, function (done, _converse) {
test_utils.createContacts(_converse, 'current');
_converse.emit('rosterContactsFetched');
_converse.time_format = 'hh:mm';
var contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@localhost';
test_utils.openChatBoxFor(_converse, contact_jid);
var view = _converse.chatboxviews.get(contact_jid);
var message = 'This message is sent from this chatbox';
test_utils.sendMessage(view, message);
const contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@localhost';
test_utils.openChatBoxFor(_converse, contact_jid)
.then(() => {
const view = _converse.chatboxviews.get(contact_jid);
const message = 'This message is sent from this chatbox';
test_utils.sendMessage(view, message);
var chatbox = _converse.chatboxes.get(contact_jid);
expect(chatbox.messages.models.length, 1);
var msg_object = chatbox.messages.models[0];
const chatbox = _converse.chatboxes.get(contact_jid);
expect(chatbox.messages.models.length, 1);
const msg_object = chatbox.messages.models[0];
var msg_author = view.el.querySelector('.chat-content .chat-msg:last-child .chat-msg__author');
expect(msg_author.textContent.trim()).toBe('Max Mustermann');
const msg_author = view.el.querySelector('.chat-content .chat-msg:last-child .chat-msg__author');
expect(msg_author.textContent.trim()).toBe('Max Mustermann');
var msg_time = view.el.querySelector('.chat-content .chat-msg:last-child .chat-msg__time');
var time = moment(msg_object.get('time')).format(_converse.time_format);
expect(msg_time.textContent).toBe(time);
done();
const msg_time = view.el.querySelector('.chat-content .chat-msg:last-child .chat-msg__time');
const time = moment(msg_object.get('time')).format(_converse.time_format);
expect(msg_time.textContent).toBe(time);
done();
});
}));
it("will be correctly identified and rendered as a followup message",
......@@ -1655,29 +1679,33 @@
}));
describe("which contains a OOB URL", function () {
describe("which contains an OOB URL", function () {
it("will render audio from oob mp3 URLs",
mock.initConverseWithPromises(
null, ['rosterGroupsFetched'], {},
function (done, _converse) {
mock.initConverseWithPromises(
null, ['rosterGroupsFetched', 'chatBoxesFetched'], {},
function (done, _converse) {
test_utils.createContacts(_converse, 'current', 1);
_converse.emit('rosterContactsFetched');
const contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@localhost';
test_utils.openChatBoxFor(_converse, contact_jid);
const view = _converse.chatboxviews.get(contact_jid);
spyOn(view.model, 'sendMessage').and.callThrough();
let view;
test_utils.openChatBoxFor(_converse, contact_jid)
.then(() => {
view = _converse.chatboxviews.get(contact_jid);
spyOn(view.model, 'sendMessage').and.callThrough();
const stanza = Strophe.xmlHtmlNode(
"<message from='"+contact_jid+"'"+
" type='chat'"+
" to='dummy@localhost/resource'>"+
" <body>Have you heard this funny audio?</body>"+
" <x xmlns='jabber:x:oob'><url>http://localhost/audio.mp3</url></x>"+
"</message>").firstChild;
_converse.connection._dataRecv(test_utils.createRequest(stanza));
const stanza = Strophe.xmlHtmlNode(
"<message from='"+contact_jid+"'"+
" type='chat'"+
" to='dummy@localhost/resource'>"+
" <body>Have you heard this funny audio?</body>"+
" <x xmlns='jabber:x:oob'><url>http://localhost/audio.mp3</url></x>"+
"</message>").firstChild
_converse.connection._dataRecv(test_utils.createRequest(stanza));
test_utils.waitUntil(() => view.el.querySelectorAll('.chat-content .chat-msg audio').length, 1000).then(function () {
return test_utils.waitUntil(() => view.el.querySelectorAll('.chat-content .chat-msg audio').length, 1000);
}).then(() => {
let msg = view.el.querySelector('.chat-msg .chat-msg__text');
expect(msg.outerHTML).toEqual('<div class="chat-msg__text">Have you heard this funny audio?</div>');
let media = view.el.querySelector('.chat-msg .chat-msg__media');
......@@ -1708,76 +1736,83 @@
}));
it("will render video from oob mp4 URLs",
mock.initConverseWithPromises(
null, ['rosterGroupsFetched'], {},
function (done, _converse) {
mock.initConverseWithPromises(
null, ['rosterGroupsFetched', 'chatBoxesFetched'], {},
function (done, _converse) {
test_utils.createContacts(_converse, 'current');
_converse.emit('rosterContactsFetched');
const contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@localhost';
test_utils.openChatBoxFor(_converse, contact_jid);
const view = _converse.chatboxviews.get(contact_jid);
spyOn(view.model, 'sendMessage').and.callThrough();
test_utils.openChatBoxFor(_converse, contact_jid)
.then(() => {
const view = _converse.chatboxviews.get(contact_jid);
spyOn(view.model, 'sendMessage').and.callThrough();
const stanza = Strophe.xmlHtmlNode(
"<message from='"+contact_jid+"'"+
" type='chat'"+
" to='dummy@localhost/resource'>"+
" <body>Have you seen this funny video?</body>"+
" <x xmlns='jabber:x:oob'><url>http://localhost/video.mp4</url></x>"+
"</message>").firstChild;
_converse.connection._dataRecv(test_utils.createRequest(stanza));
test_utils.waitUntil(() => view.el.querySelectorAll('.chat-content .chat-msg video').length, 2000).then(function () {
let msg = view.el.querySelector('.chat-msg .chat-msg__text');
expect(msg.outerHTML).toEqual('<div class="chat-msg__text">Have you seen this funny video?</div>');
let media = view.el.querySelector('.chat-msg .chat-msg__media');
expect(media.innerHTML.replace(/(\r\n|\n|\r)/gm, "")).toEqual(
'<!-- src/templates/video.html -->'+
'<video controls=""><source src="http://localhost/video.mp4" type="video/mp4"></video>'+
'<a target="_blank" rel="noopener" href="http://localhost/video.mp4">Download video file</a>');
// If the <url> and <body> contents is the same, don't duplicate.
const stanza = Strophe.xmlHtmlNode(
"<message from='"+contact_jid+"'"+
" type='chat'"+
" to='dummy@localhost/resource'>"+
" <body>http://localhost/video.mp4</body>"+
" <body>Have you seen this funny video?</body>"+
" <x xmlns='jabber:x:oob'><url>http://localhost/video.mp4</url></x>"+
"</message>").firstChild;
_converse.connection._dataRecv(test_utils.createRequest(stanza));
msg = view.el.querySelector('.chat-msg:last-child .chat-msg__text');
expect(msg.innerHTML).toEqual('<!-- message gets added here via renderMessage -->'); // Emtpy
media = view.el.querySelector('.chat-msg:last-child .chat-msg__media');
expect(media.innerHTML.replace(/(\r\n|\n|\r)/gm, "")).toEqual(
'<!-- src/templates/video.html -->'+
'<video controls=""><source src="http://localhost/video.mp4" type="video/mp4"></video>'+
'<a target="_blank" rel="noopener" href="http://localhost/video.mp4">Download video file</a>');
done();
test_utils.waitUntil(() => view.el.querySelectorAll('.chat-content .chat-msg video').length, 2000).then(function () {
let msg = view.el.querySelector('.chat-msg .chat-msg__text');
expect(msg.outerHTML).toEqual('<div class="chat-msg__text">Have you seen this funny video?</div>');
let media = view.el.querySelector('.chat-msg .chat-msg__media');
expect(media.innerHTML.replace(/(\r\n|\n|\r)/gm, "")).toEqual(
'<!-- src/templates/video.html -->'+
'<video controls=""><source src="http://localhost/video.mp4" type="video/mp4"></video>'+
'<a target="_blank" rel="noopener" href="http://localhost/video.mp4">Download video file</a>');
// If the <url> and <body> contents is the same, don't duplicate.
const stanza = Strophe.xmlHtmlNode(
"<message from='"+contact_jid+"'"+
" type='chat'"+
" to='dummy@localhost/resource'>"+
" <body>http://localhost/video.mp4</body>"+
" <x xmlns='jabber:x:oob'><url>http://localhost/video.mp4</url></x>"+
"</message>").firstChild;
_converse.connection._dataRecv(test_utils.createRequest(stanza));
msg = view.el.querySelector('.chat-msg:last-child .chat-msg__text');
expect(msg.innerHTML).toEqual('<!-- message gets added here via renderMessage -->'); // Emtpy
media = view.el.querySelector('.chat-msg:last-child .chat-msg__media');
expect(media.innerHTML.replace(/(\r\n|\n|\r)/gm, "")).toEqual(
'<!-- src/templates/video.html -->'+
'<video controls=""><source src="http://localhost/video.mp4" type="video/mp4"></video>'+
'<a target="_blank" rel="noopener" href="http://localhost/video.mp4">Download video file</a>');
done();
});
});
}));
it("will render download links for files from oob URLs",
mock.initConverseWithPromises(
null, ['rosterGroupsFetched'], {},
null, ['rosterGroupsFetched', 'chatBoxesFetched'], {},
function (done, _converse) {
test_utils.createContacts(_converse, 'current', 1);
_converse.emit('rosterContactsFetched');
const contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@localhost';
test_utils.openChatBoxFor(_converse, contact_jid);
const view = _converse.chatboxviews.get(contact_jid);
spyOn(view.model, 'sendMessage').and.callThrough();
let view;
test_utils.openChatBoxFor(_converse, contact_jid)
.then(() => {
view = _converse.chatboxviews.get(contact_jid);
spyOn(view.model, 'sendMessage').and.callThrough();
const stanza = Strophe.xmlHtmlNode(
"<message from='"+contact_jid+"'"+
" type='chat'"+
" to='dummy@localhost/resource'>"+
" <body>Have you downloaded this funny file?</body>"+
" <x xmlns='jabber:x:oob'><url>http://localhost/funny.pdf</url></x>"+
"</message>").firstChild;
_converse.connection._dataRecv(test_utils.createRequest(stanza));
const stanza = Strophe.xmlHtmlNode(
"<message from='"+contact_jid+"'"+
" type='chat'"+
" to='dummy@localhost/resource'>"+
" <body>Have you downloaded this funny file?</body>"+
" <x xmlns='jabber:x:oob'><url>http://localhost/funny.pdf</url></x>"+
"</message>").firstChild;
_converse.connection._dataRecv(test_utils.createRequest(stanza));
test_utils.waitUntil(() => view.el.querySelectorAll('.chat-content .chat-msg a').length, 1000).then(function () {
test_utils.waitUntil(() => view.el.querySelectorAll('.chat-content .chat-msg a').length, 1000);
}).then(function () {
const msg = view.el.querySelector('.chat-msg .chat-msg__text');
expect(msg.outerHTML).toEqual('<div class="chat-msg__text">Have you downloaded this funny file?</div>');
const media = view.el.querySelector('.chat-msg .chat-msg__media');
......@@ -1789,28 +1824,31 @@
}));
it("will render images from oob URLs",
mock.initConverseWithPromises(
null, ['rosterGroupsFetched'], {},
function (done, _converse) {
mock.initConverseWithPromises(
null, ['rosterGroupsFetched', 'chatBoxesFetched'], {},
function (done, _converse) {
test_utils.createContacts(_converse, 'current');
_converse.emit('rosterContactsFetched');
const contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@localhost';
test_utils.openChatBoxFor(_converse, contact_jid);
const view = _converse.chatboxviews.get(contact_jid);
spyOn(view.model, 'sendMessage').and.callThrough();
const base_url = document.URL.split(window.location.pathname)[0];
const url = base_url+"/logo/conversejs-filled.svg";
const stanza = Strophe.xmlHtmlNode(
"<message from='"+contact_jid+"'"+
" type='chat'"+
" to='dummy@localhost/resource'>"+
" <body>Have you seen this funny image?</body>"+
" <x xmlns='jabber:x:oob'><url>"+url+"</url></x>"+
"</message>").firstChild;
_converse.connection._dataRecv(test_utils.createRequest(stanza));
let view;
test_utils.openChatBoxFor(_converse, contact_jid)
.then(() => {
view = _converse.chatboxviews.get(contact_jid);
spyOn(view.model, 'sendMessage').and.callThrough();
const base_url = document.URL.split(window.location.pathname)[0];
const url = base_url+"/logo/conversejs-filled.svg";
test_utils.waitUntil(() => view.el.querySelectorAll('.chat-content .chat-msg img').length, 2000).then(function () {
const stanza = Strophe.xmlHtmlNode(
"<message from='"+contact_jid+"'"+
" type='chat'"+
" to='dummy@localhost/resource'>"+
" <body>Have you seen this funny image?</body>"+
" <x xmlns='jabber:x:oob'><url>"+url+"</url></x>"+
"</message>").firstChild;
_converse.connection._dataRecv(test_utils.createRequest(stanza));
return test_utils.waitUntil(() => view.el.querySelectorAll('.chat-content .chat-msg img').length, 2000);
}).then(function () {
const msg = view.el.querySelector('.chat-msg .chat-msg__text');
expect(msg.outerHTML).toEqual('<div class="chat-msg__text">Have you seen this funny image?</div>');
const media = view.el.querySelector('.chat-msg .chat-msg__media');
......
......@@ -13,32 +13,37 @@
function (done, _converse) {
test_utils.createContacts(_converse, 'current');
_converse.emit('rosterContactsFetched');
test_utils.openControlBox();
_converse.minimized_chats.toggleview.model.browserStorage._clear();
_converse.minimized_chats.initToggle();
var contact_jid, chatview;
contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@localhost';
test_utils.openChatBoxFor(_converse, contact_jid);
chatview = _converse.chatboxviews.get(contact_jid);
expect(chatview.model.get('minimized')).toBeFalsy();
expect($(_converse.minimized_chats.el).is(':visible')).toBeFalsy();
chatview.el.querySelector('.toggle-chatbox-button').click();
expect(chatview.model.get('minimized')).toBeTruthy();
expect($(_converse.minimized_chats.el).is(':visible')).toBeTruthy();
expect(_converse.minimized_chats.keys().length).toBe(1);
expect(_converse.minimized_chats.keys()[0]).toBe(contact_jid);
contact_jid = mock.cur_names[1].replace(/ /g,'.').toLowerCase() + '@localhost';
test_utils.openChatBoxFor(_converse, contact_jid);
chatview = _converse.chatboxviews.get(contact_jid);
expect(chatview.model.get('minimized')).toBeFalsy();
chatview.el.querySelector('.toggle-chatbox-button').click();
expect(chatview.model.get('minimized')).toBeTruthy();
expect($(_converse.minimized_chats.el).is(':visible')).toBeTruthy();
expect(_converse.minimized_chats.keys().length).toBe(2);
expect(_.includes(_converse.minimized_chats.keys(), contact_jid)).toBeTruthy();
done();
let contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@localhost';
let chatview;
test_utils.openChatBoxFor(_converse, contact_jid)
.then(() => {
chatview = _converse.chatboxviews.get(contact_jid);
expect(chatview.model.get('minimized')).toBeFalsy();
expect($(_converse.minimized_chats.el).is(':visible')).toBeFalsy();
chatview.el.querySelector('.toggle-chatbox-button').click();
expect(chatview.model.get('minimized')).toBeTruthy();
expect($(_converse.minimized_chats.el).is(':visible')).toBeTruthy();
expect(_converse.minimized_chats.keys().length).toBe(1);
expect(_converse.minimized_chats.keys()[0]).toBe(contact_jid);
contact_jid = mock.cur_names[1].replace(/ /g,'.').toLowerCase() + '@localhost';
return test_utils.openChatBoxFor(_converse, contact_jid);
}).then(() => {
chatview = _converse.chatboxviews.get(contact_jid);
expect(chatview.model.get('minimized')).toBeFalsy();
chatview.el.querySelector('.toggle-chatbox-button').click();
expect(chatview.model.get('minimized')).toBeTruthy();
expect($(_converse.minimized_chats.el).is(':visible')).toBeTruthy();
expect(_converse.minimized_chats.keys().length).toBe(2);
expect(_.includes(_converse.minimized_chats.keys(), contact_jid)).toBeTruthy();
done();
});
}));
it("can be toggled to hide or show minimized chats",
......@@ -47,24 +52,26 @@
function (done, _converse) {
test_utils.createContacts(_converse, 'current');
_converse.emit('rosterContactsFetched');
test_utils.openControlBox();
_converse.minimized_chats.toggleview.model.browserStorage._clear();
_converse.minimized_chats.initToggle();
var contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@localhost';
test_utils.openChatBoxFor(_converse, contact_jid);
var chatview = _converse.chatboxviews.get(contact_jid);
expect($(_converse.minimized_chats.el).is(':visible')).toBeFalsy();
chatview.model.set({'minimized': true});
expect($(_converse.minimized_chats.el).is(':visible')).toBeTruthy();
expect(_converse.minimized_chats.keys().length).toBe(1);
expect(_converse.minimized_chats.keys()[0]).toBe(contact_jid);
expect($(_converse.minimized_chats.el.querySelector('.minimized-chats-flyout')).is(':visible')).toBeTruthy();
expect(_converse.minimized_chats.toggleview.model.get('collapsed')).toBeFalsy();
_converse.minimized_chats.el.querySelector('#toggle-minimized-chats').click();
return test_utils.waitUntil(() => u.isVisible(u.isVisible(_converse.minimized_chats.el.querySelector('.minimized-chats-flyout'))))
.then(function () {
const contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@localhost';
test_utils.openChatBoxFor(_converse, contact_jid)
.then(() => {
const chatview = _converse.chatboxviews.get(contact_jid);
expect(u.isVisible(_converse.minimized_chats.el)).toBeFalsy();
chatview.model.set({'minimized': true});
expect(u.isVisible(_converse.minimized_chats.el)).toBeTruthy();
expect(_converse.minimized_chats.keys().length).toBe(1);
expect(_converse.minimized_chats.keys()[0]).toBe(contact_jid);
expect(u.isVisible(_converse.minimized_chats.el.querySelector('.minimized-chats-flyout'))).toBeTruthy();
expect(_converse.minimized_chats.toggleview.model.get('collapsed')).toBeFalsy();
_converse.minimized_chats.el.querySelector('#toggle-minimized-chats').click();
return test_utils.waitUntil(() => u.isVisible(_converse.minimized_chats.el.querySelector('.minimized-chats-flyout')));
}).then(() => {
expect(_converse.minimized_chats.toggleview.model.get('collapsed')).toBeTruthy();
done();
});
......
......@@ -12,44 +12,46 @@
describe("A list of open rooms", function () {
it("is shown in the \"Rooms\" panel", mock.initConverseWithPromises(
null, ['rosterGroupsFetched'],
null, ['rosterGroupsFetched', 'chatBoxesFetched'],
{ allow_bookmarks: false // Makes testing easier, otherwise we
// have to mock stanza traffic.
},
function (done, _converse) {
test_utils.openControlBox();
var controlbox = _converse.chatboxviews.get('controlbox');
var list = controlbox.el.querySelector('div.rooms-list-container');
const controlbox = _converse.chatboxviews.get('controlbox');
let list = controlbox.el.querySelector('div.rooms-list-container');
expect(_.includes(list.classList, 'hidden')).toBeTruthy();
test_utils.openChatRoom(_converse, 'room', 'conference.shakespeare.lit', 'JC');
expect(_.isUndefined(_converse.rooms_list_view)).toBeFalsy();
var room_els = _converse.rooms_list_view.el.querySelectorAll(".open-room");
expect(room_els.length).toBe(1);
expect(room_els[0].innerText).toBe('room@conference.shakespeare.lit');
test_utils.openChatRoom(_converse, 'lounge', 'localhost', 'dummy');
room_els = _converse.rooms_list_view.el.querySelectorAll(".open-room");
expect(room_els.length).toBe(2);
var view = _converse.chatboxviews.get('room@conference.shakespeare.lit');
view.close();
room_els = _converse.rooms_list_view.el.querySelectorAll(".open-room");
expect(room_els.length).toBe(1);
expect(room_els[0].innerText).toBe('lounge@localhost');
list = controlbox.el.querySelector('div.rooms-list-container');
expect(_.includes(list.classList, 'hidden')).toBeFalsy();
view = _converse.chatboxviews.get('lounge@localhost');
view.close();
room_els = _converse.rooms_list_view.el.querySelectorAll(".open-room");
expect(room_els.length).toBe(0);
list = controlbox.el.querySelector('div.rooms-list-container');
expect(_.includes(list.classList, 'hidden')).toBeTruthy();
done();
let room_els;
test_utils.openChatRoom(_converse, 'room', 'conference.shakespeare.lit', 'JC')
.then(() => {
expect(_.isUndefined(_converse.rooms_list_view)).toBeFalsy();
room_els = _converse.rooms_list_view.el.querySelectorAll(".open-room");
expect(room_els.length).toBe(1);
expect(room_els[0].innerText).toBe('room@conference.shakespeare.lit');
return test_utils.openChatRoom(_converse, 'lounge', 'localhost', 'dummy');
}).then(() => {
room_els = _converse.rooms_list_view.el.querySelectorAll(".open-room");
expect(room_els.length).toBe(2);
var view = _converse.chatboxviews.get('room@conference.shakespeare.lit');
view.close();
room_els = _converse.rooms_list_view.el.querySelectorAll(".open-room");
expect(room_els.length).toBe(1);
expect(room_els[0].innerText).toBe('lounge@localhost');
list = controlbox.el.querySelector('div.rooms-list-container');
expect(_.includes(list.classList, 'hidden')).toBeFalsy();
view = _converse.chatboxviews.get('lounge@localhost');
view.close();
room_els = _converse.rooms_list_view.el.querySelectorAll(".open-room");
expect(room_els.length).toBe(0);
list = controlbox.el.querySelector('div.rooms-list-container');
expect(_.includes(list.classList, 'hidden')).toBeTruthy();
done();
});
}
));
});
......@@ -57,79 +59,81 @@
describe("A groupchat shown in the groupchats list", function () {
it("is highlighted if its currently open", mock.initConverseWithPromises(
null, ['rosterGroupsFetched'],
null, ['rosterGroupsFetched', 'chatBoxesFetched'],
{ whitelisted_plugins: ['converse-roomslist'],
allow_bookmarks: false // Makes testing easier, otherwise we
// have to mock stanza traffic.
}, function (done, _converse) {
spyOn(_converse, 'isSingleton').and.callFake(function () {
return true;
});
spyOn(_converse, 'isSingleton').and.callFake(() => true);
let room_els, item;
test_utils.openControlBox();
_converse.api.rooms.open('coven@chat.shakespeare.lit', {'nick': 'some1'});
let room_els = _converse.rooms_list_view.el.querySelectorAll(".available-chatroom");
expect(room_els.length).toBe(1);
let item = room_els[0];
expect(u.hasClass('open', item)).toBe(true);
expect(item.textContent.trim()).toBe('coven@chat.shakespeare.lit');
_converse.api.rooms.open('coven@chat.shakespeare.lit', {'nick': 'some1'})
.then(() => {
room_els = _converse.rooms_list_view.el.querySelectorAll(".available-chatroom");
expect(room_els.length).toBe(1);
_converse.api.rooms.open('balcony@chat.shakespeare.lit', {'nick': 'some1'});
room_els = _converse.rooms_list_view.el.querySelectorAll(".open-room");
expect(room_els.length).toBe(2);
item = room_els[0];
expect(u.hasClass('open', item)).toBe(true);
expect(item.textContent.trim()).toBe('coven@chat.shakespeare.lit');
return _converse.api.rooms.open('balcony@chat.shakespeare.lit', {'nick': 'some1'});
}).then(() => {
room_els = _converse.rooms_list_view.el.querySelectorAll(".open-room");
expect(room_els.length).toBe(2);
room_els = _converse.rooms_list_view.el.querySelectorAll(".available-chatroom.open");
expect(room_els.length).toBe(1);
item = room_els[0];
expect(item.textContent.trim()).toBe('balcony@chat.shakespeare.lit');
done();
room_els = _converse.rooms_list_view.el.querySelectorAll(".available-chatroom.open");
expect(room_els.length).toBe(1);
item = room_els[0];
expect(item.textContent.trim()).toBe('balcony@chat.shakespeare.lit');
done();
});
}));
it("has an info icon which opens a details modal when clicked", mock.initConverseWithPromises(
null, ['rosterGroupsFetched'],
null, ['rosterGroupsFetched', 'chatBoxesFetched'],
{ whitelisted_plugins: ['converse-roomslist'],
allow_bookmarks: false // Makes testing easier, otherwise we
// have to mock stanza traffic.
}, function (done, _converse) {
let view;
test_utils.openControlBox();
_converse.api.rooms.open('coven@chat.shakespeare.lit', {'nick': 'some1'});
const view = _converse.chatboxviews.get('coven@chat.shakespeare.lit');
const last_stanza = _.last(_converse.connection.IQ_stanzas).nodeTree;
const IQ_id = last_stanza.getAttribute('id');
const features_stanza = $iq({
'from': 'coven@chat.shakespeare.lit',
'id': IQ_id,
'to': 'dummy@localhost/desktop',
'type': 'result'
})
.c('query', { 'xmlns': 'http://jabber.org/protocol/disco#info'})
.c('identity', {
'category': 'conference',
'name': 'A Dark Cave',
'type': 'text'
}).up()
.c('feature', {'var': 'http://jabber.org/protocol/muc'}).up()
.c('feature', {'var': 'muc_passwordprotected'}).up()
.c('feature', {'var': 'muc_hidden'}).up()
.c('feature', {'var': 'muc_temporary'}).up()
.c('feature', {'var': 'muc_open'}).up()
.c('feature', {'var': 'muc_unmoderated'}).up()
.c('feature', {'var': 'muc_nonanonymous'}).up()
.c('feature', {'var': 'urn:xmpp:mam:0'}).up()
.c('x', { 'xmlns':'jabber:x:data', 'type':'result'})
.c('field', {'var':'FORM_TYPE', 'type':'hidden'})
.c('value').t('http://jabber.org/protocol/muc#roominfo').up().up()
.c('field', {'type':'text-single', 'var':'muc#roominfo_description', 'label':'Description'})
.c('value').t('This is the description').up().up()
.c('field', {'type':'text-single', 'var':'muc#roominfo_occupants', 'label':'Number of occupants'})
.c('value').t(0);
_converse.connection._dataRecv(test_utils.createRequest(features_stanza));
test_utils.waitUntil(() => view.model.get('connection_status') === converse.ROOMSTATUS.CONNECTING)
.then(function () {
_converse.api.rooms.open('coven@chat.shakespeare.lit', {'nick': 'some1'})
.then(() => {
view = _converse.chatboxviews.get('coven@chat.shakespeare.lit');
const last_stanza = _.last(_converse.connection.IQ_stanzas).nodeTree;
const IQ_id = last_stanza.getAttribute('id');
const features_stanza = $iq({
'from': 'coven@chat.shakespeare.lit',
'id': IQ_id,
'to': 'dummy@localhost/desktop',
'type': 'result'
})
.c('query', { 'xmlns': 'http://jabber.org/protocol/disco#info'})
.c('identity', {
'category': 'conference',
'name': 'A Dark Cave',
'type': 'text'
}).up()
.c('feature', {'var': 'http://jabber.org/protocol/muc'}).up()
.c('feature', {'var': 'muc_passwordprotected'}).up()
.c('feature', {'var': 'muc_hidden'}).up()
.c('feature', {'var': 'muc_temporary'}).up()
.c('feature', {'var': 'muc_open'}).up()
.c('feature', {'var': 'muc_unmoderated'}).up()
.c('feature', {'var': 'muc_nonanonymous'}).up()
.c('feature', {'var': 'urn:xmpp:mam:0'}).up()
.c('x', { 'xmlns':'jabber:x:data', 'type':'result'})
.c('field', {'var':'FORM_TYPE', 'type':'hidden'})
.c('value').t('http://jabber.org/protocol/muc#roominfo').up().up()
.c('field', {'type':'text-single', 'var':'muc#roominfo_description', 'label':'Description'})
.c('value').t('This is the description').up().up()
.c('field', {'type':'text-single', 'var':'muc#roominfo_occupants', 'label':'Number of occupants'})
.c('value').t(0);
_converse.connection._dataRecv(test_utils.createRequest(features_stanza));
return test_utils.waitUntil(() => view.model.get('connection_status') === converse.ROOMSTATUS.CONNECTING)
}).then(function () {
var presence = $pres({
to: _converse.connection.jid,
from: 'coven@chat.shakespeare.lit/some1',
......@@ -201,23 +205,22 @@
},
function (done, _converse) {
spyOn(window, 'confirm').and.callFake(function () {
return true;
});
spyOn(window, 'confirm').and.callFake(() => true);
expect(_converse.chatboxes.length).toBe(1);
test_utils.openChatRoom(
_converse, 'lounge', 'conference.shakespeare.lit', 'JC');
expect(_converse.chatboxes.length).toBe(2);
var room_els = _converse.rooms_list_view.el.querySelectorAll(".open-room");
expect(room_els.length).toBe(1);
var close_el = _converse.rooms_list_view.el.querySelector(".close-room");
close_el.click();
expect(window.confirm).toHaveBeenCalledWith(
'Are you sure you want to leave the groupchat lounge@conference.shakespeare.lit?');
room_els = _converse.rooms_list_view.el.querySelectorAll(".open-room");
expect(room_els.length).toBe(0);
expect(_converse.chatboxes.length).toBe(1);
done();
test_utils.openChatRoom(_converse, 'lounge', 'conference.shakespeare.lit', 'JC')
.then(() => {
expect(_converse.chatboxes.length).toBe(2);
var room_els = _converse.rooms_list_view.el.querySelectorAll(".open-room");
expect(room_els.length).toBe(1);
var close_el = _converse.rooms_list_view.el.querySelector(".close-room");
close_el.click();
expect(window.confirm).toHaveBeenCalledWith(
'Are you sure you want to leave the groupchat lounge@conference.shakespeare.lit?');
room_els = _converse.rooms_list_view.el.querySelectorAll(".open-room");
expect(room_els.length).toBe(0);
expect(_converse.chatboxes.length).toBe(1);
done();
});
}));
it("shows unread messages directed at the user", mock.initConverseWithAsync(
......
......@@ -92,12 +92,14 @@
it("can be sent without a hint",
mock.initConverseWithPromises(
null, ['rosterGroupsFetched'], {},
null, ['rosterGroupsFetched', 'chatBoxesFetched'], {},
function (done, _converse) {
test_utils.createContacts(_converse, 'current');
test_utils.createContacts(_converse, 'current', 1);
_converse.emit('rosterContactsFetched');
test_utils.openControlBox();
var contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@localhost';
const contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@localhost';
// XXX: We need to send a presence from the contact, so that we
// have a resource, that resource is then queried to see
......@@ -108,9 +110,9 @@
'to': 'dummy@localhost'
});
_converse.connection._dataRecv(test_utils.createRequest(presence));
test_utils.openChatBoxFor(_converse, contact_jid);
test_utils.waitUntilDiscoConfirmed(_converse, contact_jid+'/phone', [], [Strophe.NS.SPOILER]).then(function () {
test_utils.openChatBoxFor(_converse, contact_jid)
.then(() => test_utils.waitUntilDiscoConfirmed(_converse, contact_jid+'/phone', [], [Strophe.NS.SPOILER]))
.then(() => {
var view = _converse.chatboxviews.get(contact_jid);
spyOn(view, 'onMessageSubmitted').and.callThrough();
spyOn(_converse.connection, 'send');
......@@ -167,10 +169,12 @@
it("can be sent with a hint",
mock.initConverseWithPromises(
null, ['rosterGroupsFetched'], {},
null, ['rosterGroupsFetched', 'chatBoxesFetched'], {},
function (done, _converse) {
test_utils.createContacts(_converse, 'current');
test_utils.createContacts(_converse, 'current', 1);
_converse.emit('rosterContactsFetched');
test_utils.openControlBox();
var contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@localhost';
......@@ -183,9 +187,9 @@
'to': 'dummy@localhost'
});
_converse.connection._dataRecv(test_utils.createRequest(presence));
test_utils.openChatBoxFor(_converse, contact_jid);
test_utils.waitUntilDiscoConfirmed(_converse, contact_jid+'/phone', [], [Strophe.NS.SPOILER]).then(function () {
test_utils.openChatBoxFor(_converse, contact_jid)
.then(() => test_utils.waitUntilDiscoConfirmed(_converse, contact_jid+'/phone', [], [Strophe.NS.SPOILER]))
.then(() => {
var view = _converse.chatboxviews.get(contact_jid);
var spoiler_toggle = view.el.querySelector('.toggle-compose-spoiler');
spoiler_toggle.click();
......@@ -206,17 +210,17 @@
expect(view.onMessageSubmitted).toHaveBeenCalled();
/* Test the XML stanza
*
* <message from="dummy@localhost/resource"
* to="max.frankfurter@localhost"
* type="chat"
* id="4547c38b-d98b-45a5-8f44-b4004dbc335e"
* xmlns="jabber:client">
* <body>This is the spoiler</body>
* <active xmlns="http://jabber.org/protocol/chatstates"/>
* <spoiler xmlns="urn:xmpp:spoiler:0">This is the hint</spoiler>
* </message>"
*/
*
* <message from="dummy@localhost/resource"
* to="max.frankfurter@localhost"
* type="chat"
* id="4547c38b-d98b-45a5-8f44-b4004dbc335e"
* xmlns="jabber:client">
* <body>This is the spoiler</body>
* <active xmlns="http://jabber.org/protocol/chatstates"/>
* <spoiler xmlns="urn:xmpp:spoiler:0">This is the hint</spoiler>
* </message>"
*/
var stanza = _converse.connection.send.calls.argsFor(0)[0].tree();
var spoiler_el = stanza.querySelector('spoiler[xmlns="urn:xmpp:spoiler:0"]');
......
......@@ -58,16 +58,17 @@
test_utils.createContacts(_converse, 'current');
_converse.emit('rosterContactsFetched');
let view, modal;
const contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@localhost';
test_utils.openChatBoxFor(_converse, contact_jid);
const view = _converse.chatboxviews.get(contact_jid);
const show_modal_button = view.el.querySelector('.show-user-details-modal');
expect(u.isVisible(show_modal_button)).toBeTruthy();
show_modal_button.click();
const modal = view.user_details_modal;
test_utils.waitUntil(() => u.isVisible(modal.el), 2000)
.then(function () {
test_utils.openChatBoxFor(_converse, contact_jid)
.then(() => {
view = _converse.chatboxviews.get(contact_jid);
const show_modal_button = view.el.querySelector('.show-user-details-modal');
expect(u.isVisible(show_modal_button)).toBeTruthy();
show_modal_button.click();
modal = view.user_details_modal;
return test_utils.waitUntil(() => u.isVisible(modal.el), 2000);
}).then(function () {
spyOn(window, 'confirm').and.returnValue(true);
spyOn(view.model.contact, 'removeFromRoster').and.callFake(function (callback, errback) {
errback();
......
......@@ -561,8 +561,7 @@
const handler = () => {
if (!u.isPersistableModel(this.model)) {
// Happens during tests, nothing to do if this
// is a hanging chatbox (i.e. not in the
// collection anymore).
// is a hanging chatbox (i.e. not in the collection anymore).
return;
}
this.populateAndJoin();
......
......@@ -148,8 +148,13 @@
);
xhr.onload = function () {
if (xhr.status >= 200 && xhr.status < 400) {
jed_instance = new Jed(window.JSON.parse(xhr.responseText));
resolve();
try {
const data = window.JSON.parse(xhr.responseText);
jed_instance = new Jed(data);
resolve();
} catch (e) {
xhr.onerror(e);
}
} else {
xhr.onerror();
}
......
......@@ -98,8 +98,9 @@
return views;
};
utils.openChatBoxFor = function (converse, jid) {
return converse.roster.get(jid).trigger("open");
utils.openChatBoxFor = function (_converse, jid) {
_converse.roster.get(jid).trigger("open");
return utils.waitUntil(() => _converse.chatboxviews.get(jid));
};
utils.openChatRoomViaModal = function (_converse, jid, nick) {
......@@ -121,64 +122,64 @@
};
utils.openChatRoom = function (_converse, room, server, nick) {
_converse.api.rooms.open(`${room}@${server}`);
return _converse.api.rooms.open(`${room}@${server}`);
};
utils.openAndEnterChatRoom = function (_converse, room, server, nick) {
let last_stanza;
return new Promise(function (resolve, reject) {
_converse.api.rooms.open(`${room}@${server}`);
const view = _converse.chatboxviews.get((room+'@'+server).toLowerCase());
// We pretend this is a new room, so no disco info is returned.
let last_stanza = _.last(_converse.connection.IQ_stanzas).nodeTree;
const IQ_id = last_stanza.getAttribute('id');
const features_stanza = $iq({
'from': room+'@'+server,
'id': IQ_id,
'to': nick+'@'+server,
'type': 'error'
}).c('error', {'type': 'cancel'})
.c('item-not-found', {'xmlns': "urn:ietf:params:xml:ns:xmpp-stanzas"});
_converse.connection._dataRecv(utils.createRequest(features_stanza));
utils.waitUntil(() => {
return _.filter(
_converse.connection.IQ_stanzas, (node) => {
const query = node.nodeTree.querySelector('query');
if (query && query.getAttribute('node') === 'x-roomuser-item') {
last_stanza = node.nodeTree;
return true;
}
}).length
}).then(function () {
// The XMPP server returns the reserved nick for this user.
return new Promise((resolve, reject) => {
return _converse.api.rooms.open(`${room}@${server}`).then(() => {
const view = _converse.chatboxviews.get((room+'@'+server).toLowerCase());
// We pretend this is a new room, so no disco info is returned.
let last_stanza = _.last(_converse.connection.IQ_stanzas).nodeTree;
const IQ_id = last_stanza.getAttribute('id');
const stanza = $iq({
'type': 'result',
'id': IQ_id,
'from': view.model.get('jid'),
'to': _converse.connection.jid
}).c('query', {'xmlns': 'http://jabber.org/protocol/disco#info', 'node': 'x-roomuser-item'})
.c('identity', {'category': 'conference', 'name': nick, 'type': 'text'});
_converse.connection._dataRecv(utils.createRequest(stanza));
// 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: _converse.connection.jid,
from: room+'@'+server+'/'+nick,
id: 'DC352437-C019-40EC-B590-AF29E879AF97'
}).c('x').attrs({xmlns:'http://jabber.org/protocol/muc#user'})
.c('item').attrs({
affiliation: 'member',
jid: _converse.bare_jid,
role: 'participant'
}).up()
.c('status').attrs({code:'110'});
_converse.connection._dataRecv(utils.createRequest(presence));
resolve();
const features_stanza = $iq({
'from': room+'@'+server,
'id': IQ_id,
'to': nick+'@'+server,
'type': 'error'
}).c('error', {'type': 'cancel'})
.c('item-not-found', {'xmlns': "urn:ietf:params:xml:ns:xmpp-stanzas"});
_converse.connection._dataRecv(utils.createRequest(features_stanza));
utils.waitUntil(() => {
return _.filter(
_converse.connection.IQ_stanzas, (node) => {
const query = node.nodeTree.querySelector('query');
if (query && query.getAttribute('node') === 'x-roomuser-item') {
last_stanza = node.nodeTree;
return true;
}
}).length
}).then(function () {
// The XMPP server returns the reserved nick for this user.
const IQ_id = last_stanza.getAttribute('id');
const stanza = $iq({
'type': 'result',
'id': IQ_id,
'from': view.model.get('jid'),
'to': _converse.connection.jid
}).c('query', {'xmlns': 'http://jabber.org/protocol/disco#info', 'node': 'x-roomuser-item'})
.c('identity', {'category': 'conference', 'name': nick, 'type': 'text'});
_converse.connection._dataRecv(utils.createRequest(stanza));
// 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: _converse.connection.jid,
from: room+'@'+server+'/'+nick,
id: 'DC352437-C019-40EC-B590-AF29E879AF97'
}).c('x').attrs({xmlns:'http://jabber.org/protocol/muc#user'})
.c('item').attrs({
affiliation: 'member',
jid: _converse.bare_jid,
role: 'participant'
}).up()
.c('status').attrs({code:'110'});
_converse.connection._dataRecv(utils.createRequest(presence));
resolve();
}).catch(_.partial(console.error, _));
}).catch(_.partial(console.error, _));
}).catch(_.partial(console.error, _));
};
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment