Wait for promises before opening chats in API methods

This commit is contained in:
JC Brand 2018-07-30 18:16:32 +02:00
parent cb118b9cd0
commit 506aa33131
14 changed files with 2464 additions and 2374 deletions

View File

@ -39,6 +39,9 @@
- New API method `_converse.api.vcard.update`. - New API method `_converse.api.vcard.update`.
- The `contactStatusChanged` event has been renamed to `contactPresenceChanged` - The `contactStatusChanged` event has been renamed to `contactPresenceChanged`
and a event `presenceChanged` is now also triggered on the contact. 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 ## UI changes

43
dist/converse.js vendored
View File

@ -76149,17 +76149,7 @@ var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_
this.model.on('show', this.show, this); this.model.on('show', this.show, this);
this.model.occupants.on('add', this.showJoinNotification, this); this.model.occupants.on('add', this.showJoinNotification, this);
this.model.occupants.on('remove', this.showLeaveNotification, this); this.model.occupants.on('remove', this.showLeaveNotification, this);
this.model.occupants.on('change:show', occupant => { this.model.occupants.on('change:show', this.showJoinOrLeaveNotification, this);
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.createEmojiPicker(); this.createEmojiPicker();
this.createOccupantsView(); this.createOccupantsView();
this.render().insertIntoDOM(); this.render().insertIntoDOM();
@ -76169,8 +76159,7 @@ var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_
const handler = () => { const handler = () => {
if (!u.isPersistableModel(this.model)) { if (!u.isPersistableModel(this.model)) {
// Happens during tests, nothing to do if this // Happens during tests, nothing to do if this
// is a hanging chatbox (i.e. not in the // is a hanging chatbox (i.e. not in the collection anymore).
// collection anymore).
return; 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) { showJoinNotification(occupant) {
if (this.model.get('connection_status') !== converse.ROOMSTATUS.ENTERED) { if (this.model.get('connection_status') !== converse.ROOMSTATUS.ENTERED) {
return; return;
@ -77094,10 +77095,9 @@ var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_
showLeaveNotification(occupant) { showLeaveNotification(occupant) {
const nick = occupant.get('nick'), const nick = occupant.get('nick'),
stat = occupant.get('status'), stat = occupant.get('status'),
last_el = this.content.lastElementChild, last_el = this.content.lastElementChild;
last_msg_date = last_el.getAttribute('data-isodate');
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; let message;
if (_.isNil(stat)) { if (_.isNil(stat)) {
@ -77128,7 +77128,7 @@ var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_
'data': `data-leave="${nick}"` '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); last_el.outerHTML = tpl_info(data);
} else { } else {
const el = u.stringToElement(tpl_info(data)); 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 () { xhr.onload = function () {
if (xhr.status >= 200 && xhr.status < 400) { if (xhr.status >= 200 && xhr.status < 400) {
jed_instance = new Jed(window.JSON.parse(xhr.responseText)); try {
resolve(); const data = window.JSON.parse(xhr.responseText);
jed_instance = new Jed(data);
resolve();
} catch (e) {
xhr.onerror(e);
}
} else { } else {
xhr.onerror(); xhr.onerror();
} }

View File

@ -34,24 +34,24 @@
}); });
spyOn(_converse.connection, 'getUniqueId').and.callThrough(); spyOn(_converse.connection, 'getUniqueId').and.callThrough();
test_utils.openChatRoom(_converse, 'theplay', 'conference.shakespeare.lit', 'JC'); let view;
var jid = 'theplay@conference.shakespeare.lit'; test_utils.openChatRoom(_converse, 'theplay', 'conference.shakespeare.lit', 'JC')
var view = _converse.chatboxviews.get(jid); .then(() => {
spyOn(view, 'renderBookmarkForm').and.callThrough(); var jid = 'theplay@conference.shakespeare.lit';
spyOn(view, 'closeForm').and.callThrough(); view = _converse.chatboxviews.get(jid);
spyOn(view, 'renderBookmarkForm').and.callThrough();
test_utils.waitUntil(function () { spyOn(view, 'closeForm').and.callThrough();
return !_.isNull(view.el.querySelector('.toggle-bookmark')); return test_utils.waitUntil(() => !_.isNull(view.el.querySelector('.toggle-bookmark')));
}, 300).then(function () { }).then(() => {
var $bookmark = $(view.el).find('.toggle-bookmark'); var bookmark = view.el.querySelector('.toggle-bookmark');
$bookmark[0].click(); bookmark.click();
expect(view.renderBookmarkForm).toHaveBeenCalled(); expect(view.renderBookmarkForm).toHaveBeenCalled();
view.el.querySelector('.button-cancel').click(); view.el.querySelector('.button-cancel').click();
expect(view.closeForm).toHaveBeenCalled(); 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(); expect(view.renderBookmarkForm).toHaveBeenCalled();
/* Client uploads data: /* Client uploads data:
@ -93,7 +93,7 @@
view.el.querySelector('.btn-primary').click(); view.el.querySelector('.btn-primary').click();
expect(view.model.get('bookmarked')).toBeTruthy(); expect(view.model.get('bookmarked')).toBeTruthy();
expect($bookmark.hasClass('on-button'), true); expect(u.hasClass('on-button', bookmark), true);
expect(sent_stanza.toLocaleString()).toBe( expect(sent_stanza.toLocaleString()).toBe(
"<iq type='set' from='dummy@localhost/resource' xmlns='jabber:client' id='"+IQ_id+"'>"+ "<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( it("displays that it's bookmarked through its bookmark icon", mock.initConverseWithPromises(
null, ['rosterGroupsFetched'], {}, function (done, _converse) { null, ['rosterGroupsFetched'], {}, function (done, _converse) {
let view;
test_utils.waitUntilDiscoConfirmed( test_utils.waitUntilDiscoConfirmed(
_converse, _converse.bare_jid, _converse, _converse.bare_jid,
[{'category': 'pubsub', 'type': 'pep'}], [{'category': 'pubsub', 'type': 'pep'}],
['http://jabber.org/protocol/pubsub#publish-options'] ['http://jabber.org/protocol/pubsub#publish-options']
).then(function () { ).then(() => test_utils.openChatRoom(_converse, 'lounge', 'localhost', 'dummy'))
test_utils.openChatRoom(_converse, 'lounge', 'localhost', 'dummy'); .then(() => {
var view = _converse.chatboxviews.get('lounge@localhost'); view = _converse.chatboxviews.get('lounge@localhost');
return test_utils.waitUntil(() => !_.isNull(view.el.querySelector('.toggle-bookmark')))
test_utils.waitUntil(function () { }).then(function () {
return !_.isNull(view.el.querySelector('.toggle-bookmark')); var bookmark_icon = view.el.querySelector('.toggle-bookmark');
}, 300).then(function () { expect(_.includes(bookmark_icon.classList, 'button-on')).toBeFalsy();
var bookmark_icon = view.el.querySelector('.toggle-bookmark'); view.model.set('bookmarked', true);
expect(_.includes(bookmark_icon.classList, 'button-on')).toBeFalsy(); expect(_.includes(bookmark_icon.classList, 'button-on')).toBeTruthy();
view.model.set('bookmarked', true); view.model.set('bookmarked', false);
expect(_.includes(bookmark_icon.classList, 'button-on')).toBeTruthy(); expect(_.includes(bookmark_icon.classList, 'button-on')).toBeFalsy();
view.model.set('bookmarked', false); done();
expect(_.includes(bookmark_icon.classList, 'button-on')).toBeFalsy();
done();
});
}); });
})); }));
it("can be unbookmarked", mock.initConverseWithPromises( it("can be unbookmarked", mock.initConverseWithPromises(
null, ['rosterGroupsFetched'], {}, function (done, _converse) { null, ['rosterGroupsFetched'], {}, function (done, _converse) {
let sent_stanza, IQ_id, view, sendIQ;
test_utils.waitUntilDiscoConfirmed( test_utils.waitUntilDiscoConfirmed(
_converse, _converse.bare_jid, _converse, _converse.bare_jid,
[{'category': 'pubsub', 'type': 'pep'}], [{'category': 'pubsub', 'type': 'pep'}],
['http://jabber.org/protocol/pubsub#publish-options'] ['http://jabber.org/protocol/pubsub#publish-options']
).then(function () { ).then(() => {
var sent_stanza, IQ_id; sendIQ = _converse.connection.sendIQ;
var sendIQ = _converse.connection.sendIQ; return test_utils.openChatRoom(_converse, 'theplay', 'conference.shakespeare.lit', 'JC');
}).then(() => {
test_utils.openChatRoom(_converse, 'theplay', 'conference.shakespeare.lit', 'JC');
var jid = 'theplay@conference.shakespeare.lit'; 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 () { _converse.bookmarks.create({
return !_.isNull(view.el.querySelector('.toggle-bookmark')); 'jid': view.model.get('jid'),
}, 300).then(function () { 'autojoin': false,
spyOn(view, 'toggleBookmark').and.callThrough(); 'name': 'The Play',
spyOn(_converse.bookmarks, 'sendBookmarkStanza').and.callThrough(); 'nick': ' Othello'
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();
}); });
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', 'name': 'The Play',
'nick': '' 'nick': ''
}); });
test_utils.waitUntil(function () { test_utils.waitUntil(() => $('#chatrooms .bookmarks.rooms-list .room-item:visible').length
return $('#chatrooms .bookmarks.rooms-list .room-item:visible').length; ).then(function () {
}, 300).then(function () {
expect($('#chatrooms .bookmarks.rooms-list').hasClass('collapsed')).toBeFalsy(); expect($('#chatrooms .bookmarks.rooms-list').hasClass('collapsed')).toBeFalsy();
expect($('#chatrooms .bookmarks.rooms-list .room-item:visible').length).toBe(1); expect($('#chatrooms .bookmarks.rooms-list .room-item:visible').length).toBe(1);
expect(_converse.bookmarksview.list_model.get('toggle-state')).toBe(_converse.OPENED); expect(_converse.bookmarksview.list_model.get('toggle-state')).toBe(_converse.OPENED);
@ -612,6 +607,7 @@
{ hide_open_bookmarks: true }, { hide_open_bookmarks: true },
function (done, _converse) { function (done, _converse) {
const jid = 'room@conference.example.org';
test_utils.waitUntilDiscoConfirmed( test_utils.waitUntilDiscoConfirmed(
_converse, _converse.bare_jid, _converse, _converse.bare_jid,
[{'category': 'pubsub', 'type': 'pep'}], [{'category': 'pubsub', 'type': 'pep'}],
@ -625,14 +621,12 @@
_converse.emit('bookmarksInitialized'); _converse.emit('bookmarksInitialized');
// Check that it's there // Check that it's there
var jid = 'room@conference.example.org';
_converse.bookmarks.create({ _converse.bookmarks.create({
'jid': jid, 'jid': jid,
'autojoin': false, 'autojoin': false,
'name': 'The Play', 'name': 'The Play',
'nick': ' Othello' 'nick': ' Othello'
}); });
expect(_converse.bookmarks.length).toBe(1); expect(_converse.bookmarks.length).toBe(1);
var room_els = _converse.bookmarksview.el.querySelectorAll(".open-room"); var room_els = _converse.bookmarksview.el.querySelectorAll(".open-room");
expect(room_els.length).toBe(1); expect(room_els.length).toBe(1);
@ -640,9 +634,11 @@
// Check that it disappears once the room is opened // Check that it disappears once the room is opened
var bookmark = _converse.bookmarksview.el.querySelector(".open-room"); var bookmark = _converse.bookmarksview.el.querySelector(".open-room");
bookmark.click(); bookmark.click();
return test_utils.waitUntil(() => _converse.chatboxviews.get(jid));
}).then(() => {
expect(u.hasClass('hidden', _converse.bookmarksview.el.querySelector(".available-chatroom"))).toBeTruthy(); expect(u.hasClass('hidden', _converse.bookmarksview.el.querySelector(".available-chatroom"))).toBeTruthy();
// Check that it reappears once the room is closed // Check that it reappears once the room is closed
var view = _converse.chatboxviews.get(jid); const view = _converse.chatboxviews.get(jid);
view.close(); view.close();
expect(u.hasClass('hidden', _converse.bookmarksview.el.querySelector(".available-chatroom"))).toBeFalsy(); expect(u.hasClass('hidden', _converse.bookmarksview.el.querySelector(".available-chatroom"))).toBeFalsy();
done(); done();

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -225,25 +225,28 @@
[{'category': 'server', 'type':'IM'}], [{'category': 'server', 'type':'IM'}],
['http://jabber.org/protocol/disco#items'], [], 'info').then(function () { ['http://jabber.org/protocol/disco#items'], [], 'info').then(function () {
test_utils.waitUntilDiscoConfirmed(_converse, _converse.domain, [], [], ['upload.localhost'], 'items').then(function () { let contact_jid, view;
test_utils.waitUntilDiscoConfirmed(_converse, 'upload.localhost', [], [Strophe.NS.HTTPUPLOAD], []).then(function () {
test_utils.createContacts(_converse, 'current'); test_utils.waitUntilDiscoConfirmed(_converse, _converse.domain, [], [], ['upload.localhost'], 'items')
var contact_jid = mock.cur_names[2].replace(/ /g,'.').toLowerCase() + '@localhost'; .then(() => test_utils.waitUntilDiscoConfirmed(_converse, 'upload.localhost', [], [Strophe.NS.HTTPUPLOAD], []))
test_utils.openChatBoxFor(_converse, contact_jid); .then(() => {
var view = _converse.chatboxviews.get(contact_jid); test_utils.createContacts(_converse, 'current', 3);
test_utils.waitUntil(function () { _converse.emit('rosterContactsFetched');
return view.el.querySelector('.upload-file');
}, 150).then(function () { contact_jid = mock.cur_names[2].replace(/ /g,'.').toLowerCase() + '@localhost';
expect(view.el.querySelector('.chat-toolbar .upload-file')).not.toBe(null); return test_utils.openChatBoxFor(_converse, contact_jid);
done(); }).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( it("appears in MUC chats", mock.initConverseWithPromises(
null, ['rosterGroupsFetched'], {}, null, ['rosterGroupsFetched', 'chatBoxesFetched'], {},
function (done, _converse) { function (done, _converse) {
test_utils.waitUntilDiscoConfirmed( test_utils.waitUntilDiscoConfirmed(
@ -251,19 +254,15 @@
[{'category': 'server', 'type':'IM'}], [{'category': 'server', 'type':'IM'}],
['http://jabber.org/protocol/disco#items'], [], 'info').then(function () { ['http://jabber.org/protocol/disco#items'], [], 'info').then(function () {
test_utils.waitUntilDiscoConfirmed(_converse, _converse.domain, [], [], ['upload.localhost'], 'items').then(function () { test_utils.waitUntilDiscoConfirmed(_converse, _converse.domain, [], [], ['upload.localhost'], 'items')
test_utils.waitUntilDiscoConfirmed(_converse, 'upload.localhost', [], [Strophe.NS.HTTPUPLOAD], []).then(function () { .then(() => test_utils.waitUntilDiscoConfirmed(_converse, 'upload.localhost', [], [Strophe.NS.HTTPUPLOAD], []))
test_utils.openAndEnterChatRoom(_converse, 'lounge', 'localhost', 'dummy').then(function () { .then(() => test_utils.openAndEnterChatRoom(_converse, 'lounge', 'localhost', 'dummy'))
var view = _converse.chatboxviews.get('lounge@localhost'); .then(() => test_utils.waitUntil(() => _converse.chatboxviews.get('lounge@localhost').el.querySelector('.upload-file')))
test_utils.waitUntil(function () { .then(() => {
return view.el.querySelector('.upload-file'); const view = _converse.chatboxviews.get('lounge@localhost');
}).then(function () { expect(view.el.querySelector('.chat-toolbar .upload-file')).not.toBe(null);
expect(view.el.querySelector('.chat-toolbar .upload-file')).not.toBe(null); done();
done(); }).catch(_.partial(_converse.log, _, Strophe.LogLevel.FATAL));
});
});
});
});
}); });
})); }));
@ -277,101 +276,104 @@
var send_backup = XMLHttpRequest.prototype.send; var send_backup = XMLHttpRequest.prototype.send;
var IQ_stanzas = _converse.connection.IQ_stanzas; var IQ_stanzas = _converse.connection.IQ_stanzas;
let 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(() => {
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;
});
_converse.connection._dataRecv(test_utils.createRequest(stanza));
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 test_utils.waitUntil(function () {
return _.filter(IQ_stanzas, function (iq) { return sent_stanza;
return iq.nodeTree.querySelector('iq[to="upload.montague.tld"] request'); }, 1000).then(function () {
}).length > 0; expect(sent_stanza.toLocaleString()).toBe(
}).then(function () { "<message from='dummy@localhost/resource' "+
var iq = IQ_stanzas.pop(); "to='irini.vlastuin@localhost' "+
expect(iq.toLocaleString()).toBe( "type='chat' "+
"<iq from='dummy@localhost/resource' "+ "id='"+sent_stanza.nodeTree.getAttribute('id')+"' xmlns='jabber:client'>"+
"to='upload.montague.tld' "+ "<body>"+message+"</body>"+
"type='get' "+ "<active xmlns='http://jabber.org/protocol/chatstates'/>"+
"xmlns='jabber:client' "+ "<x xmlns='jabber:x:oob'>"+
"id='"+iq.nodeTree.getAttribute('id')+"'>"+ "<url>"+message+"</url>"+
"<request xmlns='urn:xmpp:http:upload:0' "+ "</x>"+
"filename='my-juliet.jpg' "+ "</message>");
"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;
});
_converse.connection._dataRecv(test_utils.createRequest(stanza));
return test_utils.waitUntil(function () { return test_utils.waitUntil(function () {
return sent_stanza; return view.el.querySelector('.chat-image');
}, 1000).then(function () { }, 1000);
expect(sent_stanza.toLocaleString()).toBe( }).then(function () {
"<message from='dummy@localhost/resource' "+ // Check that the image renders
"to='irini.vlastuin@localhost' "+ expect(view.el.querySelector('.chat-msg .chat-msg__media').innerHTML.trim()).toEqual(
"type='chat' "+ `<!-- src/templates/image.html -->\n`+
"id='"+sent_stanza.nodeTree.getAttribute('id')+"' xmlns='jabber:client'>"+ `<a href="${window.location.origin}/logo/conversejs-filled.svg" target="_blank" rel="noopener">`+
"<body>"+message+"</body>"+ `<img class="chat-image img-thumbnail" src="${window.location.origin}/logo/conversejs-filled.svg">`+
"<active xmlns='http://jabber.org/protocol/chatstates'/>"+ `</a>`);
"<x xmlns='jabber:x:oob'>"+ XMLHttpRequest.prototype.send = send_backup;
"<url>"+message+"</url>"+ done();
"</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();
});
}); });
}); });
}); });
@ -487,56 +489,53 @@
}); });
})); }));
it("shows and error message if the file is too large", mock.initConverseWithAsync(function (done, _converse) { it("shows an error message if the file is too large", mock.initConverseWithAsync(function (done, _converse) {
var IQ_stanzas = _converse.connection.IQ_stanzas; const IQ_stanzas = _converse.connection.IQ_stanzas;
var IQ_ids = _converse.connection.IQ_ids; const IQ_ids = _converse.connection.IQ_ids;
var send_backup = XMLHttpRequest.prototype.send; const send_backup = XMLHttpRequest.prototype.send;
let view, contact_jid;
test_utils.waitUntilDiscoConfirmed(_converse, _converse.bare_jid, [], []).then(function () { test_utils.waitUntilDiscoConfirmed(_converse, _converse.bare_jid, [], [])
test_utils.waitUntil(function () { .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)];
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 _.filter(IQ_stanzas, function (iq) {
return iq.nodeTree.querySelector( return iq.nodeTree.querySelector('iq[to="localhost"] query[xmlns="http://jabber.org/protocol/disco#items"]');
'iq[to="localhost"] query[xmlns="http://jabber.org/protocol/disco#info"]');
}).length > 0; }).length > 0;
}, 300).then(function () { }, 300);
var stanza = _.find(IQ_stanzas, function (iq) { }).then(function () {
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 () {
var stanza = _.find(IQ_stanzas, function (iq) { var stanza = _.find(IQ_stanzas, function (iq) {
return iq.nodeTree.querySelector('iq[to="localhost"] query[xmlns="http://jabber.org/protocol/disco#items"]'); return iq.nodeTree.querySelector('iq[to="localhost"] query[xmlns="http://jabber.org/protocol/disco#items"]');
}); });
@ -550,77 +549,77 @@
.c('item', { .c('item', {
'jid': 'upload.localhost', 'jid': 'upload.localhost',
'name': 'HTTP File Upload'}); 'name': 'HTTP File Upload'});
_converse.connection._dataRecv(test_utils.createRequest(stanza));
_converse.api.disco.entities.get().then(function (entities) { _converse.connection._dataRecv(test_utils.createRequest(stanza));
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 _converse.api.disco.entities.get().then(function (entities) {
stanza = $iq({'type': 'result', 'to': 'dummy@localhost/resource', 'id': IQ_id, 'from': 'upload.localhost'}) expect(entities.length).toBe(2);
.c('query', {'xmlns': 'http://jabber.org/protocol/disco#info'}) expect(entities.get('localhost').items.length).toBe(1);
.c('identity', {'category':'store', 'type':'file', 'name':'HTTP File Upload'}).up() return test_utils.waitUntil(function () {
.c('feature', {'var':'urn:xmpp:http:upload:0'}).up() // Converse.js sees that the entity has a disco#info feature,
.c('x', {'type':'result', 'xmlns':'jabber:x:data'}) // so it will make a query for it.
.c('field', {'var':'FORM_TYPE', 'type':'hidden'}) return _.filter(IQ_stanzas, function (iq) {
.c('value').t('urn:xmpp:http:upload:0').up().up() return iq.nodeTree.querySelector('iq[to="upload.localhost"] query[xmlns="http://jabber.org/protocol/disco#info"]');
.c('field', {'var':'max-file-size'}) }).length > 0;
.c('value').t('5242880'); }, 300);
_converse.connection._dataRecv(test_utils.createRequest(stanza)); });
}).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>");
_converse.api.disco.entities.get().then(function (entities) { // Upload service responds and reports a maximum file size of 5MiB
expect(entities.get('localhost').items.get('upload.localhost').identities.where({'category': 'store'}).length).toBe(1); stanza = $iq({'type': 'result', 'to': 'dummy@localhost/resource', 'id': IQ_id, 'from': 'upload.localhost'})
_converse.api.disco.supports(Strophe.NS.HTTPUPLOAD, _converse.domain).then( .c('query', {'xmlns': 'http://jabber.org/protocol/disco#info'})
function (result) { .c('identity', {'category':'store', 'type':'file', 'name':'HTTP File Upload'}).up()
test_utils.createContacts(_converse, 'current'); .c('feature', {'var':'urn:xmpp:http:upload:0'}).up()
var contact_jid = mock.cur_names[2].replace(/ /g,'.').toLowerCase() + '@localhost'; .c('x', {'type':'result', 'xmlns':'jabber:x:data'})
test_utils.openChatBoxFor(_converse, contact_jid); .c('field', {'var':'FORM_TYPE', 'type':'hidden'})
var view = _converse.chatboxviews.get(contact_jid); .c('value').t('urn:xmpp:http:upload:0').up().up()
var file = { .c('field', {'var':'max-file-size'})
'type': 'image/jpeg', .c('value').t('5242880');
'size': '5242881', _converse.connection._dataRecv(test_utils.createRequest(stanza));
'lastModifiedDate': "", return _converse.api.disco.entities.get();
'name': "my-juliet.jpg" }).then(function (entities) {
}; expect(entities.get('localhost').items.get('upload.localhost').identities.where({'category': 'store'}).length).toBe(1);
view.model.sendFiles([file]); return _converse.api.disco.supports(Strophe.NS.HTTPUPLOAD, _converse.domain);
return test_utils.waitUntil(function () { }).then(function (result) {
return view.el.querySelectorAll('.message').length; test_utils.createContacts(_converse, 'current');
}).then(function () { _converse.emit('rosterContactsFetched');
const messages = view.el.querySelectorAll('.message.chat-error');
expect(messages.length).toBe(1); contact_jid = mock.cur_names[2].replace(/ /g,'.').toLowerCase() + '@localhost';
expect(messages[0].textContent).toBe( return test_utils.openChatBoxFor(_converse, contact_jid);
'The size of your file, my-juliet.jpg, exceeds the maximum allowed by your server, which is 5 MB.'); }).then(() => {
done(); view = _converse.chatboxviews.get(contact_jid);
}); var file = {
} 'type': 'image/jpeg',
); 'size': '5242881',
}).catch(_.partial(_converse.log, _, Strophe.LogLevel.FATAL)); '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 () { 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( test_utils.waitUntilDiscoConfirmed(
_converse, _converse.domain, _converse, _converse.domain,
[{'category': 'server', 'type':'IM'}], [{'category': 'server', 'type':'IM'}],
@ -628,77 +627,74 @@
var send_backup = XMLHttpRequest.prototype.send; var send_backup = XMLHttpRequest.prototype.send;
var IQ_stanzas = _converse.connection.IQ_stanzas; var IQ_stanzas = _converse.connection.IQ_stanzas;
let view, contact_jid;
test_utils.waitUntilDiscoConfirmed(_converse, _converse.domain, [], [], ['upload.montague.tld'], 'items').then(function () { test_utils.waitUntilDiscoConfirmed(_converse, _converse.domain, [], [], ['upload.montague.tld'], 'items')
test_utils.waitUntilDiscoConfirmed(_converse, 'upload.montague.tld', [], [Strophe.NS.HTTPUPLOAD], []).then(function () { .then(() => test_utils.waitUntilDiscoConfirmed(_converse, 'upload.montague.tld', [], [Strophe.NS.HTTPUPLOAD], []))
test_utils.createContacts(_converse, 'current'); .then(() => {
var contact_jid = mock.cur_names[2].replace(/ /g,'.').toLowerCase() + '@localhost'; test_utils.createContacts(_converse, 'current');
test_utils.openChatBoxFor(_converse, contact_jid); _converse.emit('rosterContactsFetched');
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]; contact_jid = mock.cur_names[2].replace(/ /g,'.').toLowerCase() + '@localhost';
var message = base_url+"/logo/conversejs-filled.svg"; 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>");
var stanza = Strophe.xmlHtmlNode( const base_url = document.URL.split(window.location.pathname)[0];
"<iq from='upload.montague.tld'"+ const message = base_url+"/logo/conversejs-filled.svg";
" id='"+iq.nodeTree.getAttribute('id')+"'"+ const stanza = Strophe.xmlHtmlNode(
" to='dummy@localhost/resource'"+ "<iq from='upload.montague.tld'"+
" type='result'>"+ " id='"+iq.nodeTree.getAttribute('id')+"'"+
"<slot xmlns='urn:xmpp:http:upload:0'>"+ " to='dummy@localhost/resource'"+
" <put url='https://upload.montague.tld/4a771ac1-f0b2-4a4a-9700-f2a26fa2bb67/my-juliet.jpg'>"+ " type='result'>"+
" <header name='Authorization'>Basic Base64String==</header>"+ "<slot xmlns='urn:xmpp:http:upload:0'>"+
" <header name='Cookie'>foo=bar; user=romeo</header>"+ " <put url='https://upload.montague.tld/4a771ac1-f0b2-4a4a-9700-f2a26fa2bb67/my-juliet.jpg'>"+
" </put>"+ " <header name='Authorization'>Basic Base64String==</header>"+
" <get url='"+message+"' />"+ " <header name='Cookie'>foo=bar; user=romeo</header>"+
"</slot>"+ " </put>"+
"</iq>").firstElementChild; " <get url='"+message+"' />"+
"</slot>"+
spyOn(XMLHttpRequest.prototype, 'send').and.callFake(function () { "</iq>").firstElementChild;
const message = view.model.messages.at(0); spyOn(XMLHttpRequest.prototype, 'send').and.callFake(function () {
expect(view.el.querySelector('.chat-content progress').getAttribute('value')).toBe('0'); const message = view.model.messages.at(0);
message.set('progress', 0.5); expect(view.el.querySelector('.chat-content progress').getAttribute('value')).toBe('0');
expect(view.el.querySelector('.chat-content progress').getAttribute('value')).toBe('0.5'); message.set('progress', 0.5);
message.set('progress', 1); expect(view.el.querySelector('.chat-content progress').getAttribute('value')).toBe('0.5');
expect(view.el.querySelector('.chat-content progress').getAttribute('value')).toBe('1'); message.set('progress', 1);
expect(view.el.querySelector('.chat-content .chat-msg__text').textContent).toBe('Uploading file: my-juliet.jpg, 22.91 KB'); expect(view.el.querySelector('.chat-content progress').getAttribute('value')).toBe('1');
done(); 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));
});
}); });
var sent_stanza;
spyOn(_converse.connection, 'send').and.callFake(function (stanza) {
sent_stanza = stanza;
});
_converse.connection._dataRecv(test_utils.createRequest(stanza));
}); });
}); });
})); }));
}); });
}); });
}); });
})); }));

File diff suppressed because it is too large Load Diff

View File

@ -13,32 +13,37 @@
function (done, _converse) { function (done, _converse) {
test_utils.createContacts(_converse, 'current'); test_utils.createContacts(_converse, 'current');
_converse.emit('rosterContactsFetched');
test_utils.openControlBox(); test_utils.openControlBox();
_converse.minimized_chats.toggleview.model.browserStorage._clear(); _converse.minimized_chats.toggleview.model.browserStorage._clear();
_converse.minimized_chats.initToggle(); _converse.minimized_chats.initToggle();
var contact_jid, chatview; let contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@localhost';
contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@localhost'; let chatview;
test_utils.openChatBoxFor(_converse, contact_jid); test_utils.openChatBoxFor(_converse, contact_jid)
chatview = _converse.chatboxviews.get(contact_jid); .then(() => {
expect(chatview.model.get('minimized')).toBeFalsy(); chatview = _converse.chatboxviews.get(contact_jid);
expect($(_converse.minimized_chats.el).is(':visible')).toBeFalsy(); expect(chatview.model.get('minimized')).toBeFalsy();
chatview.el.querySelector('.toggle-chatbox-button').click(); expect($(_converse.minimized_chats.el).is(':visible')).toBeFalsy();
expect(chatview.model.get('minimized')).toBeTruthy(); chatview.el.querySelector('.toggle-chatbox-button').click();
expect($(_converse.minimized_chats.el).is(':visible')).toBeTruthy(); expect(chatview.model.get('minimized')).toBeTruthy();
expect(_converse.minimized_chats.keys().length).toBe(1); expect($(_converse.minimized_chats.el).is(':visible')).toBeTruthy();
expect(_converse.minimized_chats.keys()[0]).toBe(contact_jid); 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'; contact_jid = mock.cur_names[1].replace(/ /g,'.').toLowerCase() + '@localhost';
test_utils.openChatBoxFor(_converse, contact_jid); return test_utils.openChatBoxFor(_converse, contact_jid);
chatview = _converse.chatboxviews.get(contact_jid); }).then(() => {
expect(chatview.model.get('minimized')).toBeFalsy(); chatview = _converse.chatboxviews.get(contact_jid);
chatview.el.querySelector('.toggle-chatbox-button').click(); expect(chatview.model.get('minimized')).toBeFalsy();
expect(chatview.model.get('minimized')).toBeTruthy(); chatview.el.querySelector('.toggle-chatbox-button').click();
expect($(_converse.minimized_chats.el).is(':visible')).toBeTruthy(); expect(chatview.model.get('minimized')).toBeTruthy();
expect(_converse.minimized_chats.keys().length).toBe(2); expect($(_converse.minimized_chats.el).is(':visible')).toBeTruthy();
expect(_.includes(_converse.minimized_chats.keys(), contact_jid)).toBeTruthy(); expect(_converse.minimized_chats.keys().length).toBe(2);
done(); expect(_.includes(_converse.minimized_chats.keys(), contact_jid)).toBeTruthy();
done();
});
})); }));
it("can be toggled to hide or show minimized chats", it("can be toggled to hide or show minimized chats",
@ -47,24 +52,26 @@
function (done, _converse) { function (done, _converse) {
test_utils.createContacts(_converse, 'current'); test_utils.createContacts(_converse, 'current');
_converse.emit('rosterContactsFetched');
test_utils.openControlBox(); test_utils.openControlBox();
_converse.minimized_chats.toggleview.model.browserStorage._clear(); _converse.minimized_chats.toggleview.model.browserStorage._clear();
_converse.minimized_chats.initToggle(); _converse.minimized_chats.initToggle();
var contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@localhost'; const contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@localhost';
test_utils.openChatBoxFor(_converse, contact_jid); test_utils.openChatBoxFor(_converse, contact_jid)
var chatview = _converse.chatboxviews.get(contact_jid); .then(() => {
expect($(_converse.minimized_chats.el).is(':visible')).toBeFalsy(); const chatview = _converse.chatboxviews.get(contact_jid);
chatview.model.set({'minimized': true}); expect(u.isVisible(_converse.minimized_chats.el)).toBeFalsy();
expect($(_converse.minimized_chats.el).is(':visible')).toBeTruthy(); chatview.model.set({'minimized': true});
expect(_converse.minimized_chats.keys().length).toBe(1); expect(u.isVisible(_converse.minimized_chats.el)).toBeTruthy();
expect(_converse.minimized_chats.keys()[0]).toBe(contact_jid); expect(_converse.minimized_chats.keys().length).toBe(1);
expect($(_converse.minimized_chats.el.querySelector('.minimized-chats-flyout')).is(':visible')).toBeTruthy(); expect(_converse.minimized_chats.keys()[0]).toBe(contact_jid);
expect(_converse.minimized_chats.toggleview.model.get('collapsed')).toBeFalsy(); expect(u.isVisible(_converse.minimized_chats.el.querySelector('.minimized-chats-flyout'))).toBeTruthy();
_converse.minimized_chats.el.querySelector('#toggle-minimized-chats').click(); 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')))) return test_utils.waitUntil(() => u.isVisible(_converse.minimized_chats.el.querySelector('.minimized-chats-flyout')));
.then(function () { }).then(() => {
expect(_converse.minimized_chats.toggleview.model.get('collapsed')).toBeTruthy(); expect(_converse.minimized_chats.toggleview.model.get('collapsed')).toBeTruthy();
done(); done();
}); });

View File

@ -12,44 +12,46 @@
describe("A list of open rooms", function () { describe("A list of open rooms", function () {
it("is shown in the \"Rooms\" panel", mock.initConverseWithPromises( it("is shown in the \"Rooms\" panel", mock.initConverseWithPromises(
null, ['rosterGroupsFetched'], null, ['rosterGroupsFetched', 'chatBoxesFetched'],
{ allow_bookmarks: false // Makes testing easier, otherwise we { allow_bookmarks: false // Makes testing easier, otherwise we
// have to mock stanza traffic. // have to mock stanza traffic.
}, },
function (done, _converse) { function (done, _converse) {
test_utils.openControlBox(); test_utils.openControlBox();
var controlbox = _converse.chatboxviews.get('controlbox'); const controlbox = _converse.chatboxviews.get('controlbox');
let list = controlbox.el.querySelector('div.rooms-list-container');
var list = controlbox.el.querySelector('div.rooms-list-container');
expect(_.includes(list.classList, 'hidden')).toBeTruthy(); expect(_.includes(list.classList, 'hidden')).toBeTruthy();
test_utils.openChatRoom(_converse, 'room', 'conference.shakespeare.lit', 'JC'); let room_els;
expect(_.isUndefined(_converse.rooms_list_view)).toBeFalsy(); test_utils.openChatRoom(_converse, 'room', 'conference.shakespeare.lit', 'JC')
var room_els = _converse.rooms_list_view.el.querySelectorAll(".open-room"); .then(() => {
expect(room_els.length).toBe(1); expect(_.isUndefined(_converse.rooms_list_view)).toBeFalsy();
expect(room_els[0].innerText).toBe('room@conference.shakespeare.lit'); 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);
test_utils.openChatRoom(_converse, 'lounge', 'localhost', 'dummy'); var view = _converse.chatboxviews.get('room@conference.shakespeare.lit');
room_els = _converse.rooms_list_view.el.querySelectorAll(".open-room"); view.close();
expect(room_els.length).toBe(2); 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();
var view = _converse.chatboxviews.get('room@conference.shakespeare.lit'); view = _converse.chatboxviews.get('lounge@localhost');
view.close(); view.close();
room_els = _converse.rooms_list_view.el.querySelectorAll(".open-room"); room_els = _converse.rooms_list_view.el.querySelectorAll(".open-room");
expect(room_els.length).toBe(1); expect(room_els.length).toBe(0);
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'); list = controlbox.el.querySelector('div.rooms-list-container');
view.close(); expect(_.includes(list.classList, 'hidden')).toBeTruthy();
room_els = _converse.rooms_list_view.el.querySelectorAll(".open-room"); done();
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 () { describe("A groupchat shown in the groupchats list", function () {
it("is highlighted if its currently open", mock.initConverseWithPromises( it("is highlighted if its currently open", mock.initConverseWithPromises(
null, ['rosterGroupsFetched'], null, ['rosterGroupsFetched', 'chatBoxesFetched'],
{ whitelisted_plugins: ['converse-roomslist'], { whitelisted_plugins: ['converse-roomslist'],
allow_bookmarks: false // Makes testing easier, otherwise we allow_bookmarks: false // Makes testing easier, otherwise we
// have to mock stanza traffic. // have to mock stanza traffic.
}, function (done, _converse) { }, function (done, _converse) {
spyOn(_converse, 'isSingleton').and.callFake(function () { spyOn(_converse, 'isSingleton').and.callFake(() => true);
return true;
});
let room_els, item;
test_utils.openControlBox(); test_utils.openControlBox();
_converse.api.rooms.open('coven@chat.shakespeare.lit', {'nick': 'some1'}); _converse.api.rooms.open('coven@chat.shakespeare.lit', {'nick': 'some1'})
let room_els = _converse.rooms_list_view.el.querySelectorAll(".available-chatroom"); .then(() => {
expect(room_els.length).toBe(1); room_els = _converse.rooms_list_view.el.querySelectorAll(".available-chatroom");
expect(room_els.length).toBe(1);
let item = room_els[0]; item = room_els[0];
expect(u.hasClass('open', item)).toBe(true); expect(u.hasClass('open', item)).toBe(true);
expect(item.textContent.trim()).toBe('coven@chat.shakespeare.lit'); 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);
_converse.api.rooms.open('balcony@chat.shakespeare.lit', {'nick': 'some1'}); room_els = _converse.rooms_list_view.el.querySelectorAll(".available-chatroom.open");
room_els = _converse.rooms_list_view.el.querySelectorAll(".open-room"); expect(room_els.length).toBe(1);
expect(room_els.length).toBe(2); item = room_els[0];
expect(item.textContent.trim()).toBe('balcony@chat.shakespeare.lit');
room_els = _converse.rooms_list_view.el.querySelectorAll(".available-chatroom.open"); done();
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( it("has an info icon which opens a details modal when clicked", mock.initConverseWithPromises(
null, ['rosterGroupsFetched'], null, ['rosterGroupsFetched', 'chatBoxesFetched'],
{ whitelisted_plugins: ['converse-roomslist'], { whitelisted_plugins: ['converse-roomslist'],
allow_bookmarks: false // Makes testing easier, otherwise we allow_bookmarks: false // Makes testing easier, otherwise we
// have to mock stanza traffic. // have to mock stanza traffic.
}, function (done, _converse) { }, function (done, _converse) {
let view;
test_utils.openControlBox(); test_utils.openControlBox();
_converse.api.rooms.open('coven@chat.shakespeare.lit', {'nick': 'some1'}); _converse.api.rooms.open('coven@chat.shakespeare.lit', {'nick': 'some1'})
const view = _converse.chatboxviews.get('coven@chat.shakespeare.lit'); .then(() => {
const last_stanza = _.last(_converse.connection.IQ_stanzas).nodeTree; view = _converse.chatboxviews.get('coven@chat.shakespeare.lit');
const IQ_id = last_stanza.getAttribute('id'); const last_stanza = _.last(_converse.connection.IQ_stanzas).nodeTree;
const features_stanza = $iq({ const IQ_id = last_stanza.getAttribute('id');
'from': 'coven@chat.shakespeare.lit', const features_stanza = $iq({
'id': IQ_id, 'from': 'coven@chat.shakespeare.lit',
'to': 'dummy@localhost/desktop', 'id': IQ_id,
'type': 'result' 'to': 'dummy@localhost/desktop',
}) 'type': 'result'
.c('query', { 'xmlns': 'http://jabber.org/protocol/disco#info'}) })
.c('identity', { .c('query', { 'xmlns': 'http://jabber.org/protocol/disco#info'})
'category': 'conference', .c('identity', {
'name': 'A Dark Cave', 'category': 'conference',
'type': 'text' 'name': 'A Dark Cave',
}).up() 'type': 'text'
.c('feature', {'var': 'http://jabber.org/protocol/muc'}).up() }).up()
.c('feature', {'var': 'muc_passwordprotected'}).up() .c('feature', {'var': 'http://jabber.org/protocol/muc'}).up()
.c('feature', {'var': 'muc_hidden'}).up() .c('feature', {'var': 'muc_passwordprotected'}).up()
.c('feature', {'var': 'muc_temporary'}).up() .c('feature', {'var': 'muc_hidden'}).up()
.c('feature', {'var': 'muc_open'}).up() .c('feature', {'var': 'muc_temporary'}).up()
.c('feature', {'var': 'muc_unmoderated'}).up() .c('feature', {'var': 'muc_open'}).up()
.c('feature', {'var': 'muc_nonanonymous'}).up() .c('feature', {'var': 'muc_unmoderated'}).up()
.c('feature', {'var': 'urn:xmpp:mam:0'}).up() .c('feature', {'var': 'muc_nonanonymous'}).up()
.c('x', { 'xmlns':'jabber:x:data', 'type':'result'}) .c('feature', {'var': 'urn:xmpp:mam:0'}).up()
.c('field', {'var':'FORM_TYPE', 'type':'hidden'}) .c('x', { 'xmlns':'jabber:x:data', 'type':'result'})
.c('value').t('http://jabber.org/protocol/muc#roominfo').up().up() .c('field', {'var':'FORM_TYPE', 'type':'hidden'})
.c('field', {'type':'text-single', 'var':'muc#roominfo_description', 'label':'Description'}) .c('value').t('http://jabber.org/protocol/muc#roominfo').up().up()
.c('value').t('This is the description').up().up() .c('field', {'type':'text-single', 'var':'muc#roominfo_description', 'label':'Description'})
.c('field', {'type':'text-single', 'var':'muc#roominfo_occupants', 'label':'Number of occupants'}) .c('value').t('This is the description').up().up()
.c('value').t(0); .c('field', {'type':'text-single', 'var':'muc#roominfo_occupants', 'label':'Number of occupants'})
_converse.connection._dataRecv(test_utils.createRequest(features_stanza)); .c('value').t(0);
_converse.connection._dataRecv(test_utils.createRequest(features_stanza));
test_utils.waitUntil(() => view.model.get('connection_status') === converse.ROOMSTATUS.CONNECTING) return test_utils.waitUntil(() => view.model.get('connection_status') === converse.ROOMSTATUS.CONNECTING)
.then(function () { }).then(function () {
var presence = $pres({ var presence = $pres({
to: _converse.connection.jid, to: _converse.connection.jid,
from: 'coven@chat.shakespeare.lit/some1', from: 'coven@chat.shakespeare.lit/some1',
@ -201,23 +205,22 @@
}, },
function (done, _converse) { function (done, _converse) {
spyOn(window, 'confirm').and.callFake(function () { spyOn(window, 'confirm').and.callFake(() => true);
return true; expect(_converse.chatboxes.length).toBe(1);
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();
}); });
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();
})); }));
it("shows unread messages directed at the user", mock.initConverseWithAsync( it("shows unread messages directed at the user", mock.initConverseWithAsync(

View File

@ -92,12 +92,14 @@
it("can be sent without a hint", it("can be sent without a hint",
mock.initConverseWithPromises( mock.initConverseWithPromises(
null, ['rosterGroupsFetched'], {}, null, ['rosterGroupsFetched', 'chatBoxesFetched'], {},
function (done, _converse) { function (done, _converse) {
test_utils.createContacts(_converse, 'current'); test_utils.createContacts(_converse, 'current', 1);
_converse.emit('rosterContactsFetched');
test_utils.openControlBox(); 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 // XXX: We need to send a presence from the contact, so that we
// have a resource, that resource is then queried to see // have a resource, that resource is then queried to see
@ -108,9 +110,9 @@
'to': 'dummy@localhost' 'to': 'dummy@localhost'
}); });
_converse.connection._dataRecv(test_utils.createRequest(presence)); _converse.connection._dataRecv(test_utils.createRequest(presence));
test_utils.openChatBoxFor(_converse, contact_jid); test_utils.openChatBoxFor(_converse, contact_jid)
.then(() => test_utils.waitUntilDiscoConfirmed(_converse, contact_jid+'/phone', [], [Strophe.NS.SPOILER]))
test_utils.waitUntilDiscoConfirmed(_converse, contact_jid+'/phone', [], [Strophe.NS.SPOILER]).then(function () { .then(() => {
var view = _converse.chatboxviews.get(contact_jid); var view = _converse.chatboxviews.get(contact_jid);
spyOn(view, 'onMessageSubmitted').and.callThrough(); spyOn(view, 'onMessageSubmitted').and.callThrough();
spyOn(_converse.connection, 'send'); spyOn(_converse.connection, 'send');
@ -167,10 +169,12 @@
it("can be sent with a hint", it("can be sent with a hint",
mock.initConverseWithPromises( mock.initConverseWithPromises(
null, ['rosterGroupsFetched'], {}, null, ['rosterGroupsFetched', 'chatBoxesFetched'], {},
function (done, _converse) { function (done, _converse) {
test_utils.createContacts(_converse, 'current'); test_utils.createContacts(_converse, 'current', 1);
_converse.emit('rosterContactsFetched');
test_utils.openControlBox(); test_utils.openControlBox();
var contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@localhost'; var contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@localhost';
@ -183,9 +187,9 @@
'to': 'dummy@localhost' 'to': 'dummy@localhost'
}); });
_converse.connection._dataRecv(test_utils.createRequest(presence)); _converse.connection._dataRecv(test_utils.createRequest(presence));
test_utils.openChatBoxFor(_converse, contact_jid); test_utils.openChatBoxFor(_converse, contact_jid)
.then(() => test_utils.waitUntilDiscoConfirmed(_converse, contact_jid+'/phone', [], [Strophe.NS.SPOILER]))
test_utils.waitUntilDiscoConfirmed(_converse, contact_jid+'/phone', [], [Strophe.NS.SPOILER]).then(function () { .then(() => {
var view = _converse.chatboxviews.get(contact_jid); var view = _converse.chatboxviews.get(contact_jid);
var spoiler_toggle = view.el.querySelector('.toggle-compose-spoiler'); var spoiler_toggle = view.el.querySelector('.toggle-compose-spoiler');
spoiler_toggle.click(); spoiler_toggle.click();
@ -206,17 +210,17 @@
expect(view.onMessageSubmitted).toHaveBeenCalled(); expect(view.onMessageSubmitted).toHaveBeenCalled();
/* Test the XML stanza /* Test the XML stanza
* *
* <message from="dummy@localhost/resource" * <message from="dummy@localhost/resource"
* to="max.frankfurter@localhost" * to="max.frankfurter@localhost"
* type="chat" * type="chat"
* id="4547c38b-d98b-45a5-8f44-b4004dbc335e" * id="4547c38b-d98b-45a5-8f44-b4004dbc335e"
* xmlns="jabber:client"> * xmlns="jabber:client">
* <body>This is the spoiler</body> * <body>This is the spoiler</body>
* <active xmlns="http://jabber.org/protocol/chatstates"/> * <active xmlns="http://jabber.org/protocol/chatstates"/>
* <spoiler xmlns="urn:xmpp:spoiler:0">This is the hint</spoiler> * <spoiler xmlns="urn:xmpp:spoiler:0">This is the hint</spoiler>
* </message>" * </message>"
*/ */
var stanza = _converse.connection.send.calls.argsFor(0)[0].tree(); var stanza = _converse.connection.send.calls.argsFor(0)[0].tree();
var spoiler_el = stanza.querySelector('spoiler[xmlns="urn:xmpp:spoiler:0"]'); var spoiler_el = stanza.querySelector('spoiler[xmlns="urn:xmpp:spoiler:0"]');

View File

@ -58,16 +58,17 @@
test_utils.createContacts(_converse, 'current'); test_utils.createContacts(_converse, 'current');
_converse.emit('rosterContactsFetched'); _converse.emit('rosterContactsFetched');
let view, modal;
const contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@localhost'; 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); view = _converse.chatboxviews.get(contact_jid);
const show_modal_button = view.el.querySelector('.show-user-details-modal'); const show_modal_button = view.el.querySelector('.show-user-details-modal');
expect(u.isVisible(show_modal_button)).toBeTruthy(); expect(u.isVisible(show_modal_button)).toBeTruthy();
show_modal_button.click(); show_modal_button.click();
const modal = view.user_details_modal; modal = view.user_details_modal;
test_utils.waitUntil(() => u.isVisible(modal.el), 2000) return test_utils.waitUntil(() => u.isVisible(modal.el), 2000);
.then(function () { }).then(function () {
spyOn(window, 'confirm').and.returnValue(true); spyOn(window, 'confirm').and.returnValue(true);
spyOn(view.model.contact, 'removeFromRoster').and.callFake(function (callback, errback) { spyOn(view.model.contact, 'removeFromRoster').and.callFake(function (callback, errback) {
errback(); errback();

View File

@ -561,8 +561,7 @@
const handler = () => { const handler = () => {
if (!u.isPersistableModel(this.model)) { if (!u.isPersistableModel(this.model)) {
// Happens during tests, nothing to do if this // Happens during tests, nothing to do if this
// is a hanging chatbox (i.e. not in the // is a hanging chatbox (i.e. not in the collection anymore).
// collection anymore).
return; return;
} }
this.populateAndJoin(); this.populateAndJoin();

View File

@ -148,8 +148,13 @@
); );
xhr.onload = function () { xhr.onload = function () {
if (xhr.status >= 200 && xhr.status < 400) { if (xhr.status >= 200 && xhr.status < 400) {
jed_instance = new Jed(window.JSON.parse(xhr.responseText)); try {
resolve(); const data = window.JSON.parse(xhr.responseText);
jed_instance = new Jed(data);
resolve();
} catch (e) {
xhr.onerror(e);
}
} else { } else {
xhr.onerror(); xhr.onerror();
} }

View File

@ -98,8 +98,9 @@
return views; return views;
}; };
utils.openChatBoxFor = function (converse, jid) { utils.openChatBoxFor = function (_converse, jid) {
return converse.roster.get(jid).trigger("open"); _converse.roster.get(jid).trigger("open");
return utils.waitUntil(() => _converse.chatboxviews.get(jid));
}; };
utils.openChatRoomViaModal = function (_converse, jid, nick) { utils.openChatRoomViaModal = function (_converse, jid, nick) {
@ -121,64 +122,64 @@
}; };
utils.openChatRoom = function (_converse, room, server, nick) { 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) { utils.openAndEnterChatRoom = function (_converse, room, server, nick) {
let last_stanza; let last_stanza;
return new Promise(function (resolve, reject) { return new Promise((resolve, reject) => {
_converse.api.rooms.open(`${room}@${server}`); return _converse.api.rooms.open(`${room}@${server}`).then(() => {
const view = _converse.chatboxviews.get((room+'@'+server).toLowerCase()); const view = _converse.chatboxviews.get((room+'@'+server).toLowerCase());
// We pretend this is a new room, so no disco info is returned. // We pretend this is a new room, so no disco info is returned.
let last_stanza = _.last(_converse.connection.IQ_stanzas).nodeTree; 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.
const IQ_id = last_stanza.getAttribute('id'); const IQ_id = last_stanza.getAttribute('id');
const stanza = $iq({ const features_stanza = $iq({
'type': 'result', 'from': room+'@'+server,
'id': IQ_id, 'id': IQ_id,
'from': view.model.get('jid'), 'to': nick+'@'+server,
'to': _converse.connection.jid 'type': 'error'
}).c('query', {'xmlns': 'http://jabber.org/protocol/disco#info', 'node': 'x-roomuser-item'}) }).c('error', {'type': 'cancel'})
.c('identity', {'category': 'conference', 'name': nick, 'type': 'text'}); .c('item-not-found', {'xmlns': "urn:ietf:params:xml:ns:xmpp-stanzas"});
_converse.connection._dataRecv(utils.createRequest(stanza)); _converse.connection._dataRecv(utils.createRequest(features_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();
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, _));
}).catch(_.partial(console.error, _)); }).catch(_.partial(console.error, _));
}; };