Переглянути джерело

Fix failing tests and rewrite to use async/await

JC Brand 6 роки тому
батько
коміт
53b3f2d0d6
8 змінених файлів з 641 додано та 675 видалено
  1. 214 209
      spec/bookmarks.js
  2. 80 106
      spec/chatbox.js
  3. 25 26
      spec/chatroom.js
  4. 259 263
      spec/http-file-upload.js
  5. 42 39
      spec/notification.js
  6. 18 31
      spec/roster.js
  7. 3 0
      spec/spoilers.js
  8. 0 1
      tests/runner.js

+ 214 - 209
spec/bookmarks.js

@@ -9,12 +9,13 @@
         ], factory);
         ], factory);
 } (this, function (jasmine, $, mock, test_utils) {
 } (this, function (jasmine, $, mock, test_utils) {
     "use strict";
     "use strict";
-    var $iq = converse.env.$iq,
-        $msg = converse.env.$msg,
-        Backbone = converse.env.Backbone,
-        Strophe = converse.env.Strophe,
-        _ = converse.env._,
-        u = converse.env.utils;
+    const $iq = converse.env.$iq,
+         $msg = converse.env.$msg,
+         Backbone = converse.env.Backbone,
+         Strophe = converse.env.Strophe,
+         sizzle = converse.env.sizzle,
+         _ = converse.env._,
+         u = converse.env.utils;
 
 
     describe("A chat room", function () {
     describe("A chat room", function () {
 
 
@@ -369,242 +370,246 @@
             });
             });
         }));
         }));
 
 
+
         it("can be retrieved from the XMPP server", mock.initConverseWithPromises(
         it("can be retrieved from the XMPP server", mock.initConverseWithPromises(
             ['send'], ['chatBoxesFetched', 'roomsPanelRendered', 'rosterGroupsFetched'], {},
             ['send'], ['chatBoxesFetched', 'roomsPanelRendered', 'rosterGroupsFetched'], {},
-            function (done, _converse) {
+            async function (done, _converse) {
 
 
-            test_utils.waitUntilDiscoConfirmed(
+            await test_utils.waitUntilDiscoConfirmed(
                 _converse, _converse.bare_jid,
                 _converse, _converse.bare_jid,
                 [{'category': 'pubsub', 'type': 'pep'}],
                 [{'category': 'pubsub', 'type': 'pep'}],
                 ['http://jabber.org/protocol/pubsub#publish-options']
                 ['http://jabber.org/protocol/pubsub#publish-options']
-            ).then(function () {
-                /* Client requests all items
-                 * -------------------------
-                 *
-                 *  <iq from='juliet@capulet.lit/randomID' type='get' id='retrieve1'>
-                 *  <pubsub xmlns='http://jabber.org/protocol/pubsub'>
-                 *      <items node='storage:bookmarks'/>
-                 *  </pubsub>
-                 *  </iq>
-                 */
-                var IQ_id;
-                expect(_.filter(_converse.connection.send.calls.all(), function (call) {
-                    var stanza = call.args[0];
-                    if (!(stanza instanceof Element) || stanza.nodeName !== 'iq') {
-                        return;
-                    }
-                    // XXX: Wrapping in a div is a workaround for PhantomJS
-                    var div = document.createElement('div');
-                    div.appendChild(stanza);
-                    if (div.innerHTML ===
-                        '<iq from="dummy@localhost/resource" type="get" '+
-                            'xmlns="jabber:client" id="'+stanza.getAttribute('id')+'">'+
-                        '<pubsub xmlns="http://jabber.org/protocol/pubsub">'+
-                            '<items node="storage:bookmarks"></items>'+
-                        '</pubsub>'+
-                        '</iq>') {
-                        IQ_id = stanza.getAttribute('id');
-                        return true;
+            );
+            /* Client requests all items
+             * -------------------------
+             *
+             *  <iq from='juliet@capulet.lit/randomID' type='get' id='retrieve1'>
+             *  <pubsub xmlns='http://jabber.org/protocol/pubsub'>
+             *      <items node='storage:bookmarks'/>
+             *  </pubsub>
+             *  </iq>
+             */
+            let IQ_id;
+            const call = await test_utils.waitUntil(() =>
+                _.filter(
+                    _converse.connection.send.calls.all(),
+                    call => {
+                        const stanza = call.args[0];
+                        if (!(stanza instanceof Element) || stanza.nodeName !== 'iq') {
+                            return;
+                        }
+                        if (sizzle('items[node="storage:bookmarks"]', stanza).length) {
+                            IQ_id = stanza.getAttribute('id');
+                            return true;
+                        }
                     }
                     }
-                }).length).toBe(1);
-
-                /*
-                 * Server returns all items
-                 * ------------------------
-                 * <iq type='result'
-                 *     to='juliet@capulet.lit/randomID'
-                 *     id='retrieve1'>
-                 * <pubsub xmlns='http://jabber.org/protocol/pubsub'>
-                 *     <items node='storage:bookmarks'>
-                 *     <item id='current'>
-                 *         <storage xmlns='storage:bookmarks'>
-                 *         <conference name='The Play&apos;s the Thing'
-                 *                     autojoin='true'
-                 *                     jid='theplay@conference.shakespeare.lit'>
-                 *             <nick>JC</nick>
-                 *         </conference>
-                 *         </storage>
-                 *     </item>
-                 *     </items>
-                 * </pubsub>
-                 * </iq>
-                 */
-                expect(_converse.bookmarks.models.length).toBe(0);
-
-                spyOn(_converse.bookmarks, 'onBookmarksReceived').and.callThrough();
-                var stanza = $iq({'to': _converse.connection.jid, 'type':'result', 'id':IQ_id})
+                ).pop()
+            );
+
+            expect(Strophe.serialize(call.args[0])).toBe(
+                `<iq from="dummy@localhost/resource" id="${IQ_id}" type="get" xmlns="jabber:client">`+
+                '<pubsub xmlns="http://jabber.org/protocol/pubsub">'+
+                    '<items node="storage:bookmarks"/>'+
+                '</pubsub>'+
+                '</iq>');
+                
+            /*
+             * Server returns all items
+             * ------------------------
+             * <iq type='result'
+             *     to='juliet@capulet.lit/randomID'
+             *     id='retrieve1'>
+             * <pubsub xmlns='http://jabber.org/protocol/pubsub'>
+             *     <items node='storage:bookmarks'>
+             *     <item id='current'>
+             *         <storage xmlns='storage:bookmarks'>
+             *         <conference name='The Play&apos;s the Thing'
+             *                     autojoin='true'
+             *                     jid='theplay@conference.shakespeare.lit'>
+             *             <nick>JC</nick>
+             *         </conference>
+             *         </storage>
+             *     </item>
+             *     </items>
+             * </pubsub>
+             * </iq>
+             */
+            expect(_converse.bookmarks.models.length).toBe(0);
+
+            spyOn(_converse.bookmarks, 'onBookmarksReceived').and.callThrough();
+            var stanza = $iq({'to': _converse.connection.jid, 'type':'result', 'id':IQ_id})
+                .c('pubsub', {'xmlns': Strophe.NS.PUBSUB})
+                    .c('items', {'node': 'storage:bookmarks'})
+                        .c('item', {'id': 'current'})
+                            .c('storage', {'xmlns': 'storage:bookmarks'})
+                                .c('conference', {
+                                    'name': 'The Play&apos;s the Thing',
+                                    'autojoin': 'true',
+                                    'jid': 'theplay@conference.shakespeare.lit'
+                                }).c('nick').t('JC').up().up()
+                                .c('conference', {
+                                    'name': 'Another room',
+                                    'autojoin': 'false',
+                                    'jid': 'another@conference.shakespeare.lit'
+                                }); // Purposefully exclude the <nick> element to test #1043
+            _converse.connection._dataRecv(test_utils.createRequest(stanza));
+            await test_utils.waitUntil(() => _converse.bookmarks.onBookmarksReceived.calls.count());
+            expect(_converse.bookmarks.models.length).toBe(2);
+            expect(_converse.bookmarks.findWhere({'jid': 'theplay@conference.shakespeare.lit'}).get('autojoin')).toBe(true);
+            expect(_converse.bookmarks.findWhere({'jid': 'another@conference.shakespeare.lit'}).get('autojoin')).toBe(false);
+            done();
+        }));
+
+        describe("The rooms panel", function () {
+
+            it("shows a list of bookmarks", mock.initConverseWithPromises(
+                ['send'], ['rosterGroupsFetched'], {},
+                async function (done, _converse) {
+
+                await test_utils.waitUntilDiscoConfirmed(
+                    _converse, _converse.bare_jid,
+                    [{'category': 'pubsub', 'type': 'pep'}],
+                    ['http://jabber.org/protocol/pubsub#publish-options']
+                );
+                test_utils.openControlBox();
+
+                let IQ_id;
+                const call = await test_utils.waitUntil(() =>
+                    _.filter(
+                        _converse.connection.send.calls.all(),
+                        call => {
+                            const stanza = call.args[0];
+                            if (!(stanza instanceof Element) || stanza.nodeName !== 'iq') {
+                                return;
+                            }
+                            if (sizzle('items[node="storage:bookmarks"]', stanza).length) {
+                                IQ_id = stanza.getAttribute('id');
+                                return true;
+                            }
+                        }
+                    ).pop()
+                );
+                expect(Strophe.serialize(call.args[0])).toBe(
+                    `<iq from="dummy@localhost/resource" id="${IQ_id}" type="get" xmlns="jabber:client">`+
+                    '<pubsub xmlns="http://jabber.org/protocol/pubsub">'+
+                        '<items node="storage:bookmarks"/>'+
+                    '</pubsub>'+
+                    '</iq>'
+                );
+
+                const stanza = $iq({'to': _converse.connection.jid, 'type':'result', 'id':IQ_id})
                     .c('pubsub', {'xmlns': Strophe.NS.PUBSUB})
                     .c('pubsub', {'xmlns': Strophe.NS.PUBSUB})
                         .c('items', {'node': 'storage:bookmarks'})
                         .c('items', {'node': 'storage:bookmarks'})
                             .c('item', {'id': 'current'})
                             .c('item', {'id': 'current'})
                                 .c('storage', {'xmlns': 'storage:bookmarks'})
                                 .c('storage', {'xmlns': 'storage:bookmarks'})
                                     .c('conference', {
                                     .c('conference', {
                                         'name': 'The Play&apos;s the Thing',
                                         'name': 'The Play&apos;s the Thing',
-                                        'autojoin': 'true',
+                                        'autojoin': 'false',
                                         'jid': 'theplay@conference.shakespeare.lit'
                                         'jid': 'theplay@conference.shakespeare.lit'
                                     }).c('nick').t('JC').up().up()
                                     }).c('nick').t('JC').up().up()
+                                    .c('conference', {
+                                        'name': '1st Bookmark',
+                                        'autojoin': 'false',
+                                        'jid': 'first@conference.shakespeare.lit'
+                                    }).c('nick').t('JC').up().up()
+                                    .c('conference', {
+                                        'autojoin': 'false',
+                                        'jid': 'noname@conference.shakespeare.lit'
+                                    }).c('nick').t('JC').up().up()
+                                    .c('conference', {
+                                        'name': 'Bookmark with a very very long name that will be shortened',
+                                        'autojoin': 'false',
+                                        'jid': 'longname@conference.shakespeare.lit'
+                                    }).c('nick').t('JC').up().up()
                                     .c('conference', {
                                     .c('conference', {
                                         'name': 'Another room',
                                         'name': 'Another room',
                                         'autojoin': 'false',
                                         'autojoin': 'false',
                                         'jid': 'another@conference.shakespeare.lit'
                                         'jid': 'another@conference.shakespeare.lit'
-                                    }); // Purposefully exclude the <nick> element to test #1043
+                                    }).c('nick').t('JC').up().up();
                 _converse.connection._dataRecv(test_utils.createRequest(stanza));
                 _converse.connection._dataRecv(test_utils.createRequest(stanza));
-                return test_utils.waitUntil(() => _converse.bookmarks.onBookmarksReceived.calls.count(), 300)
-            }).then(() => {
-                expect(_converse.bookmarks.models.length).toBe(2);
-                expect(_converse.bookmarks.findWhere({'jid': 'theplay@conference.shakespeare.lit'}).get('autojoin')).toBe(true);
-                expect(_converse.bookmarks.findWhere({'jid': 'another@conference.shakespeare.lit'}).get('autojoin')).toBe(false);
-                done();
-            }).catch(_.partial(console.error, _));
-        }));
-
-        describe("The rooms panel", function () {
-
-            it("shows a list of bookmarks", mock.initConverseWithPromises(
-                ['send'], ['rosterGroupsFetched'], {}, function (done, _converse) {
 
 
-                test_utils.waitUntilDiscoConfirmed(
-                    _converse, _converse.bare_jid,
-                    [{'category': 'pubsub', 'type': 'pep'}],
-                    ['http://jabber.org/protocol/pubsub#publish-options']
-                ).then(function () {
-                    test_utils.openControlBox();
-
-                    var IQ_id;
-                    expect(_.filter(_converse.connection.send.calls.all(), function (call) {
-                        var stanza = call.args[0];
-                        if (!(stanza instanceof Element) || stanza.nodeName !== 'iq') {
-                            return;
-                        }
-                        // XXX: Wrapping in a div is a workaround for PhantomJS
-                        var div = document.createElement('div');
-                        div.appendChild(stanza);
-                        if (div.innerHTML ===
-                            '<iq from="dummy@localhost/resource" type="get" '+
-                                'xmlns="jabber:client" id="'+stanza.getAttribute('id')+'">'+
-                            '<pubsub xmlns="http://jabber.org/protocol/pubsub">'+
-                                '<items node="storage:bookmarks"></items>'+
-                            '</pubsub>'+
-                            '</iq>') {
-                            IQ_id = stanza.getAttribute('id');
-                            return true;
-                        }
-                    }).length).toBe(1);
-
-                    var stanza = $iq({'to': _converse.connection.jid, 'type':'result', 'id':IQ_id})
-                        .c('pubsub', {'xmlns': Strophe.NS.PUBSUB})
-                            .c('items', {'node': 'storage:bookmarks'})
-                                .c('item', {'id': 'current'})
-                                    .c('storage', {'xmlns': 'storage:bookmarks'})
-                                        .c('conference', {
-                                            'name': 'The Play&apos;s the Thing',
-                                            'autojoin': 'false',
-                                            'jid': 'theplay@conference.shakespeare.lit'
-                                        }).c('nick').t('JC').up().up()
-                                        .c('conference', {
-                                            'name': '1st Bookmark',
-                                            'autojoin': 'false',
-                                            'jid': 'first@conference.shakespeare.lit'
-                                        }).c('nick').t('JC').up().up()
-                                        .c('conference', {
-                                            'autojoin': 'false',
-                                            'jid': 'noname@conference.shakespeare.lit'
-                                        }).c('nick').t('JC').up().up()
-                                        .c('conference', {
-                                            'name': 'Bookmark with a very very long name that will be shortened',
-                                            'autojoin': 'false',
-                                            'jid': 'longname@conference.shakespeare.lit'
-                                        }).c('nick').t('JC').up().up()
-                                        .c('conference', {
-                                            'name': 'Another room',
-                                            'autojoin': 'false',
-                                            'jid': 'another@conference.shakespeare.lit'
-                                        }).c('nick').t('JC').up().up();
-                    _converse.connection._dataRecv(test_utils.createRequest(stanza));
-
-                    test_utils.waitUntil(() => document.querySelectorAll('#chatrooms div.bookmarks.rooms-list .room-item').length, 300)
-                    .then(() => {
-                        expect(document.querySelectorAll('#chatrooms div.bookmarks.rooms-list .room-item').length).toBe(5);
-                        const els = document.querySelectorAll('#chatrooms div.bookmarks.rooms-list .room-item a.list-item-link');
-                        expect(els[0].textContent).toBe("1st Bookmark");
-                        expect(els[1].textContent).toBe("Another room");
-                        expect(els[2].textContent).toBe("Bookmark with a very very long name that will be shortened");
-                        expect(els[3].textContent).toBe("noname@conference.shakespeare.lit");
-                        expect(els[4].textContent).toBe("The Play's the Thing");
-
-                        spyOn(window, 'confirm').and.returnValue(true);
-                        document.querySelector('#chatrooms .bookmarks.rooms-list .room-item:nth-child(2) a:nth-child(2)').click();
-                        expect(window.confirm).toHaveBeenCalled();
-                        return test_utils.waitUntil(() => document.querySelectorAll('#chatrooms div.bookmarks.rooms-list .room-item').length === 4, 300)
-                    }).then(() => {
-                        const els = document.querySelectorAll('#chatrooms div.bookmarks.rooms-list .room-item a.list-item-link');
-                        expect(els[0].textContent).toBe("1st Bookmark");
-                        expect(els[1].textContent).toBe("Bookmark with a very very long name that will be shortened");
-                        expect(els[2].textContent).toBe("noname@conference.shakespeare.lit");
-                        expect(els[3].textContent).toBe("The Play's the Thing");
-                        done();
-                    }).catch(_.partial(console.error, _));
-                });
+                await test_utils.waitUntil(() => document.querySelectorAll('#chatrooms div.bookmarks.rooms-list .room-item').length);
+                expect(document.querySelectorAll('#chatrooms div.bookmarks.rooms-list .room-item').length).toBe(5);
+                let els = document.querySelectorAll('#chatrooms div.bookmarks.rooms-list .room-item a.list-item-link');
+                expect(els[0].textContent).toBe("1st Bookmark");
+                expect(els[1].textContent).toBe("Another room");
+                expect(els[2].textContent).toBe("Bookmark with a very very long name that will be shortened");
+                expect(els[3].textContent).toBe("noname@conference.shakespeare.lit");
+                expect(els[4].textContent).toBe("The Play's the Thing");
+
+                spyOn(window, 'confirm').and.returnValue(true);
+                document.querySelector('#chatrooms .bookmarks.rooms-list .room-item:nth-child(2) a:nth-child(2)').click();
+                expect(window.confirm).toHaveBeenCalled();
+                await test_utils.waitUntil(() => document.querySelectorAll('#chatrooms div.bookmarks.rooms-list .room-item').length === 4)
+                els = document.querySelectorAll('#chatrooms div.bookmarks.rooms-list .room-item a.list-item-link');
+                expect(els[0].textContent).toBe("1st Bookmark");
+                expect(els[1].textContent).toBe("Bookmark with a very very long name that will be shortened");
+                expect(els[2].textContent).toBe("noname@conference.shakespeare.lit");
+                expect(els[3].textContent).toBe("The Play's the Thing");
+                done();
             }));
             }));
 
 
+
             it("remembers the toggle state of the bookmarks list", mock.initConverseWithPromises(
             it("remembers the toggle state of the bookmarks list", mock.initConverseWithPromises(
-                ['send'], ['rosterGroupsFetched'], {}, function (done, _converse) {
+                ['send'], ['rosterGroupsFetched'], {},
+                async function (done, _converse) {
 
 
                 test_utils.openControlBox();
                 test_utils.openControlBox();
-
-                test_utils.waitUntilDiscoConfirmed(
+                await test_utils.waitUntilDiscoConfirmed(
                     _converse, _converse.bare_jid,
                     _converse, _converse.bare_jid,
                     [{'category': 'pubsub', 'type': 'pep'}],
                     [{'category': 'pubsub', 'type': 'pep'}],
                     ['http://jabber.org/protocol/pubsub#publish-options']
                     ['http://jabber.org/protocol/pubsub#publish-options']
-                ).then(function () {
-                    var IQ_id;
-                    expect(_.filter(_converse.connection.send.calls.all(), function (call) {
-                        var stanza = call.args[0];
-                        if (!(stanza instanceof Element) || stanza.nodeName !== 'iq') {
-                            return;
-                        }
-                        // XXX: Wrapping in a div is a workaround for PhantomJS
-                        var div = document.createElement('div');
-                        div.appendChild(stanza);
-                        if (div.innerHTML ===
-                            '<iq from="dummy@localhost/resource" type="get" '+
-                                'xmlns="jabber:client" id="'+stanza.getAttribute('id')+'">'+
-                            '<pubsub xmlns="http://jabber.org/protocol/pubsub">'+
-                                '<items node="storage:bookmarks"></items>'+
-                            '</pubsub>'+
-                            '</iq>') {
-                            IQ_id = stanza.getAttribute('id');
-                            return true;
+                );
+
+                let IQ_id;
+                const call = await test_utils.waitUntil(() =>
+                    _.filter(
+                        _converse.connection.send.calls.all(),
+                        call => {
+                            const stanza = call.args[0];
+                            if (!(stanza instanceof Element) || stanza.nodeName !== 'iq') {
+                                return;
+                            }
+                            if (sizzle('items[node="storage:bookmarks"]', stanza).length) {
+                                IQ_id = stanza.getAttribute('id');
+                                return true;
+                            }
                         }
                         }
-                    }).length).toBe(1);
+                    ).pop()
+                );
+                expect(Strophe.serialize(call.args[0])).toBe(
+                    `<iq from="dummy@localhost/resource" id="${IQ_id}" type="get" xmlns="jabber:client">`+
+                    '<pubsub xmlns="http://jabber.org/protocol/pubsub">'+
+                        '<items node="storage:bookmarks"/>'+
+                    '</pubsub>'+
+                    '</iq>'
+                );
 
 
-                    var stanza = $iq({'to': _converse.connection.jid, 'type':'result', 'id':IQ_id})
-                        .c('pubsub', {'xmlns': Strophe.NS.PUBSUB})
-                            .c('items', {'node': 'storage:bookmarks'})
-                                .c('item', {'id': 'current'})
-                                    .c('storage', {'xmlns': 'storage:bookmarks'});
-                    _converse.connection._dataRecv(test_utils.createRequest(stanza));
+                const stanza = $iq({'to': _converse.connection.jid, 'type':'result', 'id':IQ_id})
+                    .c('pubsub', {'xmlns': Strophe.NS.PUBSUB})
+                        .c('items', {'node': 'storage:bookmarks'})
+                            .c('item', {'id': 'current'})
+                                .c('storage', {'xmlns': 'storage:bookmarks'});
+                _converse.connection._dataRecv(test_utils.createRequest(stanza));
 
 
-                    _converse.bookmarks.create({
-                        'jid': 'theplay@conference.shakespeare.lit',
-                        'autojoin': false,
-                        'name':  'The Play',
-                        'nick': ''
-                    });
-                    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);
-                        $('#chatrooms .bookmarks-toggle')[0].click();
-                        expect($('#chatrooms .bookmarks.rooms-list').hasClass('collapsed')).toBeTruthy();
-                        expect(_converse.bookmarksview.list_model.get('toggle-state')).toBe(_converse.CLOSED);
-                        $('#chatrooms .bookmarks-toggle')[0].click();
-                        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);
-                        done();
-                    });
+                _converse.bookmarks.create({
+                    'jid': 'theplay@conference.shakespeare.lit',
+                    'autojoin': false,
+                    'name':  'The Play',
+                    'nick': ''
                 });
                 });
+                await test_utils.waitUntil(() => $('#chatrooms .bookmarks.rooms-list .room-item:visible').length);
+                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);
+                $('#chatrooms .bookmarks-toggle')[0].click();
+                expect($('#chatrooms .bookmarks.rooms-list').hasClass('collapsed')).toBeTruthy();
+                expect(_converse.bookmarksview.list_model.get('toggle-state')).toBe(_converse.CLOSED);
+                $('#chatrooms .bookmarks-toggle')[0].click();
+                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);
+                done();
             }));
             }));
         });
         });
     });
     });

+ 80 - 106
spec/chatbox.js

@@ -150,7 +150,8 @@
             }));
             }));
 
 
             it("can be trimmed to conserve space",
             it("can be trimmed to conserve space",
-                mock.initConverseWithPromises(null, ['rosterGroupsFetched'], {}, function (done, _converse) {
+                mock.initConverseWithPromises(null, ['rosterGroupsFetched'], {},
+                async function (done, _converse) {
 
 
                 spyOn(_converse.chatboxviews, 'trimChats');
                 spyOn(_converse.chatboxviews, 'trimChats');
 
 
@@ -163,51 +164,47 @@
 
 
                 test_utils.openControlBox();
                 test_utils.openControlBox();
 
 
-                let online_contacts;
-                var i, jid, chatbox, chatboxview, trimmedview;
+                let jid, chatboxview;
                 // openControlBox was called earlier, so the controlbox is
                 // openControlBox was called earlier, so the controlbox is
                 // visible, but no other chat boxes have been created.
                 // visible, but no other chat boxes have been created.
                 expect(_converse.chatboxes.length).toEqual(1);
                 expect(_converse.chatboxes.length).toEqual(1);
                 expect(document.querySelectorAll("#conversejs .chatbox").length).toBe(1); // Controlbox is open
                 expect(document.querySelectorAll("#conversejs .chatbox").length).toBe(1); // Controlbox is open
 
 
                 _converse.rosterview.update(); // XXX: Hack to make sure $roster element is attached.
                 _converse.rosterview.update(); // XXX: Hack to make sure $roster element is attached.
-                test_utils.waitUntil(() => _converse.rosterview.el.querySelectorAll('.roster-group li').length)
-                .then(() => {
-                    // Test that they can be maximized again
-                    online_contacts = _converse.rosterview.el.querySelectorAll('.roster-group .current-xmpp-contact a.open-chat');
-                    expect(online_contacts.length).toBe(15);
-                    for (i=0; i<online_contacts.length; i++) {
-                        const el = online_contacts[i];
-                        el.click();
-                    }
-                    return test_utils.waitUntil(() => _converse.chatboxes.length == 16)
-                }).then(() => {
-                    expect(_converse.chatboxviews.trimChats.calls.count()).toBe(16);
-
-                    for (i=0; i<online_contacts.length; i++) {
-                        const el = online_contacts[i];
-                        jid = _.trim(el.textContent.trim()).replace(/ /g,'.').toLowerCase() + '@localhost';
-                        chatboxview = _converse.chatboxviews.get(jid);
-                        spyOn(chatboxview, 'minimize').and.callThrough();
-                        chatboxview.model.set({'minimized': true});
-                        expect(trimmed_chatboxes.addChat).toHaveBeenCalled();
-                        expect(chatboxview.minimize).toHaveBeenCalled();
-                    }
-                    return test_utils.waitUntil(() => _converse.chatboxviews.keys().length);
-                }).then(function () {
-                    var key = _converse.chatboxviews.keys()[1];
-                    trimmedview = trimmed_chatboxes.get(key);
-                    chatbox = trimmedview.model;
-                    spyOn(chatbox, 'maximize').and.callThrough();
-                    spyOn(trimmedview, 'restore').and.callThrough();
-                    trimmedview.delegateEvents();
-                    trimmedview.el.querySelector("a.restore-chat").click();
-
-                    expect(trimmedview.restore).toHaveBeenCalled();
-                    expect(chatbox.maximize).toHaveBeenCalled();
-                    expect(_converse.chatboxviews.trimChats.calls.count()).toBe(17);
-                    done();
-                });
+                await test_utils.waitUntil(() => _converse.rosterview.el.querySelectorAll('.roster-group li').length);
+                // Test that they can be maximized again
+                const online_contacts = _converse.rosterview.el.querySelectorAll('.roster-group .current-xmpp-contact a.open-chat');
+                expect(online_contacts.length).toBe(15);
+                let i;
+                for (i=0; i<online_contacts.length; i++) {
+                    const el = online_contacts[i];
+                    el.click();
+                }
+                await test_utils.waitUntil(() => _converse.chatboxes.length == 16);
+                expect(_converse.chatboxviews.trimChats.calls.count()).toBe(16);
+
+                for (i=0; i<online_contacts.length; i++) {
+                    const el = online_contacts[i];
+                    jid = _.trim(el.textContent.trim()).replace(/ /g,'.').toLowerCase() + '@localhost';
+                    chatboxview = _converse.chatboxviews.get(jid);
+                    spyOn(chatboxview, 'minimize').and.callThrough();
+                    chatboxview.model.set({'minimized': true});
+                    expect(trimmed_chatboxes.addChat).toHaveBeenCalled();
+                    expect(chatboxview.minimize).toHaveBeenCalled();
+                }
+                await test_utils.waitUntil(() => _converse.chatboxviews.keys().length);
+                var key = _converse.chatboxviews.keys()[1];
+                const trimmedview = trimmed_chatboxes.get(key);
+                const chatbox = trimmedview.model;
+                spyOn(chatbox, 'maximize').and.callThrough();
+                spyOn(trimmedview, 'restore').and.callThrough();
+                trimmedview.delegateEvents();
+                trimmedview.el.querySelector("a.restore-chat").click();
+
+                expect(trimmedview.restore).toHaveBeenCalled();
+                expect(chatbox.maximize).toHaveBeenCalled();
+                expect(_converse.chatboxviews.trimChats.calls.count()).toBe(17);
+                done();
             }));
             }));
 
 
             it("can be opened in minimized mode initially",
             it("can be opened in minimized mode initially",
@@ -453,105 +450,82 @@
                 it("contains a button for inserting emojis",
                 it("contains a button for inserting emojis",
                     mock.initConverseWithPromises(
                     mock.initConverseWithPromises(
                         null, ['rosterGroupsFetched', 'chatBoxesFetched'], {},
                         null, ['rosterGroupsFetched', 'chatBoxesFetched'], {},
-                        function (done, _converse) {
+                        async function (done, _converse) {
 
 
                     test_utils.createContacts(_converse, 'current');
                     test_utils.createContacts(_converse, 'current');
                     _converse.emit('rosterContactsFetched');
                     _converse.emit('rosterContactsFetched');
                     test_utils.openControlBox();
                     test_utils.openControlBox();
 
 
-                    let timeout = false, view, toolbar;
                     const contact_jid = mock.cur_names[2].replace(/ /g,'.').toLowerCase() + '@localhost';
                     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();
-
-                        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(() => timeout, 500);
-                    }).then(() => {
-                        timeout = false;
-                        toolbar.querySelector('li.toggle-smiley').click(); // Close the panel again
-                        return test_utils.waitUntil(() => !view.el.querySelector('.toggle-smiley .toolbar-menu').offsetHeight, 500);
-                    }).then(() => {
-                        setTimeout(function () { timeout = true; }, 100);
-                        return test_utils.waitUntil(() => timeout, 500);
-                    }).then(() => {
-                        toolbar.querySelector('li.toggle-smiley').click();
-                        expect(view.toggleEmojiMenu).toHaveBeenCalled();
-                        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: ');
-                        expect(view.insertEmoji).toHaveBeenCalled();
-                        done();
-                    }).catch(_.partial(_converse.log, _, Strophe.LogLevel.FATAL));
+                    await test_utils.openChatBoxFor(_converse, contact_jid);
+                    const view = _converse.chatboxviews.get(contact_jid);
+                    const 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();
+
+                    await test_utils.waitUntil(() => u.isVisible(view.el.querySelector('.toggle-smiley .emoji-picker-container')));
+                    var picker = view.el.querySelector('.toggle-smiley .emoji-picker-container');
+                    var items = picker.querySelectorAll('.emoji-picker li');
+                    items[0].click()
+                    expect(view.insertEmoji).toHaveBeenCalled();
+                    expect(view.el.querySelector('textarea.chat-textarea').value).toBe(':grinning: ');
+                    toolbar.querySelector('li.toggle-smiley').click(); // Close the panel again
+                    done();
                 }));
                 }));
 
 
                 it("can contain a button for starting a call",
                 it("can contain a button for starting a call",
                     mock.initConverseWithPromises(
                     mock.initConverseWithPromises(
                         null, ['rosterGroupsFetched', 'chatBoxesFetched'], {},
                         null, ['rosterGroupsFetched', 'chatBoxesFetched'], {},
-                        function (done, _converse) {
+                        async function (done, _converse) {
 
 
                     test_utils.createContacts(_converse, 'current');
                     test_utils.createContacts(_converse, 'current');
                     _converse.emit('rosterContactsFetched');
                     _converse.emit('rosterContactsFetched');
                     test_utils.openControlBox();
                     test_utils.openControlBox();
 
 
-                    let view, toolbar, call_button;
+                    let toolbar, call_button;
                     const contact_jid = mock.cur_names[2].replace(/ /g,'.').toLowerCase() + '@localhost';
                     const contact_jid = mock.cur_names[2].replace(/ /g,'.').toLowerCase() + '@localhost';
                     spyOn(_converse, 'emit');
                     spyOn(_converse, 'emit');
                     // First check that the button doesn't show if it's not enabled
                     // First check that the button doesn't show if it's not enabled
                     // via "visible_toolbar_buttons"
                     // via "visible_toolbar_buttons"
                     _converse.visible_toolbar_buttons.call = false;
                     _converse.visible_toolbar_buttons.call = false;
-                    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();
-                    });
+                    await test_utils.openChatBoxFor(_converse, contact_jid);
+                    let 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
+                    await 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();
                 }));
                 }));
             });
             });
 
 
             describe("A Chat Status Notification", function () {
             describe("A Chat Status Notification", function () {
 
 
                 it("does not open a new chatbox",
                 it("does not open a new chatbox",
-                        mock.initConverseWithPromises(
-                            null, ['rosterGroupsFetched'], {},
-                            function (done, _converse) {
+                    mock.initConverseWithPromises(
+                        null, ['rosterGroupsFetched'], {},
+                        function (done, _converse) {
 
 
                     test_utils.createContacts(_converse, 'current');
                     test_utils.createContacts(_converse, 'current');
                     test_utils.openControlBox();
                     test_utils.openControlBox();
 
 
                     spyOn(_converse, 'emit');
                     spyOn(_converse, 'emit');
-                    var sender_jid = mock.cur_names[1].replace(/ /g,'.').toLowerCase() + '@localhost';
+                    const sender_jid = mock.cur_names[1].replace(/ /g,'.').toLowerCase() + '@localhost';
                     // <composing> state
                     // <composing> state
-                    var msg = $msg({
+                    const msg = $msg({
                             'from': sender_jid,
                             'from': sender_jid,
                             'to': _converse.connection.jid,
                             'to': _converse.connection.jid,
                             'type': 'chat',
                             'type': 'chat',

+ 25 - 26
spec/chatroom.js

@@ -2329,35 +2329,34 @@
             }));
             }));
 
 
             it("can be minimized by clicking a DOM element with class 'toggle-chatbox-button'",
             it("can be minimized by clicking a DOM element with class 'toggle-chatbox-button'",
-                    mock.initConverseWithPromises(
-                        null, ['rosterGroupsFetched', 'chatBoxesFetched'], {},
-                        function (done, _converse) {
+                mock.initConverseWithPromises(
+                    null, ['rosterGroupsFetched', 'chatBoxesFetched'], {},
+                    async function (done, _converse) {
 
 
-                test_utils.openChatRoom(_converse, 'lounge', 'localhost', 'dummy')
-                .then(() => {
-                    const view = _converse.chatboxviews.get('lounge@localhost'),
-                          trimmed_chatboxes = _converse.minimized_chats;
+                await test_utils.openChatRoom(_converse, 'lounge', 'localhost', 'dummy');
+                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();
-
-                    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();
+                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();
+                await test_utils.waitUntil(() => trimmed_chatboxes.get(view.model.get('id')));
+                const 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'",
             it("can be closed again by clicking a DOM element with class 'close-chatbox-button'",

+ 259 - 263
spec/http-file-upload.js

@@ -14,159 +14,159 @@
 
 
         describe("Discovering support", function () {
         describe("Discovering support", function () {
 
 
-            it("is done automatically", mock.initConverseWithAsync(function (done, _converse) {
+            it("is done automatically", mock.initConverseWithAsync(async function (done, _converse) {
                 var IQ_stanzas = _converse.connection.IQ_stanzas;
                 var IQ_stanzas = _converse.connection.IQ_stanzas;
                 var IQ_ids =  _converse.connection.IQ_ids;
                 var IQ_ids =  _converse.connection.IQ_ids;
 
 
-                test_utils.waitUntilDiscoConfirmed(_converse, _converse.bare_jid, [], []).then(function () {
-                    test_utils.waitUntil(function () {
+                await test_utils.waitUntilDiscoConfirmed(_converse, _converse.bare_jid, [], []);
+                await test_utils.waitUntil(() => _.filter(
+                    IQ_stanzas,
+                    iq => iq.nodeTree.querySelector('iq[to="localhost"] query[xmlns="http://jabber.org/protocol/disco#info"]')).length
+                );
+
+                /* <iq type='result'
+                 *      from='plays.shakespeare.lit'
+                 *      to='romeo@montague.net/orchard'
+                 *      id='info1'>
+                 *  <query xmlns='http://jabber.org/protocol/disco#info'>
+                 *      <identity
+                 *          category='server'
+                 *          type='im'/>
+                 *      <feature var='http://jabber.org/protocol/disco#info'/>
+                 *      <feature var='http://jabber.org/protocol/disco#items'/>
+                 *  </query>
+                 *  </iq>
+                 */
+                let 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));
+
+                const entities = await _converse.api.disco.entities.get();
+                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);
+
+                // Converse.js sees that the entity has a disco#items feature,
+                // so it will make a query for it.
+                await test_utils.waitUntil(() => _.filter(
+                        IQ_stanzas,
+                        iq => iq.nodeTree.querySelector('iq[to="localhost"] query[xmlns="http://jabber.org/protocol/disco#items"]')
+                    ).length
+                );
+                /* <iq from='montague.tld'
+                 *      id='step_01'
+                 *      to='romeo@montague.tld/garden'
+                 *      type='result'>
+                 *  <query xmlns='http://jabber.org/protocol/disco#items'>
+                 *      <item jid='upload.montague.tld' name='HTTP File Upload' />
+                 *      <item jid='conference.montague.tld' name='Chatroom Service' />
+                 *  </query>
+                 *  </iq>
+                 */
+                stanza = _.find(IQ_stanzas, function (iq) {
+                    return iq.nodeTree.querySelector('iq[to="localhost"] query[xmlns="http://jabber.org/protocol/disco#items"]');
+                });
+                var items_IQ_id = IQ_ids[IQ_stanzas.indexOf(stanza)];
+                stanza = $iq({
+                    'type': 'result',
+                    'from': 'localhost',
+                    'to': 'dummy@localhost/resource',
+                    'id': items_IQ_id
+                }).c('query', {'xmlns': 'http://jabber.org/protocol/disco#items'})
+                    .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 _.filter(IQ_stanzas, function (iq) {
-                            return iq.nodeTree.querySelector(
-                                'iq[to="localhost"] query[xmlns="http://jabber.org/protocol/disco#info"]');
-                        }).length > 0;
-                    }, 300).then(function () {
-                        /* <iq type='result'
-                         *      from='plays.shakespeare.lit'
-                         *      to='romeo@montague.net/orchard'
-                         *      id='info1'>
-                         *  <query xmlns='http://jabber.org/protocol/disco#info'>
-                         *      <identity
-                         *          category='server'
-                         *          type='im'/>
-                         *      <feature var='http://jabber.org/protocol/disco#info'/>
-                         *      <feature var='http://jabber.org/protocol/disco#items'/>
-                         *  </query>
-                         *  </iq>
-                         */
-                        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 () {
-                        /* <iq from='montague.tld'
-                         *      id='step_01'
-                         *      to='romeo@montague.tld/garden'
-                         *      type='result'>
-                         *  <query xmlns='http://jabber.org/protocol/disco#items'>
-                         *      <item jid='upload.montague.tld' name='HTTP File Upload' />
-                         *      <item jid='conference.montague.tld' name='Chatroom Service' />
-                         *  </query>
-                         *  </iq>
-                         */
-                    var stanza = _.find(IQ_stanzas, function (iq) {
-                        return iq.nodeTree.querySelector('iq[to="localhost"] query[xmlns="http://jabber.org/protocol/disco#items"]');
-                    });
-                    var items_IQ_id = IQ_ids[IQ_stanzas.indexOf(stanza)];
-                    stanza = $iq({
-                        'type': 'result',
-                        'from': 'localhost',
-                        'to': 'dummy@localhost/resource',
-                        'id': items_IQ_id
-                    }).c('query', {'xmlns': 'http://jabber.org/protocol/disco#items'})
-                        .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"]');
                             return iq.nodeTree.querySelector('iq[to="upload.localhost"] query[xmlns="http://jabber.org/protocol/disco#info"]');
-                        });
-                        var IQ_id = IQ_ids[IQ_stanzas.indexOf(stanza)];
-                        expect(stanza.toLocaleString()).toBe(
-                            `<iq from="dummy@localhost/resource" id="`+IQ_id+`" to="upload.localhost" type="get" xmlns="jabber:client">`+
-                                `<query xmlns="http://jabber.org/protocol/disco#info"/>`+
-                            `</iq>`);
-
-                        // Upload service responds and reports a maximum file size of 5MiB
-                        /* <iq from='upload.montague.tld'
-                         *     id='step_02'
-                         *     to='romeo@montague.tld/garden'
-                         *     type='result'>
-                         * <query xmlns='http://jabber.org/protocol/disco#info'>
-                         *     <identity category='store'
-                         *             type='file'
-                         *             name='HTTP File Upload' />
-                         *     <feature var='urn:xmpp:http:upload:0' />
-                         *     <x type='result' xmlns='jabber:x:data'>
-                         *     <field var='FORM_TYPE' type='hidden'>
-                         *         <value>urn:xmpp:http:upload:0</value>
-                         *     </field>
-                         *     <field var='max-file-size'>
-                         *         <value>5242880</value>
-                         *     </field>
-                         *     </x>
-                         * </query>
-                         * </iq>
-                         */
-                        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));
+                        }).length > 0;
+                    }, 300);
+                });
 
 
-                        _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) {
-                                    expect(result.length).toBe(1);
-                                    expect(result[0].get('jid')).toBe('upload.localhost');
-                                    expect(result[0].dataforms.where({'FORM_TYPE': {value: "urn:xmpp:http:upload:0", type: "hidden"}}).length).toBe(1);
-                                    done();
-                                }
-                            );
-                        }).catch(_.partial(_converse.log, _, Strophe.LogLevel.FATAL));
-                    })
-                })
+                stanza = await test_utils.waitUntil(() =>
+                    _.filter(
+                        IQ_stanzas,
+                        iq => iq.nodeTree.querySelector('iq[to="upload.localhost"] query[xmlns="http://jabber.org/protocol/disco#info"]')
+                    ).pop()
+                );
+                const IQ_id = IQ_ids[IQ_stanzas.indexOf(stanza)];
+
+                expect(stanza.toLocaleString()).toBe(
+                    `<iq from="dummy@localhost/resource" id="`+IQ_id+`" to="upload.localhost" type="get" xmlns="jabber:client">`+
+                        `<query xmlns="http://jabber.org/protocol/disco#info"/>`+
+                    `</iq>`);
+
+                // Upload service responds and reports a maximum file size of 5MiB
+                /* <iq from='upload.montague.tld'
+                 *     id='step_02'
+                 *     to='romeo@montague.tld/garden'
+                 *     type='result'>
+                 * <query xmlns='http://jabber.org/protocol/disco#info'>
+                 *     <identity category='store'
+                 *             type='file'
+                 *             name='HTTP File Upload' />
+                 *     <feature var='urn:xmpp:http:upload:0' />
+                 *     <x type='result' xmlns='jabber:x:data'>
+                 *     <field var='FORM_TYPE' type='hidden'>
+                 *         <value>urn:xmpp:http:upload:0</value>
+                 *     </field>
+                 *     <field var='max-file-size'>
+                 *         <value>5242880</value>
+                 *     </field>
+                 *     </x>
+                 * </query>
+                 * </iq>
+                 */
+                stanza = $iq({'type': 'result', 'to': 'dummy@localhost/resource', 'id': IQ_id, 'from': 'upload.localhost'})
+                    .c('query', {'xmlns': 'http://jabber.org/protocol/disco#info'})
+                        .c('identity', {'category':'store', 'type':'file', 'name':'HTTP File Upload'}).up()
+                        .c('feature', {'var':'urn:xmpp:http:upload:0'}).up()
+                        .c('x', {'type':'result', 'xmlns':'jabber:x:data'})
+                            .c('field', {'var':'FORM_TYPE', 'type':'hidden'})
+                                .c('value').t('urn:xmpp:http:upload:0').up().up()
+                            .c('field', {'var':'max-file-size'})
+                                .c('value').t('5242880');
+                _converse.connection._dataRecv(test_utils.createRequest(stanza));
+
+                _converse.api.disco.entities.get().then(function (entities) {
+                    expect(entities.get('localhost').items.get('upload.localhost').identities.where({'category': 'store'}).length).toBe(1);
+                    _converse.api.disco.supports(Strophe.NS.HTTPUPLOAD, _converse.domain).then(
+                        function (result) {
+                            expect(result.length).toBe(1);
+                            expect(result[0].get('jid')).toBe('upload.localhost');
+                            expect(result[0].dataforms.where({'FORM_TYPE': {value: "urn:xmpp:http:upload:0", type: "hidden"}}).length).toBe(1);
+                            done();
+                        }
+                    );
+                }).catch(_.partial(_converse.log, _, Strophe.LogLevel.FATAL));
             }));
             }));
         });
         });
 
 
@@ -474,128 +474,124 @@
                         done();
                         done();
                     }));
                     }));
 
 
-                    it("shows an error message if the file is too large", mock.initConverseWithAsync(function (done, _converse) {
+                    it("shows an error message if the file is too large", mock.initConverseWithAsync(async function (done, _converse) {
                         const IQ_stanzas = _converse.connection.IQ_stanzas;
                         const IQ_stanzas = _converse.connection.IQ_stanzas;
                         const IQ_ids =  _converse.connection.IQ_ids;
                         const IQ_ids =  _converse.connection.IQ_ids;
                         const send_backup = XMLHttpRequest.prototype.send;
                         const send_backup = XMLHttpRequest.prototype.send;
-                        let view, contact_jid;
-
-                        test_utils.waitUntilDiscoConfirmed(_converse, _converse.bare_jid, [], [])
-                        .then(() => test_utils.waitUntil(() => _.filter(
-                            IQ_stanzas, (iq) => iq.nodeTree.querySelector('iq[to="localhost"] query[xmlns="http://jabber.org/protocol/disco#info"]')).length
-                        )).then(() => {
-                            var stanza = _.find(IQ_stanzas, function (iq) {
-                                return iq.nodeTree.querySelector(
-                                    'iq[to="localhost"] query[xmlns="http://jabber.org/protocol/disco#info"]');
-                            });
-                            var info_IQ_id = IQ_ids[IQ_stanzas.indexOf(stanza)];
-
-                            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#items"]');
-                                }).length > 0;
-                            }, 300);
-                        }).then(function () {
-                            var stanza = _.find(IQ_stanzas, function (iq) {
+
+                        await test_utils.waitUntilDiscoConfirmed(_converse, _converse.bare_jid, [], []);
+                        await test_utils.waitUntil(() => _.filter(
+                            IQ_stanzas,
+                            iq => iq.nodeTree.querySelector('iq[to="localhost"] query[xmlns="http://jabber.org/protocol/disco#info"]')).length
+                        );
+
+                        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));
+                        let entities = await _converse.api.disco.entities.get();
+
+                        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);
+
+                        await 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"]');
                                 return iq.nodeTree.querySelector('iq[to="localhost"] query[xmlns="http://jabber.org/protocol/disco#items"]');
-                            });
-                            var items_IQ_id = IQ_ids[IQ_stanzas.indexOf(stanza)];
-                            stanza = $iq({
-                                'type': 'result',
-                                'from': 'localhost',
-                                'to': 'dummy@localhost/resource',
-                                'id': items_IQ_id
-                            }).c('query', {'xmlns': 'http://jabber.org/protocol/disco#items'})
-                                .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) {
+                            }).length > 0;
+                        }, 300);
+
+                        stanza = _.find(IQ_stanzas, function (iq) {
+                            return iq.nodeTree.querySelector('iq[to="localhost"] query[xmlns="http://jabber.org/protocol/disco#items"]');
+                        });
+                        var items_IQ_id = IQ_ids[IQ_stanzas.indexOf(stanza)];
+                        stanza = $iq({
+                            'type': 'result',
+                            'from': 'localhost',
+                            'to': 'dummy@localhost/resource',
+                            'id': items_IQ_id
+                        }).c('query', {'xmlns': 'http://jabber.org/protocol/disco#items'})
+                            .c('item', {
+                                'jid': 'upload.localhost',
+                                'name': 'HTTP File Upload'});
+
+                        _converse.connection._dataRecv(test_utils.createRequest(stanza));
+
+                        entities = await _converse.api.disco.entities.get()
+
+                        expect(entities.length).toBe(2);
+                        expect(entities.get('localhost').items.length).toBe(1);
+                        await 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"]');
                                 return iq.nodeTree.querySelector('iq[to="upload.localhost"] query[xmlns="http://jabber.org/protocol/disco#info"]');
-                            });
-                            var IQ_id = IQ_ids[IQ_stanzas.indexOf(stanza)];
-                            expect(stanza.toLocaleString()).toBe(
-                                `<iq from="dummy@localhost/resource" id="${IQ_id}" to="upload.localhost" type="get" xmlns="jabber:client">`+
-                                    `<query xmlns="http://jabber.org/protocol/disco#info"/>`+
-                                `</iq>`);
-
-                            // Upload service responds and reports a maximum file size of 5MiB
-                            stanza = $iq({'type': 'result', 'to': 'dummy@localhost/resource', 'id': IQ_id, 'from': 'upload.localhost'})
-                                .c('query', {'xmlns': 'http://jabber.org/protocol/disco#info'})
-                                    .c('identity', {'category':'store', 'type':'file', 'name':'HTTP File Upload'}).up()
-                                    .c('feature', {'var':'urn:xmpp:http:upload:0'}).up()
-                                    .c('x', {'type':'result', 'xmlns':'jabber:x:data'})
-                                        .c('field', {'var':'FORM_TYPE', 'type':'hidden'})
-                                            .c('value').t('urn:xmpp:http:upload:0').up().up()
-                                        .c('field', {'var':'max-file-size'})
-                                            .c('value').t('5242880');
-                            _converse.connection._dataRecv(test_utils.createRequest(stanza));
-                            return _converse.api.disco.entities.get();
-                        }).then(function (entities) {
-                            expect(entities.get('localhost').items.get('upload.localhost').identities.where({'category': 'store'}).length).toBe(1);
-                            return _converse.api.disco.supports(Strophe.NS.HTTPUPLOAD, _converse.domain);
-                        }).then(function (result) {
-                            test_utils.createContacts(_converse, 'current');
-                            _converse.emit('rosterContactsFetched');
+                            }).length > 0;
+                        }, 300);
 
 
-                            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))
+                        stanza = _.find(IQ_stanzas, function (iq) {
+                            return iq.nodeTree.querySelector('iq[to="upload.localhost"] query[xmlns="http://jabber.org/protocol/disco#info"]');
+                        });
+                        var IQ_id = IQ_ids[IQ_stanzas.indexOf(stanza)];
+                        expect(stanza.toLocaleString()).toBe(
+                            `<iq from="dummy@localhost/resource" id="${IQ_id}" to="upload.localhost" type="get" xmlns="jabber:client">`+
+                                `<query xmlns="http://jabber.org/protocol/disco#info"/>`+
+                            `</iq>`);
+
+                        // Upload service responds and reports a maximum file size of 5MiB
+                        stanza = $iq({'type': 'result', 'to': 'dummy@localhost/resource', 'id': IQ_id, 'from': 'upload.localhost'})
+                            .c('query', {'xmlns': 'http://jabber.org/protocol/disco#info'})
+                                .c('identity', {'category':'store', 'type':'file', 'name':'HTTP File Upload'}).up()
+                                .c('feature', {'var':'urn:xmpp:http:upload:0'}).up()
+                                .c('x', {'type':'result', 'xmlns':'jabber:x:data'})
+                                    .c('field', {'var':'FORM_TYPE', 'type':'hidden'})
+                                        .c('value').t('urn:xmpp:http:upload:0').up().up()
+                                    .c('field', {'var':'max-file-size'})
+                                        .c('value').t('5242880');
+                        _converse.connection._dataRecv(test_utils.createRequest(stanza));
+                        entities = await _converse.api.disco.entities.get();
+                        expect(entities.get('localhost').items.get('upload.localhost').identities.where({'category': 'store'}).length).toBe(1);
+                        const result = await _converse.api.disco.supports(Strophe.NS.HTTPUPLOAD, _converse.domain);
+                        test_utils.createContacts(_converse, 'current');
+                        _converse.emit('rosterContactsFetched');
+
+                        const contact_jid = mock.cur_names[2].replace(/ /g,'.').toLowerCase() + '@localhost';
+                        await test_utils.openChatBoxFor(_converse, contact_jid);
+                        const view = _converse.chatboxviews.get(contact_jid);
+                        var file = {
+                            'type': 'image/jpeg',
+                            'size': '5242881',
+                            'lastModifiedDate': "",
+                            'name': "my-juliet.jpg"
+                        };
+                        view.model.sendFiles([file]);
+                        await test_utils.waitUntil(() => view.el.querySelectorAll('.message').length)
+                        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();
                     }));
                     }));
                 });
                 });
             });
             });

+ 42 - 39
spec/notification.js

@@ -159,47 +159,50 @@
                 it("is played when the current user is mentioned in a chat room",
                 it("is played when the current user is mentioned in a chat room",
                     mock.initConverseWithPromises(
                     mock.initConverseWithPromises(
                         null, ['rosterGroupsFetched'], {},
                         null, ['rosterGroupsFetched'], {},
-                        function (done, _converse) {
+                        async function (done, _converse) {
 
 
                     test_utils.createContacts(_converse, 'current');
                     test_utils.createContacts(_converse, 'current');
-                    test_utils.openAndEnterChatRoom(_converse, 'lounge', 'localhost', 'dummy').then(function () {
-                        _converse.play_sounds = true;
-                        spyOn(_converse, 'playSoundNotification');
-                        var view = _converse.chatboxviews.get('lounge@localhost');
-                        if (!$(view.el).find('.chat-area').length) { view.renderChatArea(); }
-                        var text = 'This message will play a sound because it mentions dummy';
-                        var message = $msg({
-                            from: 'lounge@localhost/otheruser',
-                            id: '1',
-                            to: 'dummy@localhost',
-                            type: 'groupchat'
-                        }).c('body').t(text);
-                        view.model.onMessage(message.nodeTree);
-                        expect(_converse.playSoundNotification).toHaveBeenCalled();
-
-                        text = "This message won't play a sound";
-                        message = $msg({
-                            from: 'lounge@localhost/otheruser',
-                            id: '2',
-                            to: 'dummy@localhost',
-                            type: 'groupchat'
-                        }).c('body').t(text);
-                        view.model.onMessage(message.nodeTree);
-                        expect(_converse.playSoundNotification, 1);
-                        _converse.play_sounds = false;
-
-                        text = "This message won't play a sound because it is sent by dummy";
-                        message = $msg({
-                            from: 'lounge@localhost/dummy',
-                            id: '3',
-                            to: 'dummy@localhost',
-                            type: 'groupchat'
-                        }).c('body').t(text);
-                        view.model.onMessage(message.nodeTree);
-                        expect(_converse.playSoundNotification, 1);
-                        _converse.play_sounds = false;
-                        done();
-                    });
+                    await test_utils.openAndEnterChatRoom(_converse, 'lounge', 'localhost', 'dummy');
+                    _converse.play_sounds = true;
+                    spyOn(_converse, 'playSoundNotification');
+                    const view = _converse.chatboxviews.get('lounge@localhost');
+                    if (!view.el.querySelectorAll('.chat-area').length) {
+                        view.renderChatArea();
+                    }
+                    let text = 'This message will play a sound because it mentions dummy';
+                    let message = $msg({
+                        from: 'lounge@localhost/otheruser',
+                        id: '1',
+                        to: 'dummy@localhost',
+                        type: 'groupchat'
+                    }).c('body').t(text);
+                    view.model.onMessage(message.nodeTree);
+
+                    await test_utils.waitUntil(() => _converse.playSoundNotification.calls.count());
+                    expect(_converse.playSoundNotification).toHaveBeenCalled();
+
+                    text = "This message won't play a sound";
+                    message = $msg({
+                        from: 'lounge@localhost/otheruser',
+                        id: '2',
+                        to: 'dummy@localhost',
+                        type: 'groupchat'
+                    }).c('body').t(text);
+                    view.model.onMessage(message.nodeTree);
+                    expect(_converse.playSoundNotification, 1);
+                    _converse.play_sounds = false;
+
+                    text = "This message won't play a sound because it is sent by dummy";
+                    message = $msg({
+                        from: 'lounge@localhost/dummy',
+                        id: '3',
+                        to: 'dummy@localhost',
+                        type: 'groupchat'
+                    }).c('body').t(text);
+                    view.model.onMessage(message.nodeTree);
+                    expect(_converse.playSoundNotification, 1);
+                    _converse.play_sounds = false;
+                    done();
                 }));
                 }));
             });
             });
         });
         });

+ 18 - 31
spec/roster.js

@@ -10,28 +10,21 @@
     const u = converse.env.utils;
     const u = converse.env.utils;
 
 
 
 
-    const checkHeaderToggling = function (group) {
-        var $group = $(group);
+    const checkHeaderToggling = async function (group) {
         var toggle = group.querySelector('a.group-toggle');
         var toggle = group.querySelector('a.group-toggle');
-        expect(u.isVisible($group[0])).toBeTruthy();
-        expect($group.find('ul.collapsed').length).toBe(0);
+        expect(u.isVisible(group)).toBeTruthy();
+        expect(group.querySelectorAll('ul.collapsed').length).toBe(0);
         expect(u.hasClass('fa-caret-right', toggle.firstElementChild)).toBeFalsy();
         expect(u.hasClass('fa-caret-right', toggle.firstElementChild)).toBeFalsy();
         expect(u.hasClass('fa-caret-down', toggle.firstElementChild)).toBeTruthy();
         expect(u.hasClass('fa-caret-down', toggle.firstElementChild)).toBeTruthy();
         toggle.click();
         toggle.click();
 
 
-        return test_utils.waitUntil(function () {
-            return $group.find('ul.collapsed').length === 1;
-        }, 500).then(function () {
-            expect(u.hasClass('fa-caret-right', toggle.firstElementChild)).toBeTruthy();
-            expect(u.hasClass('fa-caret-down', toggle.firstElementChild)).toBeFalsy();
-            toggle.click();
-            return test_utils.waitUntil(function () {
-                return $group.find('li').length === $group.find('li:visible').length
-            }, 500);
-        }).then(function () {
-            expect(u.hasClass('fa-caret-right', toggle.firstElementChild)).toBeFalsy();
-            expect(u.hasClass('fa-caret-down', toggle.firstElementChild)).toBeTruthy();
-        });
+        await test_utils.waitUntil(() => group.querySelectorAll('ul.collapsed').length === 1);
+        expect(u.hasClass('fa-caret-right', toggle.firstElementChild)).toBeTruthy();
+        expect(u.hasClass('fa-caret-down', toggle.firstElementChild)).toBeFalsy();
+        toggle.click();
+        await test_utils.waitUntil(() => group.querySelectorAll('li').length === $(group).find('li:visible').length);
+        expect(u.hasClass('fa-caret-right', toggle.firstElementChild)).toBeFalsy();
+        expect(u.hasClass('fa-caret-down', toggle.firstElementChild)).toBeTruthy();
     };
     };
 
 
 
 
@@ -501,7 +494,7 @@
             it("remembers whether it is closed or opened",
             it("remembers whether it is closed or opened",
                 mock.initConverseWithPromises(
                 mock.initConverseWithPromises(
                     null, ['rosterGroupsFetched'], {},
                     null, ['rosterGroupsFetched'], {},
-                    function (done, _converse) {
+                    async function (done, _converse) {
 
 
                 _converse.roster_groups = true;
                 _converse.roster_groups = true;
                 test_utils.openControlBox();
                 test_utils.openControlBox();
@@ -524,20 +517,14 @@
                         });
                         });
                     }
                     }
                 });
                 });
-                var view = _converse.rosterview.get('colleagues');
-                var $toggle = $(view.el).find('a.group-toggle');
+                const view = _converse.rosterview.get('colleagues');
+                const toggle = view.el.querySelector('a.group-toggle');
                 expect(view.model.get('state')).toBe('opened');
                 expect(view.model.get('state')).toBe('opened');
-                $toggle[0].click();
-                return test_utils.waitUntil(function () {
-                    return view.model.get('state') === 'closed';
-                }, 500).then(function () {
-                    $toggle[0].click();
-                    return test_utils.waitUntil(function () {
-                        return view.model.get('state') === 'opened';
-                    }, 500)
-                }).then(function () {
-                    done();
-                });
+                toggle.click();
+                await test_utils.waitUntil(() => view.model.get('state') === 'closed');
+                toggle.click();
+                await test_utils.waitUntil(() => view.model.get('state') === 'opened');
+                done();
             }));
             }));
         });
         });
 
 

+ 3 - 0
spec/spoilers.js

@@ -105,6 +105,7 @@
             spyOn(view, 'onMessageSubmitted').and.callThrough();
             spyOn(view, 'onMessageSubmitted').and.callThrough();
             spyOn(_converse.connection, 'send');
             spyOn(_converse.connection, 'send');
 
 
+            await test_utils.waitUntil(() => view.el.querySelector('.toggle-compose-spoiler'));
             let spoiler_toggle = view.el.querySelector('.toggle-compose-spoiler');
             let spoiler_toggle = view.el.querySelector('.toggle-compose-spoiler');
             spoiler_toggle.click();
             spoiler_toggle.click();
 
 
@@ -178,6 +179,8 @@
             await test_utils.openChatBoxFor(_converse, contact_jid);
             await test_utils.openChatBoxFor(_converse, contact_jid);
             await test_utils.waitUntilDiscoConfirmed(_converse, contact_jid+'/phone', [], [Strophe.NS.SPOILER]);
             await test_utils.waitUntilDiscoConfirmed(_converse, contact_jid+'/phone', [], [Strophe.NS.SPOILER]);
             const view = _converse.chatboxviews.get(contact_jid);
             const view = _converse.chatboxviews.get(contact_jid);
+
+            await test_utils.waitUntil(() => view.el.querySelector('.toggle-compose-spoiler'));
             let spoiler_toggle = view.el.querySelector('.toggle-compose-spoiler');
             let spoiler_toggle = view.el.querySelector('.toggle-compose-spoiler');
             spoiler_toggle.click();
             spoiler_toggle.click();
 
 

+ 0 - 1
tests/runner.js

@@ -179,7 +179,6 @@ require.config(config);
 var specs = [
 var specs = [
     "jasmine",
     "jasmine",
     //"spec/transcripts",
     //"spec/transcripts",
-    //"spec/otr",
     "spec/spoilers",
     "spec/spoilers",
     "spec/profiling",
     "spec/profiling",
     "spec/utils",
     "spec/utils",