From 506aa33131d8b4982925a3893ecc62ce716085ea Mon Sep 17 00:00:00 2001 From: JC Brand Date: Mon, 30 Jul 2018 18:16:32 +0200 Subject: [PATCH] Wait for promises before opening chats in API methods --- CHANGES.md | 3 + dist/converse.js | 43 +- spec/bookmarks.js | 190 +++-- spec/chatbox.js | 906 ++++++++++++----------- spec/chatroom.js | 1428 ++++++++++++++++++------------------ spec/http-file-upload.js | 578 ++++++++------- spec/messages.js | 1228 ++++++++++++++++--------------- spec/minchats.js | 77 +- spec/roomslist.js | 199 ++--- spec/spoilers.js | 48 +- spec/user-details-modal.js | 19 +- src/converse-muc-views.js | 3 +- src/i18n.js | 9 +- tests/utils.js | 107 +-- 14 files changed, 2464 insertions(+), 2374 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 194e7d158..f79cf1e66 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -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 diff --git a/dist/converse.js b/dist/converse.js index c57cc32a6..ba57ab624 100644 --- a/dist/converse.js +++ b/dist/converse.js @@ -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(); } diff --git a/spec/bookmarks.js b/spec/bookmarks.js index 37e491ea0..39227e3c3 100644 --- a/spec/bookmarks.js +++ b/spec/bookmarks.js @@ -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( ""+ @@ -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( - ""+ - ""+ - ""+ - ""+ - ""+ - ""+ - ""+ - ""+ - ""+ - ""+ - "http://jabber.org/protocol/pubsub#publish-options"+ - ""+ - ""+ - "true"+ - ""+ - ""+ - "whitelist"+ - ""+ - ""+ - ""+ - ""+ - "" - ); - 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( + ""+ + ""+ + ""+ + ""+ + ""+ + ""+ + ""+ + ""+ + ""+ + ""+ + "http://jabber.org/protocol/pubsub#publish-options"+ + ""+ + ""+ + "true"+ + ""+ + ""+ + "whitelist"+ + ""+ + ""+ + ""+ + ""+ + "" + ); + 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(); diff --git a/spec/chatbox.js b/spec/chatbox.js index ac8368971..5e5dbc34f 100644 --- a/spec/chatbox.js +++ b/spec/chatbox.js @@ -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) { - test_utils.createContacts(_converse, 'current'); - test_utils.openControlBox(); - - var i, $el, 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'); + + const trimmed_chatboxes = _converse.minimized_chats; spyOn(trimmed_chatboxes, 'addChat').and.callThrough(); spyOn(trimmed_chatboxes, 'removeChat').and.callThrough(); - expect($("#conversejs .chatbox").length).toBe(1); // Controlbox is open + + test_utils.createContacts(_converse, 'current'); + _converse.emit('rosterContactsFetched'); + + test_utils.openControlBox(); + + 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. + expect(_converse.chatboxes.length).toEqual(1); + 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 _converse.chatboxes.length == 16) + }).then(() => { + expect(_converse.chatboxviews.trimChats.calls.count()).toBe(16); + for (i=0; i 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 _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 _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(); + 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(); + view.delegateEvents(); // We need to rebind all events otherwise our spy won't be called + toolbar.querySelector('li.toggle-smiley').click(); - var timeout = false; - - 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 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 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); + 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; + 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'); + const 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); - - _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'); + const 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); - - _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( - 'https://www.openstreetmap.org/?mlat=37.7869'+ - '71&mlon=-122.399677#map=18/37.786971/-122.399677'); - 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( + 'https://www.openstreetmap.org/?mlat=37.7869'+ + '71&mlon=-122.399677#map=18/37.786971/-122.399677'); + done(); + }); + })); }); }); })); diff --git a/spec/chatroom.js b/spec/chatroom.js index fcf429a97..397f62666 100644 --- a/spec/chatroom.js +++ b/spec/chatroom.js @@ -1,15 +1,16 @@ (function (root, factory) { define(["jquery", "jasmine", "mock", "test-utils" ], factory); } (this, function ($, jasmine, mock, test_utils) { - var _ = converse.env._; - var $pres = converse.env.$pres; - var $iq = converse.env.$iq; - var $msg = converse.env.$msg; - var Strophe = converse.env.Strophe; - var Promise = converse.env.Promise; - var moment = converse.env.moment; - var sizzle = converse.env.sizzle; - var u = converse.env.utils; + const _ = converse.env._, + $pres = converse.env.$pres, + $iq = converse.env.$iq, + $msg = converse.env.$msg, + Strophe = converse.env.Strophe, + Promise = converse.env.Promise, + moment = converse.env.moment, + sizzle = converse.env.sizzle, + Backbone = converse.env.Backbone, + u = converse.env.utils; return describe("ChatRooms", function () { describe("The \"rooms\" API", function () { @@ -106,9 +107,9 @@ })); it("has a method 'open' which opens (optionally configures) and returns a wrapped chat box", - mock.initConverseWithPromises( - null, ['rosterGroupsFetched'], {}, - function (done, _converse) { + mock.initConverseWithPromises( + null, ['rosterGroupsFetched', 'chatBoxesFetched'], {}, + function (done, _converse) { // Mock 'getRoomFeatures', otherwise the room won't be // displayed as it waits first for the features to be returned @@ -119,22 +120,24 @@ return deferred.promise(); }); + const sent_IQ_els = []; + let jid = 'lounge@localhost'; + let chatroomview, sent_IQ, IQ_id; test_utils.openControlBox(); test_utils.createContacts(_converse, 'current'); - test_utils.waitUntil(function () { - return $(_converse.rosterview.el).find('.roster-group .group-toggle').length; - }, 300).then(function () { - var jid = 'lounge@localhost'; - var room = _converse.api.rooms.open(jid); + test_utils.waitUntil(() => _converse.rosterview.el.querySelectorAll('.roster-group .group-toggle').length) + .then(() => _converse.api.rooms.open(jid)) + .then((room) => { // Test on groupchat that's not yet open - expect(room instanceof Object).toBeTruthy(); - var chatroomview = _converse.chatboxviews.get(jid); + expect(room instanceof Backbone.Model).toBeTruthy(); + chatroomview = _converse.chatboxviews.get(jid); expect(chatroomview.is_chatroom).toBeTruthy(); expect(u.isVisible(chatroomview.el)).toBeTruthy(); // Test again, now that the room exists. - room = _converse.api.rooms.open(jid); - expect(room instanceof Object).toBeTruthy(); + return _converse.api.rooms.open(jid); + }).then((room) => { + expect(room instanceof Backbone.Model).toBeTruthy(); chatroomview = _converse.chatboxviews.get(jid); expect(chatroomview.is_chatroom).toBeTruthy(); expect(u.isVisible(chatroomview.el)).toBeTruthy(); @@ -142,26 +145,28 @@ // Test with mixed case in JID jid = 'Leisure@localhost'; - room = _converse.api.rooms.open(jid); - expect(room instanceof Object).toBeTruthy(); + return _converse.api.rooms.open(jid); + }).then((room) => { + expect(room instanceof Backbone.Model).toBeTruthy(); chatroomview = _converse.chatboxviews.get(jid.toLowerCase()); expect(u.isVisible(chatroomview.el)).toBeTruthy(); jid = 'leisure@localhost'; - room = _converse.api.rooms.open(jid); - expect(room instanceof Object).toBeTruthy(); + return _converse.api.rooms.open(jid); + }).then((room) => { + expect(room instanceof Backbone.Model).toBeTruthy(); chatroomview = _converse.chatboxviews.get(jid.toLowerCase()); expect(u.isVisible(chatroomview.el)).toBeTruthy(); jid = 'leiSure@localhost'; - room = _converse.api.rooms.open(jid); - expect(room instanceof Object).toBeTruthy(); + return _converse.api.rooms.open(jid); + }).then((room) => { + expect(room instanceof Backbone.Model).toBeTruthy(); chatroomview = _converse.chatboxviews.get(jid.toLowerCase()); expect(u.isVisible(chatroomview.el)).toBeTruthy(); chatroomview.close(); _converse.muc_instant_rooms = false; - var sent_IQ, IQ_id, sent_IQ_els = []; var sendIQ = _converse.connection.sendIQ; spyOn(_converse.connection, 'sendIQ').and.callFake(function (iq, callback, errback) { sent_IQ = iq; @@ -169,7 +174,7 @@ IQ_id = sendIQ.bind(this)(iq, callback, errback); }); // Test with configuration - _converse.api.rooms.open('room@conference.example.org', { + return _converse.api.rooms.open('room@conference.example.org', { 'nick': 'some1', 'auto_configure': true, 'roomconfig': { @@ -181,6 +186,7 @@ 'whois': 'anyone' } }); + }).then((room) => { chatroomview = _converse.chatboxviews.get('room@conference.example.org'); // We pretend this is a new room, so no disco info is returned. @@ -252,25 +258,21 @@ spyOn(chatroomview.model, 'sendConfiguration').and.callThrough(); _converse.connection._dataRecv(test_utils.createRequest(node.firstElementChild)); - - - return test_utils.waitUntil(function () { - return chatroomview.model.sendConfiguration.calls.count() === 1; - }, 300).then(function () { - var sent_stanza = sent_IQ_els.pop(); - while (sent_stanza.getAttribute('type') !== 'set') { - sent_stanza = sent_IQ_els.pop(); - } - expect(sizzle('field[var="muc#roomconfig_roomname"] value', sent_stanza).pop().textContent).toBe('Room'); - expect(sizzle('field[var="muc#roomconfig_roomdesc"] value', sent_stanza).pop().textContent).toBe('Welcome to this groupchat'); - expect(sizzle('field[var="muc#roomconfig_persistentroom"] value', sent_stanza).pop().textContent).toBe('1'); - expect(sizzle('field[var="muc#roomconfig_publicroom"] value ', sent_stanza).pop().textContent).toBe('1'); - expect(sizzle('field[var="muc#roomconfig_changesubject"] value', sent_stanza).pop().textContent).toBe('0'); - expect(sizzle('field[var="muc#roomconfig_whois"] value ', sent_stanza).pop().textContent).toBe('anyone'); - expect(sizzle('field[var="muc#roomconfig_membersonly"] value', sent_stanza).pop().textContent).toBe('1'); - expect(sizzle('field[var="muc#roomconfig_historylength"] value', sent_stanza).pop().textContent).toBe('20'); - done(); - }); + return test_utils.waitUntil(() => chatroomview.model.sendConfiguration.calls.count() === 1); + }).then(() => { + var sent_stanza = sent_IQ_els.pop(); + while (sent_stanza.getAttribute('type') !== 'set') { + sent_stanza = sent_IQ_els.pop(); + } + expect(sizzle('field[var="muc#roomconfig_roomname"] value', sent_stanza).pop().textContent).toBe('Room'); + expect(sizzle('field[var="muc#roomconfig_roomdesc"] value', sent_stanza).pop().textContent).toBe('Welcome to this groupchat'); + expect(sizzle('field[var="muc#roomconfig_persistentroom"] value', sent_stanza).pop().textContent).toBe('1'); + expect(sizzle('field[var="muc#roomconfig_publicroom"] value ', sent_stanza).pop().textContent).toBe('1'); + expect(sizzle('field[var="muc#roomconfig_changesubject"] value', sent_stanza).pop().textContent).toBe('0'); + expect(sizzle('field[var="muc#roomconfig_whois"] value ', sent_stanza).pop().textContent).toBe('anyone'); + expect(sizzle('field[var="muc#roomconfig_membersonly"] value', sent_stanza).pop().textContent).toBe('1'); + expect(sizzle('field[var="muc#roomconfig_historylength"] value', sent_stanza).pop().textContent).toBe('20'); + done(); }); })); }); @@ -278,13 +280,13 @@ describe("An instant groupchat", function () { it("will be created when muc_instant_rooms is set to true", - mock.initConverseWithPromises( - null, ['rosterGroupsFetched'], {}, - function (done, _converse) { + mock.initConverseWithPromises( + null, ['rosterGroupsFetched', 'chatBoxesFetched'], {}, + function (done, _converse) { - var IQ_stanzas = _converse.connection.IQ_stanzas; - var sent_IQ, IQ_id; - var sendIQ = _converse.connection.sendIQ; + const IQ_stanzas = _converse.connection.IQ_stanzas; + const sendIQ = _converse.connection.sendIQ; + let sent_IQ, IQ_id, view; spyOn(_converse.connection, 'sendIQ').and.callFake(function (iq, callback, errback) { if (iq.nodeTree.getAttribute('to') === 'lounge@localhost') { sent_IQ = iq; @@ -293,44 +295,41 @@ sendIQ.bind(this)(iq, callback, errback); } }); - test_utils.openChatRoom(_converse, 'lounge', 'localhost', 'dummy'); + test_utils.openChatRoom(_converse, 'lounge', 'localhost', 'dummy') + .then(() => { + // We pretend this is a new room, so no disco info is returned. + // + /* + * + * + * + * + * + * + * + */ + var features_stanza = $iq({ + 'from': 'lounge@localhost', + 'id': IQ_id, + 'to': 'dummy@localhost/desktop', + 'type': 'error' + }).c('error', {'type': 'cancel'}) + .c('item-not-found', {'xmlns': "urn:ietf:params:xml:ns:xmpp-stanzas"}); + _converse.connection._dataRecv(test_utils.createRequest(features_stanza)); - // We pretend this is a new room, so no disco info is returned. - // - /* - * - * - * - * - * - * - * - */ - var features_stanza = $iq({ - 'from': 'lounge@localhost', - 'id': IQ_id, - 'to': 'dummy@localhost/desktop', - 'type': 'error' - }).c('error', {'type': 'cancel'}) - .c('item-not-found', {'xmlns': "urn:ietf:params:xml:ns:xmpp-stanzas"}); - _converse.connection._dataRecv(test_utils.createRequest(features_stanza)); + view = _converse.chatboxviews.get('lounge@localhost'); + spyOn(view, 'join').and.callThrough(); + spyOn(view, 'submitNickname').and.callThrough(); - var view = _converse.chatboxviews.get('lounge@localhost'); - spyOn(view, 'join').and.callThrough(); - spyOn(view, 'submitNickname').and.callThrough(); - - /* - * - * - */ - test_utils.waitUntil(function () { - return _.filter(IQ_stanzas, function (iq) { - return iq.nodeTree.querySelector('query[node="x-roomuser-item"]'); - }).length > 0; - }, 300).then(function () { + /* + * + * + */ + return test_utils.waitUntil(() => _.filter(IQ_stanzas, (iq) => iq.nodeTree.querySelector('query[node="x-roomuser-item"]')).length); + }).then(() => { const iq = _.filter(IQ_stanzas, function (iq) { return iq.nodeTree.querySelector(`query[node="x-roomuser-item"]`); }).pop(); @@ -410,200 +409,202 @@ describe("A Groupchat", function () { it("shows join/leave messages when users enter or exit a groupchat", - mock.initConverseWithPromises( - null, ['rosterGroupsFetched'], {}, - function (done, _converse) { + mock.initConverseWithPromises( + null, ['rosterGroupsFetched', 'chatBoxesFetched'], {}, + function (done, _converse) { - test_utils.openChatRoom(_converse, "coven", 'chat.shakespeare.lit', 'some1'); - var view = _converse.chatboxviews.get('coven@chat.shakespeare.lit'); - var $chat_content = $(view.el).find('.chat-content'); + test_utils.openChatRoom(_converse, "coven", 'chat.shakespeare.lit', 'some1') + .then(() => { + var view = _converse.chatboxviews.get('coven@chat.shakespeare.lit'); + var $chat_content = $(view.el).find('.chat-content'); - /* We don't show join/leave messages for existing occupants. We - * know about them because we receive their presences before we - * receive our own. - */ - var presence = $pres({ - to: 'dummy@localhost/_converse.js-29092160', - from: 'coven@chat.shakespeare.lit/oldguy' - }).c('x', {xmlns: Strophe.NS.MUC_USER}) - .c('item', { - 'affiliation': 'none', - 'jid': 'oldguy@localhost/_converse.js-290929789', - 'role': 'participant' - }); - _converse.connection._dataRecv(test_utils.createRequest(presence)); - expect($chat_content[0].querySelectorAll('div.chat-info').length).toBe(0); + /* We don't show join/leave messages for existing occupants. We + * know about them because we receive their presences before we + * receive our own. + */ + var presence = $pres({ + to: 'dummy@localhost/_converse.js-29092160', + from: 'coven@chat.shakespeare.lit/oldguy' + }).c('x', {xmlns: Strophe.NS.MUC_USER}) + .c('item', { + 'affiliation': 'none', + 'jid': 'oldguy@localhost/_converse.js-290929789', + 'role': 'participant' + }); + _converse.connection._dataRecv(test_utils.createRequest(presence)); + expect($chat_content[0].querySelectorAll('div.chat-info').length).toBe(0); - /* - * - * - * - * - * - */ - presence = $pres({ - to: 'dummy@localhost/_converse.js-29092160', - from: 'coven@chat.shakespeare.lit/some1' - }).c('x', {xmlns: Strophe.NS.MUC_USER}) - .c('item', { - 'affiliation': 'owner', - 'jid': 'dummy@localhost/_converse.js-29092160', - 'role': 'moderator' - }).up() - .c('status', {code: '110'}); - _converse.connection._dataRecv(test_utils.createRequest(presence)); - expect($chat_content.find('div.chat-info:first').html()).toBe("some1 has entered the groupchat"); + /* + * + * + * + * + * + */ + presence = $pres({ + to: 'dummy@localhost/_converse.js-29092160', + from: 'coven@chat.shakespeare.lit/some1' + }).c('x', {xmlns: Strophe.NS.MUC_USER}) + .c('item', { + 'affiliation': 'owner', + 'jid': 'dummy@localhost/_converse.js-29092160', + 'role': 'moderator' + }).up() + .c('status', {code: '110'}); + _converse.connection._dataRecv(test_utils.createRequest(presence)); + expect($chat_content.find('div.chat-info:first').html()).toBe("some1 has entered the groupchat"); - presence = $pres({ - to: 'dummy@localhost/_converse.js-29092160', - from: 'coven@chat.shakespeare.lit/newguy' - }) - .c('x', {xmlns: Strophe.NS.MUC_USER}) - .c('item', { - 'affiliation': 'none', - 'jid': 'newguy@localhost/_converse.js-290929789', - 'role': 'participant' - }); - _converse.connection._dataRecv(test_utils.createRequest(presence)); - expect($chat_content[0].querySelectorAll('div.chat-info').length).toBe(2); - expect($chat_content.find('div.chat-info:last').html()).toBe("newguy has entered the groupchat"); - - // Add another entrant, otherwise the above message will be - // collapsed if "newguy" leaves immediately again - presence = $pres({ - to: 'dummy@localhost/_converse.js-29092160', - from: 'coven@chat.shakespeare.lit/newgirl' - }) - .c('x', {xmlns: Strophe.NS.MUC_USER}) - .c('item', { - 'affiliation': 'none', - 'jid': 'newgirl@localhost/_converse.js-213098781', - 'role': 'participant' - }); - _converse.connection._dataRecv(test_utils.createRequest(presence)); - expect($chat_content[0].querySelectorAll('div.chat-info').length).toBe(3); - expect($chat_content.find('div.chat-info:last').html()).toBe("newgirl has entered the groupchat"); - - // Don't show duplicate join messages - presence = $pres({ - to: 'dummy@localhost/_converse.js-290918392', - from: 'coven@chat.shakespeare.lit/newguy' - }).c('x', {xmlns: Strophe.NS.MUC_USER}) - .c('item', { - 'affiliation': 'none', - 'jid': 'newguy@localhost/_converse.js-290929789', - 'role': 'participant' - }); - _converse.connection._dataRecv(test_utils.createRequest(presence)); - expect($chat_content[0].querySelectorAll('div.chat-info').length).toBe(3); - - /* - * Disconnected: Replaced by new connection - * - * - * - * - */ - presence = $pres({ - to: 'dummy@localhost/_converse.js-29092160', - type: 'unavailable', - from: 'coven@chat.shakespeare.lit/newguy' - }) - .c('status', 'Disconnected: Replaced by new connection').up() - .c('x', {xmlns: Strophe.NS.MUC_USER}) + presence = $pres({ + to: 'dummy@localhost/_converse.js-29092160', + from: 'coven@chat.shakespeare.lit/newguy' + }) + .c('x', {xmlns: Strophe.NS.MUC_USER}) .c('item', { 'affiliation': 'none', 'jid': 'newguy@localhost/_converse.js-290929789', - 'role': 'none' + 'role': 'participant' }); - _converse.connection._dataRecv(test_utils.createRequest(presence)); - expect($chat_content.find('div.chat-info').length).toBe(4); - expect($chat_content.find('div.chat-info:last').html()).toBe( - 'newguy has left the groupchat. '+ - '"Disconnected: Replaced by new connection"'); + _converse.connection._dataRecv(test_utils.createRequest(presence)); + expect($chat_content[0].querySelectorAll('div.chat-info').length).toBe(2); + expect($chat_content.find('div.chat-info:last').html()).toBe("newguy has entered the groupchat"); - // When the user immediately joins again, we collapse the - // multiple join/leave messages. - presence = $pres({ - to: 'dummy@localhost/_converse.js-29092160', - from: 'coven@chat.shakespeare.lit/newguy' - }).c('x', {xmlns: Strophe.NS.MUC_USER}) - .c('item', { - 'affiliation': 'none', - 'jid': 'newguy@localhost/_converse.js-290929789', - 'role': 'participant' - }); - _converse.connection._dataRecv(test_utils.createRequest(presence)); - expect($chat_content.find('div.chat-info').length).toBe(4); - var $msg_el = $chat_content.find('div.chat-info:last'); - expect($msg_el.html()).toBe("newguy has left and re-entered the groupchat"); - expect($msg_el.data('leavejoin')).toBe('"newguy"'); + // Add another entrant, otherwise the above message will be + // collapsed if "newguy" leaves immediately again + presence = $pres({ + to: 'dummy@localhost/_converse.js-29092160', + from: 'coven@chat.shakespeare.lit/newgirl' + }) + .c('x', {xmlns: Strophe.NS.MUC_USER}) + .c('item', { + 'affiliation': 'none', + 'jid': 'newgirl@localhost/_converse.js-213098781', + 'role': 'participant' + }); + _converse.connection._dataRecv(test_utils.createRequest(presence)); + expect($chat_content[0].querySelectorAll('div.chat-info').length).toBe(3); + expect($chat_content.find('div.chat-info:last').html()).toBe("newgirl has entered the groupchat"); - presence = $pres({ - to: 'dummy@localhost/_converse.js-29092160', - type: 'unavailable', - from: 'coven@chat.shakespeare.lit/newguy' - }) - .c('x', {xmlns: Strophe.NS.MUC_USER}) + // Don't show duplicate join messages + presence = $pres({ + to: 'dummy@localhost/_converse.js-290918392', + from: 'coven@chat.shakespeare.lit/newguy' + }).c('x', {xmlns: Strophe.NS.MUC_USER}) .c('item', { 'affiliation': 'none', 'jid': 'newguy@localhost/_converse.js-290929789', + 'role': 'participant' + }); + _converse.connection._dataRecv(test_utils.createRequest(presence)); + expect($chat_content[0].querySelectorAll('div.chat-info').length).toBe(3); + + /* + * Disconnected: Replaced by new connection + * + * + * + * + */ + presence = $pres({ + to: 'dummy@localhost/_converse.js-29092160', + type: 'unavailable', + from: 'coven@chat.shakespeare.lit/newguy' + }) + .c('status', 'Disconnected: Replaced by new connection').up() + .c('x', {xmlns: Strophe.NS.MUC_USER}) + .c('item', { + 'affiliation': 'none', + 'jid': 'newguy@localhost/_converse.js-290929789', + 'role': 'none' + }); + _converse.connection._dataRecv(test_utils.createRequest(presence)); + expect($chat_content.find('div.chat-info').length).toBe(4); + expect($chat_content.find('div.chat-info:last').html()).toBe( + 'newguy has left the groupchat. '+ + '"Disconnected: Replaced by new connection"'); + + // When the user immediately joins again, we collapse the + // multiple join/leave messages. + presence = $pres({ + to: 'dummy@localhost/_converse.js-29092160', + from: 'coven@chat.shakespeare.lit/newguy' + }).c('x', {xmlns: Strophe.NS.MUC_USER}) + .c('item', { + 'affiliation': 'none', + 'jid': 'newguy@localhost/_converse.js-290929789', + 'role': 'participant' + }); + _converse.connection._dataRecv(test_utils.createRequest(presence)); + expect($chat_content.find('div.chat-info').length).toBe(4); + var $msg_el = $chat_content.find('div.chat-info:last'); + expect($msg_el.html()).toBe("newguy has left and re-entered the groupchat"); + expect($msg_el.data('leavejoin')).toBe('"newguy"'); + + presence = $pres({ + to: 'dummy@localhost/_converse.js-29092160', + type: 'unavailable', + from: 'coven@chat.shakespeare.lit/newguy' + }) + .c('x', {xmlns: Strophe.NS.MUC_USER}) + .c('item', { + 'affiliation': 'none', + 'jid': 'newguy@localhost/_converse.js-290929789', + 'role': 'none' + }); + _converse.connection._dataRecv(test_utils.createRequest(presence)); + expect($chat_content.find('div.chat-info').length).toBe(4); + $msg_el = $chat_content.find('div.chat-info:last'); + expect($msg_el.html()).toBe('newguy has left the groupchat'); + expect($msg_el.data('leave')).toBe('"newguy"'); + + presence = $pres({ + to: 'dummy@localhost/_converse.js-29092160', + from: 'coven@chat.shakespeare.lit/nomorenicks' + }) + .c('x', {xmlns: Strophe.NS.MUC_USER}) + .c('item', { + 'affiliation': 'none', + 'jid': 'nomorenicks@localhost/_converse.js-290929789', + 'role': 'participant' + }); + _converse.connection._dataRecv(test_utils.createRequest(presence)); + expect($chat_content[0].querySelectorAll('div.chat-info').length).toBe(5); + expect($chat_content.find('div.chat-info:last').html()).toBe("nomorenicks has entered the groupchat"); + + presence = $pres({ + to: 'dummy@localhost/_converse.js-290918392', + type: 'unavailable', + from: 'coven@chat.shakespeare.lit/nomorenicks' + }).c('x', {xmlns: Strophe.NS.MUC_USER}) + .c('item', { + 'affiliation': 'none', + 'jid': 'nomorenicks@localhost/_converse.js-290929789', 'role': 'none' }); - _converse.connection._dataRecv(test_utils.createRequest(presence)); - expect($chat_content.find('div.chat-info').length).toBe(4); - $msg_el = $chat_content.find('div.chat-info:last'); - expect($msg_el.html()).toBe('newguy has left the groupchat'); - expect($msg_el.data('leave')).toBe('"newguy"'); + _converse.connection._dataRecv(test_utils.createRequest(presence)); + expect($chat_content[0].querySelectorAll('div.chat-info').length).toBe(5); + expect($chat_content.find('div.chat-info:last').html()).toBe("nomorenicks has entered and left the groupchat"); - presence = $pres({ - to: 'dummy@localhost/_converse.js-29092160', - from: 'coven@chat.shakespeare.lit/nomorenicks' - }) - .c('x', {xmlns: Strophe.NS.MUC_USER}) - .c('item', { - 'affiliation': 'none', - 'jid': 'nomorenicks@localhost/_converse.js-290929789', - 'role': 'participant' - }); - _converse.connection._dataRecv(test_utils.createRequest(presence)); - expect($chat_content[0].querySelectorAll('div.chat-info').length).toBe(5); - expect($chat_content.find('div.chat-info:last').html()).toBe("nomorenicks has entered the groupchat"); - - presence = $pres({ - to: 'dummy@localhost/_converse.js-290918392', - type: 'unavailable', - from: 'coven@chat.shakespeare.lit/nomorenicks' - }).c('x', {xmlns: Strophe.NS.MUC_USER}) - .c('item', { - 'affiliation': 'none', - 'jid': 'nomorenicks@localhost/_converse.js-290929789', - 'role': 'none' - }); - _converse.connection._dataRecv(test_utils.createRequest(presence)); - expect($chat_content[0].querySelectorAll('div.chat-info').length).toBe(5); - expect($chat_content.find('div.chat-info:last').html()).toBe("nomorenicks has entered and left the groupchat"); - - presence = $pres({ - to: 'dummy@localhost/_converse.js-29092160', - from: 'coven@chat.shakespeare.lit/nomorenicks' - }) - .c('x', {xmlns: Strophe.NS.MUC_USER}) - .c('item', { - 'affiliation': 'none', - 'jid': 'nomorenicks@localhost/_converse.js-290929789', - 'role': 'participant' - }); - _converse.connection._dataRecv(test_utils.createRequest(presence)); - expect($chat_content[0].querySelectorAll('div.chat-info').length).toBe(5); - expect($chat_content.find('div.chat-info:last').html()).toBe("nomorenicks has entered the groupchat"); - done(); + presence = $pres({ + to: 'dummy@localhost/_converse.js-29092160', + from: 'coven@chat.shakespeare.lit/nomorenicks' + }) + .c('x', {xmlns: Strophe.NS.MUC_USER}) + .c('item', { + 'affiliation': 'none', + 'jid': 'nomorenicks@localhost/_converse.js-290929789', + 'role': 'participant' + }); + _converse.connection._dataRecv(test_utils.createRequest(presence)); + expect($chat_content[0].querySelectorAll('div.chat-info').length).toBe(5); + expect($chat_content.find('div.chat-info:last').html()).toBe("nomorenicks has entered the groupchat"); + done(); + }); })); it("shows a new day indicator if a join/leave message is received on a new day", @@ -773,50 +774,50 @@ })); it("shows its description in the chat heading", - mock.initConverseWithPromises( - null, ['rosterGroupsFetched'], {}, - function (done, _converse) { + mock.initConverseWithPromises( + null, ['rosterGroupsFetched', 'chatBoxesFetched'], {}, + function (done, _converse) { - var sent_IQ, IQ_id; - var sendIQ = _converse.connection.sendIQ; + let sent_IQ, IQ_id, view; + const sendIQ = _converse.connection.sendIQ; spyOn(_converse.connection, 'sendIQ').and.callFake(function (iq, callback, errback) { sent_IQ = iq; IQ_id = sendIQ.bind(this)(iq, callback, errback); }); - _converse.api.rooms.open('coven@chat.shakespeare.lit', {'nick': 'some1'}); - var view = _converse.chatboxviews.get('coven@chat.shakespeare.lit'); - - var 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 participants'}) - .c('value').t(0); - _converse.connection._dataRecv(test_utils.createRequest(features_stanza)); - test_utils.waitUntil(() => _.get(view.el.querySelector('.chatroom-description'), 'textContent')) - .then(function () { - expect($(view.el.querySelector('.chatroom-description')).text()).toBe('This is the description'); + _converse.api.rooms.open('coven@chat.shakespeare.lit', {'nick': 'some1'}) + .then(() => { + view = _converse.chatboxviews.get('coven@chat.shakespeare.lit'); + 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 participants'}) + .c('value').t(0); + _converse.connection._dataRecv(test_utils.createRequest(features_stanza)); + return test_utils.waitUntil(() => _.get(view.el.querySelector('.chatroom-description'), 'textContent')) + }).then(function () { + expect(view.el.querySelector('.chatroom-description').textContent).toBe('This is the description'); done(); }); })); @@ -885,9 +886,9 @@ })); it("can be configured if you're its owner", - mock.initConverseWithPromises( - null, ['rosterGroupsFetched'], {}, - function (done, _converse) { + mock.initConverseWithPromises( + null, ['rosterGroupsFetched', 'chatBoxesFetched'], {}, + function (done, _converse) { var view; var sent_IQ, IQ_id; @@ -897,48 +898,46 @@ IQ_id = sendIQ.bind(this)(iq, callback, errback); }); - _converse.api.rooms.open('coven@chat.shakespeare.lit', {'nick': 'some1'}); - view = _converse.chatboxviews.get('coven@chat.shakespeare.lit'); + _converse.api.rooms.open('coven@chat.shakespeare.lit', {'nick': 'some1'}) + .then(() => { + view = _converse.chatboxviews.get('coven@chat.shakespeare.lit'); - spyOn(view.model, 'saveAffiliationAndRole').and.callThrough(); + spyOn(view.model, 'saveAffiliationAndRole').and.callThrough(); - // We pretend this is a new room, so no disco info is returned. - var features_stanza = $iq({ - from: 'coven@chat.shakespeare.lit', - 'id': IQ_id, - 'to': 'dummy@localhost/desktop', - 'type': 'error' - }).c('error', {'type': 'cancel'}) - .c('item-not-found', {'xmlns': "urn:ietf:params:xml:ns:xmpp-stanzas"}); - _converse.connection._dataRecv(test_utils.createRequest(features_stanza)); + // We pretend this is a new room, so no disco info is returned. + var features_stanza = $iq({ + from: 'coven@chat.shakespeare.lit', + 'id': IQ_id, + 'to': 'dummy@localhost/desktop', + 'type': 'error' + }).c('error', {'type': 'cancel'}) + .c('item-not-found', {'xmlns': "urn:ietf:params:xml:ns:xmpp-stanzas"}); + _converse.connection._dataRecv(test_utils.createRequest(features_stanza)); - /* - * - * - * - * - * - */ - var presence = $pres({ - to: 'dummy@localhost/_converse.js-29092160', - from: 'coven@chat.shakespeare.lit/some1' - }).c('x', {xmlns: Strophe.NS.MUC_USER}) - .c('item', { - 'affiliation': 'owner', - 'jid': 'dummy@localhost/_converse.js-29092160', - 'role': 'moderator' - }).up() - .c('status', {code: '110'}); - _converse.connection._dataRecv(test_utils.createRequest(presence)); - expect(view.model.saveAffiliationAndRole).toHaveBeenCalled(); - expect($(view.el.querySelector('.toggle-chatbox-button')).is(':visible')).toBeTruthy(); - - test_utils.waitUntil(function () { - return !_.isNull(view.el.querySelector('.configure-chatroom-button')); - }, 300).then(function () { + /* + * + * + * + * + * + */ + var presence = $pres({ + to: 'dummy@localhost/_converse.js-29092160', + from: 'coven@chat.shakespeare.lit/some1' + }).c('x', {xmlns: Strophe.NS.MUC_USER}) + .c('item', { + 'affiliation': 'owner', + 'jid': 'dummy@localhost/_converse.js-29092160', + 'role': 'moderator' + }).up() + .c('status', {code: '110'}); + _converse.connection._dataRecv(test_utils.createRequest(presence)); + expect(view.model.saveAffiliationAndRole).toHaveBeenCalled(); + expect($(view.el.querySelector('.toggle-chatbox-button')).is(':visible')).toBeTruthy(); + return test_utils.waitUntil(() => !_.isNull(view.el.querySelector('.configure-chatroom-button'))) + }).then(() => { expect($(view.el.querySelector('.configure-chatroom-button')).is(':visible')).toBeTruthy(); - view.el.querySelector('.configure-chatroom-button').click(); /* Check that an IQ is sent out, asking for the @@ -1074,42 +1073,40 @@ .c('value').t('cauldronburn'); _converse.connection._dataRecv(test_utils.createRequest(config_stanza)); - test_utils.waitUntil(function () { - return $(view.el.querySelector('form.chatroom-form')).length; - }, 300).then(function () { - expect($(view.el.querySelector('form.chatroom-form')).length).toBe(1); - expect(view.el.querySelectorAll('form.chatroom-form fieldset').length).toBe(2); - var $membersonly = $(view.el.querySelector('input[name="muc#roomconfig_membersonly"]')); - expect($membersonly.length).toBe(1); - expect($membersonly.attr('type')).toBe('checkbox'); - $membersonly.prop('checked', true); + return test_utils.waitUntil(() => view.el.querySelectorAll('form.chatroom-form').length) + }).then(() => { + expect($(view.el.querySelector('form.chatroom-form')).length).toBe(1); + expect(view.el.querySelectorAll('form.chatroom-form fieldset').length).toBe(2); + var $membersonly = $(view.el.querySelector('input[name="muc#roomconfig_membersonly"]')); + expect($membersonly.length).toBe(1); + expect($membersonly.attr('type')).toBe('checkbox'); + $membersonly.prop('checked', true); - var $moderated = $(view.el.querySelector('input[name="muc#roomconfig_moderatedroom"]')); - expect($moderated.length).toBe(1); - expect($moderated.attr('type')).toBe('checkbox'); - $moderated.prop('checked', true); + var $moderated = $(view.el.querySelector('input[name="muc#roomconfig_moderatedroom"]')); + expect($moderated.length).toBe(1); + expect($moderated.attr('type')).toBe('checkbox'); + $moderated.prop('checked', true); - var $password = $(view.el.querySelector('input[name="muc#roomconfig_roomsecret"]')); - expect($password.length).toBe(1); - expect($password.attr('type')).toBe('password'); + var $password = $(view.el.querySelector('input[name="muc#roomconfig_roomsecret"]')); + expect($password.length).toBe(1); + expect($password.attr('type')).toBe('password'); - var $allowpm = $(view.el.querySelector('select[name="muc#roomconfig_allowpm"]')); - expect($allowpm.length).toBe(1); - $allowpm.val('moderators'); + var $allowpm = $(view.el.querySelector('select[name="muc#roomconfig_allowpm"]')); + expect($allowpm.length).toBe(1); + $allowpm.val('moderators'); - var $presencebroadcast = $(view.el.querySelector('select[name="muc#roomconfig_presencebroadcast"]')); - expect($presencebroadcast.length).toBe(1); - $presencebroadcast.val(['moderator']); + var $presencebroadcast = $(view.el.querySelector('select[name="muc#roomconfig_presencebroadcast"]')); + expect($presencebroadcast.length).toBe(1); + $presencebroadcast.val(['moderator']); - view.el.querySelector('input[type="submit"]').click(); + view.el.querySelector('input[type="submit"]').click(); - var $sent_stanza = $(sent_IQ.toLocaleString()); - expect($sent_stanza.find('field[var="muc#roomconfig_membersonly"] value').text()).toBe('1'); - expect($sent_stanza.find('field[var="muc#roomconfig_moderatedroom"] value').text()).toBe('1'); - expect($sent_stanza.find('field[var="muc#roomconfig_allowpm"] value').text()).toBe('moderators'); - expect($sent_stanza.find('field[var="muc#roomconfig_presencebroadcast"] value').text()).toBe('moderator'); - done(); - }); + var $sent_stanza = $(sent_IQ.toLocaleString()); + expect($sent_stanza.find('field[var="muc#roomconfig_membersonly"] value').text()).toBe('1'); + expect($sent_stanza.find('field[var="muc#roomconfig_moderatedroom"] value').text()).toBe('1'); + expect($sent_stanza.find('field[var="muc#roomconfig_allowpm"] value').text()).toBe('moderators'); + expect($sent_stanza.find('field[var="muc#roomconfig_presencebroadcast"] value').text()).toBe('moderator'); + done(); }).catch(_.partial(_converse.log, _, Strophe.LogLevel.FATAL)); })); @@ -1317,13 +1314,13 @@ })); it("will use the user's reserved nickname, if it exists", - mock.initConverseWithPromises( - null, ['rosterGroupsFetched'], {}, - function (done, _converse) { + mock.initConverseWithPromises( + null, ['rosterGroupsFetched', 'chatBoxesFetched'], {}, + function (done, _converse) { - var IQ_stanzas = _converse.connection.IQ_stanzas; - var sent_IQ, IQ_id; - var sendIQ = _converse.connection.sendIQ; + let sent_IQ, IQ_id, view; + const IQ_stanzas = _converse.connection.IQ_stanzas; + const sendIQ = _converse.connection.sendIQ; spyOn(_converse.connection, 'sendIQ').and.callFake(function (iq, callback, errback) { if (iq.nodeTree.getAttribute('to') === 'lounge@localhost') { sent_IQ = iq; @@ -1333,35 +1330,31 @@ } }); - test_utils.openChatRoom(_converse, 'lounge', 'localhost', 'dummy'); + test_utils.openChatRoom(_converse, 'lounge', 'localhost', 'dummy') + .then(() => { + // We pretend this is a new room, so no disco info is returned. + var features_stanza = $iq({ + from: 'lounge@localhost', + 'id': IQ_id, + 'to': 'dummy@localhost/desktop', + 'type': 'error' + }).c('error', {'type': 'cancel'}) + .c('item-not-found', {'xmlns': "urn:ietf:params:xml:ns:xmpp-stanzas"}); + _converse.connection._dataRecv(test_utils.createRequest(features_stanza)); - // We pretend this is a new room, so no disco info is returned. - var features_stanza = $iq({ - from: 'lounge@localhost', - 'id': IQ_id, - 'to': 'dummy@localhost/desktop', - 'type': 'error' - }).c('error', {'type': 'cancel'}) - .c('item-not-found', {'xmlns': "urn:ietf:params:xml:ns:xmpp-stanzas"}); - _converse.connection._dataRecv(test_utils.createRequest(features_stanza)); + view = _converse.chatboxviews.get('lounge@localhost'); + spyOn(view, 'join').and.callThrough(); - var view = _converse.chatboxviews.get('lounge@localhost'); - spyOn(view, 'join').and.callThrough(); - - /* - * - * - */ - - test_utils.waitUntil(function () { - return _.filter(IQ_stanzas, function (iq) { - return iq.nodeTree.querySelector('query[node="x-roomuser-item"]'); - }).length > 0; - }, 300).then(function () { + /* + * + * + */ + return test_utils.waitUntil(() => _.filter(IQ_stanzas, (iq) => iq.nodeTree.querySelector('query[node="x-roomuser-item"]')).length) + }).then(() => { const iq = _.filter(IQ_stanzas, function (iq) { return iq.nodeTree.querySelector(`query[node="x-roomuser-item"]`); }).pop(); @@ -1420,33 +1413,35 @@ })); it("allows the user to invite their roster contacts to enter the groupchat", - mock.initConverseWithPromises( - null, ['rosterGroupsFetched'], {}, - function (done, _converse) { + mock.initConverseWithPromises( + null, ['rosterGroupsFetched', 'chatBoxesFetched'], {}, + function (done, _converse) { - test_utils.openChatRoom(_converse, 'lounge', 'localhost', 'dummy'); test_utils.createContacts(_converse, 'current'); // We need roster contacts, so that we have someone to invite // Since we don't actually fetch roster contacts, we need to // cheat here and emit the event. _converse.emit('rosterContactsFetched'); - spyOn(_converse, 'emit'); - spyOn(window, 'prompt').and.callFake(function () { - return "Please join!"; - }); - var view = _converse.chatboxviews.get('lounge@localhost'); + let view; + test_utils.openChatRoom(_converse, 'lounge', 'localhost', 'dummy') + .then(() => { - // XXX: cheating a lttle bit, normally this'll be set after - // receiving the features for the groupchat. - view.model.set('open', 'true'); + spyOn(_converse, 'emit'); + spyOn(window, 'prompt').and.callFake(function () { + return "Please join!"; + }); + view = _converse.chatboxviews.get('lounge@localhost'); - spyOn(view.model, 'directInvite').and.callThrough(); - var $input; - $(view.el).find('.chat-area').remove(); + // XXX: cheating a lttle bit, normally this'll be set after + // receiving the features for the groupchat. + view.model.set('open', 'true'); - test_utils.waitUntil(function () { - return $(view.el).find('input.invited-contact').length; - }, 300).then(function () { + spyOn(view.model, 'directInvite').and.callThrough(); + var $input; + $(view.el).find('.chat-area').remove(); + + return test_utils.waitUntil(() => view.el.querySelectorAll('input.invited-contact').length) + }).then(function () { var $input = $(view.el).find('input.invited-contact'); expect($input.attr('placeholder')).toBe('Invite'); $input.val("Felix"); @@ -1781,9 +1776,9 @@ })); it("queries for the groupchat information before attempting to join the user", - mock.initConverseWithPromises( - null, ['rosterGroupsFetched'], {}, - function (done, _converse) { + mock.initConverseWithPromises( + null, ['rosterGroupsFetched', 'chatBoxesFetched'], {}, + function (done, _converse) { var sent_IQ, IQ_id; var sendIQ = _converse.connection.sendIQ; @@ -1792,57 +1787,58 @@ IQ_id = sendIQ.bind(this)(iq, callback, errback); }); - _converse.api.rooms.open('coven@chat.shakespeare.lit', {'nick': 'some1'}); - - // Check that the groupchat queried for the feautures. - expect(sent_IQ.toLocaleString()).toBe( - ""+ - ""+ - ""); - - var view = _converse.chatboxviews.get('coven@chat.shakespeare.lit'); - spyOn(view.model, 'parseRoomFeatures').and.callThrough(); - /* - * - * - * - * - * - * - * - * - * - * - * - */ - var 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'}); - _converse.connection._dataRecv(test_utils.createRequest(features_stanza)); - test_utils.waitUntil(() => view.model.parseRoomFeatures.calls.count(), 300) + let view; + _converse.api.rooms.open('coven@chat.shakespeare.lit', {'nick': 'some1'}) .then(() => { + // Check that the groupchat queried for the feautures. + expect(sent_IQ.toLocaleString()).toBe( + ""+ + ""+ + ""); + + view = _converse.chatboxviews.get('coven@chat.shakespeare.lit'); + spyOn(view.model, 'parseRoomFeatures').and.callThrough(); + /* + * + * + * + * + * + * + * + * + * + * + * + */ + 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'}); + _converse.connection._dataRecv(test_utils.createRequest(features_stanza)); + return test_utils.waitUntil(() => view.model.parseRoomFeatures.calls.count(), 300) + }).then(() => { expect(view.model.get('features_fetched')).toBeTruthy(); expect(view.model.get('passwordprotected')).toBe(true); expect(view.model.get('hidden')).toBe(true); @@ -2013,82 +2009,89 @@ })); it("can be saved to, and retrieved from, browserStorage", - mock.initConverseWithPromises( - null, ['rosterGroupsFetched'], {}, - function (done, _converse) { + mock.initConverseWithPromises( + null, ['rosterGroupsFetched', 'chatBoxesFetched'], {}, + function (done, _converse) { - test_utils.openChatRoom(_converse, 'lounge', 'localhost', 'dummy'); - // We instantiate a new ChatBoxes collection, which by default - // will be empty. - test_utils.openControlBox(); - 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(2); - // Check that the chatrooms 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 { + // We instantiate a new ChatBoxes collection, which by default + // will be empty. + test_utils.openControlBox(); + 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(2); + // Check that the chatrooms 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 { + const view = _converse.chatboxviews.get('lounge@localhost'), + trimmed_chatboxes = _converse.minimized_chats; - spyOn(view, 'minimize').and.callThrough(); - spyOn(view, 'maximize').and.callThrough(); - spyOn(_converse, 'emit'); - view.delegateEvents(); // We need to rebind all events otherwise our spy won't be called - view.el.querySelector('.toggle-chatbox-button').click(); + spyOn(view, 'minimize').and.callThrough(); + spyOn(view, 'maximize').and.callThrough(); + spyOn(_converse, 'emit'); + view.delegateEvents(); // We need to rebind all events otherwise our spy won't be called + view.el.querySelector('.toggle-chatbox-button').click(); - expect(view.minimize).toHaveBeenCalled(); - expect(_converse.emit).toHaveBeenCalledWith('chatBoxMinimized', jasmine.any(Object)); - expect(u.isVisible(view.el)).toBeFalsy(); - expect(view.model.get('minimized')).toBeTruthy(); - expect(view.minimize).toHaveBeenCalled(); - var trimmedview = trimmed_chatboxes.get(view.model.get('id')); - trimmedview.el.querySelector("a.restore-chat").click(); - expect(view.maximize).toHaveBeenCalled(); - expect(_converse.emit).toHaveBeenCalledWith('chatBoxMaximized', jasmine.any(Object)); - expect(view.model.get('minimized')).toBeFalsy(); - expect(_converse.emit.calls.count(), 3); - done(); + expect(view.minimize).toHaveBeenCalled(); + expect(_converse.emit).toHaveBeenCalledWith('chatBoxMinimized', jasmine.any(Object)); + expect(u.isVisible(view.el)).toBeFalsy(); + expect(view.model.get('minimized')).toBeTruthy(); + expect(view.minimize).toHaveBeenCalled(); + var trimmedview = trimmed_chatboxes.get(view.model.get('id')); + trimmedview.el.querySelector("a.restore-chat").click(); + expect(view.maximize).toHaveBeenCalled(); + expect(_converse.emit).toHaveBeenCalledWith('chatBoxMaximized', jasmine.any(Object)); + expect(view.model.get('minimized')).toBeFalsy(); + expect(_converse.emit.calls.count(), 3); + done(); + + }); })); it("can be closed again by clicking a DOM element with class 'close-chatbox-button'", - mock.initConverseWithPromises( - null, ['rosterGroupsFetched'], {}, - function (done, _converse) { + mock.initConverseWithPromises( + null, ['rosterGroupsFetched', 'chatBoxesFetched'], {}, + function (done, _converse) { - test_utils.openChatRoom(_converse, 'lounge', 'localhost', 'dummy'); - var view = _converse.chatboxviews.get('lounge@localhost'); - spyOn(view, 'close').and.callThrough(); - spyOn(_converse, 'emit'); - spyOn(view.model, 'leave'); - view.delegateEvents(); // We need to rebind all events otherwise our spy won't be called - view.el.querySelector('.close-chatbox-button').click(); - expect(view.close).toHaveBeenCalled(); - expect(view.model.leave).toHaveBeenCalled(); - expect(_converse.emit).toHaveBeenCalledWith('chatBoxClosed', jasmine.any(Object)); - done(); + test_utils.openChatRoom(_converse, 'lounge', 'localhost', 'dummy') + .then(() => { + const view = _converse.chatboxviews.get('lounge@localhost'); + spyOn(view, 'close').and.callThrough(); + spyOn(_converse, 'emit'); + spyOn(view.model, 'leave'); + view.delegateEvents(); // We need to rebind all events otherwise our spy won't be called + view.el.querySelector('.close-chatbox-button').click(); + expect(view.close).toHaveBeenCalled(); + expect(view.model.leave).toHaveBeenCalled(); + expect(_converse.emit).toHaveBeenCalledWith('chatBoxClosed', jasmine.any(Object)); + done(); + }); })); }); @@ -2952,44 +2955,44 @@ describe("Someone being invited to a groupchat", function () { it("will first be added to the member list if the groupchat is members only", - mock.initConverseWithPromises( - null, ['rosterGroupsFetched'], {}, - function (done, _converse) { + mock.initConverseWithPromises( + null, ['rosterGroupsFetched', 'chatBoxesFetched'], {}, + function (done, _converse) { var sent_IQs = [], IQ_ids = []; - var invitee_jid, sent_stanza, sent_id; + let invitee_jid, sent_stanza, sent_id, view; var sendIQ = _converse.connection.sendIQ; spyOn(_converse.connection, 'sendIQ').and.callFake(function (iq, callback, errback) { sent_IQs.push(iq); IQ_ids.push(sendIQ.bind(this)(iq, callback, errback)); }); - _converse.api.rooms.open('coven@chat.shakespeare.lit', {'nick': 'dummy'}); - - var view = _converse.chatboxviews.get('coven@chat.shakespeare.lit'); - spyOn(view.model, 'parseRoomFeatures').and.callThrough(); - - // State that the chat is members-only via the features IQ - var features_stanza = $iq({ - from: 'coven@chat.shakespeare.lit', - 'id': IQ_ids.pop(), - '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_hidden'}).up() - .c('feature', {'var': 'muc_temporary'}).up() - .c('feature', {'var': 'muc_membersonly'}).up(); - _converse.connection._dataRecv(test_utils.createRequest(features_stanza)); - - test_utils.waitUntil(() => view.model.parseRoomFeatures.calls.count(), 300) + _converse.api.rooms.open('coven@chat.shakespeare.lit', {'nick': 'dummy'}) .then(() => { + view = _converse.chatboxviews.get('coven@chat.shakespeare.lit'); + spyOn(view.model, 'parseRoomFeatures').and.callThrough(); + + // State that the chat is members-only via the features IQ + var features_stanza = $iq({ + from: 'coven@chat.shakespeare.lit', + 'id': IQ_ids.pop(), + '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_hidden'}).up() + .c('feature', {'var': 'muc_temporary'}).up() + .c('feature', {'var': 'muc_membersonly'}).up(); + _converse.connection._dataRecv(test_utils.createRequest(features_stanza)); + + return test_utils.waitUntil(() => view.model.parseRoomFeatures.calls.count(), 300); + }).then(() => { expect(view.model.get('membersonly')).toBeTruthy(); test_utils.createContacts(_converse, 'current'); @@ -3173,11 +3176,13 @@ describe("The \"Groupchats\" section", function () { it("contains a link to a modal through which a new chatroom can be created", - mock.initConverseWithPromises( - null, ['rosterGroupsFetched'], {}, - function (done, _converse) { + mock.initConverseWithPromises( + null, ['rosterGroupsFetched', 'chatBoxesFetched'], {}, + function (done, _converse) { test_utils.openControlBox(); + _converse.emit('rosterContactsFetched'); + var roomspanel = _converse.chatboxviews.get('controlbox').roomspanel; roomspanel.el.querySelector('.show-add-muc-modal').click(); test_utils.closeControlBox(_converse); @@ -3193,16 +3198,17 @@ modal.el.querySelector('input[name="chatroom"]').value = 'lounce@muc.localhost'; modal.el.querySelector('form input[type="submit"]').click(); + return test_utils.waitUntil(() => _converse.chatboxes.length); + }).then(() => { expect($('.chatroom:visible').length).toBe(1); // There should now be an open chatroom done(); }).catch(_.partial(console.error, _)); })); it("contains a link to a modal which can list groupchats publically available on the server", - mock.initConverseWithPromises( - null, ['rosterGroupsFetched'], {}, - function (done, _converse) { - + mock.initConverseWithPromises( + null, ['rosterGroupsFetched', 'chatBoxesFetched'], {}, + function (done, _converse) { var sendIQ = _converse.connection.sendIQ; var sent_stanza, IQ_id; @@ -3216,9 +3222,8 @@ roomspanel.el.querySelector('.show-list-muc-modal').click(); test_utils.closeControlBox(_converse); const modal = roomspanel.list_rooms_modal; - test_utils.waitUntil(function () { - return u.isVisible(modal.el); - }, 1000).then(function () { + test_utils.waitUntil(() => u.isVisible(modal.el), 1000) + .then(() => { spyOn(_converse.ChatRoom.prototype, 'getRoomFeatures').and.callFake(function () { var deferred = new $.Deferred(); deferred.resolve(); @@ -3231,7 +3236,8 @@ const input = modal.el.querySelector('input[name="server"]').value = 'chat.shakespear.lit'; modal.el.querySelector('input[type="submit"]').click(); - + return test_utils.waitUntil(() => _converse.chatboxes.length); + }).then(() => { expect(sent_stanza.toLocaleString()).toBe( ""+ ""+ @@ -3260,6 +3266,8 @@ expect(rooms[4].textContent.trim()).toBe("Macbeth's Castle"); rooms[4].querySelector('.open-room').click(); + return test_utils.waitUntil(() => _converse.chatboxes.length > 1); + }).then(() => { expect($('.chatroom:visible').length).toBe(1); // There should now be an open chatroom var view = _converse.chatboxviews.get('inverness@chat.shakespeare.lit'); expect(view.el.querySelector('.chat-head-chatroom').textContent.trim()).toBe("Macbeth's Castle"); @@ -3508,143 +3516,145 @@ describe("A paused notification", function () { it("will be shown if received", - mock.initConverseWithPromises( - null, ['rosterGroupsFetched'], {}, - function (done, _converse) { + mock.initConverseWithPromises( + null, ['rosterGroupsFetched', 'chatBoxesFetched'], {}, + function (done, _converse) { - test_utils.openChatRoom(_converse, "coven", 'chat.shakespeare.lit', 'some1'); - var room_jid = 'coven@chat.shakespeare.lit'; - var view = _converse.chatboxviews.get('coven@chat.shakespeare.lit'); - var $chat_content = $(view.el).find('.chat-content'); + test_utils.openChatRoom(_converse, "coven", 'chat.shakespeare.lit', 'some1') + .then(() => { + var room_jid = 'coven@chat.shakespeare.lit'; + var view = _converse.chatboxviews.get('coven@chat.shakespeare.lit'); + var $chat_content = $(view.el).find('.chat-content'); - /* - * - * - * - * - * - */ - var presence = $pres({ - to: 'dummy@localhost/_converse.js-29092160', - from: 'coven@chat.shakespeare.lit/some1' - }).c('x', {xmlns: Strophe.NS.MUC_USER}) - .c('item', { - 'affiliation': 'owner', - 'jid': 'dummy@localhost/_converse.js-29092160', - 'role': 'moderator' - }).up() - .c('status', {code: '110'}); - _converse.connection._dataRecv(test_utils.createRequest(presence)); - expect($chat_content.find('div.chat-info:first').html()).toBe("some1 has entered the groupchat"); + /* + * + * + * + * + * + */ + var presence = $pres({ + to: 'dummy@localhost/_converse.js-29092160', + from: 'coven@chat.shakespeare.lit/some1' + }).c('x', {xmlns: Strophe.NS.MUC_USER}) + .c('item', { + 'affiliation': 'owner', + 'jid': 'dummy@localhost/_converse.js-29092160', + 'role': 'moderator' + }).up() + .c('status', {code: '110'}); + _converse.connection._dataRecv(test_utils.createRequest(presence)); + expect($chat_content.find('div.chat-info:first').html()).toBe("some1 has entered the groupchat"); - presence = $pres({ - to: 'dummy@localhost/_converse.js-29092160', - from: 'coven@chat.shakespeare.lit/newguy' - }) - .c('x', {xmlns: Strophe.NS.MUC_USER}) - .c('item', { - 'affiliation': 'none', - 'jid': 'newguy@localhost/_converse.js-290929789', - 'role': 'participant' - }); - _converse.connection._dataRecv(test_utils.createRequest(presence)); - expect($chat_content[0].querySelectorAll('div.chat-info').length).toBe(2); - expect($chat_content.find('div.chat-info:last').html()).toBe("newguy has entered the groupchat"); + presence = $pres({ + to: 'dummy@localhost/_converse.js-29092160', + from: 'coven@chat.shakespeare.lit/newguy' + }) + .c('x', {xmlns: Strophe.NS.MUC_USER}) + .c('item', { + 'affiliation': 'none', + 'jid': 'newguy@localhost/_converse.js-290929789', + 'role': 'participant' + }); + _converse.connection._dataRecv(test_utils.createRequest(presence)); + expect($chat_content[0].querySelectorAll('div.chat-info').length).toBe(2); + expect($chat_content.find('div.chat-info:last').html()).toBe("newguy has entered the groupchat"); - presence = $pres({ - to: 'dummy@localhost/_converse.js-29092160', - from: 'coven@chat.shakespeare.lit/nomorenicks' - }) - .c('x', {xmlns: Strophe.NS.MUC_USER}) - .c('item', { - 'affiliation': 'none', - 'jid': 'nomorenicks@localhost/_converse.js-290929789', - 'role': 'participant' - }); - _converse.connection._dataRecv(test_utils.createRequest(presence)); - expect($chat_content[0].querySelectorAll('div.chat-info').length).toBe(3); - expect($chat_content.find('div.chat-info:last').html()).toBe("nomorenicks has entered the groupchat"); + presence = $pres({ + to: 'dummy@localhost/_converse.js-29092160', + from: 'coven@chat.shakespeare.lit/nomorenicks' + }) + .c('x', {xmlns: Strophe.NS.MUC_USER}) + .c('item', { + 'affiliation': 'none', + 'jid': 'nomorenicks@localhost/_converse.js-290929789', + 'role': 'participant' + }); + _converse.connection._dataRecv(test_utils.createRequest(presence)); + expect($chat_content[0].querySelectorAll('div.chat-info').length).toBe(3); + expect($chat_content.find('div.chat-info:last').html()).toBe("nomorenicks has entered the groupchat"); - // See XEP-0085 http://xmpp.org/extensions/xep-0085.html#definitions + // See XEP-0085 http://xmpp.org/extensions/xep-0085.html#definitions - // state - var msg = $msg({ - from: room_jid+'/newguy', - id: (new Date()).getTime(), - to: 'dummy@localhost', - type: 'groupchat' - }).c('body').c('composing', {'xmlns': Strophe.NS.CHATSTATES}).tree(); - view.model.onMessage(msg); + // state + var msg = $msg({ + from: room_jid+'/newguy', + id: (new Date()).getTime(), + to: 'dummy@localhost', + type: 'groupchat' + }).c('body').c('composing', {'xmlns': Strophe.NS.CHATSTATES}).tree(); + view.model.onMessage(msg); - // Check that the notification appears inside the chatbox in the DOM - var events = view.el.querySelectorAll('.chat-event'); - expect(events.length).toBe(3); - expect(events[0].textContent).toEqual('some1 has entered the groupchat'); - expect(events[1].textContent).toEqual('newguy has entered the groupchat'); - expect(events[2].textContent).toEqual('nomorenicks has entered the groupchat'); + // Check that the notification appears inside the chatbox in the DOM + var events = view.el.querySelectorAll('.chat-event'); + expect(events.length).toBe(3); + expect(events[0].textContent).toEqual('some1 has entered the groupchat'); + expect(events[1].textContent).toEqual('newguy has entered the groupchat'); + expect(events[2].textContent).toEqual('nomorenicks has entered the groupchat'); - var notifications = view.el.querySelectorAll('.chat-state-notification'); - expect(notifications.length).toBe(1); - expect(notifications[0].textContent).toEqual('newguy is typing'); + var notifications = view.el.querySelectorAll('.chat-state-notification'); + expect(notifications.length).toBe(1); + expect(notifications[0].textContent).toEqual('newguy is typing'); - // Check that it doesn't appear twice - msg = $msg({ - from: room_jid+'/newguy', - id: (new Date()).getTime(), - to: 'dummy@localhost', - type: 'groupchat' - }).c('body').c('composing', {'xmlns': Strophe.NS.CHATSTATES}).tree(); - view.model.onMessage(msg); + // Check that it doesn't appear twice + msg = $msg({ + from: room_jid+'/newguy', + id: (new Date()).getTime(), + to: 'dummy@localhost', + type: 'groupchat' + }).c('body').c('composing', {'xmlns': Strophe.NS.CHATSTATES}).tree(); + view.model.onMessage(msg); - events = view.el.querySelectorAll('.chat-event'); - expect(events.length).toBe(3); - expect(events[0].textContent).toEqual('some1 has entered the groupchat'); - expect(events[1].textContent).toEqual('newguy has entered the groupchat'); - expect(events[2].textContent).toEqual('nomorenicks has entered the groupchat'); + events = view.el.querySelectorAll('.chat-event'); + expect(events.length).toBe(3); + expect(events[0].textContent).toEqual('some1 has entered the groupchat'); + expect(events[1].textContent).toEqual('newguy has entered the groupchat'); + expect(events[2].textContent).toEqual('nomorenicks has entered the groupchat'); - notifications = view.el.querySelectorAll('.chat-state-notification'); - expect(notifications.length).toBe(1); - expect(notifications[0].textContent).toEqual('newguy is typing'); + notifications = view.el.querySelectorAll('.chat-state-notification'); + expect(notifications.length).toBe(1); + expect(notifications[0].textContent).toEqual('newguy is typing'); - // state for a different occupant - msg = $msg({ - from: room_jid+'/nomorenicks', - id: (new Date()).getTime(), - to: 'dummy@localhost', - type: 'groupchat' - }).c('body').c('composing', {'xmlns': Strophe.NS.CHATSTATES}).tree(); - view.model.onMessage(msg); - events = view.el.querySelectorAll('.chat-event'); - expect(events.length).toBe(3); - expect(events[0].textContent).toEqual('some1 has entered the groupchat'); - expect(events[1].textContent).toEqual('newguy has entered the groupchat'); - expect(events[2].textContent).toEqual('nomorenicks has entered the groupchat'); + // state for a different occupant + msg = $msg({ + from: room_jid+'/nomorenicks', + id: (new Date()).getTime(), + to: 'dummy@localhost', + type: 'groupchat' + }).c('body').c('composing', {'xmlns': Strophe.NS.CHATSTATES}).tree(); + view.model.onMessage(msg); + events = view.el.querySelectorAll('.chat-event'); + expect(events.length).toBe(3); + expect(events[0].textContent).toEqual('some1 has entered the groupchat'); + expect(events[1].textContent).toEqual('newguy has entered the groupchat'); + expect(events[2].textContent).toEqual('nomorenicks has entered the groupchat'); - notifications = view.el.querySelectorAll('.chat-state-notification'); - expect(notifications.length).toBe(2); - expect(notifications[0].textContent).toEqual('newguy is typing'); - expect(notifications[1].textContent).toEqual('nomorenicks is typing'); + notifications = view.el.querySelectorAll('.chat-state-notification'); + expect(notifications.length).toBe(2); + expect(notifications[0].textContent).toEqual('newguy is typing'); + expect(notifications[1].textContent).toEqual('nomorenicks is typing'); - // state from occupant who typed first - msg = $msg({ - from: room_jid+'/newguy', - id: (new Date()).getTime(), - to: 'dummy@localhost', - type: 'groupchat' - }).c('body').c('paused', {'xmlns': Strophe.NS.CHATSTATES}).tree(); - view.model.onMessage(msg); - events = view.el.querySelectorAll('.chat-event'); - expect(events.length).toBe(3); - expect(events[0].textContent).toEqual('some1 has entered the groupchat'); - expect(events[1].textContent).toEqual('newguy has entered the groupchat'); - expect(events[2].textContent).toEqual('nomorenicks has entered the groupchat'); + // state from occupant who typed first + msg = $msg({ + from: room_jid+'/newguy', + id: (new Date()).getTime(), + to: 'dummy@localhost', + type: 'groupchat' + }).c('body').c('paused', {'xmlns': Strophe.NS.CHATSTATES}).tree(); + view.model.onMessage(msg); + events = view.el.querySelectorAll('.chat-event'); + expect(events.length).toBe(3); + expect(events[0].textContent).toEqual('some1 has entered the groupchat'); + expect(events[1].textContent).toEqual('newguy has entered the groupchat'); + expect(events[2].textContent).toEqual('nomorenicks has entered the groupchat'); - notifications = view.el.querySelectorAll('.chat-state-notification'); - expect(notifications.length).toBe(2); - expect(notifications[0].textContent).toEqual('nomorenicks is typing'); - expect(notifications[1].textContent).toEqual('newguy has stopped typing'); - done(); + notifications = view.el.querySelectorAll('.chat-state-notification'); + expect(notifications.length).toBe(2); + expect(notifications[0].textContent).toEqual('nomorenicks is typing'); + expect(notifications[1].textContent).toEqual('newguy has stopped typing'); + done(); + }); })); }); }); diff --git a/spec/http-file-upload.js b/spec/http-file-upload.js index 907cc0c54..b68f8e1a0 100644 --- a/spec/http-file-upload.js +++ b/spec/http-file-upload.js @@ -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(() => 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( + ""+ + ""+ + ""); + + var base_url = document.URL.split(window.location.pathname)[0]; + var message = base_url+"/logo/conversejs-filled.svg"; + + var stanza = Strophe.xmlHtmlNode( + ""+ + ""+ + " "+ + "
Basic Base64String==
"+ + "
foo=bar; user=romeo
"+ + "
"+ + " "+ + "
"+ + "
").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 _.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( - ""+ - ""+ - ""); - - var base_url = document.URL.split(window.location.pathname)[0]; - var message = base_url+"/logo/conversejs-filled.svg"; - - var stanza = Strophe.xmlHtmlNode( - ""+ - ""+ - " "+ - "
Basic Base64String==
"+ - "
foo=bar; user=romeo
"+ - "
"+ - " "+ - "
"+ - "
").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 sent_stanza; + }, 1000).then(function () { + expect(sent_stanza.toLocaleString()).toBe( + ""+ + ""+message+""+ + ""+ + ""+ + ""+message+""+ + ""+ + ""); return test_utils.waitUntil(function () { - return sent_stanza; - }, 1000).then(function () { - expect(sent_stanza.toLocaleString()).toBe( - ""+ - ""+message+""+ - ""+ - ""+ - ""+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( - `\n`+ - ``+ - ``+ - ``); - 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( + `\n`+ + ``+ + ``+ + ``); + 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(function () { - test_utils.waitUntil(function () { + 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)]; + + 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( - ""+ - ""+ - ""); + _converse.connection._dataRecv(test_utils.createRequest(stanza)); - // 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.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( + ""+ + ""+ + ""); - _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)); - }) - }); + // 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; + let view, 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( - ""+ - ""+ - ""); + 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'); - var base_url = document.URL.split(window.location.pathname)[0]; - var message = base_url+"/logo/conversejs-filled.svg"; + 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( + ""+ + ""+ + ""); - var stanza = Strophe.xmlHtmlNode( - ""+ - ""+ - " "+ - "
Basic Base64String==
"+ - "
foo=bar; user=romeo
"+ - "
"+ - " "+ - "
"+ - "
").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)); - }); + const base_url = document.URL.split(window.location.pathname)[0]; + const message = base_url+"/logo/conversejs-filled.svg"; + const stanza = Strophe.xmlHtmlNode( + ""+ + ""+ + " "+ + "
Basic Base64String==
"+ + "
foo=bar; user=romeo
"+ + "
"+ + " "+ + "
"+ + "
").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)); }); }); })); }); - }); }); })); diff --git a/spec/messages.js b/spec/messages.js index 65c603672..f70d915b5 100644 --- a/spec/messages.js +++ b/spec/messages.js @@ -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 + 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(``+ + `But soft, what light through yonder window breaks?`+ + ``+ + ``+ + ``); + 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(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 - }); - expect(_converse.connection.send).toHaveBeenCalled(); - - const msg = _converse.connection.send.calls.all()[0].args[0]; - expect(msg.toLocaleString()) - .toBe(``+ - `But soft, what light through yonder window breaks?`+ - ``+ - ``+ - ``); - 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 + 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(``+ + `But soft, what light through yonder window breaks?`+ + ``+ + ``+ + ``); + 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(''); - - 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(``+ - `But soft, what light through yonder window breaks?`+ - ``+ - ``+ - ``); - 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(); })); @@ -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. /* - * yo - * - * - */ + * to="kirk@enterprise.com.com" + * type="chat" + * id="82bc02ce-9651-4336-baf0-fa04762ed8d2" + * xmlns="jabber:client"> + * yo + * + * + */ 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 + _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); + + /* + * + * + * Server-to-server connection failed: Connecting failed: connection timeout + * + * + */ + 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); - 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); - - /* - * - * - * Server-to-server connection failed: Connecting failed: connection timeout - * - * - */ - 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); + 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(); - 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 () { + // 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 = '

This message contains some markup

'; - 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('<p>This message contains <em>some</em> <b>markup</b></p>'); - 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 some markup

'; + 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('<p>This message contains <em>some</em> <b>markup</b></p>'); + 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: www.opkode.com'); - 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: www.opkode.com'); + 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('http://www.opkode.com/\'onmouseover=\'alert(1)\'whatever'); - message = 'http://www.opkode.com/"onmouseover="alert(1)"whatever'; - test_utils.sendMessage(view, message); + 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('http://www.opkode.com/\'onmouseover=\'alert(1)\'whatever'); + 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('http://www.opkode.com/"onmouseover="alert(1)"whatever'); + 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('http://www.opkode.com/"onmouseover="alert(1)"whatever'); - message = "https://en.wikipedia.org/wiki/Ender's_Game"; - test_utils.sendMessage(view, message); + 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(''+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(''+message+''); - message = "https://en.wikipedia.org/wiki/Ender's_Game"; - test_utils.sendMessage(view, message); + 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(''+message+''); - done(); + 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(''+message+''); + 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( - ""+ - " Have you heard this funny audio?"+ - " http://localhost/audio.mp3"+ - "").firstChild; - _converse.connection._dataRecv(test_utils.createRequest(stanza)); + const stanza = Strophe.xmlHtmlNode( + ""+ + " Have you heard this funny audio?"+ + " http://localhost/audio.mp3"+ + "").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('
Have you heard this funny audio?
'); 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( - ""+ - " Have you seen this funny video?"+ - " http://localhost/video.mp4"+ - "").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('
Have you seen this funny video?
'); - let media = view.el.querySelector('.chat-msg .chat-msg__media'); - expect(media.innerHTML.replace(/(\r\n|\n|\r)/gm, "")).toEqual( - ''+ - ''+ - 'Download video file'); - - // If the and contents is the same, don't duplicate. const stanza = Strophe.xmlHtmlNode( ""+ - " http://localhost/video.mp4"+ + " Have you seen this funny video?"+ " http://localhost/video.mp4"+ "").firstChild; _converse.connection._dataRecv(test_utils.createRequest(stanza)); - msg = view.el.querySelector('.chat-msg:last-child .chat-msg__text'); - expect(msg.innerHTML).toEqual(''); // Emtpy - media = view.el.querySelector('.chat-msg:last-child .chat-msg__media'); - expect(media.innerHTML.replace(/(\r\n|\n|\r)/gm, "")).toEqual( - ''+ - ''+ - 'Download video file'); - 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('
Have you seen this funny video?
'); + let media = view.el.querySelector('.chat-msg .chat-msg__media'); + expect(media.innerHTML.replace(/(\r\n|\n|\r)/gm, "")).toEqual( + ''+ + ''+ + 'Download video file'); + + // If the and contents is the same, don't duplicate. + const stanza = Strophe.xmlHtmlNode( + ""+ + " http://localhost/video.mp4"+ + " http://localhost/video.mp4"+ + "").firstChild; + _converse.connection._dataRecv(test_utils.createRequest(stanza)); + + msg = view.el.querySelector('.chat-msg:last-child .chat-msg__text'); + expect(msg.innerHTML).toEqual(''); // Emtpy + media = view.el.querySelector('.chat-msg:last-child .chat-msg__media'); + expect(media.innerHTML.replace(/(\r\n|\n|\r)/gm, "")).toEqual( + ''+ + ''+ + 'Download video file'); + 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( - ""+ - " Have you downloaded this funny file?"+ - " http://localhost/funny.pdf"+ - "").firstChild; - _converse.connection._dataRecv(test_utils.createRequest(stanza)); + const stanza = Strophe.xmlHtmlNode( + ""+ + " Have you downloaded this funny file?"+ + " http://localhost/funny.pdf"+ + "").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('
Have you downloaded this funny file?
'); 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"; + 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"; - const stanza = Strophe.xmlHtmlNode( - ""+ - " Have you seen this funny image?"+ - " "+url+""+ - "").firstChild; - _converse.connection._dataRecv(test_utils.createRequest(stanza)); - - test_utils.waitUntil(() => view.el.querySelectorAll('.chat-content .chat-msg img').length, 2000).then(function () { + const stanza = Strophe.xmlHtmlNode( + ""+ + " Have you seen this funny image?"+ + " "+url+""+ + "").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('
Have you seen this funny image?
'); const media = view.el.querySelector('.chat-msg .chat-msg__media'); diff --git a/spec/minchats.js b/spec/minchats.js index 5c3fc210c..2fa79237e 100644 --- a/spec/minchats.js +++ b/spec/minchats.js @@ -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); + 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'; - 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(); + 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(); }); diff --git a/spec/roomslist.js b/spec/roomslist.js index c1761846f..932b122f7 100644 --- a/spec/roomslist.js +++ b/spec/roomslist.js @@ -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'); + let room_els; - 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, '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); - 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(); - 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); - 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(); + 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); + _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); - let item = room_els[0]; - expect(u.hasClass('open', item)).toBe(true); - expect(item.textContent.trim()).toBe('coven@chat.shakespeare.lit'); + 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); - _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); - - 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') + .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( diff --git a/spec/spoilers.js b/spec/spoilers.js index a63789855..1de792aa5 100644 --- a/spec/spoilers.js +++ b/spec/spoilers.js @@ -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 - * - * - * This is the spoiler - * - * This is the hint - * " - */ + * + * + * This is the spoiler + * + * This is the hint + * " + */ var stanza = _converse.connection.send.calls.argsFor(0)[0].tree(); var spoiler_el = stanza.querySelector('spoiler[xmlns="urn:xmpp:spoiler:0"]'); diff --git a/spec/user-details-modal.js b/spec/user-details-modal.js index b4de6e0f6..296755b1b 100644 --- a/spec/user-details-modal.js +++ b/spec/user-details-modal.js @@ -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(); diff --git a/src/converse-muc-views.js b/src/converse-muc-views.js index f7d1dcaba..384bb217b 100644 --- a/src/converse-muc-views.js +++ b/src/converse-muc-views.js @@ -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(); diff --git a/src/i18n.js b/src/i18n.js index b570537a5..07c2bb353 100644 --- a/src/i18n.js +++ b/src/i18n.js @@ -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(); } diff --git a/tests/utils.js b/tests/utils.js index ca0f0c1e1..115ab8e23 100644 --- a/tests/utils.js +++ b/tests/utils.js @@ -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, _)); };