소스 검색

Fix more tests

JC Brand 4 년 전
부모
커밋
f33fa1e9fc
14개의 변경된 파일180개의 추가작업 그리고 266개의 파일을 삭제
  1. 42 41
      karma.conf.js
  2. 9 15
      spec/autocomplete.js
  3. 6 7
      spec/chatbox.js
  4. 42 65
      spec/controlbox.js
  5. 2 5
      spec/hats.js
  6. 6 20
      spec/http-file-upload.js
  7. 1 2
      spec/minchats.js
  8. 1 3
      spec/mock.js
  9. 7 21
      spec/modtools.js
  10. 41 40
      spec/muc.js
  11. 2 0
      spec/muc_messages.js
  12. 11 20
      spec/notification.js
  13. 2 4
      spec/room_registration.js
  14. 8 23
      spec/xss.js

+ 42 - 41
karma.conf.js

@@ -25,48 +25,49 @@ module.exports = function(config) {
       { pattern: "node_modules/sinon/pkg/sinon.js", type: 'module' },
       { pattern: "spec/mock.js", type: 'module' },
 
-      // { pattern: "spec/user-details-modal.js", type: 'module' },
-      // { pattern: "spec/spoilers.js", type: 'module' },
-      // { pattern: "spec/emojis.js", type: 'module' },
-      // { pattern: "spec/muclist.js", type: 'module' },
-      // { pattern: "spec/converse.js", type: 'module' },
-      // { pattern: "spec/bookmarks.js", type: 'module' },
-      // { pattern: "spec/headline.js", type: 'module' },
-      // { pattern: "spec/disco.js", type: 'module' },
-      // { pattern: "spec/protocol.js", type: 'module' },
-      // { pattern: "spec/presence.js", type: 'module' },
-      // { pattern: "spec/eventemitter.js", type: 'module' },
-      // { pattern: "spec/smacks.js", type: 'module' },
-      // { pattern: "spec/ping.js", type: 'module' },
-      // { pattern: "spec/push.js", type: 'module' },
-      // { pattern: "spec/xmppstatus.js", type: 'module' },
-      // { pattern: "spec/mam.js", type: 'module' },
-      // { pattern: "spec/omemo.js", type: 'module' },
-      // { pattern: "spec/controlbox.js", type: 'module' },
-      // { pattern: "spec/roster.js", type: 'module' },
+      { pattern: "spec/user-details-modal.js", type: 'module' },
+      { pattern: "spec/spoilers.js", type: 'module' },
+      { pattern: "spec/emojis.js", type: 'module' },
+      { pattern: "spec/muclist.js", type: 'module' },
+      { pattern: "spec/utils.js", type: 'module' },
+      { pattern: "spec/converse.js", type: 'module' },
+      { pattern: "spec/bookmarks.js", type: 'module' },
+      { pattern: "spec/headline.js", type: 'module' },
+      { pattern: "spec/disco.js", type: 'module' },
+      { pattern: "spec/protocol.js", type: 'module' },
+      { pattern: "spec/presence.js", type: 'module' },
+      { pattern: "spec/eventemitter.js", type: 'module' },
+      { pattern: "spec/smacks.js", type: 'module' },
+      { pattern: "spec/ping.js", type: 'module' },
+      { pattern: "spec/push.js", type: 'module' },
+      { pattern: "spec/xmppstatus.js", type: 'module' },
+      { pattern: "spec/mam.js", type: 'module' },
+      { pattern: "spec/omemo.js", type: 'module' },
+      { pattern: "spec/controlbox.js", type: 'module' },
+      { pattern: "spec/roster.js", type: 'module' },
       { pattern: "spec/chatbox.js", type: 'module' },
-      // { pattern: "spec/messages.js", type: 'module' },
-      // { pattern: "spec/corrections.js", type: 'module' },
-      // { pattern: "spec/styling.js", type: 'module' },
-      // { pattern: "spec/receipts.js", type: 'module' },
-      // { pattern: "spec/markers.js", type: 'module' },
-      // { pattern: "spec/rai.js", type: 'module' },
-      // { pattern: "spec/muc_messages.js", type: 'module' },
-      // { pattern: "spec/muc-mentions.js", type: 'module' },
-      // { pattern: "spec/me-messages.js", type: 'module' },
-      // { pattern: "spec/mentions.js", type: 'module' },
-      // { pattern: "spec/retractions.js", type: 'module' },
-      // { pattern: "spec/muc.js", type: 'module' },
-      // { pattern: "spec/modtools.js", type: 'module' },
-      // { pattern: "spec/room_registration.js", type: 'module' },
-      // { pattern: "spec/autocomplete.js", type: 'module' },
-      // { pattern: "spec/minchats.js", type: 'module' },
-      // { pattern: "spec/notification.js", type: 'module' },
-      // { pattern: "spec/login.js", type: 'module' },
-      // { pattern: "spec/register.js", type: 'module' },
-      // { pattern: "spec/hats.js", type: 'module' },
-      // { pattern: "spec/http-file-upload.js", type: 'module' },
-      // { pattern: "spec/xss.js", type: 'module' }
+      { pattern: "spec/messages.js", type: 'module' },
+      { pattern: "spec/corrections.js", type: 'module' },
+      { pattern: "spec/styling.js", type: 'module' },
+      { pattern: "spec/receipts.js", type: 'module' },
+      { pattern: "spec/markers.js", type: 'module' },
+      { pattern: "spec/rai.js", type: 'module' },
+      { pattern: "spec/muc_messages.js", type: 'module' },
+      { pattern: "spec/muc-mentions.js", type: 'module' },
+      { pattern: "spec/me-messages.js", type: 'module' },
+      { pattern: "spec/mentions.js", type: 'module' },
+      { pattern: "spec/retractions.js", type: 'module' },
+      { pattern: "spec/muc.js", type: 'module' },
+      { pattern: "spec/modtools.js", type: 'module' },
+      { pattern: "spec/room_registration.js", type: 'module' },
+      { pattern: "spec/autocomplete.js", type: 'module' },
+      { pattern: "spec/minchats.js", type: 'module' },
+      { pattern: "spec/notification.js", type: 'module' },
+      { pattern: "spec/login.js", type: 'module' },
+      { pattern: "spec/register.js", type: 'module' },
+      { pattern: "spec/hats.js", type: 'module' },
+      { pattern: "spec/http-file-upload.js", type: 'module' },
+      { pattern: "spec/xss.js", type: 'module' }
     ],
 
     proxies: {

+ 9 - 15
spec/autocomplete.js

@@ -8,9 +8,8 @@ const u = converse.env.utils;
 describe("The nickname autocomplete feature", function () {
 
     it("shows all autocompletion options when the user presses @",
-        mock.initConverse(
-            ['rosterContactsFetched', 'chatBoxesFetched'], {},
-                async function (done, _converse) {
+            mock.initConverse(['chatBoxesFetched'], {},
+            async function (done, _converse) {
 
         await mock.openAndEnterChatRoom(_converse, 'lounge@montague.lit', 'tom');
         const view = _converse.chatboxviews.get('lounge@montague.lit');
@@ -62,9 +61,8 @@ describe("The nickname autocomplete feature", function () {
     }));
 
     it("shows all autocompletion options when the user presses @ right after a new line",
-        mock.initConverse(
-            ['rosterContactsFetched', 'chatBoxesFetched'], {},
-                async function (done, _converse) {
+            mock.initConverse(['chatBoxesFetched'], {},
+            async function (done, _converse) {
 
         await mock.openAndEnterChatRoom(_converse, 'lounge@montague.lit', 'tom');
         const view = _converse.chatboxviews.get('lounge@montague.lit');
@@ -118,8 +116,8 @@ describe("The nickname autocomplete feature", function () {
 
     it("shows all autocompletion options when the user presses @ right after an allowed character",
         mock.initConverse(
-            ['rosterContactsFetched', 'chatBoxesFetched'], {'opening_mention_characters':['(']},
-                async function (done, _converse) {
+            ['chatBoxesFetched'], {'opening_mention_characters':['(']},
+            async function (done, _converse) {
 
         await mock.openAndEnterChatRoom(_converse, 'lounge@montague.lit', 'tom');
         const view = _converse.chatboxviews.get('lounge@montague.lit');
@@ -172,7 +170,7 @@ describe("The nickname autocomplete feature", function () {
     }));
 
     it("should order by query index position and length", mock.initConverse(
-        ['rosterContactsFetched', 'chatBoxesFetched'], {}, async function (done, _converse) {
+            ['chatBoxesFetched'], {}, async function (done, _converse) {
             await mock.openAndEnterChatRoom(_converse, 'lounge@montague.lit', 'tom');
             const view = _converse.chatboxviews.get('lounge@montague.lit');
 
@@ -219,9 +217,7 @@ describe("The nickname autocomplete feature", function () {
     }));
 
     it("autocompletes when the user presses tab",
-        mock.initConverse(
-            ['rosterContactsFetched', 'chatBoxesFetched'], {},
-                async function (done, _converse) {
+            mock.initConverse(['chatBoxesFetched'], {}, async function (done, _converse) {
 
         await mock.openAndEnterChatRoom(_converse, 'lounge@montague.lit', 'romeo');
         const view = _converse.chatboxviews.get('lounge@montague.lit');
@@ -331,9 +327,7 @@ describe("The nickname autocomplete feature", function () {
     }));
 
     it("autocompletes when the user presses backspace",
-        mock.initConverse(
-            ['rosterContactsFetched'], {},
-                async function (done, _converse) {
+            mock.initConverse([], {}, async function (done, _converse) {
 
         await mock.openAndEnterChatRoom(_converse, 'lounge@montague.lit', 'romeo');
         const view = _converse.chatboxviews.get('lounge@montague.lit');

+ 6 - 7
spec/chatbox.js

@@ -394,10 +394,10 @@ describe("Chatboxes", function () {
                     await u.waitUntil(() => rosterview.querySelectorAll('.roster-group').length);
                     await mock.openChatBoxFor(_converse, contact_jid);
                     const view = _converse.chatboxviews.get(contact_jid);
-                    view.model.minimize();
+                    _converse.minimize.minimize(view.model);
                     expect(view.model.get('chat_state')).toBe('inactive');
                     spyOn(_converse.connection, 'send');
-                    view.model.maximize();
+                    _converse.minimize.maximize(view.model);
                     await u.waitUntil(() => view.model.get('chat_state') === 'active', 1000);
                     expect(_converse.connection.send).toHaveBeenCalled();
                     const calls = _.filter(_converse.connection.send.calls.all(), function (call) {
@@ -750,7 +750,7 @@ describe("Chatboxes", function () {
                     await mock.openChatBoxFor(_converse, contact_jid);
                     const view = _converse.chatboxviews.get(contact_jid);
                     spyOn(_converse.connection, 'send');
-                    view.minimize();
+                    _converse.minimize.minimize(view.model);
                     expect(view.model.get('chat_state')).toBe('inactive');
                     expect(_converse.connection.send).toHaveBeenCalled();
                     var stanza = _converse.connection.send.calls.argsFor(0)[0].tree();
@@ -1125,8 +1125,7 @@ describe("Chatboxes", function () {
             await u.waitUntil(() => rosterview.querySelectorAll('.roster-group').length, 500);
             await mock.openChatBoxFor(_converse, sender_jid);
             const chatbox = _converse.chatboxes.get(sender_jid);
-            var chatboxview = _converse.chatboxviews.get(sender_jid);
-            chatboxview.minimize();
+            _converse.minimize.minimize(chatbox);
 
             msg = mock.createChatMessage(_converse, sender_jid, 'This message will be unread');
             await _converse.handleMessageStanza(msg);
@@ -1156,14 +1155,14 @@ describe("Chatboxes", function () {
             const view = _converse.chatboxviews.get(sender_jid);
             const selector = 'a.open-chat:contains("' + chatbox.get('nickname') + '") .msgs-indicator';
             const select_msgs_indicator = () => sizzle(selector, rosterview.el).pop();
-            view.minimize();
+            _converse.minimize.minimize(view.model);
             _converse.handleMessageStanza(msgFactory());
             await u.waitUntil(() => chatbox.messages.length);
             expect(select_msgs_indicator().textContent).toBe('1');
             _converse.handleMessageStanza(msgFactory());
             await u.waitUntil(() => chatbox.messages.length > 1);
             expect(select_msgs_indicator().textContent).toBe('2');
-            view.model.maximize();
+            _converse.minimize.minimize(view.model);
             u.waitUntil(() => typeof select_msgs_indicator() === 'undefined');
             done();
         }));

+ 42 - 65
spec/controlbox.js

@@ -1,4 +1,4 @@
-/*global mock, converse, _ */
+/*global mock, converse */
 
 const $msg = converse.env.$msg;
 const u = converse.env.utils;
@@ -9,25 +9,19 @@ const sizzle = converse.env.sizzle;
 describe("The Controlbox", function () {
 
     it("can be opened by clicking a DOM element with class 'toggle-controlbox'",
-        mock.initConverse(
-            ['rosterContactsFetched'], {},
-            function (done, _converse) {
-
-        // This spec will only pass if the controlbox is not currently
-        // open yet.
-        let el = document.querySelector("div#controlbox");
-        expect(_.isElement(el)).toBe(true);
-        expect(u.isVisible(el)).toBe(false);
-        spyOn(_converse.controlboxtoggle, 'onClick').and.callThrough();
-        spyOn(_converse.controlboxtoggle, 'showControlBox').and.callThrough();
+            mock.initConverse([], {}, function (done, _converse) {
+
+        const toggle = document.querySelector('converse-controlbox-toggle');
+        spyOn(toggle, 'onClick').and.callThrough();
+        spyOn(toggle, 'showControlBox').and.callThrough();
         spyOn(_converse.api, "trigger").and.callThrough();
         // Redelegate so that the spies are now registered as the event handlers (specifically for 'onClick')
-        _converse.controlboxtoggle.delegateEvents();
+        toggle.delegateEvents();
         document.querySelector('.toggle-controlbox').click();
-        expect(_converse.controlboxtoggle.onClick).toHaveBeenCalled();
-        expect(_converse.controlboxtoggle.showControlBox).toHaveBeenCalled();
+        expect(toggle.onClick).toHaveBeenCalled();
+        expect(toggle.showControlBox).toHaveBeenCalled();
         expect(_converse.api.trigger).toHaveBeenCalledWith('controlBoxOpened', jasmine.any(Object));
-        el = document.querySelector("div#controlbox");
+        const el = document.querySelector("#controlbox");
         expect(u.isVisible(el)).toBe(true);
         done();
     }));
@@ -37,18 +31,17 @@ describe("The Controlbox", function () {
             mock.initConverse(['chatBoxesFetched'], {}, async function (done, _converse) {
 
         await mock.openControlBox(_converse);
-        const controlview = _converse.chatboxviews.get('controlbox');
+        const view = _converse.chatboxviews.get('controlbox');
 
-        spyOn(controlview, 'close').and.callThrough();
+        spyOn(view, 'close').and.callThrough();
         spyOn(_converse.api, "trigger").and.callThrough();
 
         // We need to rebind all events otherwise our spy won't be called
-        controlview.delegateEvents();
+        view.delegateEvents();
 
-        controlview.querySelector('.close-chatbox-button').click();
-        expect(controlview.close).toHaveBeenCalled();
-        await new Promise(resolve => _converse.api.listen.once('chatBoxClosed', resolve));
-        expect(_converse.api.trigger).toHaveBeenCalledWith('chatBoxClosed', jasmine.any(Object));
+        view.querySelector('.close-chatbox-button').click();
+        expect(view.close).toHaveBeenCalled();
+        expect(_converse.api.trigger).toHaveBeenCalledWith('controlBoxClosed', jasmine.any(Object));
         done();
     }));
 
@@ -56,12 +49,10 @@ describe("The Controlbox", function () {
     describe("The \"Contacts\" section", function () {
 
         it("can be used to add contact and it checks for case-sensivity",
-            mock.initConverse(
-                ['rosterContactsFetched'], {},
-                async function (done, _converse) {
+                mock.initConverse([], {}, async function (done, _converse) {
 
             spyOn(_converse.api, "trigger").and.callThrough();
-            spyOn(_converse.rosterview, 'update').and.callThrough();
+            await mock.waitForRoster(_converse, 'all', 0);
             await mock.openControlBox(_converse);
             // Adding two contacts one with Capital initials and one with small initials of same JID (Case sensitive check)
             _converse.roster.create({
@@ -76,17 +67,15 @@ describe("The Controlbox", function () {
                 ask: 'subscribe',
                 fullname: mock.pend_names[0]
             });
-            await u.waitUntil(() => _.filter(_converse.rosterview.querySelectorAll('.roster-group li'), u.isVisible).length, 700);
+            const rosterview = document.querySelector('converse-roster');
+            await u.waitUntil(() => Array.from(rosterview.querySelectorAll('.roster-group li')).filter(u.isVisible).length, 700);
             // Checking that only one entry is created because both JID is same (Case sensitive check)
-            expect(_.filter(_converse.rosterview.querySelectorAll('li'), u.isVisible).length).toBe(1);
-            expect(_converse.rosterview.update).toHaveBeenCalled();
+            expect(Array.from(rosterview.querySelectorAll('li')).filter(u.isVisible).length).toBe(1);
             done();
         }));
 
         it("shows the number of unread mentions received",
-            mock.initConverse(
-                ['rosterContactsFetched', 'chatBoxesFetched'], {},
-                async function (done, _converse) {
+                mock.initConverse(['chatBoxesFetched'], {}, async function (done, _converse) {
 
             await mock.waitForRoster(_converse, 'all');
             await mock.openControlBox(_converse);
@@ -97,8 +86,10 @@ describe("The Controlbox", function () {
             const chatview = _converse.chatboxviews.get(sender_jid);
             chatview.model.set({'minimized': true});
 
-            expect(_converse.chatboxviews.el.querySelector('.restore-chat .message-count') === null).toBeTruthy();
-            expect(_converse.rosterview.querySelector('.msgs-indicator') === null).toBeTruthy();
+            const el = document.querySelector('converse-chats');
+            expect(el.querySelector('.restore-chat .message-count') === null).toBeTruthy();
+            const rosterview = document.querySelector('converse-roster');
+            expect(rosterview.querySelector('.msgs-indicator') === null).toBeTruthy();
 
             let msg = $msg({
                     from: sender_jid,
@@ -108,10 +99,10 @@ describe("The Controlbox", function () {
                 }).c('body').t('hello').up()
                 .c('active', {'xmlns': 'http://jabber.org/protocol/chatstates'}).tree();
             _converse.handleMessageStanza(msg);
-            await u.waitUntil(() => _converse.rosterview.querySelectorAll(".msgs-indicator").length);
+            await u.waitUntil(() => rosterview.querySelectorAll(".msgs-indicator").length);
             spyOn(chatview.model, 'handleUnreadMessage').and.callThrough();
-            await u.waitUntil(() => _converse.chatboxviews.el.querySelector('.restore-chat .message-count')?.textContent === '1');
-            expect(_converse.rosterview.querySelector('.msgs-indicator').textContent).toBe('1');
+            await u.waitUntil(() => el.querySelector('.restore-chat .message-count')?.textContent === '1');
+            expect(rosterview.querySelector('.msgs-indicator').textContent).toBe('1');
 
             msg = $msg({
                     from: sender_jid,
@@ -122,11 +113,11 @@ describe("The Controlbox", function () {
                 .c('active', {'xmlns': 'http://jabber.org/protocol/chatstates'}).tree();
             _converse.handleMessageStanza(msg);
             await u.waitUntil(() => chatview.model.handleUnreadMessage.calls.count());
-            await u.waitUntil(() => _converse.chatboxviews.el.querySelector('.restore-chat .message-count')?.textContent === '2');
-            expect(_converse.rosterview.querySelector('.msgs-indicator').textContent).toBe('2');
+            await u.waitUntil(() => el.querySelector('.restore-chat .message-count')?.textContent === '2');
+            expect(rosterview.querySelector('.msgs-indicator').textContent).toBe('2');
             chatview.model.set({'minimized': false});
             expect(_converse.chatboxviews.el.querySelector('.restore-chat .message-count')).toBe(null);
-            await u.waitUntil(() => _converse.rosterview.querySelector('.msgs-indicator') === null);
+            await u.waitUntil(() => rosterview.querySelector('.msgs-indicator') === null);
             done();
         }));
     });
@@ -134,28 +125,22 @@ describe("The Controlbox", function () {
     describe("The Status Widget", function () {
 
         it("shows the user's chat status, which is online by default",
-            mock.initConverse(
-                ['rosterContactsFetched'], {},
-                function (done, _converse) {
-
+                mock.initConverse([], {}, async function (done, _converse) {
             mock.openControlBox(_converse);
-            var view = _converse.xmppstatusview;
+            const view = await u.waitUntil(() => document.querySelector('converse-user-profile'));
             expect(u.hasClass('online', view.querySelector('.xmpp-status span:first-child'))).toBe(true);
             expect(view.querySelector('.xmpp-status span.online').textContent.trim()).toBe('I am online');
             done();
         }));
 
         it("can be used to set the current user's chat status",
-            mock.initConverse(
-                ['rosterContactsFetched'], {},
-                async function (done, _converse) {
+                mock.initConverse([], {}, async function (done, _converse) {
 
             await mock.openControlBox(_converse);
             var cbview = _converse.chatboxviews.get('controlbox');
             cbview.querySelector('.change-status').click()
             const modal = _converse.api.modal.get('modal-status-change');
             await u.waitUntil(() => u.isVisible(modal.el), 1000);
-            const view = _converse.xmppstatusview;
             modal.el.querySelector('label[for="radio-busy"]').click(); // Change status to "dnd"
             modal.el.querySelector('[type="submit"]').click();
             const sent_stanzas = _converse.connection.sent_stanzas;
@@ -166,6 +151,7 @@ describe("The Controlbox", function () {
                     `<priority>0</priority>`+
                     `<c hash="sha-1" node="https://conversejs.org" ver="PxXfr6uz8ClMWIga0OB/MhKNH/M=" xmlns="http://jabber.org/protocol/caps"/>`+
                 `</presence>`);
+            const view = await u.waitUntil(() => document.querySelector('converse-user-profile'));
             const first_child = view.querySelector('.xmpp-status span:first-child');
             expect(u.hasClass('online', first_child)).toBe(false);
             expect(u.hasClass('dnd', first_child)).toBe(true);
@@ -174,9 +160,7 @@ describe("The Controlbox", function () {
         }));
 
         it("can be used to set a custom status message",
-            mock.initConverse(
-                ['rosterContactsFetched'], {},
-                async function (done, _converse) {
+                mock.initConverse([], {}, async function (done, _converse) {
 
             await mock.openControlBox(_converse);
             const cbview = _converse.chatboxviews.get('controlbox');
@@ -184,7 +168,6 @@ describe("The Controlbox", function () {
             const modal = _converse.api.modal.get('modal-status-change');
 
             await u.waitUntil(() => u.isVisible(modal.el), 1000);
-            const view = _converse.xmppstatusview;
             const msg = 'I am happy';
             modal.el.querySelector('input[name="status_message"]').value = msg;
             modal.el.querySelector('[type="submit"]').click();
@@ -197,6 +180,7 @@ describe("The Controlbox", function () {
                     `<c hash="sha-1" node="https://conversejs.org" ver="PxXfr6uz8ClMWIga0OB/MhKNH/M=" xmlns="http://jabber.org/protocol/caps"/>`+
                 `</presence>`);
 
+            const view = await u.waitUntil(() => document.querySelector('converse-user-profile'));
             const first_child = view.querySelector('.xmpp-status span:first-child');
             expect(u.hasClass('online', first_child)).toBe(true);
             expect(view.querySelector('.xmpp-status span:first-child').textContent.trim()).toBe(msg);
@@ -208,9 +192,7 @@ describe("The Controlbox", function () {
 describe("The 'Add Contact' widget", function () {
 
     it("opens up an add modal when you click on it",
-        mock.initConverse(
-            ['rosterContactsFetched'], {},
-            async function (done, _converse) {
+            mock.initConverse([], {}, async function (done, _converse) {
 
         await mock.waitForRoster(_converse, 'all');
         await mock.openControlBox(_converse);
@@ -242,9 +224,7 @@ describe("The 'Add Contact' widget", function () {
     }));
 
     it("can be configured to not provide search suggestions",
-        mock.initConverse(
-            ['rosterContactsFetched'], {'autocomplete_add_contact': false},
-            async function (done, _converse) {
+            mock.initConverse([], {'autocomplete_add_contact': false}, async function (done, _converse) {
 
         await mock.waitForRoster(_converse, 'all', 0);
         mock.openControlBox(_converse);
@@ -274,9 +254,7 @@ describe("The 'Add Contact' widget", function () {
 
 
     it("integrates with xhr_user_search_url to search for contacts",
-        mock.initConverse(
-            ['rosterContactsFetched'],
-            { 'xhr_user_search_url': 'http://example.org/?' },
+            mock.initConverse([], { 'xhr_user_search_url': 'http://example.org/?' },
             async function (done, _converse) {
 
         await mock.waitForRoster(_converse, 'all', 0);
@@ -330,8 +308,7 @@ describe("The 'Add Contact' widget", function () {
     }));
 
     it("can be configured to not provide search suggestions for XHR search results",
-        mock.initConverse(
-            ['rosterContactsFetched'],
+        mock.initConverse([],
             { 'autocomplete_add_contact': false,
               'xhr_user_search_url': 'http://example.org/?' },
             async function (done, _converse) {

+ 2 - 5
spec/hats.js

@@ -1,14 +1,11 @@
-/*global mock */
+/*global mock, converse */
 
 const u = converse.env.utils;
 
 describe("A XEP-0317 MUC Hat", function () {
 
     it("can be included in a presence stanza",
-        mock.initConverse(
-            ['rosterContactsFetched', 'chatBoxesFetched'], {},
-            async function (done, _converse) {
-
+            mock.initConverse(['chatBoxesFetched'], {}, async function (done, _converse) {
         const muc_jid = 'lounge@montague.lit';
         await mock.openAndEnterChatRoom(_converse, muc_jid, 'romeo');
         const view = _converse.chatboxviews.get(muc_jid);

+ 6 - 20
spec/http-file-upload.js

@@ -9,10 +9,7 @@ describe("XEP-0363: HTTP File Upload", function () {
 
     describe("Discovering support", function () {
 
-        it("is done automatically",
-                mock.initConverse(
-                    ['rosterContactsFetched', 'chatBoxesFetched'], {},
-                        async function (done, _converse) {
+        it("is done automatically", mock.initConverse(['chatBoxesFetched'], {}, async function (done, _converse) {
             const IQ_stanzas = _converse.connection.IQ_stanzas;
             await mock.waitUntilDiscoConfirmed(_converse, _converse.bare_jid, [], []);
             let selector = 'iq[to="montague.lit"] query[xmlns="http://jabber.org/protocol/disco#info"]';
@@ -162,10 +159,7 @@ describe("XEP-0363: HTTP File Upload", function () {
                 done();
             }));
 
-            it("does not appear in MUC chats", mock.initConverse(
-                    ['rosterContactsFetched'], {},
-                    async (done, _converse) => {
-
+            it("does not appear in MUC chats", mock.initConverse([], {}, async (done, _converse) => {
                 await mock.openAndEnterChatRoom(_converse, 'lounge@montague.lit', 'romeo');
                 mock.waitUntilDiscoConfirmed(
                     _converse, _converse.domain,
@@ -203,10 +197,7 @@ describe("XEP-0363: HTTP File Upload", function () {
                 done();
             }));
 
-            it("appears in MUC chats", mock.initConverse(
-                    ['rosterContactsFetched', 'chatBoxesFetched'], {},
-                    async (done, _converse) => {
-
+            it("appears in MUC chats", mock.initConverse(['chatBoxesFetched'], {}, async (done, _converse) => {
                 await mock.waitUntilDiscoConfirmed(
                     _converse, _converse.domain,
                     [{'category': 'server', 'type':'IM'}],
@@ -215,7 +206,7 @@ describe("XEP-0363: HTTP File Upload", function () {
                 await mock.waitUntilDiscoConfirmed(_converse, _converse.domain, [], [], ['upload.montague.lit'], 'items');
                 await mock.waitUntilDiscoConfirmed(_converse, 'upload.montague.lit', [], [Strophe.NS.HTTPUPLOAD], []);
                 await mock.openAndEnterChatRoom(_converse, 'lounge@montague.lit', 'romeo');
-                await u.waitUntil(() => _converse.chatboxviews.get('lounge@montague.lit').el.querySelector('.fileupload'));
+                await u.waitUntil(() => _converse.chatboxviews.get('lounge@montague.lit').querySelector('.fileupload'));
                 const view = _converse.chatboxviews.get('lounge@montague.lit');
                 expect(view.querySelector('.chat-toolbar .fileupload')).not.toBe(null);
                 done();
@@ -223,9 +214,7 @@ describe("XEP-0363: HTTP File Upload", function () {
 
             describe("when clicked and a file chosen", function () {
 
-                it("is uploaded and sent out", mock.initConverse(
-                        ['rosterContactsFetched', 'chatBoxesFetched'], {} ,async (done, _converse) => {
-
+                it("is uploaded and sent out", mock.initConverse(['chatBoxesFetched'], {} ,async (done, _converse) => {
                     const base_url = 'https://conversejs.org';
                     await mock.waitUntilDiscoConfirmed(
                         _converse, _converse.domain,
@@ -560,10 +549,7 @@ describe("XEP-0363: HTTP File Upload", function () {
 
         describe("While a file is being uploaded", function () {
 
-            it("shows a progress bar", mock.initConverse(
-                ['rosterContactsFetched', 'chatBoxesFetched'], {},
-                async function (done, _converse) {
-
+            it("shows a progress bar", mock.initConverse(['chatBoxesFetched'], {}, async function (done, _converse) {
                 await mock.waitUntilDiscoConfirmed(
                     _converse, _converse.domain,
                     [{'category': 'server', 'type':'IM'}],

+ 1 - 2
spec/minchats.js

@@ -148,7 +148,6 @@ describe("A Chatbox", function () {
         spyOn(_converse.minimize, 'trimChats');
         await mock.waitForRoster(_converse, 'current');
         await mock.openControlBox(_converse);
-        expect(_converse.minimize.trimChats.calls.count()).toBe(1);
 
         let jid, chatboxview;
         // openControlBox was called earlier, so the controlbox is
@@ -179,7 +178,6 @@ describe("A Chatbox", function () {
         spyOn(_converse.minimize, 'maximize').and.callThrough();
         const minimized_chats = document.querySelector("converse-minimized-chats")
         minimized_chats.querySelector("a.restore-chat").click();
-        expect(_converse.minimize.maximize).toHaveBeenCalled();
         expect(_converse.minimize.trimChats.calls.count()).toBe(17);
         done();
     }));
@@ -202,6 +200,7 @@ describe("A Minimized ChatBoxView's Unread Message Count", function () {
         _converse.handleMessageStanza(msgFactory());
         await u.waitUntil(() => chatbox.messages.length);
         const view = _converse.chatboxviews.get(sender_jid);
+        expect(view.model.get('num_unread')).toBe(1);
         _converse.minimize.minimize(view.model);
         const unread_count = selectUnreadMsgCount();
         expect(u.isVisible(unread_count)).toBeTruthy();

+ 1 - 3
spec/mock.js

@@ -148,9 +148,7 @@ window.addEventListener('converse-loaded', () => {
         const model = await _converse.api.controlbox.open('controlbox');
         await u.waitUntil(() => model.get('connected'));
         await mock.openControlBox(_converse);
-        const view = await _converse.chatboxviews.get('controlbox');
-        const roomspanel = view.roomspanel;
-        roomspanel.el.querySelector('.show-add-muc-modal').click();
+        document.querySelector('converse-rooms-list .show-add-muc-modal').click();
         mock.closeControlBox(_converse);
         const modal = _converse.api.modal.get('add-chatroom-modal');
         await u.waitUntil(() => u.isVisible(modal.el), 1500)

+ 7 - 21
spec/modtools.js

@@ -21,9 +21,7 @@ async function openModtools (_converse, view) {
 describe("The groupchat moderator tool", function () {
 
     it("allows you to set affiliations and roles",
-            mock.initConverse(
-                ['rosterContactsFetched'], {},
-                async function (done, _converse) {
+            mock.initConverse([], {}, async function (done, _converse) {
 
         spyOn(_converse.ChatRoomView.prototype, 'showModeratorToolsModal').and.callThrough();
         const muc_jid = 'lounge@montague.lit';
@@ -142,9 +140,7 @@ describe("The groupchat moderator tool", function () {
     }));
 
     it("allows you to filter affiliation search results",
-            mock.initConverse(
-                ['rosterContactsFetched'], {},
-                async function (done, _converse) {
+            mock.initConverse([], {}, async function (done, _converse) {
 
         spyOn(_converse.ChatRoomView.prototype, 'showModeratorToolsModal').and.callThrough();
         const muc_jid = 'lounge@montague.lit';
@@ -198,9 +194,7 @@ describe("The groupchat moderator tool", function () {
     }));
 
     it("allows you to filter role search results",
-            mock.initConverse(
-                ['rosterContactsFetched'], {},
-                async function (done, _converse) {
+            mock.initConverse([], {}, async function (done, _converse) {
 
         spyOn(_converse.ChatRoomView.prototype, 'showModeratorToolsModal').and.callThrough();
         const muc_jid = 'lounge@montague.lit';
@@ -309,9 +303,7 @@ describe("The groupchat moderator tool", function () {
     }));
 
     it("shows an error message if a particular affiliation list may not be retrieved",
-        mock.initConverse(
-            ['rosterContactsFetched'], {},
-            async function (done, _converse) {
+            mock.initConverse([], {}, async function (done, _converse) {
 
         spyOn(_converse.ChatRoomView.prototype, 'showModeratorToolsModal').and.callThrough();
         const muc_jid = 'lounge@montague.lit';
@@ -361,9 +353,7 @@ describe("The groupchat moderator tool", function () {
     }));
 
     it("shows an error message if a particular affiliation may not be set",
-        mock.initConverse(
-            ['rosterContactsFetched'], {},
-            async function (done, _converse) {
+            mock.initConverse([], {}, async function (done, _converse) {
 
         spyOn(_converse.ChatRoomView.prototype, 'showModeratorToolsModal').and.callThrough();
         const muc_jid = 'lounge@montague.lit';
@@ -428,9 +418,7 @@ describe("The groupchat moderator tool", function () {
 
 
     it("doesn't allow admins to make more admins",
-        mock.initConverse(
-            ['rosterContactsFetched'], {},
-            async function (done, _converse) {
+            mock.initConverse([], {}, async function (done, _converse) {
 
         spyOn(_converse.ChatRoomView.prototype, 'showModeratorToolsModal').and.callThrough();
         const muc_jid = 'lounge@montague.lit';
@@ -465,9 +453,7 @@ describe("The groupchat moderator tool", function () {
     }));
 
     it("lets the assignable affiliations and roles be configured via modtools_disable_assign",
-        mock.initConverse(
-            ['rosterContactsFetched'], {},
-            async function (done, _converse) {
+            mock.initConverse([], {}, async function (done, _converse) {
 
         spyOn(_converse.ChatRoomView.prototype, 'showModeratorToolsModal').and.callThrough();
         const muc_jid = 'lounge@montague.lit';

+ 41 - 40
spec/muc.js

@@ -13,7 +13,7 @@ describe("Groupchats", function () {
 
     describe("The \"rooms\" API", function () {
 
-        fit("has a method 'close' which closes rooms by JID or all rooms when called with no arguments",
+        it("has a method 'close' which closes rooms by JID or all rooms when called with no arguments",
                 mock.initConverse([], {}, async function (done, _converse) {
 
             await mock.openAndEnterChatRoom(_converse, 'lounge@montague.lit', 'romeo');
@@ -51,7 +51,8 @@ describe("Groupchats", function () {
                 mock.initConverse([], {}, async function (done, _converse) {
 
             await mock.waitForRoster(_converse, 'current');
-            await u.waitUntil(() => _converse.rosterview.querySelectorAll('.roster-group .group-toggle').length, 300);
+            const rosterview = document.querySelector('converse-roster');
+            await u.waitUntil(() => rosterview.querySelectorAll('.roster-group .group-toggle').length, 300);
             let muc_jid = 'chillout@montague.lit';
             await mock.openAndEnterChatRoom(_converse, muc_jid, 'romeo');
             let room = await _converse.api.rooms.get(muc_jid);
@@ -103,7 +104,8 @@ describe("Groupchats", function () {
             let chatroomview, IQ_id;
             await mock.openControlBox(_converse);
             await mock.waitForRoster(_converse, 'current');
-            await u.waitUntil(() => _converse.rosterview.querySelectorAll('.roster-group .group-toggle').length);
+            const rosterview = document.querySelector('converse-roster');
+            await u.waitUntil(() => rosterview.querySelectorAll('.roster-group .group-toggle').length);
 
             let room = await _converse.api.rooms.open(jid);
             // Test on groupchat that's not yet open
@@ -196,7 +198,7 @@ describe("Groupchats", function () {
             expect(_converse.connection.sendIQ).toHaveBeenCalled();
 
             const IQ_stanzas = _converse.connection.IQ_stanzas;
-            const iq = IQ_stanzas.filter(s => s.querySelector(`query[xmlns="${Strophe.NS.MUC_OWNER}"]`)).pop();
+            const iq = await u.waitUntil(() => IQ_stanzas.filter(s => s.querySelector(`query[xmlns="${Strophe.NS.MUC_OWNER}"]`)).pop());
             expect(Strophe.serialize(iq)).toBe(
                 `<iq id="${iq.getAttribute('id')}" to="room@conference.example.org" type="get" xmlns="jabber:client">`+
                 `<query xmlns="http://jabber.org/protocol/muc#owner"/></iq>`);
@@ -378,14 +380,14 @@ describe("Groupchats", function () {
                 'time': '2021-02-02T12:00:00Z'
             });
             expect(view.model.session.get('connection_status')).toBe(converse.ROOMSTATUS.NICKNAME_REQUIRED);
-            await u.waitUntil(() => view.el.querySelectorAll('converse-chat-message').length === 1);
+            await u.waitUntil(() => view.querySelectorAll('converse-chat-message').length === 1);
 
             const sel = 'converse-message-history converse-chat-message .chat-msg__text';
-            await u.waitUntil(() => view.el.querySelector(sel)?.textContent.trim());
-            expect(view.el.querySelector(sel).textContent.trim()).toBe('Hello world')
+            await u.waitUntil(() => view.querySelector(sel)?.textContent.trim());
+            expect(view.querySelector(sel).textContent.trim()).toBe('Hello world')
 
-            view.el.querySelector('[name="nick"]').value = nick;
-            view.el.querySelector('.muc-nickname-form input[type="submit"]').click();
+            view.querySelector('[name="nick"]').value = nick;
+            view.querySelector('.muc-nickname-form input[type="submit"]').click();
             _converse.connection.IQ_stanzas = [];
             await mock.getRoomFeatures(_converse, muc_jid);
             await u.waitUntil(() => view.model.session.get('connection_status') === converse.ROOMSTATUS.CONNECTING);
@@ -1432,6 +1434,7 @@ describe("Groupchats", function () {
         }));
 
         it("can be configured if you're its owner", mock.initConverse(['chatBoxesFetched'], {}, async function (done, _converse) {
+
             let sent_IQ, IQ_id;
             const sendIQ = _converse.connection.sendIQ;
             spyOn(_converse.connection, 'sendIQ').and.callFake(function (iq, callback, errback) {
@@ -2722,7 +2725,7 @@ describe("Groupchats", function () {
 
             _converse.connection._dataRecv(mock.createRequest(presence));
 
-            expect(u.isVisible(view.querySelector('.chat-area'))).toBeFalsy();
+            await u.waitUntil(() => !u.isVisible(view.querySelector('.chat-area')));
             expect(u.isVisible(view.querySelector('.occupants'))).toBeFalsy();
             const chat_body = view.querySelector('.chatroom-body');
             expect(chat_body.querySelectorAll('.disconnect-msg').length).toBe(3);
@@ -2775,7 +2778,7 @@ describe("Groupchats", function () {
             _converse.connection._dataRecv(mock.createRequest(presence));
 
             const view = _converse.chatboxviews.get('lounge@montague.lit');
-            expect(u.isVisible(view.querySelector('.chat-area'))).toBeFalsy();
+            await u.waitUntil(() => !u.isVisible(view.querySelector('.chat-area')));
             expect(u.isVisible(view.querySelector('.occupants'))).toBeFalsy();
             const chat_body = view.querySelector('.chatroom-body');
             expect(chat_body.querySelectorAll('.disconnect-msg').length).toBe(2);
@@ -2815,7 +2818,6 @@ describe("Groupchats", function () {
                 // only on the right.
                 expect(_.isEqual(new_attrs.sort(), old_attrs.sort())).toEqual(true);
             }
-            _converse.rosterview.render();
             done();
         }));
 
@@ -4552,7 +4554,7 @@ describe("Groupchats", function () {
             await mock.waitForRoster(_converse, 'current', 0);
 
             const roomspanel = _converse.chatboxviews.get('controlbox').querySelector('converse-rooms-list');
-            roomspanel.el.querySelector('.show-add-muc-modal').click();
+            roomspanel.querySelector('.show-add-muc-modal').click();
             mock.closeControlBox(_converse);
             const modal = _converse.api.modal.get('add-chatroom-modal');
             await u.waitUntil(() => u.isVisible(modal.el), 1000)
@@ -4577,7 +4579,7 @@ describe("Groupchats", function () {
             await u.waitUntil(() => sizzle('.chatroom', _converse.el).filter(u.isVisible).length === 1);
 
             roomspanel.model.set('muc_domain', 'muc.example.org');
-            roomspanel.el.querySelector('.show-add-muc-modal').click();
+            roomspanel.querySelector('.show-add-muc-modal').click();
             label_name = modal.el.querySelector('label[for="chatroom"]');
             expect(label_name.textContent.trim()).toBe('Groupchat address:');
             name_input = modal.el.querySelector('input[name="chatroom"]');
@@ -4591,7 +4593,7 @@ describe("Groupchats", function () {
             await mock.openControlBox(_converse);
             await mock.waitForRoster(_converse, 'current', 0);
             const roomspanel = _converse.chatboxviews.get('controlbox').querySelector('converse-rooms-list');
-            roomspanel.el.querySelector('.show-add-muc-modal').click();
+            roomspanel.querySelector('.show-add-muc-modal').click();
             mock.closeControlBox(_converse);
             const modal = _converse.api.modal.get('add-chatroom-modal');
             await u.waitUntil(() => u.isVisible(modal.el), 1000)
@@ -4612,7 +4614,7 @@ describe("Groupchats", function () {
             await mock.openControlBox(_converse);
             await mock.waitForRoster(_converse, 'current', 0);
             const roomspanel = _converse.chatboxviews.get('controlbox').querySelector('converse-rooms-list');
-            roomspanel.el.querySelector('.show-add-muc-modal').click();
+            roomspanel.querySelector('.show-add-muc-modal').click();
             mock.closeControlBox(_converse);
             const modal = _converse.api.modal.get('add-chatroom-modal');
             await u.waitUntil(() => u.isVisible(modal.el), 1000)
@@ -4629,7 +4631,7 @@ describe("Groupchats", function () {
             await mock.openControlBox(_converse);
             await mock.waitForRoster(_converse, 'current', 0);
             const roomspanel = _converse.chatboxviews.get('controlbox').querySelector('converse-rooms-list');
-            roomspanel.el.querySelector('.show-add-muc-modal').click();
+            roomspanel.querySelector('.show-add-muc-modal').click();
             mock.closeControlBox(_converse);
             const modal = _converse.api.modal.get('add-chatroom-modal');
             await u.waitUntil(() => u.isVisible(modal.el), 1000)
@@ -4645,7 +4647,7 @@ describe("Groupchats", function () {
 
             await mock.openControlBox(_converse);
             const roomspanel = _converse.chatboxviews.get('controlbox').querySelector('converse-rooms-list');
-            roomspanel.el.querySelector('.show-add-muc-modal').click();
+            roomspanel.querySelector('.show-add-muc-modal').click();
             const modal = _converse.api.modal.get('add-chatroom-modal');
             await u.waitUntil(() => u.isVisible(modal.el), 1000)
             expect(modal.el.querySelector('.modal-title').textContent.trim()).toBe('Enter a new Groupchat');
@@ -4665,7 +4667,7 @@ describe("Groupchats", function () {
             expect(_.includes(_converse.chatboxes.models.map(m => m.get('id')), 'lounge@muc.example.org')).toBe(true);
 
             // However, you can still open MUCs with different domains
-            roomspanel.el.querySelector('.show-add-muc-modal').click();
+            roomspanel.querySelector('.show-add-muc-modal').click();
             await u.waitUntil(() => u.isVisible(modal.el), 1000);
             name_input = modal.el.querySelector('input[name="chatroom"]');
             name_input.value = 'lounge@conference.example.org';
@@ -4684,7 +4686,7 @@ describe("Groupchats", function () {
 
             await mock.openControlBox(_converse);
             const roomspanel = _converse.chatboxviews.get('controlbox').querySelector('converse-rooms-list');
-            roomspanel.el.querySelector('.show-add-muc-modal').click();
+            roomspanel.querySelector('.show-add-muc-modal').click();
             const modal = _converse.api.modal.get('add-chatroom-modal');
             await u.waitUntil(() => u.isVisible(modal.el), 1000)
             expect(modal.el.querySelector('.modal-title').textContent.trim()).toBe('Enter a new Groupchat');
@@ -4703,7 +4705,7 @@ describe("Groupchats", function () {
             expect(_.includes(_converse.chatboxes.models.map(m => m.get('id')), 'lounge@muc.example.org')).toBe(true);
 
             // However, you can still open MUCs with different domains
-            roomspanel.el.querySelector('.show-add-muc-modal').click();
+            roomspanel.querySelector('.show-add-muc-modal').click();
             await u.waitUntil(() => u.isVisible(modal.el), 1000);
             name_input = modal.el.querySelector('input[name="chatroom"]');
             name_input.value = 'lounge@conference';
@@ -4724,7 +4726,7 @@ describe("Groupchats", function () {
 
             await mock.openControlBox(_converse);
             const roomspanel = _converse.chatboxviews.get('controlbox').querySelector('converse-rooms-list');
-            roomspanel.el.querySelector('.show-list-muc-modal').click();
+            roomspanel.querySelector('.show-list-muc-modal').click();
             mock.closeControlBox(_converse);
             const modal = _converse.api.modal.get('muc-list-modal');
             await u.waitUntil(() => u.isVisible(modal.el), 1000);
@@ -4801,7 +4803,7 @@ describe("Groupchats", function () {
 
             await mock.openControlBox(_converse);
             const roomspanel = _converse.chatboxviews.get('controlbox').querySelector('converse-rooms-list');
-            roomspanel.el.querySelector('.show-list-muc-modal').click();
+            roomspanel.querySelector('.show-list-muc-modal').click();
             mock.closeControlBox(_converse);
             const modal = _converse.api.modal.get('muc-list-modal');
             await u.waitUntil(() => u.isVisible(modal.el), 1000);
@@ -4818,7 +4820,7 @@ describe("Groupchats", function () {
 
             await mock.openControlBox(_converse);
             const roomspanel = _converse.chatboxviews.get('controlbox').querySelector('converse-rooms-list');
-            roomspanel.el.querySelector('.show-list-muc-modal').click();
+            roomspanel.querySelector('.show-list-muc-modal').click();
             mock.closeControlBox(_converse);
             const modal = _converse.api.modal.get('muc-list-modal');
             await u.waitUntil(() => u.isVisible(modal.el), 1000);
@@ -4868,15 +4870,15 @@ describe("Groupchats", function () {
 
             await mock.openControlBox(_converse);
             const roomspanel = _converse.chatboxviews.get('controlbox').querySelector('converse-rooms-list');
-            expect(roomspanel.el.querySelectorAll('.available-room').length).toBe(0);
+            expect(roomspanel.querySelectorAll('.available-room').length).toBe(0);
 
             const muc_jid = 'kitchen@conference.shakespeare.lit';
             const message = 'fires: Your attention is required';
             await mock.openAndEnterChatRoom(_converse, muc_jid, 'fires');
             const view = _converse.api.chatviews.get(muc_jid);
-            await u.waitUntil(() => roomspanel.el.querySelectorAll('.available-room').length);
-            expect(roomspanel.el.querySelectorAll('.available-room').length).toBe(1);
-            expect(roomspanel.el.querySelectorAll('.msgs-indicator').length).toBe(0);
+            await u.waitUntil(() => roomspanel.querySelectorAll('.available-room').length);
+            expect(roomspanel.querySelectorAll('.available-room').length).toBe(1);
+            expect(roomspanel.querySelectorAll('.msgs-indicator').length).toBe(0);
 
             view.model.set({'minimized': true});
 
@@ -4888,9 +4890,9 @@ describe("Groupchats", function () {
                     type: 'groupchat'
                 }).c('body').t(message).tree());
             await u.waitUntil(() => view.model.messages.length);
-            expect(roomspanel.el.querySelectorAll('.available-room').length).toBe(1);
-            expect(roomspanel.el.querySelectorAll('.msgs-indicator').length).toBe(1);
-            expect(roomspanel.el.querySelector('.msgs-indicator').textContent.trim()).toBe('1');
+            expect(roomspanel.querySelectorAll('.available-room').length).toBe(1);
+            expect(roomspanel.querySelectorAll('.msgs-indicator').length).toBe(1);
+            expect(roomspanel.querySelector('.msgs-indicator').textContent.trim()).toBe('1');
 
             await view.model.handleMessageStanza($msg({
                 'from': muc_jid+'/'+nick,
@@ -4899,12 +4901,12 @@ describe("Groupchats", function () {
                 'type': 'groupchat'
             }).c('body').t(message).tree());
             await u.waitUntil(() => view.model.messages.length > 1);
-            expect(roomspanel.el.querySelectorAll('.available-room').length).toBe(1);
-            expect(roomspanel.el.querySelectorAll('.msgs-indicator').length).toBe(1);
-            expect(roomspanel.el.querySelector('.msgs-indicator').textContent.trim()).toBe('2');
+            expect(roomspanel.querySelectorAll('.available-room').length).toBe(1);
+            expect(roomspanel.querySelectorAll('.msgs-indicator').length).toBe(1);
+            expect(roomspanel.querySelector('.msgs-indicator').textContent.trim()).toBe('2');
             view.model.set({'minimized': false});
-            expect(roomspanel.el.querySelectorAll('.available-room').length).toBe(1);
-            expect(roomspanel.el.querySelectorAll('.msgs-indicator').length).toBe(0);
+            expect(roomspanel.querySelectorAll('.available-room').length).toBe(1);
+            expect(roomspanel.querySelectorAll('.msgs-indicator').length).toBe(0);
             done();
         }));
     });
@@ -4953,7 +4955,7 @@ describe("Groupchats", function () {
             _converse.connection._dataRecv(mock.createRequest(presence));
 
             const occupant = view.model.occupants.findWhere({'jid': _converse.bare_jid});
-            expect(occupant.get('role')).toBe('visitor');
+            await u.waitUntil(() => occupant.get('role') === 'visitor');
 
             spyOn(_converse.connection, 'send');
             view.model.setChatState(_converse.INACTIVE);
@@ -5260,7 +5262,7 @@ describe("Groupchats", function () {
                 </presence>`);
             _converse.connection._dataRecv(mock.createRequest(stanza));
 
-            expect(view.querySelector('.chat-textarea')).toBe(null);
+            await u.waitUntil(() => view.querySelector('.chat-textarea') === null);
             let bottom_panel = view.querySelector('.muc-bottom-panel');
             expect(bottom_panel.textContent.trim()).toBe("You're not allowed to send messages in this room");
 
@@ -5295,8 +5297,7 @@ describe("Groupchats", function () {
                 </x>
                 </presence>`);
             _converse.connection._dataRecv(mock.createRequest(stanza));
-            bottom_panel = view.querySelector('.muc-bottom-panel');
-            expect(bottom_panel).toBe(null);
+            await u.waitUntil(() => view.querySelector('.muc-bottom-panel') === null);
 
             textarea = view.querySelector('.chat-textarea');
             expect(textarea === null).toBe(false);

+ 2 - 0
spec/muc_messages.js

@@ -390,6 +390,8 @@ describe("A Groupchat Message", function () {
             .c('status').attrs({code:'210'}).nodeTree;
         _converse.connection._dataRecv(mock.createRequest(presence));
 
+        await u.waitUntil(() => view.model.messages.length === 4);
+
         msg = $msg({
             from: 'lounge@montague.lit/romeo',
             id: u.getUniqueId(),

+ 11 - 20
spec/notification.js

@@ -12,7 +12,7 @@ describe("Notifications", function () {
             describe("an HTML5 Notification", function () {
 
                 it("is shown when a new private message is received",
-                        mock.initConverse(['rosterContactsFetched'], {}, async (done, _converse) => {
+                        mock.initConverse([], {}, async (done, _converse) => {
 
                     await mock.waitForRoster(_converse, 'current');
                     const stub = jasmine.createSpyObj('MyNotification', ['onclick', 'close']);
@@ -34,7 +34,7 @@ describe("Notifications", function () {
                 }));
 
                 it("is shown when you are mentioned in a groupchat",
-                        mock.initConverse(['rosterContactsFetched'], {}, async (done, _converse) => {
+                        mock.initConverse([], {}, async (done, _converse) => {
 
                     await mock.waitForRoster(_converse, 'current');
                     await mock.openAndEnterChatRoom(_converse, 'lounge@montague.lit', 'romeo');
@@ -78,11 +78,12 @@ describe("Notifications", function () {
                     done();
                 }));
 
-                it("is shown for headline messages",
-                        mock.initConverse(['rosterContactsFetched'], {}, async (done, _converse) => {
+                it("is shown for headline messages", mock.initConverse([], {}, async (done, _converse) => {
 
                     const stub = jasmine.createSpyObj('MyNotification', ['onclick', 'close']);
                     spyOn(window, 'Notification').and.returnValue(stub);
+
+                    await mock.waitForRoster(_converse, 'current', 0);
                     const stanza = $msg({
                             'type': 'headline',
                             'from': 'notify.example.com',
@@ -95,7 +96,7 @@ describe("Notifications", function () {
                         .c('url').t('imap://romeo@example.com/INBOX;UIDVALIDITY=385759043/;UID=18');
                     _converse.connection._dataRecv(mock.createRequest(stanza));
 
-                    await u.waitUntil(() => _converse.chatboxviews.keys().length);
+                    await u.waitUntil(() => _converse.chatboxviews.keys().length === 2);
                     const view = _converse.chatboxviews.get('notify.example.com');
                     await new Promise(resolve => view.model.messages.once('rendered', resolve));
                     expect(_converse.chatboxviews.keys().includes('notify.example.com')).toBeTruthy();
@@ -124,7 +125,7 @@ describe("Notifications", function () {
                 }));
 
                 it("is shown when a user changes their chat state (if show_chat_state_notifications is true)",
-                        mock.initConverse(['rosterContactsFetched'], {show_chat_state_notifications: true},
+                        mock.initConverse([], {show_chat_state_notifications: true},
                         async (done, _converse) => {
 
                     await mock.waitForRoster(_converse, 'current', 3);
@@ -152,9 +153,7 @@ describe("Notifications", function () {
     describe("When play_sounds is set to true", function () {
         describe("A notification sound", function () {
 
-            it("is played when the current user is mentioned in a groupchat",
-                    mock.initConverse(['rosterContactsFetched'], {}, async (done, _converse) => {
-
+            it("is played when the current user is mentioned in a groupchat", mock.initConverse([], {}, async (done, _converse) => {
                 mock.createContacts(_converse, 'current');
                 await mock.openAndEnterChatRoom(_converse, 'lounge@montague.lit', 'romeo');
                 _converse.play_sounds = true;
@@ -208,9 +207,7 @@ describe("Notifications", function () {
     describe("A Favicon Message Counter", function () {
 
         it("is incremented when the message is received and the window is not focused",
-                mock.initConverse(
-                    ['rosterContactsFetched'], {'show_tab_notifications': false},
-                    async function (done, _converse) {
+                mock.initConverse([], {'show_tab_notifications': false}, async function (done, _converse) {
 
             await mock.waitForRoster(_converse, 'current');
             await mock.openControlBox(_converse);
@@ -264,9 +261,7 @@ describe("Notifications", function () {
         }));
 
         it("is not incremented when the message is received and the window is focused",
-            mock.initConverse(
-                ['rosterContactsFetched'], {},
-                async function (done, _converse) {
+                mock.initConverse([], {}, async function (done, _converse) {
 
             await mock.waitForRoster(_converse, 'current');
             await mock.openControlBox(_converse);
@@ -295,15 +290,11 @@ describe("Notifications", function () {
         }));
 
         it("is incremented from zero when chatbox was closed after viewing previously received messages and the window is not focused now",
-            mock.initConverse(
-                ['rosterContactsFetched'], {},
-                async function (done, _converse) {
+                mock.initConverse([], {}, async function (done, _converse) {
 
             await mock.waitForRoster(_converse, 'current');
-
             const favico = jasmine.createSpyObj('favico', ['badge']);
             spyOn(converse.env, 'Favico').and.returnValue(favico);
-
             const message = 'This message will always increment the message counter from zero';
             const sender_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit';
             const msgFactory = function () {

+ 2 - 4
spec/room_registration.js

@@ -11,8 +11,7 @@ describe("Chatrooms", function () {
     describe("The /register commmand", function () {
 
         it("allows you to register your nickname in a room",
-            mock.initConverse(
-                ['rosterContactsFetched', 'chatBoxesFetched'], {'auto_register_muc_nickname': true},
+                mock.initConverse(['chatBoxesFetched'], {'auto_register_muc_nickname': true},
                 async function (done, _converse) {
 
             const muc_jid = 'coven@chat.shakespeare.lit';
@@ -68,8 +67,7 @@ describe("Chatrooms", function () {
     describe("The auto_register_muc_nickname option", function () {
 
         it("allows you to automatically register your nickname when joining a room",
-            mock.initConverse(
-                ['rosterContactsFetched', 'chatBoxesFetched'], {'auto_register_muc_nickname': true},
+                mock.initConverse(['chatBoxesFetched'], {'auto_register_muc_nickname': true},
                 async function (done, _converse) {
 
             const muc_jid = 'coven@chat.shakespeare.lit';

+ 8 - 23
spec/xss.js

@@ -7,11 +7,7 @@ const u = converse.env.utils;
 describe("XSS", function () {
     describe("A Chat Message", function () {
 
-        it("will escape IMG payload XSS attempts",
-            mock.initConverse(
-                ['rosterContactsFetched', 'chatBoxesFetched'], {},
-                async function (done, _converse) {
-
+        it("will escape IMG payload XSS attempts", mock.initConverse(['chatBoxesFetched'], {}, async function (done, _converse) {
             spyOn(window, 'alert').and.callThrough();
             await mock.waitForRoster(_converse, 'current');
             await mock.openControlBox(_converse);
@@ -67,11 +63,7 @@ describe("XSS", function () {
             done();
         }));
 
-        it("will escape SVG payload XSS attempts",
-            mock.initConverse(
-                ['rosterContactsFetched', 'chatBoxesFetched'], {},
-                async function (done, _converse) {
-
+        it("will escape SVG payload XSS attempts", mock.initConverse(['chatBoxesFetched'], {}, async function (done, _converse) {
             spyOn(window, 'alert').and.callThrough();
             await mock.waitForRoster(_converse, 'current');
             await mock.openControlBox(_converse);
@@ -127,9 +119,7 @@ describe("XSS", function () {
         }));
 
         it("will have properly escaped URLs",
-            mock.initConverse(
-                ['rosterContactsFetched', 'chatBoxesFetched'], {},
-                async function (done, _converse) {
+                mock.initConverse(['chatBoxesFetched'], {}, async function (done, _converse) {
 
             await mock.waitForRoster(_converse, 'current');
             await mock.openControlBox(_converse);
@@ -185,9 +175,7 @@ describe("XSS", function () {
         }));
 
         it("will avoid malformed and unsafe urls urls from rendering as anchors",
-            mock.initConverse(
-                ['rosterContactsFetched', 'chatBoxesFetched'], {},
-                async function (done, _converse) {
+                mock.initConverse(['chatBoxesFetched'], {}, async function (done, _converse) {
 
             await mock.waitForRoster(_converse, 'current');
             await mock.openControlBox(_converse);
@@ -270,8 +258,7 @@ describe("XSS", function () {
     describe("A Groupchat", function () {
 
         it("escapes occupant nicknames when rendering them, to avoid JS-injection attacks",
-                mock.initConverse(['rosterContactsFetched'], {},
-                async function (done, _converse) {
+                mock.initConverse([], {}, async function (done, _converse) {
 
             await mock.openAndEnterChatRoom(_converse, 'lounge@montague.lit', 'romeo');
             /* <presence xmlns="jabber:client" to="jc@chat.example.org/converse.js-17184538"
@@ -294,17 +281,15 @@ describe("XSS", function () {
 
             _converse.connection._dataRecv(mock.createRequest(presence));
             const view = _converse.chatboxviews.get('lounge@montague.lit');
-            await u.waitUntil(() => view.querySelectorAll('li .occupant-nick').length, 500);
-            const occupants = view.querySelector('.occupant-list').querySelectorAll('li .occupant-nick');
+            await u.waitUntil(() => view.querySelectorAll('.occupant-list .occupant-nick').length === 2);
+            const occupants = view.querySelectorAll('.occupant-list li .occupant-nick');
             expect(occupants.length).toBe(2);
             expect(occupants[0].textContent.trim()).toBe("&lt;img src=&quot;x&quot; onerror=&quot;alert(123)&quot;/&gt;");
             done();
         }));
 
         it("escapes the subject before rendering it, to avoid JS-injection attacks",
-            mock.initConverse(
-                ['rosterContactsFetched'], {},
-                async function (done, _converse) {
+                mock.initConverse([], {}, async function (done, _converse) {
 
             await mock.openAndEnterChatRoom(_converse, 'jdev@conference.jabber.org', 'jc');
             spyOn(window, 'alert');