Sfoglia il codice sorgente

muc: use stx tagged template literal

JC Brand 3 mesi fa
parent
commit
b7d55e24ae

+ 85 - 97
src/headless/plugins/muc/muc.js

@@ -21,8 +21,8 @@ import {
     NEW_NICK_CODES,
     DISCONNECT_CODES,
 } from './constants.js';
-import { CHATROOMS_TYPE, GONE, INACTIVE, METADATA_ATTRIBUTES } from '../../shared/constants.js';
-import { Strophe, $build, $iq, $msg, $pres } from 'strophe.js';
+import { ACTIVE, CHATROOMS_TYPE, COMPOSING, GONE, INACTIVE, METADATA_ATTRIBUTES, PAUSED } from '../../shared/constants.js';
+import { Strophe, Stanza, $build } from 'strophe.js';
 import { TimeoutError, ItemNotFoundError, StanzaError } from '../../shared/errors.js';
 import { computeAffiliationsDelta, setAffiliations, getAffiliationList } from './affiliations/utils.js';
 import { initStorage, createStore } from '../../utils/storage.js';
@@ -207,26 +207,29 @@ class MUC extends ModelWithVCard(ModelWithMessages(ColorAwareModel(ChatBoxBase))
         const maxstanzas = (is_new || this.features.get('mam_enabled'))
             ? 0
             : api.settings.get('muc_history_max_stanzas');
-
-        let stanza = $pres({
-            'id': getUniqueId(),
-            'from': api.connection.get().jid,
-            'to': this.getRoomJIDAndNick()
-        }).c('x', { 'xmlns': Strophe.NS.MUC })
-          .c('history', { maxstanzas }).up();
-
         password = password || this.get('password');
-        if (password) {
-            stanza.cnode(Strophe.xmlElement('password', [], password));
-        }
-        stanza.up(); // Go one level up, out of the `x` element.
+
+        const { xmppstatus } = _converse.state;
+        const status = xmppstatus.get('status');
+        const status_message = xmppstatus.get('status_message');
+        const stanza = stx`
+            <presence xmlns="jabber:client"
+                      id="${getUniqueId()}"
+                      from="${api.connection.get().jid}"
+                      to="${this.getRoomJIDAndNick()}">
+                <x xmlns="${Strophe.NS.MUC}">
+                    <history maxstanzas="${maxstanzas}"/>
+                    ${password ? stx`<password>${password}</password>` : '' }
+                </x>
+                ${ ['away', 'chat', 'dnd', 'xa'].includes(status) ? stx`<show>${status}</show>` : '' }
+                ${ status_message ? stx`<status>${status_message}</status>` : '' }
+            </presence>`;
         /**
          * *Hook* which allows plugins to update an outgoing MUC join presence stanza
          * @event _converse#constructedMUCPresence
          * @type {Element} The stanza which will be sent out
          */
-        stanza = await api.hook('constructedMUCPresence', this, stanza);
-        return stanza;
+        return await api.hook('constructedMUCPresence', this, stanza);
     }
 
     clearOccupantsCache () {
@@ -919,19 +922,14 @@ class MUC extends ModelWithVCard(ModelWithMessages(ColorAwareModel(ChatBoxBase))
      * @param {string} [new_jid] - The JID of the new groupchat which replaces this one.
      */
     sendDestroyIQ (reason, new_jid) {
-        const destroy = $build('destroy');
-        if (new_jid) {
-            destroy.attrs({ 'jid': new_jid });
-        }
-        const iq = $iq({
-            'to': this.get('jid'),
-            'type': 'set',
-        })
-            .c('query', { 'xmlns': Strophe.NS.MUC_OWNER })
-            .cnode(destroy.node);
-        if (reason && reason.length > 0) {
-            iq.c('reason', reason);
-        }
+        const iq = stx`
+            <iq to="${this.get('jid')}" type="set" xmlns="jabber:client">
+                <query xmlns="${Strophe.NS.MUC_OWNER}">
+                    <destroy ${new_jid ? Stanza.unsafeXML(`jid="${Strophe.xmlescape(new_jid)}"`) : ''}>
+                        ${reason ? stx`<reason>${reason}</reason>` : ''}
+                    </destroy>
+                </query>
+            </iq>`;
         return api.sendIQ(iq);
     }
 
@@ -1157,15 +1155,17 @@ class MUC extends ModelWithVCard(ModelWithMessages(ColorAwareModel(ChatBoxBase))
             return;
         }
         const chat_state = this.get('chat_state');
-        if (chat_state === GONE) {
-            // <gone/> is not applicable within MUC context
-            return;
-        }
-        api.send(
-            $msg({ 'to': this.get('jid'), 'type': 'groupchat' })
-                .c(chat_state, { 'xmlns': Strophe.NS.CHATSTATES }).up()
-                .c('no-store', { 'xmlns': Strophe.NS.HINTS }).up()
-                .c('no-permanent-store', { 'xmlns': Strophe.NS.HINTS })
+        if (chat_state === GONE) return; // <gone/> is not applicable within MUC context
+
+        api.send(stx`
+            <message to="${this.get('jid')}" type="groupchat" xmlns="jabber:client">
+                ${ chat_state === INACTIVE ? stx`<inactive xmlns="${Strophe.NS.CHATSTATES}"/>` : '' }
+                ${ chat_state === ACTIVE ? stx`<active xmlns="${Strophe.NS.CHATSTATES}"/>` : '' }
+                ${ chat_state === COMPOSING ? stx`<composing xmlns="${Strophe.NS.CHATSTATES}"/>` : '' }
+                ${ chat_state === PAUSED ? stx`<paused xmlns="${Strophe.NS.CHATSTATES}"/>` : '' }
+                <no-store xmlns="${Strophe.NS.HINTS}"/>
+                <no-permanent-store xmlns="${Strophe.NS.HINTS}"/>
+            </message>`
         );
     }
 
@@ -1179,23 +1179,15 @@ class MUC extends ModelWithVCard(ModelWithMessages(ColorAwareModel(ChatBoxBase))
             // When inviting to a members-only groupchat, we first add
             // the person to the member list by giving them an
             // affiliation of 'member' otherwise they won't be able to join.
-            this.updateMemberLists([{ 'jid': recipient, 'affiliation': 'member', 'reason': reason }]);
-        }
-        const attrs = {
-            'xmlns': 'jabber:x:conference',
-            'jid': this.get('jid'),
-        };
-        if (reason !== null) {
-            attrs.reason = reason;
-        }
-        if (this.get('password')) {
-            attrs.password = this.get('password');
-        }
-        const invitation = $msg({
-            'from': api.connection.get().jid,
-            'to': recipient,
-            'id': getUniqueId(),
-        }).c('x', attrs);
+            this.updateMemberLists([{ jid: recipient, affiliation: 'member', reason }]);
+        }
+        const invitation = stx`
+            <message xmlns="jabber:client" to="${recipient}" id="${getUniqueId()}">
+                <x xmlns="jabber:x:conference"
+                    jid="${this.get('jid')}"
+                    ${ this.get('password') ? Stanza.unsafeXML(`password="${Strophe.xmlescape(this.get('password'))}"`) : '' }
+                    ${ reason ? Stanza.unsafeXML(`reason="${Strophe.xmlescape(reason)}"`) : '' } />
+            </message>`;
         api.send(invitation);
         /**
          * After the user has sent out a direct invitation (as per XEP-0249),
@@ -1208,9 +1200,9 @@ class MUC extends ModelWithVCard(ModelWithMessages(ColorAwareModel(ChatBoxBase))
          * @example _converse.api.listen.on('chatBoxMaximized', view => { ... });
          */
         api.trigger('roomInviteSent', {
-            'room': this,
-            'recipient': recipient,
-            'reason': reason,
+            room: this,
+            recipient,
+            reason,
         });
     }
 
@@ -1349,20 +1341,27 @@ class MUC extends ModelWithVCard(ModelWithMessages(ColorAwareModel(ChatBoxBase))
      * @returns {Promise<Element>}
      */
     fetchRoomConfiguration () {
-        return api.sendIQ($iq({ 'to': this.get('jid'), 'type': 'get' }).c('query', { xmlns: Strophe.NS.MUC_OWNER }));
+        return api.sendIQ(stx`
+            <iq to="${this.get('jid')}" type="get" xmlns="jabber:client">
+                <query xmlns="${Strophe.NS.MUC_OWNER}"/>
+            </iq>`);
     }
 
     /**
      * Sends an IQ stanza with the groupchat configuration.
-     * @param {Array} config - The groupchat configuration
+     * @param {Element[]} config - The groupchat configuration
      * @returns {Promise<Element>} - A promise which resolves with
      *  the `result` stanza received from the XMPP server.
      */
     sendConfiguration (config = []) {
-        const iq = $iq({ to: this.get('jid'), type: 'set' })
-            .c('query', { xmlns: Strophe.NS.MUC_OWNER })
-            .c('x', { xmlns: Strophe.NS.XFORM, type: 'submit' });
-        config.forEach(node => iq.cnode(node).up());
+        const iq = stx`
+            <iq to="${this.get('jid')}" type="set" xmlns="jabber:client">
+                <query xmlns="${Strophe.NS.MUC_OWNER}">
+                    <x xmlns="${Strophe.NS.XFORM}" type="submit">
+                        ${ config.map((el) => Strophe.Builder.fromString(el.outerHTML)) }
+                    </x>
+                </query>
+            </iq>`;
         return api.sendIQ(iq);
     }
 
@@ -1538,19 +1537,14 @@ class MUC extends ModelWithVCard(ModelWithMessages(ColorAwareModel(ChatBoxBase))
      * @param {function} onError - callback for an error response
      */
     setRole(occupant, role, reason, onSuccess, onError) {
-        const item = $build('item', {
-            'nick': occupant.get('nick'),
-            role,
-        });
-        const iq = $iq({
-            'to': this.get('jid'),
-            'type': 'set',
-        })
-            .c('query', { xmlns: Strophe.NS.MUC_ADMIN })
-            .cnode(item.node);
-        if (reason !== null) {
-            iq.c('reason', reason);
-        }
+        const iq = stx`
+            <iq to="${this.get('jid')}" type="set" xmlns="jabber:client">
+                <query xmlns="${Strophe.NS.MUC_ADMIN}">
+                    <item nick="${occupant.get('nick')}" role="${role}">
+                        ${ reason !== null ? stx`<reason>${reason}</reason>` : '' }
+                    </item>
+                </query>
+            </iq>`;
         return api
             .sendIQ(iq)
             .then(onSuccess)
@@ -1691,14 +1685,10 @@ class MUC extends ModelWithVCard(ModelWithMessages(ColorAwareModel(ChatBoxBase))
      * @returns {Promise<string>} A promise which resolves with the reserved nick or null
      */
     async getReservedNick () {
-        const stanza = $iq({
-            'to': this.get('jid'),
-            'from': api.connection.get().jid,
-            'type': 'get',
-        }).c('query', {
-            'xmlns': Strophe.NS.DISCO_INFO,
-            'node': 'x-roomuser-item',
-        });
+        const stanza = stx`
+            <iq to="${this.get('jid')}" type="get" xmlns="jabber:client">
+                <query xmlns="${Strophe.NS.DISCO_INFO}" node="x-roomuser-item"/>
+            </iq>`;
         const result = await api.sendIQ(stanza, null, false);
         if (u.isErrorObject(result)) {
             throw result;
@@ -1790,9 +1780,12 @@ class MUC extends ModelWithVCard(ModelWithMessages(ColorAwareModel(ChatBoxBase))
      * registered) by other users.
      */
     sendUnregistrationIQ () {
-        const iq = $iq({ 'to': this.get('jid'), 'type': 'set' })
-            .c('query', { 'xmlns': Strophe.NS.MUC_REGISTER })
-            .c('remove');
+        const iq = stx`
+            <iq to="${this.get('jid')}" type="set" xmlns="jabber:client">
+                <query xmlns="${Strophe.NS.MUC_REGISTER}">
+                    <remove/>
+                </query>
+            </iq>`;
         return api.sendIQ(iq).catch((e) => log.error(e));
     }
 
@@ -1953,15 +1946,10 @@ class MUC extends ModelWithVCard(ModelWithMessages(ColorAwareModel(ChatBoxBase))
      * @param {String} value
      */
     setSubject (value = '') {
-        api.send(
-            $msg({
-                to: this.get('jid'),
-                from: api.connection.get().jid,
-                type: 'groupchat',
-            })
-                .c('subject', { xmlns: 'jabber:client' })
-                .t(value)
-                .tree()
+        api.send(stx`
+            <message to="${this.get('jid')}" type="groupchat" xmlns="jabber:client">
+                <subject>${value}</subject>
+            </message>`
         );
     }
 

+ 0 - 2
src/headless/plugins/status/plugin.js

@@ -5,7 +5,6 @@ import converse from '../../shared/api/public.js';
 import status_api from './api.js';
 import { shouldClearCache } from '../../utils/session.js';
 import {
-    addStatusToMUCJoinPresence,
     initStatus,
     onEverySecond,
     onUserActivity,
@@ -56,6 +55,5 @@ converse.plugins.add('converse-status', {
 
         api.listen.on('connected', () => initStatus(false));
         api.listen.on('reconnected', () => initStatus(true));
-        api.listen.on('constructedMUCPresence', addStatusToMUCJoinPresence);
     }
 });

+ 0 - 14
src/headless/plugins/status/utils.js

@@ -162,17 +162,3 @@ export function tearDown () {
         everySecondTrigger = null;
     }
 }
-
-export function addStatusToMUCJoinPresence (_, stanza) {
-    const { xmppstatus } = _converse.state;
-
-    const status = xmppstatus.get('status');
-    if (['away', 'chat', 'dnd', 'xa'].includes(status)) {
-        stanza.c('show').t(status).up();
-    }
-    const status_message = xmppstatus.get('status_message');
-    if (status_message) {
-        stanza.c('status').t(status_message).up();
-    }
-    return stanza;
-}

+ 50 - 71
src/plugins/muc-views/tests/commands.js

@@ -309,10 +309,10 @@ describe("Groupchats", function () {
             });
 
             let sent_stanza = await u.waitUntil(() => sent_stanzas.filter(s => s.textContent.trim() === 'This is a new subject').pop());
-            expect(Strophe.serialize(sent_stanza).toLocaleString()).toBe(
-                '<message from="romeo@montague.lit/orchard" to="lounge@montague.lit" type="groupchat" xmlns="jabber:client">'+
-                    '<subject xmlns="jabber:client">This is a new subject</subject>'+
-                '</message>');
+            expect(sent_stanza).toEqualStanza(stx`
+                <message to="lounge@montague.lit" type="groupchat" xmlns="jabber:client">
+                    <subject>This is a new subject</subject>
+                </message>`);
 
             // Check case insensitivity
             textarea.value = '/Subject This is yet another subject';
@@ -322,10 +322,10 @@ describe("Groupchats", function () {
                 key: "Enter",
             });
             sent_stanza = await u.waitUntil(() => sent_stanzas.filter(s => s.textContent.trim() === 'This is yet another subject').pop());
-            expect(Strophe.serialize(sent_stanza).toLocaleString()).toBe(
-                '<message from="romeo@montague.lit/orchard" to="lounge@montague.lit" type="groupchat" xmlns="jabber:client">'+
-                    '<subject xmlns="jabber:client">This is yet another subject</subject>'+
-                '</message>');
+            expect(sent_stanza).toEqualStanza(stx`
+                <message to="lounge@montague.lit" type="groupchat" xmlns="jabber:client">
+                    <subject>This is yet another subject</subject>
+                </message>`);
 
             while (sent_stanzas.length) {
                 sent_stanzas.pop();
@@ -338,10 +338,10 @@ describe("Groupchats", function () {
                 key: "Enter",
             });
             sent_stanza = await u.waitUntil(() => sent_stanzas.pop());
-            expect(Strophe.serialize(sent_stanza).toLocaleString()).toBe(
-                '<message from="romeo@montague.lit/orchard" to="lounge@montague.lit" type="groupchat" xmlns="jabber:client">'+
-                    '<subject xmlns="jabber:client"></subject>'+
-                '</message>');
+            expect(sent_stanza).toEqualStanza(stx`
+                <message to="lounge@montague.lit" type="groupchat" xmlns="jabber:client">
+                    <subject></subject>
+                </message>`);
         }));
 
         it("takes /clear to clear messages", mock.initConverse([], {}, async function (_converse) {
@@ -679,16 +679,6 @@ describe("Groupchats", function () {
                     `</query>`+
                 `</iq>`);
 
-            /* <presence
-             *     from='coven@chat.shakespeare.lit/thirdwitch'
-             *     to='crone1@shakespeare.lit/desktop'>
-             * <x xmlns='http://jabber.org/protocol/muc#user'>
-             *     <item affiliation='member'
-             *         jid='hag66@shakespeare.lit/pda'
-             *         role='moderator'/>
-             * </x>
-             * </presence>
-             */
             _converse.api.connection.get()._dataRecv(mock.createRequest(
                 stx`<presence
                         from="lounge@montague.lit/trustworthyguy"
@@ -712,14 +702,14 @@ describe("Groupchats", function () {
 
             await u.waitUntil(() => view.model.validateRoleOrAffiliationChangeArgs.calls.count() === 3);
             expect(view.model.setRole).toHaveBeenCalled();
-            expect(Strophe.serialize(sent_IQ)).toBe(
-                `<iq id="${IQ_id}" to="lounge@montague.lit" type="set" xmlns="jabber:client">`+
-                    `<query xmlns="http://jabber.org/protocol/muc#admin">`+
-                        `<item nick="trustworthyguy" role="participant">`+
-                            `<reason>Perhaps not</reason>`+
-                        `</item>`+
-                    `</query>`+
-                `</iq>`);
+            expect(sent_IQ).toEqualStanza(stx`
+                <iq id="${IQ_id}" to="lounge@montague.lit" type="set" xmlns="jabber:client">
+                    <query xmlns="http://jabber.org/protocol/muc#admin">
+                        <item nick="trustworthyguy" role="participant">
+                            <reason>Perhaps not</reason>
+                        </item>
+                    </query>
+                </iq>`);
 
             _converse.api.connection.get()._dataRecv(mock.createRequest(
                 stx`<presence
@@ -750,15 +740,6 @@ describe("Groupchats", function () {
             spyOn(view.model, 'validateRoleOrAffiliationChangeArgs').and.callThrough();
 
             // New user enters the groupchat
-            /* <presence
-             *     from='coven@chat.shakespeare.lit/thirdwitch'
-             *     id='27C55F89-1C6A-459A-9EB5-77690145D624'
-             *     to='crone1@shakespeare.lit/desktop'>
-             * <x xmlns='http://jabber.org/protocol/muc#user'>
-             *     <item affiliation='member' role='participant'/>
-             * </x>
-             * </presence>
-             */
             _converse.api.connection.get()._dataRecv(mock.createRequest(
                     stx`<presence
                             from="lounge@montague.lit/annoyingGuy"
@@ -794,14 +775,14 @@ describe("Groupchats", function () {
 
             await u.waitUntil(() => view.model.validateRoleOrAffiliationChangeArgs.calls.count() === 2)
             expect(view.model.setRole).toHaveBeenCalled();
-            expect(Strophe.serialize(sent_IQ)).toBe(
-                `<iq id="${IQ_id}" to="lounge@montague.lit" type="set" xmlns="jabber:client">`+
-                    `<query xmlns="http://jabber.org/protocol/muc#admin">`+
-                        `<item nick="annoyingGuy" role="visitor">`+
-                            `<reason>You&apos;re annoying</reason>`+
-                        `</item>`+
-                    `</query>`+
-                `</iq>`);
+            expect(sent_IQ).toEqualStanza(stx`
+                <iq id="${IQ_id}" to="lounge@montague.lit" type="set" xmlns="jabber:client">
+                    <query xmlns="http://jabber.org/protocol/muc#admin">
+                        <item nick="annoyingGuy" role="visitor">
+                            <reason>You&apos;re annoying</reason>
+                        </item>
+                    </query>
+                </iq>`);
 
             /* <presence
              *     from='coven@chat.shakespeare.lit/thirdwitch'
@@ -832,14 +813,14 @@ describe("Groupchats", function () {
 
             await u.waitUntil(() => view.model.validateRoleOrAffiliationChangeArgs.calls.count() === 3);
             expect(view.model.setRole).toHaveBeenCalled();
-            expect(Strophe.serialize(sent_IQ)).toBe(
-                `<iq id="${IQ_id}" to="lounge@montague.lit" type="set" xmlns="jabber:client">`+
-                    `<query xmlns="http://jabber.org/protocol/muc#admin">`+
-                        `<item nick="annoyingGuy" role="participant">`+
-                            `<reason>Now you can talk again</reason>`+
-                        `</item>`+
-                    `</query>`+
-                `</iq>`);
+            expect(sent_IQ).toEqualStanza(stx`
+                <iq id="${IQ_id}" to="lounge@montague.lit" type="set" xmlns="jabber:client">
+                    <query xmlns="http://jabber.org/protocol/muc#admin">
+                        <item nick="annoyingGuy" role="participant">
+                            <reason>Now you can talk again</reason>
+                        </item>
+                    </query>
+                </iq>`);
 
             _converse.api.connection.get()._dataRecv(mock.createRequest(
                 stx`<presence
@@ -884,16 +865,14 @@ describe("Groupchats", function () {
 
             let sent_IQs = _converse.api.connection.get().IQ_stanzas;
             let sent_IQ = await u.waitUntil(() => sent_IQs.filter(iq => iq.querySelector('destroy')).pop());
-            expect(Strophe.serialize(sent_IQ)).toBe(
-                `<iq id="${sent_IQ.getAttribute('id')}" to="${muc_jid}" type="set" xmlns="jabber:client">`+
-                    `<query xmlns="http://jabber.org/protocol/muc#owner">`+
-                        `<destroy jid="${new_muc_jid}">`+
-                            `<reason>`+
-                                `Moved to a new location`+
-                            `</reason>`+
-                        `</destroy>`+
-                    `</query>`+
-                `</iq>`);
+            expect(sent_IQ).toEqualStanza(stx`
+                <iq id="${sent_IQ.getAttribute('id')}" to="${muc_jid}" type="set" xmlns="jabber:client">
+                    <query xmlns="http://jabber.org/protocol/muc#owner">
+                        <destroy jid="${new_muc_jid}">
+                            <reason>Moved to a new location</reason>
+                        </destroy>
+                    </query>
+                </iq>`);
 
             let result_stanza = stx`<iq type="result"
                 id="${sent_IQ.getAttribute('id')}"
@@ -925,12 +904,12 @@ describe("Groupchats", function () {
             submit.click();
 
             sent_IQ = await u.waitUntil(() => sent_IQs.filter(iq => iq.querySelector('destroy')).pop());
-            expect(Strophe.serialize(sent_IQ)).toBe(
-                `<iq id="${sent_IQ.getAttribute('id')}" to="${new_muc_jid}" type="set" xmlns="jabber:client">`+
-                    `<query xmlns="http://jabber.org/protocol/muc#owner">`+
-                        `<destroy/>`+
-                    `</query>`+
-                `</iq>`);
+            expect(sent_IQ).toEqualStanza(stx`
+                <iq id="${sent_IQ.getAttribute('id')}" to="${new_muc_jid}" type="set" xmlns="jabber:client">
+                    <query xmlns="http://jabber.org/protocol/muc#owner">
+                        <destroy/>
+                    </query>
+                </iq>`);
 
             result_stanza = stx`<iq type="result"
                 id="${sent_IQ.getAttribute('id')}"

+ 8 - 6
src/plugins/muc-views/tests/csn.js

@@ -3,6 +3,8 @@
 const { Strophe, stx, u }  = converse.env;
 
 describe("Groupchats", function () {
+    beforeAll(() => jasmine.addMatchers({ toEqualStanza: jasmine.toEqualStanza }));
+
     describe("A XEP-0085 Chat Status Notification", function () {
 
         it("is is not sent out to a MUC if the user is a visitor in a moderated room",
@@ -30,12 +32,12 @@ describe("Groupchats", function () {
 
             expect(view.model.sendChatState).toHaveBeenCalled();
             const last_stanza = _converse.api.connection.get().sent_stanzas.pop();
-            expect(Strophe.serialize(last_stanza)).toBe(
-                `<message to="lounge@montague.lit" type="groupchat" xmlns="jabber:client">`+
-                    `<active xmlns="http://jabber.org/protocol/chatstates"/>`+
-                    `<no-store xmlns="urn:xmpp:hints"/>`+
-                    `<no-permanent-store xmlns="urn:xmpp:hints"/>`+
-                `</message>`);
+            expect(last_stanza).toEqualStanza(stx`
+                <message to="lounge@montague.lit" type="groupchat" xmlns="jabber:client">
+                    <active xmlns="http://jabber.org/protocol/chatstates"/>
+                    <no-store xmlns="urn:xmpp:hints"/>
+                    <no-permanent-store xmlns="urn:xmpp:hints"/>
+                </message>`);
 
             // Romeo loses his voice
             _converse.api.connection.get()._dataRecv(

+ 9 - 5
src/plugins/muc-views/tests/member-lists.js

@@ -3,6 +3,8 @@ const { $iq, Strophe, u, stx }  = converse.env;
 
 describe("A Groupchat", function () {
 
+    beforeAll(() => jasmine.addMatchers({ toEqualStanza: jasmine.toEqualStanza }));
+
     describe("upon being entered", function () {
 
         it("will fetch the member list if muc_fetch_members is true",
@@ -157,6 +159,8 @@ describe("A Groupchat", function () {
 
 describe("Someone being invited to a groupchat", function () {
 
+    beforeAll(() => jasmine.addMatchers({ toEqualStanza: jasmine.toEqualStanza }));
+
     it("will first be added to the member list if the groupchat is members only",
             mock.initConverse(['chatBoxesFetched'], {}, async function (_converse) {
 
@@ -288,10 +292,10 @@ describe("Someone being invited to a groupchat", function () {
         await u.waitUntil(() => view.model.occupants.fetchMembers.calls.count());
 
         // Finally check that the user gets invited.
-        expect(Strophe.serialize(sent_stanza)).toBe( // Strophe adds the xmlns attr (although not in spec)
-            `<message from="romeo@montague.lit/orchard" id="${sent_id}" to="${invitee_jid}" xmlns="jabber:client">`+
-                `<x jid="coven@chat.shakespeare.lit" reason="Please join this groupchat" xmlns="jabber:x:conference"/>`+
-            `</message>`
-        );
+        expect(sent_stanza).toEqualStanza(stx`
+            <message id="${sent_id}" to="${invitee_jid}" xmlns="jabber:client">
+                <x jid="coven@chat.shakespeare.lit" reason="Please join this groupchat" xmlns="jabber:x:conference"/>
+            </message>
+        `);
     }));
 });

+ 1 - 1
src/plugins/muc-views/tests/muc-add-modal.js

@@ -160,7 +160,7 @@ describe('The "Groupchats" Add modal', function () {
             _converse.api.connection.get()._dataRecv(mock.createRequest(presence));
 
             const IQ_stanzas = _converse.api.connection.get().IQ_stanzas;
-            const iq = await u.waitUntil(() => IQ_stanzas.filter(s => s.querySelector(`query[xmlns="${Strophe.NS.MUC_OWNER}"]`)).pop());
+            const iq = await u.waitUntil(() => IQ_stanzas.filter((s) => sizzle(`query[xmlns="${Strophe.NS.MUC_OWNER}"]`, s).length).pop());
 
             spyOn(muc, 'sendConfiguration').and.callThrough();
 

+ 1 - 1
src/plugins/muc-views/tests/muc-api.js

@@ -189,7 +189,7 @@ describe("Groupchats", function () {
                 </presence>`));
 
             const IQ_stanzas = _converse.api.connection.get().IQ_stanzas;
-            const iq = await u.waitUntil(() => IQ_stanzas.filter(s => s.querySelector(`query[xmlns="${Strophe.NS.MUC_OWNER}"]`)).pop());
+            const iq = await u.waitUntil(() => IQ_stanzas.filter((s) => sizzle(`query[xmlns="${Strophe.NS.MUC_OWNER}"]`, s).length).pop());
             expect(Strophe.serialize(iq)).toBe(
                 `<iq id="${iq.getAttribute('id')}" to="room@conference.example.org" type="get" xmlns="jabber:client">`+
                 `<query xmlns="http://jabber.org/protocol/muc#owner"/></iq>`);

+ 75 - 78
src/plugins/muc-views/tests/muc.js

@@ -66,18 +66,15 @@ describe("Groupchats", function () {
             expect(csntext.trim()).toEqual("nicky has entered the groupchat");
 
             // An instant room is created by saving the default configuratoin.
-            //
-            /* <iq to="myroom@conference.chat.example.org" type="set" xmlns="jabber:client" id="5025e055-036c-4bc5-a227-706e7e352053:sendIQ">
-             *   <query xmlns="http://jabber.org/protocol/muc#owner"><x xmlns="jabber:x:data" type="submit"/></query>
-             * </iq>
-             */
             const selector = `query[xmlns="${Strophe.NS.MUC_OWNER}"]`;
             IQ_stanzas = _converse.api.connection.get().IQ_stanzas;
-            const iq = await u.waitUntil(() => IQ_stanzas.filter(s => s.querySelector(selector)).pop());
-            expect(Strophe.serialize(iq)).toBe(
-                `<iq id="${iq.getAttribute('id')}" to="lounge@montague.lit" type="set" xmlns="jabber:client">`+
-                    `<query xmlns="http://jabber.org/protocol/muc#owner"><x type="submit" xmlns="jabber:x:data"/>`+
-                `</query></iq>`);
+            const iq = await u.waitUntil(() => IQ_stanzas.filter((s) => sizzle(selector, s).length).pop());
+            expect(iq).toEqualStanza(stx`
+                <iq id="${iq.getAttribute('id')}" to="lounge@montague.lit" type="set" xmlns="jabber:client">
+                    <query xmlns="http://jabber.org/protocol/muc#owner">
+                        <x type="submit" xmlns="jabber:x:data"/>
+                    </query>
+                </iq>`);
         }));
     });
 
@@ -240,7 +237,7 @@ describe("Groupchats", function () {
             const all_affiliations = Array.isArray(affs) ? affs :  (affs ? ['member', 'admin', 'owner'] : []);
             await mock.returnMemberLists(_converse, muc_jid, [], all_affiliations);
 
-            iq_get = await u.waitUntil(() => sent_IQs.filter(iq => sizzle(`query[xmlns="${Strophe.NS.MAM}"]`, iq).length).pop());
+            iq_get = await u.waitUntil(() => sent_IQs.filter((iq) => sizzle(`query[xmlns="${Strophe.NS.MAM}"]`, iq).length).pop());
             expect(iq_get).toEqualStanza(stx`
                 <iq id="${iq_get.getAttribute('id')}" to="${muc_jid}" type="set" xmlns="jabber:client">
                     <query queryid="${iq_get.querySelector('query').getAttribute('queryid')}" xmlns="${Strophe.NS.MAM}">
@@ -1101,10 +1098,10 @@ describe("Groupchats", function () {
              * configuration form.
              * See: // https://xmpp.org/extensions/xep-0045.html#example-163
              */
-            expect(Strophe.serialize(iq)).toBe(
-                `<iq id="${iq.getAttribute('id')}" to="${muc_jid}" type="get" xmlns="jabber:client">`+
-                    `<query xmlns="http://jabber.org/protocol/muc#owner"/>`+
-                `</iq>`);
+            expect(iq).toEqualStanza(stx`
+                <iq id="${iq.getAttribute('id')}" to="${muc_jid}" type="get" xmlns="jabber:client">
+                    <query xmlns="http://jabber.org/protocol/muc#owner"/>
+                </iq>`);
 
             /* Server responds with the configuration form.
              * See: // https://xmpp.org/extensions/xep-0045.html#example-165
@@ -1230,30 +1227,28 @@ describe("Groupchats", function () {
 
             modal.querySelector('.chatroom-form input[type="submit"]').click();
 
-            console.log(Strophe.serialize(sent_IQ));
-
-            expect(Strophe.serialize(sent_IQ)).toBe(
-            `<iq id="${IQ_id}" to="${muc_jid}" type="set" xmlns="jabber:client">`+
-                `<query xmlns="http://jabber.org/protocol/muc#owner">`+
-                `<x type="submit" xmlns="jabber:x:data">`+
-                    `<field var="FORM_TYPE"><value>http://jabber.org/protocol/muc#roomconfig</value></field>`+
-                    `<field var="muc#roomconfig_roomname"><value>A Dark Cave</value></field>`+
-                    `<field var="muc#roomconfig_roomdesc"><value>The place for all good witches!</value></field>`+
-                    `<field var="muc#roomconfig_enablelogging"><value>0</value></field>`+
-                    `<field var="muc#roomconfig_changesubject"><value>0</value></field>`+
-                    `<field var="muc#roomconfig_allowinvites"><value>0</value></field>`+
-                    `<field var="muc#roomconfig_allowpm"><value>moderators</value></field>`+
-                    `<field var="muc#roomconfig_presencebroadcast"><value>moderator</value></field>`+
-                    `<field var="muc#roomconfig_getmemberlist"><value>moderator</value>,<value>participant</value>,<value>visitor</value></field>`+
-                    `<field var="muc#roomconfig_publicroom"><value>0</value></field>`+
-                    `<field var="muc#roomconfig_persistentroom"><value>0</value></field>`+
-                    `<field var="muc#roomconfig_moderatedroom"><value>1</value></field>`+
-                    `<field var="muc#roomconfig_membersonly"><value>1</value></field>`+
-                    `<field var="muc#roomconfig_passwordprotectedroom"><value>1</value></field>`+
-                    `<field var="muc#roomconfig_roomsecret"><value>cauldronburn</value></field>`+
-                `</x>`+
-                `</query>`+
-            `</iq>`);
+            expect(sent_IQ).toEqualStanza(stx`
+                <iq id="${IQ_id}" to="${muc_jid}" type="set" xmlns="jabber:client">
+                    <query xmlns="http://jabber.org/protocol/muc#owner">
+                    <x type="submit" xmlns="jabber:x:data">
+                        <field var="FORM_TYPE"><value>http://jabber.org/protocol/muc#roomconfig</value></field>
+                        <field var="muc#roomconfig_roomname"><value>A Dark Cave</value></field>
+                        <field var="muc#roomconfig_roomdesc"><value>The place for all good witches!</value></field>
+                        <field var="muc#roomconfig_enablelogging"><value>0</value></field>
+                        <field var="muc#roomconfig_changesubject"><value>0</value></field>
+                        <field var="muc#roomconfig_allowinvites"><value>0</value></field>
+                        <field var="muc#roomconfig_allowpm"><value>moderators</value></field>
+                        <field var="muc#roomconfig_presencebroadcast"><value>moderator</value></field>
+                        <field var="muc#roomconfig_getmemberlist"><value>moderator</value>,<value>participant</value>,<value>visitor</value></field>
+                        <field var="muc#roomconfig_publicroom"><value>0</value></field>
+                        <field var="muc#roomconfig_persistentroom"><value>0</value></field>
+                        <field var="muc#roomconfig_moderatedroom"><value>1</value></field>
+                        <field var="muc#roomconfig_membersonly"><value>1</value></field>
+                        <field var="muc#roomconfig_passwordprotectedroom"><value>1</value></field>
+                        <field var="muc#roomconfig_roomsecret"><value>cauldronburn</value></field>
+                    </x>
+                    </query>
+                </iq>`);
         }));
 
         it("can be configured if your its owner",
@@ -1307,10 +1302,10 @@ describe("Groupchats", function () {
             /* Check that an IQ is sent out, asking for the
              * configuration form.
              */
-            expect(Strophe.serialize(iq)).toBe(
-                `<iq id="${iq.getAttribute('id')}" to="${muc_jid}" type="get" xmlns="jabber:client">`+
-                    `<query xmlns="http://jabber.org/protocol/muc#owner"/>`+
-                `</iq>`);
+            expect(iq).toEqualStanza(stx`
+                <iq id="${iq.getAttribute('id')}" to="${muc_jid}" type="get" xmlns="jabber:client">
+                    <query xmlns="http://jabber.org/protocol/muc#owner"/>
+                </iq>`);
 
             /* Server responds with the configuration form.
              * See: // https://xmpp.org/extensions/xep-0045.html#example-165
@@ -1451,28 +1446,28 @@ describe("Groupchats", function () {
 
             modal.querySelector('.chatroom-form input[type="submit"]').click();
 
-            expect(Strophe.serialize(sent_IQ)).toBe(
-                `<iq id="${IQ_id}" to="${muc_jid}" type="set" xmlns="jabber:client">`+
-                    `<query xmlns="http://jabber.org/protocol/muc#owner">`+
-                        `<x type="submit" xmlns="jabber:x:data">`+
-                            `<field var="FORM_TYPE"><value>http://jabber.org/protocol/muc#roomconfig</value></field>`+
-                            `<field var="muc#roomconfig_roomname"><value>A Dark Cave</value></field>`+
-                            `<field var="muc#roomconfig_roomdesc"><value>The place for all good witches!</value></field>`+
-                            `<field var="muc#roomconfig_enablelogging"><value>0</value></field>`+
-                            `<field var="muc#roomconfig_changesubject"><value>0</value></field>`+
-                            `<field var="muc#roomconfig_allowinvites"><value>0</value></field>`+
-                            `<field var="muc#roomconfig_allowpm"><value>moderators</value></field>`+
-                            `<field var="muc#roomconfig_presencebroadcast"><value>moderator</value></field>`+
-                            `<field var="muc#roomconfig_getmemberlist"><value>moderator</value>,<value>participant</value>,<value>visitor</value></field>`+
-                            `<field var="muc#roomconfig_publicroom"><value>0</value></field>`+
-                            `<field var="muc#roomconfig_persistentroom"><value>0</value></field>`+
-                            `<field var="muc#roomconfig_moderatedroom"><value>1</value></field>`+
-                            `<field var="muc#roomconfig_membersonly"><value>1</value></field>`+
-                            `<field var="muc#roomconfig_passwordprotectedroom"><value>1</value></field>`+
-                            `<field var="muc#roomconfig_roomsecret"><value>cauldronburn</value></field>`+
-                        `</x>`+
-                    `</query>`+
-                `</iq>`);
+            expect(sent_IQ).toEqualStanza(stx`
+                <iq id="${IQ_id}" to="${muc_jid}" type="set" xmlns="jabber:client">
+                    <query xmlns="http://jabber.org/protocol/muc#owner">
+                        <x type="submit" xmlns="jabber:x:data">
+                            <field var="FORM_TYPE"><value>http://jabber.org/protocol/muc#roomconfig</value></field>
+                            <field var="muc#roomconfig_roomname"><value>A Dark Cave</value></field>
+                            <field var="muc#roomconfig_roomdesc"><value>The place for all good witches!</value></field>
+                            <field var="muc#roomconfig_enablelogging"><value>0</value></field>
+                            <field var="muc#roomconfig_changesubject"><value>0</value></field>
+                            <field var="muc#roomconfig_allowinvites"><value>0</value></field>
+                            <field var="muc#roomconfig_allowpm"><value>moderators</value></field>
+                            <field var="muc#roomconfig_presencebroadcast"><value>moderator</value></field>
+                            <field var="muc#roomconfig_getmemberlist"><value>moderator</value>,<value>participant</value>,<value>visitor</value></field>
+                            <field var="muc#roomconfig_publicroom"><value>0</value></field>
+                            <field var="muc#roomconfig_persistentroom"><value>0</value></field>
+                            <field var="muc#roomconfig_moderatedroom"><value>1</value></field>
+                            <field var="muc#roomconfig_membersonly"><value>1</value></field>
+                            <field var="muc#roomconfig_passwordprotectedroom"><value>1</value></field>
+                            <field var="muc#roomconfig_roomsecret"><value>cauldronburn</value></field>
+                        </x>
+                    </query>
+                </iq>`);
         }));
 
         it("properly handles notification that a room has been destroyed",
@@ -1572,13 +1567,12 @@ describe("Groupchats", function () {
             modal.querySelector('input[type="submit"]').click();
 
             expect(view.model.directInvite).toHaveBeenCalled();
-           expect(Strophe.serialize(sent_stanza)).toBe(
-                `<message from="romeo@montague.lit/orchard" `+
-                        `id="${sent_stanza.getAttribute("id")}" `+
-                        `to="balthasar@montague.lit" `+
-                        `xmlns="jabber:client">`+
-                    `<x jid="lounge@montague.lit" reason="Please join!" xmlns="jabber:x:conference"/>`+
-                `</message>`
+            expect(sent_stanza).toEqualStanza(stx`
+                <message id="${sent_stanza.getAttribute("id")}"
+                        to="balthasar@montague.lit"
+                        xmlns="jabber:client">
+                    <x jid="lounge@montague.lit" reason="Please join!" xmlns="jabber:x:conference"/>
+                </message>`
             );
         }));
 
@@ -1771,10 +1765,14 @@ describe("Groupchats", function () {
                 )).pop());
 
             // Check that the groupchat queried for the feautures.
-            expect(Strophe.serialize(stanza)).toBe(
-                `<iq from="romeo@montague.lit/orchard" id="${stanza.getAttribute("id")}" to="${muc_jid}" type="get" xmlns="jabber:client">`+
-                    `<query xmlns="http://jabber.org/protocol/disco#info"/>`+
-                `</iq>`);
+            expect(stanza).toEqualStanza(stx`
+                <iq from="romeo@montague.lit/orchard"
+                        id="${stanza.getAttribute("id")}"
+                        to="${muc_jid}"
+                        type="get"
+                        xmlns="jabber:client">
+                    <query xmlns="http://jabber.org/protocol/disco#info"/>
+                </iq>`);
 
             const features_stanza =
                 stx`<iq from="${muc_jid}"
@@ -1860,7 +1858,7 @@ describe("Groupchats", function () {
 
             const IQs = _converse.api.connection.get().IQ_stanzas;
             const s = `iq[to="${muc_jid}"] query[xmlns="${Strophe.NS.MUC_OWNER}"]`;
-            let iq = await u.waitUntil(() => IQs.filter(iq => iq.querySelector(s)).pop());
+            let iq = await u.waitUntil(() => IQs.filter((iq) => sizzle(s, iq).length).pop());
 
             const response_el = stx`<iq xmlns="jabber:client"
                      type="result"
@@ -2117,7 +2115,6 @@ describe("Groupchats", function () {
         it("can be saved to, and retrieved from, browserStorage",
                 mock.initConverse(['chatBoxesFetched'], {}, async function (_converse) {
 
-            const { api } = _converse;
             const muc_jid = 'lounge@montague.lit';
             await mock.openAndEnterMUC(_converse, muc_jid, 'romeo');
 

+ 1 - 1
src/plugins/muc-views/tests/nickname.js

@@ -254,7 +254,7 @@ describe("A MUC", function () {
                 ).pop());
 
             expect(iq).toEqualStanza(stx`
-                <iq from="romeo@montague.lit/orchard" id="${iq.getAttribute('id')}" to="${muc_jid}" type="get" xmlns="jabber:client">
+                <iq id="${iq.getAttribute('id')}" to="${muc_jid}" type="get" xmlns="jabber:client">
                     <query node="x-roomuser-item" xmlns="http://jabber.org/protocol/disco#info"/>
                 </iq>`);