UNPKG

converse.js

Version:
290 lines (242 loc) 16.1 kB
/*global mock, converse */ const { sizzle, u } = converse.env; describe('The "Groupchats" Add modal', function () { beforeAll(() => jasmine.addMatchers({ toEqualStanza: jasmine.toEqualStanza })); it('can be opened from a link in the "Groupchats" section of the controlbox', mock.initConverse(['chatBoxesFetched'], {}, async function (_converse) { const modal = await mock.openAddMUCModal(_converse); const muc_jid = 'lounge@muc.montague.lit'; let label_name = modal.querySelector('label[for="chatroom"]'); expect(modal.querySelector('.modal-title').textContent.trim()).toBe('Enter a new Groupchat'); expect(label_name.textContent.trim()).toBe('Groupchat name or address:'); const label_nick = modal.querySelector('label[for="nickname"]'); expect(label_nick.textContent.trim()).toBe('Nickname:'); const nick_input = modal.querySelector('input[name="nickname"]'); expect(nick_input.value).toBe('Romeo'); nick_input.value = 'romeo'; modal.querySelector('input[name="chatroom"]').value = muc_jid; modal.querySelector('form input[type="submit"]').click(); await mock.waitForMUCDiscoInfo(_converse, muc_jid); await u.waitUntil(() => _converse.chatboxes.length); await u.waitUntil(() => sizzle('.chatroom', _converse.el).filter(u.isVisible).length === 1); }) ); it("doesn't require the domain when muc_domain is set", mock.initConverse(['chatBoxesFetched'], { muc_domain: 'muc.example.org' }, async function (_converse) { let modal = await mock.openAddMUCModal(_converse); expect(modal.querySelector('.modal-title').textContent.trim()).toBe('Enter a new Groupchat'); spyOn(_converse.ChatRoom.prototype, 'getDiscoInfo').and.callFake(() => Promise.resolve()); const label_name = modal.querySelector('label[for="chatroom"]'); expect(label_name.textContent.trim()).toBe('Groupchat name or address:'); let name_input = modal.querySelector('input[name="chatroom"]'); name_input.value = 'lounge'; let nick_input = modal.querySelector('input[name="nickname"]'); nick_input.value = 'max'; modal.querySelector('form input[type="submit"]').click(); await mock.waitForMUCDiscoInfo(_converse, 'lounge@muc.example.org'); await u.waitUntil(() => _converse.chatboxes.length); await u.waitUntil(() => sizzle('.chatroom', _converse.el).filter(u.isVisible).length === 1); expect(_converse.chatboxes.models.map(m => m.get('id')).includes('lounge@muc.example.org')).toBe(true); // However, you can still open MUCs with different domains const roomspanel = _converse.chatboxviews.get('controlbox').querySelector('converse-rooms-list'); roomspanel.querySelector('.show-add-muc-modal').click(); modal = await u.waitUntil(() => document.querySelector('converse-add-muc-modal'), 1000); name_input = modal.querySelector('input[name="chatroom"]'); name_input.value = 'lounge@conference.example.org'; nick_input = modal.querySelector('input[name="nickname"]'); nick_input.value = 'max'; modal.querySelector('form input[type="submit"]').click(); await mock.waitForMUCDiscoInfo(_converse, 'lounge@conference.example.org'); await u.waitUntil(() => _converse.chatboxes.models.filter(c => c.get('type') === 'chatroom').length === 2); await u.waitUntil(() => sizzle('.chatroom', _converse.el).filter(u.isVisible).length === 2); expect(_converse.chatboxes.models.map(m => m.get('id')).includes('lounge@conference.example.org')).toBe( true ); }) ); it('uses the muc_domain if locked_muc_domain is true', mock.initConverse( ['chatBoxesFetched'], { muc_domain: 'muc.example.org', locked_muc_domain: true }, async function (_converse) { let modal = await mock.openAddMUCModal(_converse); expect(modal.querySelector('.modal-title').textContent.trim()).toBe('Enter a new Groupchat'); spyOn(_converse.ChatRoom.prototype, 'getDiscoInfo').and.callFake(() => Promise.resolve()); const label_name = modal.querySelector('label[for="chatroom"]'); expect(label_name.textContent.trim()).toBe('Groupchat name:'); let name_input = modal.querySelector('input[name="chatroom"]'); expect(name_input.placeholder).toBe(''); name_input.value = 'lounge'; let nick_input = modal.querySelector('input[name="nickname"]'); nick_input.value = 'max'; modal.querySelector('form input[type="submit"]').click(); await mock.waitForMUCDiscoInfo(_converse, 'lounge@muc.example.org'); await u.waitUntil(() => _converse.chatboxes.length); await u.waitUntil(() => sizzle('.chatroom', _converse.el).filter(u.isVisible).length === 1); expect(_converse.chatboxes.models.map(m => m.get('id')).includes('lounge@muc.example.org')).toBe(true); // However, you can still open MUCs with different domains const roomspanel = _converse.chatboxviews.get('controlbox').querySelector('converse-rooms-list'); roomspanel.querySelector('.show-add-muc-modal').click(); modal = await u.waitUntil(() => document.querySelector('converse-add-muc-modal')); name_input = modal.querySelector('input[name="chatroom"]'); name_input.value = 'lounge@conference'; nick_input = modal.querySelector('input[name="nickname"]'); nick_input.value = 'max'; modal.querySelector('form input[type="submit"]').click(); await mock.waitForMUCDiscoInfo(_converse, 'lounge-conference@muc.example.org'); await u.waitUntil( () => _converse.chatboxes.models.filter(c => c.get('type') === 'chatroom').length === 2 ); await u.waitUntil(() => sizzle('.chatroom', _converse.el).filter(u.isVisible).length === 2); expect( _converse.chatboxes.models.map(m => m.get('id')).includes('lounge-conference@muc.example.org') ).toBe(true); }) ); it("lets you create a MUC with only the name", mock.initConverse(['chatBoxesFetched'], {}, async function (_converse) { const { domain } = _converse; await mock.waitUntilDiscoConfirmed( _converse, domain, [{ category: 'server', type: 'IM' }], [Strophe.NS.DISCO_ITEMS], ); const nick = 'max'; const muc_jid = 'the-lounge@muc.example.org'; const own_jid = _converse.session.get('jid'); const modal = await mock.openAddMUCModal(_converse); spyOn(_converse.ChatRoom.prototype, 'getDiscoInfo').and.callFake(() => Promise.resolve()); const name_input = modal.querySelector('input[name="chatroom"]'); name_input.value = 'The Lounge'; const nick_input = modal.querySelector('input[name="nickname"]'); nick_input.value = nick; modal.querySelector('form input[type="submit"]').click(); await mock.waitUntilDiscoConfirmed(_converse, domain, [], [], ['muc.example.org'], 'items'); await mock.waitUntilDiscoConfirmed(_converse, 'muc.example.org', [], [Strophe.NS.MUC]); await mock.waitForMUCDiscoInfo(_converse, muc_jid); await u.waitUntil(() => sizzle('.chatroom', _converse.el).filter(u.isVisible).length === 1); expect(_converse.chatboxes.models.map(m => m.get('id')).includes(muc_jid)).toBe(true); const muc = _converse.chatboxes.get(muc_jid); expect(muc.get('name')).toBe('The Lounge'); await mock.waitForMUCDiscoInfo(_converse, muc_jid); // Own presence which states that the room is locked and needs to // be configured (code 201) const presence = stx`<presence id="5025e055-036c-4bc5-a227-706e7e352053" to="${own_jid}" from="${muc_jid}/${nick}" xmlns="jabber:client"> <x xmlns="http://jabber.org/protocol/muc#user"> <item affiliation="owner" jid="${own_jid}" role="moderator"/> <status code="110"/> <status code="201"/> </x> </presence>`; _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) => sizzle(`query[xmlns="${Strophe.NS.MUC_OWNER}"]`, s).length).pop()); spyOn(muc, 'sendConfiguration').and.callThrough(); 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>`); _converse.api.connection.get()._dataRecv(mock.createRequest( stx`<iq xmlns="jabber:client" type="result" to="${own_jid}" from="${muc_jid}" id="${iq.getAttribute('id')}"> <query xmlns="http://jabber.org/protocol/muc#owner"> <x xmlns="jabber:x:data" type="form"> <title>Configuration for ${muc_jid}</title> <instructions>Complete and submit this form to configure the room.</instructions> <field var="FORM_TYPE" type="hidden"> <value>http://jabber.org/protocol/muc#roomconfig</value> </field> <field type="text-single" var="muc#roomconfig_roomname" label="Name"><value></value></field> <field type="text-single" var="muc#roomconfig_roomdesc" label="Description"><value/></field> <field type="boolean" var="muc#roomconfig_persistentroom" label="Make Room Persistent?"/> <field type="boolean" var="muc#roomconfig_publicroom" label="Make Room Publicly Searchable?"><value>1</value></field> <field type="boolean" var="muc#roomconfig_changesubject" label="Allow Occupants to Change Subject?"/> <field type="list-single" var="muc#roomconfig_whois" label="Who May Discover Real JIDs?"><option label="Moderators Only"> <value>moderators</value></option><option label="Anyone"><value>anyone</value></option> </field> <field label="Roles and Affiliations that May Retrieve Member List" type="list-multi" var="muc#roomconfig_getmemberlist"> <value>moderator</value> <value>participant</value> <value>visitor</value> </field> <field type="text-private" var="muc#roomconfig_roomsecret" label="Password"><value/></field> <field type="boolean" var="muc#roomconfig_moderatedroom" label="Make Room Moderated?"/> <field type="boolean" var="muc#roomconfig_membersonly" label="Make Room Members-Only?"/> <field type="text-single" var="muc#roomconfig_historylength" label="Maximum Number of History Messages Returned by Room"> <value>20</value></field> </x> </query> </iq>`)); await u.waitUntil(() => muc.sendConfiguration.calls.count() === 1); const sent_stanza = IQ_stanzas.filter(s => s.getAttribute('type') === 'set').pop(); expect(sizzle('field[var="muc#roomconfig_roomname"] value', sent_stanza).pop().textContent.trim()).toBe('The Lounge'); }) ); it("shows a validation error when only the name was specified and there's no default MUC service", mock.initConverse(['chatBoxesFetched'], {}, async function (_converse) { const { domain } = _converse; await mock.waitUntilDiscoConfirmed( _converse, domain, [{ category: 'server', type: 'IM' }], [], ); const nick = 'max'; const modal = await mock.openAddMUCModal(_converse); spyOn(_converse.ChatRoom.prototype, 'getDiscoInfo').and.callFake(() => Promise.resolve()); const name_input = modal.querySelector('input[name="chatroom"]'); name_input.value = 'The Lounge'; const nick_input = modal.querySelector('input[name="nickname"]'); nick_input.value = nick; modal.querySelector('form input[type="submit"]').click(); await u.waitUntil(() => name_input.classList.contains('error')); expect(name_input.classList.contains('is-invalid')).toBe(true); expect(modal.querySelector('.invalid-feedback')?.textContent).toBe( "No default groupchat service found. "+ "You'll need to specify the full address, for example room@conference.example.org" ); }) ); it("normalizes the MUC name when creating the corresponding JID", mock.initConverse(['chatBoxesFetched'], {muc_domain: 'montague.lit'}, async function (_converse) { const modal = await mock.openAddMUCModal(_converse); spyOn(_converse.ChatRoom.prototype, 'getDiscoInfo').and.callFake(() => Promise.resolve()); const name_input = modal.querySelector('input[name="chatroom"]'); name_input.value = 'Into the Äther: A Journey'; const nick_input = modal.querySelector('input[name="nickname"]'); nick_input.value = 'max'; modal.querySelector('form input[type="submit"]').click(); await mock.waitForMUCDiscoInfo(_converse, 'into-the-ather-a-journey@montague.lit'); await u.waitUntil(() => sizzle('.chatroom', _converse.el).filter(u.isVisible).length === 1); expect(_converse.chatboxes.models.map(m => m.get('id')).includes('into-the-ather-a-journey@montague.lit')).toBe(true); expect(modal.normalizeNode('Into the Äther: A Journey')).toBe('into-the-ather-a-journey'); expect(modal.normalizeNode(' A silly summer song ∷ ')).toBe('a-silly-summer-song'); }) ); it("applies a muc_roomid_policy", mock.initConverse(['chatBoxesFetched'], { muc_domain: 'montague.lit', muc_roomid_policy: /^[a-z0-9._-]{5,40}$/, muc_roomid_policy_hint: '<br><b>Policy for groupchat id:</b><br>- between 5 and 40 characters,<br>- lowercase from a to z (no special characters) or<br>- digits or<br>- dots (.) or<br>- underlines (_) or<br>- hyphens (-),<br>- no spaces<br>', }, async function (_converse) { const modal = await mock.openAddMUCModal(_converse); spyOn(_converse.ChatRoom.prototype, 'getDiscoInfo').and.callFake(() => Promise.resolve()); const name_input = modal.querySelector('input[name="chatroom"]'); name_input.value = 'lounge\ music@montague.lit'; const nick_input = modal.querySelector('input[name="nickname"]'); nick_input.value = 'max'; modal.querySelector('form input[type="submit"]').click(); await u.waitUntil(() => name_input.classList.contains('error')); expect(name_input.classList.contains('is-invalid')).toBe(true); expect(modal.querySelector('.invalid-feedback')?.textContent).toBe('Groupchat id is invalid.'); }) ); });