From 615397b7daa55410c0b0a662dd8c7cc8d71335ed Mon Sep 17 00:00:00 2001 From: JC Brand Date: Sat, 28 Dec 2024 23:42:01 +0200 Subject: [PATCH] Set `auto_register_muc_nickname` to true by default and fix tests. Also add tests for registering of nickname with a MUC --- .../plugins/muc/affiliations/utils.js | 13 +- src/headless/plugins/muc/muc.js | 28 ++-- src/headless/plugins/muc/plugin.js | 2 +- .../plugins/muc/tests/registration.js | 130 ++++++++++-------- src/headless/types/plugins/muc/muc.d.ts | 2 +- src/plugins/muc-views/tests/commands.js | 62 +++++---- src/plugins/muc-views/tests/mentions.js | 2 +- src/plugins/muc-views/tests/nickname.js | 59 +++++++- src/plugins/muc-views/tests/unfurls.js | 3 +- 9 files changed, 192 insertions(+), 109 deletions(-) diff --git a/src/headless/plugins/muc/affiliations/utils.js b/src/headless/plugins/muc/affiliations/utils.js index 55da18195b..072ca4f638 100644 --- a/src/headless/plugins/muc/affiliations/utils.js +++ b/src/headless/plugins/muc/affiliations/utils.js @@ -91,17 +91,18 @@ export function setAffiliation (affiliation, muc_jids, members) { /** * Send an IQ stanza specifying an affiliation change. - * @param {AFFILIATIONS[number]} affiliation: affiliation (could also be stored on the member object). - * @param {string} muc_jid: The JID of the MUC in which the affiliation should be set. - * @param {object} member: Map containing the member's jid and optionally a reason and affiliation. + * @param {AFFILIATIONS[number]} affiliation - Affiliation (could also be stored on the member object). + * @param {string} muc_jid - The JID of the MUC in which the affiliation should be set. + * @param {object} member - Map containing the member's jid and optionally a reason and affiliation. */ function sendAffiliationIQ (affiliation, muc_jid, member) { + affiliation = member.affiliation || affiliation; const iq = $iq({ to: muc_jid, type: 'set' }) .c('query', { xmlns: Strophe.NS.MUC_ADMIN }) .c('item', { - 'affiliation': member.affiliation || affiliation, - 'nick': member.nick, - 'jid': member.jid + affiliation, + ...(affiliation === 'outcast' ? {} : {nick: member.nick }), + jid: member.jid }); if (member.reason !== undefined) { iq.c('reason', member.reason); diff --git a/src/headless/plugins/muc/muc.js b/src/headless/plugins/muc/muc.js index d417b216d2..acd8044735 100644 --- a/src/headless/plugins/muc/muc.js +++ b/src/headless/plugins/muc/muc.js @@ -1687,10 +1687,9 @@ class MUC extends ModelWithMessages(ColorAwareModel(ChatBoxBase)) { let iq, err_msg; try { iq = await api.sendIQ( - $iq({ - 'to': jid, - 'type': 'get', - }).c('query', { 'xmlns': Strophe.NS.MUC_REGISTER }) + stx` + + ` ); } catch (e) { if (sizzle(`not-allowed[xmlns="${Strophe.NS.STANZAS}"]`, e).length) { @@ -1707,15 +1706,18 @@ class MUC extends ModelWithMessages(ColorAwareModel(ChatBoxBase)) { } try { await api.sendIQ( - $iq({ - 'to': jid, - 'type': 'set' - }).c('query', { 'xmlns': Strophe.NS.MUC_REGISTER }) - .c('x', { 'xmlns': Strophe.NS.XFORM, 'type': 'submit' }) - .c('field', { 'var': 'FORM_TYPE' }) - .c('value').t('http://jabber.org/protocol/muc#register').up().up() - .c('field', { 'var': 'muc#register_roomnick' }) - .c('value').t(nick) + stx` + + + + http://jabber.org/protocol/muc#register + + + ${nick} + + + + ` ); } catch (e) { const err = await parseErrorStanza(e); diff --git a/src/headless/plugins/muc/plugin.js b/src/headless/plugins/muc/plugin.js index 6903179c26..9249dabd15 100644 --- a/src/headless/plugins/muc/plugin.js +++ b/src/headless/plugins/muc/plugin.js @@ -86,7 +86,7 @@ converse.plugins.add('converse-muc', { allow_muc_invitations: true, auto_join_on_invite: false, auto_join_rooms: [], - auto_register_muc_nickname: false, + auto_register_muc_nickname: true, colorize_username: false, hide_muc_participants: false, locked_muc_domain: false, diff --git a/src/headless/plugins/muc/tests/registration.js b/src/headless/plugins/muc/tests/registration.js index bc3e9f4105..72bbd3de71 100644 --- a/src/headless/plugins/muc/tests/registration.js +++ b/src/headless/plugins/muc/tests/registration.js @@ -2,7 +2,8 @@ const { $iq, Strophe, sizzle, u } = converse.env; -describe("Chatrooms", function () { +describe("Groupchats", function () { + beforeAll(() => jasmine.addMatchers({ toEqualStanza: jasmine.toEqualStanza })); describe("The auto_register_muc_nickname option", function () { @@ -11,42 +12,53 @@ describe("Chatrooms", function () { async function (_converse) { const muc_jid = 'coven@chat.shakespeare.lit'; - const room = await mock.openAndEnterChatRoom(_converse, muc_jid, 'romeo'); + await mock.openAndEnterChatRoom(_converse, muc_jid, 'romeo'); - let stanza = await u.waitUntil(() => _converse.api.connection.get().IQ_stanzas.filter( - iq => sizzle(`iq[to="${muc_jid}"][type="get"] query[xmlns="jabber:iq:register"]`, iq).length - ).pop()); + const IQ_stanzas = _converse.api.connection.get().IQ_stanzas; + let stanza = await u.waitUntil(() => IQ_stanzas.find( + iq => sizzle(`iq[type="get"] query[xmlns="${Strophe.NS.MUC_REGISTER}"]`, iq).length)); - expect(Strophe.serialize(stanza)) - .toBe(``+ - ``); - const result = $iq({ - 'from': room.get('jid'), - 'id': stanza.getAttribute('id'), - 'to': _converse.bare_jid, - 'type': 'result', - }).c('query', {'xmlns': 'jabber:iq:register'}) - .c('x', {'xmlns': 'jabber:x:data', 'type': 'form'}) - .c('field', { - 'label': 'Desired Nickname', - 'type': 'text-single', - 'var': 'muc#register_roomnick' - }).c('required'); - _converse.api.connection.get()._dataRecv(mock.createRequest(result)); - stanza = await u.waitUntil(() => _converse.api.connection.get().IQ_stanzas.filter( - iq => sizzle(`iq[to="${muc_jid}"][type="set"] query[xmlns="jabber:iq:register"]`, iq).length - ).pop()); + expect(stanza).toEqualStanza( + stx``); + + _converse.api.connection.get()._dataRecv(mock.createRequest( + stx` + + + + http://jabber.org/protocol/muc#register + + + + + + + `)); - expect(Strophe.serialize(stanza)).toBe( - ``+ - ``+ - ``+ - `http://jabber.org/protocol/muc#register`+ - `romeo`+ - ``+ - ``+ - ``); + stanza = await u.waitUntil(() => IQ_stanzas.find( + iq => sizzle(`iq[type="set"] query[xmlns="${Strophe.NS.MUC_REGISTER}"]`, iq).length)); + + expect(stanza).toEqualStanza( + stx` + + + http://jabber.org/protocol/muc#register + romeo + + + `); })); it("allows you to automatically deregister your nickname when closing a room", @@ -59,18 +71,21 @@ describe("Chatrooms", function () { let stanza = await u.waitUntil(() => _converse.api.connection.get().IQ_stanzas.filter( iq => sizzle(`iq[to="${muc_jid}"][type="get"] query[xmlns="jabber:iq:register"]`, iq).length ).pop()); - let result = $iq({ - 'from': room.get('jid'), - 'id': stanza.getAttribute('id'), - 'to': _converse.bare_jid, - 'type': 'result', - }).c('query', {'xmlns': 'jabber:iq:register'}) - .c('x', {'xmlns': 'jabber:x:data', 'type': 'form'}) - .c('field', { - 'label': 'Desired Nickname', - 'type': 'text-single', - 'var': 'muc#register_roomnick' - }).c('required'); + let result = stx` + + + + + + + + `; _converse.api.connection.get()._dataRecv(mock.createRequest(result)); await u.waitUntil(() => _converse.api.connection.get().IQ_stanzas.filter( iq => sizzle(`iq[to="${muc_jid}"][type="set"] query[xmlns="jabber:iq:register"]`, iq).length @@ -82,17 +97,18 @@ describe("Chatrooms", function () { stanza = await u.waitUntil(() => _converse.api.connection.get().IQ_stanzas.filter( iq => sizzle(`iq[to="${muc_jid}"][type="set"] query[xmlns="jabber:iq:register"]`, iq).length ).pop()); - expect(Strophe.serialize(stanza)).toBe( - ``+ - ``+ - ``); - - result = $iq({ - 'from': room.get('jid'), - 'id': stanza.getAttribute('id'), - 'to': _converse.bare_jid, - 'type': 'result', - }).c('query', {'xmlns': 'jabber:iq:register'}); + expect(stanza).toEqualStanza( + stx` + + `); + + result = stx` + + `; _converse.api.connection.get()._dataRecv(mock.createRequest(result)); })); diff --git a/src/headless/types/plugins/muc/muc.d.ts b/src/headless/types/plugins/muc/muc.d.ts index 6839a9b414..2267938b51 100644 --- a/src/headless/types/plugins/muc/muc.d.ts +++ b/src/headless/types/plugins/muc/muc.d.ts @@ -530,7 +530,7 @@ declare class MUC extends MUC_base { getOwnOccupant(): import("./occupant.js").default; /** * Send a presence stanza to update the user's nickname in this MUC. - * @param { String } nick + * @param {String} nick */ setNickname(nick: string): Promise; /** diff --git a/src/plugins/muc-views/tests/commands.js b/src/plugins/muc-views/tests/commands.js index 189d113bfd..6aa3a5c90e 100644 --- a/src/plugins/muc-views/tests/commands.js +++ b/src/plugins/muc-views/tests/commands.js @@ -3,6 +3,8 @@ const { Strophe, Promise, sizzle, stx, u } = converse.env; describe("Groupchats", function () { + beforeAll(() => jasmine.addMatchers({ toEqualStanza: jasmine.toEqualStanza })); + describe("Each chat groupchat can take special commands", function () { it("takes /help to show the available commands", @@ -142,8 +144,9 @@ describe("Groupchats", function () { mock.initConverse([], {}, async function (_converse) { let iq_stanza; - await mock.openAndEnterChatRoom(_converse, 'lounge@muc.montague.lit', 'romeo'); - const view = _converse.chatboxviews.get('lounge@muc.montague.lit'); + const nick = 'romeo'; + const muc_jid = 'lounge@muc.montague.lit'; + const muc = await mock.openAndEnterChatRoom(_converse, muc_jid, nick); /* We don't show join/leave messages for existing occupants. We * know about them because we receive their presences before we @@ -159,8 +162,10 @@ describe("Groupchats", function () { ` )); - expect(view.model.occupants.length).toBe(2); + expect(muc.occupants.length).toBe(2); + + const view = _converse.chatboxviews.get(muc_jid); const textarea = await u.waitUntil(() => view.querySelector('.chat-textarea')); let sent_stanza; spyOn(_converse.api.connection.get(), 'send').and.callFake((stanza) => { @@ -188,14 +193,17 @@ describe("Groupchats", function () { preventDefault: function preventDefault () {}, keyCode: 13 }); - await u.waitUntil(() => Strophe.serialize(sent_stanza) === - ``+ - ``+ - ``+ - `Welcome to the club!`+ - ``+ - ``+ - ``); + + await u.waitUntil(() => sent_stanza.querySelector('item[affiliation="member"]')); + + expect(sent_stanza).toEqualStanza( + stx` + + + Welcome to the club! + + + `); let result = stx` view.model.validateRoleOrAffiliationChangeArgs.calls.count() === 3); // Check that the member list now gets updated - expect(Strophe.serialize(sent_IQ)).toBe( - ``+ - ``+ - ``+ - `You're responsible`+ - ``+ - ``+ - ``); + expect(sent_IQ).toEqualStanza( + stx` + + + You're responsible + + + `); _converse.api.connection.get()._dataRecv(mock.createRequest( stx` view.model.validateRoleOrAffiliationChangeArgs.calls.count() === 2); // Check that the member list now gets updated - expect(Strophe.serialize(sent_IQ)).toBe( - ``+ - ``+ - ``+ - `You're annoying`+ - ``+ - ``+ - ``); + expect(sent_IQ).toEqualStanza( + stx` + + + You're annoying + + + `); _converse.api.connection.get()._dataRecv(mock.createRequest( stx` jasmine.addMatchers({ toEqualStanza: jasmine.toEqualStanza })); + it("allows you to change your nickname via a modal", - mock.initConverse([], {'view_mode': 'fullscreen'}, async function (_converse) { + mock.initConverse( + [], + { view_mode: 'fullscreen', auto_register_muc_nickname: true }, + async function (_converse) { - const muc_jid = 'lounge@montague.lit'; const nick = 'romeo'; + const muc_jid = 'lounge@montague.lit'; const model = await mock.openAndEnterChatRoom(_converse, muc_jid, nick); expect(model.get('nick')).toBe(nick); @@ -58,6 +63,11 @@ describe("A MUC", function () { expect(model.get('nick')).toBe(newnick); + // clear sent stanzas + const IQ_stanzas = _converse.api.connection.get().IQ_stanzas; + while (IQ_stanzas.length) IQ_stanzas.pop(); + + // Check that the new nickname gets registered with the MUC _converse.api.connection.get()._dataRecv(mock.createRequest( stx` model.occupants.at(0).get('nick') === newnick); expect(model.occupants.length).toBe(1); + + let stanza = await u.waitUntil(() => IQ_stanzas.find( + iq => sizzle(`iq[type="get"] query[xmlns="${Strophe.NS.MUC_REGISTER}"]`, iq).length)); + + expect(stanza).toEqualStanza( + stx``); + + _converse.api.connection.get()._dataRecv(mock.createRequest( + stx` + + + + http://jabber.org/protocol/muc#register + + + + + + + `)); + + stanza = await u.waitUntil(() => IQ_stanzas.find( + iq => sizzle(`iq[type="set"] query[xmlns="${Strophe.NS.MUC_REGISTER}"]`, iq).length)); + + expect(stanza).toEqualStanza( + stx` + + + http://jabber.org/protocol/muc#register + loverboy + + + `); })); it("informs users if their nicknames have been changed.", diff --git a/src/plugins/muc-views/tests/unfurls.js b/src/plugins/muc-views/tests/unfurls.js index 1b3547b1ba..84862076b3 100644 --- a/src/plugins/muc-views/tests/unfurls.js +++ b/src/plugins/muc-views/tests/unfurls.js @@ -402,7 +402,8 @@ describe("A Groupchat Message", function () { await u.waitUntil(() => view.querySelector('converse-message-unfurl .chat-image') !== null); })); - it("will not render an unfurl that has been removed in a subsequent correction", mock.initConverse(['chatBoxesFetched'], {}, async function (_converse) { + it("will not render an unfurl that has been removed in a subsequent correction", + mock.initConverse(['chatBoxesFetched'], { auto_register_muc_nickname: false }, async function (_converse) { const nick = 'romeo'; const muc_jid = 'lounge@muc.montague.lit'; await mock.openAndEnterChatRoom(_converse, muc_jid, nick);