Stop using the Jasmine "done" callback

This commit is contained in:
JC Brand 2021-06-28 12:00:47 +02:00
parent 3e9f028bf4
commit 335a491e0d
68 changed files with 482 additions and 965 deletions

View File

@ -15,7 +15,7 @@ mock.initConverse = function (promise_names=[], settings=null, func) {
settings = null; settings = null;
} }
return async done => { return async () => {
if (_converse && _converse.api.connection.connected()) { if (_converse && _converse.api.connection.connected()) {
await _converse.api.user.logout(); await _converse.api.user.logout();
} }
@ -28,11 +28,10 @@ mock.initConverse = function (promise_names=[], settings=null, func) {
await initConverse(settings); await initConverse(settings);
await Promise.all((promise_names || []).map(_converse.api.waitUntil)); await Promise.all((promise_names || []).map(_converse.api.waitUntil));
try { try {
await func(done, _converse); await func(_converse);
} catch(e) { } catch(e) {
console.error(e); console.error(e);
fail(e); fail(e);
await done();
} }
} }
}; };

View File

@ -18,7 +18,7 @@ describe("XEP-0357 Push Notifications", function () {
'jid': 'push-5@client.example', 'jid': 'push-5@client.example',
'node': 'yxs32uqsflafdk3iuqo' 'node': 'yxs32uqsflafdk3iuqo'
}] }]
}, async function (done, _converse) { }, async function (_converse) {
const IQ_stanzas = _converse.connection.IQ_stanzas; const IQ_stanzas = _converse.connection.IQ_stanzas;
expect(_converse.session.get('push_enabled')).toBeFalsy(); expect(_converse.session.get('push_enabled')).toBeFalsy();
@ -46,7 +46,6 @@ describe("XEP-0357 Push Notifications", function () {
'id': stanza.getAttribute('id') 'id': stanza.getAttribute('id')
}))); })));
await u.waitUntil(() => _converse.session.get('push_enabled')); await u.waitUntil(() => _converse.session.get('push_enabled'));
done();
})); }));
it("can be enabled for a MUC domain", it("can be enabled for a MUC domain",
@ -57,7 +56,7 @@ describe("XEP-0357 Push Notifications", function () {
'jid': 'push-5@client.example', 'jid': 'push-5@client.example',
'node': 'yxs32uqsflafdk3iuqo' 'node': 'yxs32uqsflafdk3iuqo'
}] }]
}, async function (done, _converse) { }, async function (_converse) {
const IQ_stanzas = _converse.connection.IQ_stanzas; const IQ_stanzas = _converse.connection.IQ_stanzas;
await mock.waitUntilDiscoConfirmed( await mock.waitUntilDiscoConfirmed(
@ -103,7 +102,6 @@ describe("XEP-0357 Push Notifications", function () {
'id': iq.getAttribute('id') 'id': iq.getAttribute('id')
}))); })));
await u.waitUntil(() => _.includes(_converse.session.get('push_enabled'), 'chat.shakespeare.lit')); await u.waitUntil(() => _.includes(_converse.session.get('push_enabled'), 'chat.shakespeare.lit'));
done();
})); }));
it("can be disabled", it("can be disabled",
@ -114,7 +112,7 @@ describe("XEP-0357 Push Notifications", function () {
'node': 'yxs32uqsflafdk3iuqo', 'node': 'yxs32uqsflafdk3iuqo',
'disable': true 'disable': true
}] }]
}, async function (done, _converse) { }, async function (_converse) {
const IQ_stanzas = _converse.connection.IQ_stanzas; const IQ_stanzas = _converse.connection.IQ_stanzas;
expect(_converse.session.get('push_enabled')).toBeFalsy(); expect(_converse.session.get('push_enabled')).toBeFalsy();
@ -136,7 +134,6 @@ describe("XEP-0357 Push Notifications", function () {
'id': stanza.getAttribute('id') 'id': stanza.getAttribute('id')
}))); })));
await u.waitUntil(() => _converse.session.get('push_enabled')) await u.waitUntil(() => _converse.session.get('push_enabled'))
done();
})); }));
@ -147,7 +144,7 @@ describe("XEP-0357 Push Notifications", function () {
'node': 'yxs32uqsflafdk3iuqo', 'node': 'yxs32uqsflafdk3iuqo',
'secret': 'eruio234vzxc2kla-91' 'secret': 'eruio234vzxc2kla-91'
}] }]
}, async function (done, _converse) { }, async function (_converse) {
const IQ_stanzas = _converse.connection.IQ_stanzas; const IQ_stanzas = _converse.connection.IQ_stanzas;
expect(_converse.session.get('push_enabled')).toBeFalsy(); expect(_converse.session.get('push_enabled')).toBeFalsy();
@ -179,6 +176,5 @@ describe("XEP-0357 Push Notifications", function () {
'id': stanza.getAttribute('id') 'id': stanza.getAttribute('id')
}))); })));
await u.waitUntil(() => _converse.session.get('push_enabled')) await u.waitUntil(() => _converse.session.get('push_enabled'))
done();
})); }));
}); });

View File

@ -5,7 +5,7 @@ const u = converse.env.utils;
describe("The User Details Modal", function () { describe("The User Details Modal", function () {
it("can be used to remove a contact", it("can be used to remove a contact",
mock.initConverse(['chatBoxesFetched'], {}, async function (done, _converse) { mock.initConverse(['chatBoxesFetched'], {}, async function (_converse) {
await mock.waitForRoster(_converse, 'current', 1); await mock.waitForRoster(_converse, 'current', 1);
_converse.api.trigger('rosterContactsFetched'); _converse.api.trigger('rosterContactsFetched');
@ -30,11 +30,10 @@ describe("The User Details Modal", function () {
show_modal_button.click(); show_modal_button.click();
remove_contact_button = modal.el.querySelector('button.remove-contact'); remove_contact_button = modal.el.querySelector('button.remove-contact');
expect(remove_contact_button === null).toBeTruthy(); expect(remove_contact_button === null).toBeTruthy();
done();
})); }));
it("shows an alert when an error happened while removing the contact", it("shows an alert when an error happened while removing the contact",
mock.initConverse([], {}, async function (done, _converse) { mock.initConverse([], {}, async function (_converse) {
await mock.waitForRoster(_converse, 'current', 1); await mock.waitForRoster(_converse, 'current', 1);
_converse.api.trigger('rosterContactsFetched'); _converse.api.trigger('rosterContactsFetched');
@ -71,6 +70,5 @@ describe("The User Details Modal", function () {
remove_contact_button = modal.el.querySelector('button.remove-contact'); remove_contact_button = modal.el.querySelector('button.remove-contact');
expect(u.isVisible(remove_contact_button)).toBeTruthy(); expect(u.isVisible(remove_contact_button)).toBeTruthy();
done();
})); }));
}); });

View File

@ -9,7 +9,7 @@ describe("A sent presence stanza", function () {
afterEach(() => (jasmine.DEFAULT_TIMEOUT_INTERVAL = original_timeout)); afterEach(() => (jasmine.DEFAULT_TIMEOUT_INTERVAL = original_timeout));
it("includes a entity capabilities node", it("includes a entity capabilities node",
mock.initConverse([], {}, async (done, _converse) => { mock.initConverse([], {}, async (_converse) => {
await mock.waitForRoster(_converse, 'current', 0); await mock.waitForRoster(_converse, 'current', 0);
_converse.api.disco.own.identities.clear(); _converse.api.disco.own.identities.clear();
@ -27,10 +27,9 @@ describe("A sent presence stanza", function () {
`<priority>0</priority>`+ `<priority>0</priority>`+
`<c hash="sha-1" node="https://conversejs.org" ver="QgayPKawpkPSDYmwT/WM94uAlu0=" xmlns="http://jabber.org/protocol/caps"/>`+ `<c hash="sha-1" node="https://conversejs.org" ver="QgayPKawpkPSDYmwT/WM94uAlu0=" xmlns="http://jabber.org/protocol/caps"/>`+
`</presence>`) `</presence>`)
done();
})); }));
it("has a given priority", mock.initConverse(['statusInitialized'], {}, async (done, _converse) => { it("has a given priority", mock.initConverse(['statusInitialized'], {}, async (_converse) => {
const { api } = _converse; const { api } = _converse;
let pres = await _converse.xmppstatus.constructPresence('online', null, 'Hello world'); let pres = await _converse.xmppstatus.constructPresence('online', null, 'Hello world');
expect(pres.toLocaleString()).toBe( expect(pres.toLocaleString()).toBe(
@ -62,6 +61,5 @@ describe("A sent presence stanza", function () {
`<c hash="sha-1" node="https://conversejs.org" ver="PxXfr6uz8ClMWIga0OB/MhKNH/M=" xmlns="http://jabber.org/protocol/caps"/>`+ `<c hash="sha-1" node="https://conversejs.org" ver="PxXfr6uz8ClMWIga0OB/MhKNH/M=" xmlns="http://jabber.org/protocol/caps"/>`+
`</presence>` `</presence>`
); );
done();
})); }));
}); });

View File

@ -4,7 +4,7 @@ describe("The \"chats\" API", function() {
it("has a method 'get' which returns the promise that resolves to a chat model", mock.initConverse( it("has a method 'get' which returns the promise that resolves to a chat model", mock.initConverse(
['rosterInitialized', 'chatBoxesInitialized'], {}, ['rosterInitialized', 'chatBoxesInitialized'], {},
async (done, _converse) => { async (_converse) => {
const u = converse.env.utils; const u = converse.env.utils;
@ -34,11 +34,10 @@ describe("The \"chats\" API", function() {
expect(Array.isArray(list)).toBeTruthy(); expect(Array.isArray(list)).toBeTruthy();
expect(list[0].get('box_id')).toBe(`box-${jid}`); expect(list[0].get('box_id')).toBe(`box-${jid}`);
expect(list[1].get('box_id')).toBe(`box-${jid2}`); expect(list[1].get('box_id')).toBe(`box-${jid2}`);
done();
})); }));
it("has a method 'open' which opens and returns a promise that resolves to a chat model", mock.initConverse( it("has a method 'open' which opens and returns a promise that resolves to a chat model", mock.initConverse(
['chatBoxesInitialized'], {}, async (done, _converse) => { ['chatBoxesInitialized'], {}, async (_converse) => {
await mock.openControlBox(_converse); await mock.openControlBox(_converse);
await mock.waitForRoster(_converse, 'current', 2); await mock.waitForRoster(_converse, 'current', 2);
@ -62,6 +61,5 @@ describe("The \"chats\" API", function() {
expect(Array.isArray(list)).toBeTruthy(); expect(Array.isArray(list)).toBeTruthy();
expect(list[0].get('box_id')).toBe(`box-${jid}`); expect(list[0].get('box_id')).toBe(`box-${jid}`);
expect(list[1].get('box_id')).toBe(`box-${jid2}`); expect(list[1].get('box_id')).toBe(`box-${jid2}`);
done();
})); }));
}); });

View File

@ -7,7 +7,7 @@ describe("Service Discovery", function () {
it("stores the features it receives", it("stores the features it receives",
mock.initConverse( mock.initConverse(
['discoInitialized'], {}, ['discoInitialized'], {},
async function (done, _converse) { async function (_converse) {
const { u, $iq } = converse.env; const { u, $iq } = converse.env;
const IQ_stanzas = _converse.connection.IQ_stanzas; const IQ_stanzas = _converse.connection.IQ_stanzas;
@ -161,7 +161,6 @@ describe("Service Discovery", function () {
expect(entities.get(_converse.domain).items.pluck('jid').includes('words.shakespeare.lit')).toBeTruthy(); expect(entities.get(_converse.domain).items.pluck('jid').includes('words.shakespeare.lit')).toBeTruthy();
expect(entities.get(_converse.domain).identities.where({'category': 'conference'}).length).toBe(1); expect(entities.get(_converse.domain).identities.where({'category': 'conference'}).length).toBe(1);
expect(entities.get(_converse.domain).identities.where({'category': 'directory'}).length).toBe(1); expect(entities.get(_converse.domain).identities.where({'category': 'directory'}).length).toBe(1);
done();
})); }));
}); });
@ -169,7 +168,7 @@ describe("Service Discovery", function () {
it("emits the serviceDiscovered event", it("emits the serviceDiscovered event",
mock.initConverse( mock.initConverse(
['discoInitialized'], {}, ['discoInitialized'], {},
function (done, _converse) { function (_converse) {
const { Strophe } = converse.env; const { Strophe } = converse.env;
spyOn(_converse.api, "trigger").and.callThrough(); spyOn(_converse.api, "trigger").and.callThrough();
@ -178,7 +177,6 @@ describe("Service Discovery", function () {
const last_call = _converse.api.trigger.calls.all().pop(); const last_call = _converse.api.trigger.calls.all().pop();
expect(last_call.args[0]).toBe('serviceDiscovered'); expect(last_call.args[0]).toBe('serviceDiscovered');
expect(last_call.args[1].get('var')).toBe(Strophe.NS.MAM); expect(last_call.args[1].get('var')).toBe(Strophe.NS.MAM);
done();
})); }));
}); });
}); });

View File

@ -112,7 +112,7 @@ export function populateStreamFeatures () {
// Strophe.js sets the <stream:features> element on the // Strophe.js sets the <stream:features> element on the
// Strophe.Connection instance (_converse.connection). // Strophe.Connection instance (_converse.connection).
// //
// Once this is done, we populate the _converse.stream_features collection // Once this is we populate the _converse.stream_features collection
// and trigger streamFeaturesAdded. // and trigger streamFeaturesAdded.
initStreamFeatures(); initStreamFeatures();
Array.from(_converse.connection.features.childNodes).forEach(feature => { Array.from(_converse.connection.features.childNodes).forEach(feature => {

View File

@ -6,7 +6,7 @@ const Strophe = converse.env.Strophe;
describe('The MUC Affiliations API', function () { describe('The MUC Affiliations API', function () {
it('can be used to set affiliations in MUCs without having to join them first', it('can be used to set affiliations in MUCs without having to join them first',
mock.initConverse([], {}, async function (done, _converse) { mock.initConverse([], {}, async function (_converse) {
const { api } = _converse; const { api } = _converse;
const user_jid = 'annoyingguy@montague.lit'; const user_jid = 'annoyingguy@montague.lit';
const muc_jid = 'lounge@montague.lit'; const muc_jid = 'lounge@montague.lit';
@ -36,7 +36,6 @@ describe('The MUC Affiliations API', function () {
`</query>` + `</query>` +
`</iq>`); `</iq>`);
done();
}) })
); );
}); });

View File

@ -8,7 +8,7 @@ describe("A Groupchat Message", function () {
mock.initConverse( mock.initConverse(
['chatBoxesFetched'], ['chatBoxesFetched'],
{'prune_messages_above': 3}, {'prune_messages_above': 3},
async function (done, _converse) { async function (_converse) {
const muc_jid = 'lounge@montague.lit'; const muc_jid = 'lounge@montague.lit';
const model = await mock.openAndEnterChatRoom(_converse, muc_jid, 'romeo'); const model = await mock.openAndEnterChatRoom(_converse, muc_jid, 'romeo');
@ -47,6 +47,5 @@ describe("A Groupchat Message", function () {
_converse.connection._dataRecv(mock.createRequest(stanza)); _converse.connection._dataRecv(mock.createRequest(stanza));
await u.waitUntil(() => model.messages.length === 4); await u.waitUntil(() => model.messages.length === 4);
await u.waitUntil(() => model.messages.length === 3, 550); await u.waitUntil(() => model.messages.length === 3, 550);
done();
})); }));
}); });

View File

@ -8,7 +8,7 @@ describe("Chatrooms", function () {
it("allows you to automatically register your nickname when joining a room", it("allows you to automatically register your nickname when joining a room",
mock.initConverse(['chatBoxesFetched'], {'auto_register_muc_nickname': true}, mock.initConverse(['chatBoxesFetched'], {'auto_register_muc_nickname': true},
async function (done, _converse) { async function (_converse) {
const muc_jid = 'coven@chat.shakespeare.lit'; const muc_jid = 'coven@chat.shakespeare.lit';
const room = await mock.openAndEnterChatRoom(_converse, muc_jid, 'romeo'); const room = await mock.openAndEnterChatRoom(_converse, muc_jid, 'romeo');
@ -47,12 +47,11 @@ describe("Chatrooms", function () {
`</x>`+ `</x>`+
`</query>`+ `</query>`+
`</iq>`); `</iq>`);
done();
})); }));
it("allows you to automatically deregister your nickname when closing a room", it("allows you to automatically deregister your nickname when closing a room",
mock.initConverse(['chatBoxesFetched'], {'auto_register_muc_nickname': 'unregister'}, mock.initConverse(['chatBoxesFetched'], {'auto_register_muc_nickname': 'unregister'},
async function (done, _converse) { async function (_converse) {
const muc_jid = 'coven@chat.shakespeare.lit'; const muc_jid = 'coven@chat.shakespeare.lit';
const room = await mock.openAndEnterChatRoom(_converse, muc_jid, 'romeo'); const room = await mock.openAndEnterChatRoom(_converse, muc_jid, 'romeo');
@ -96,7 +95,6 @@ describe("Chatrooms", function () {
}).c('query', {'xmlns': 'jabber:iq:register'}); }).c('query', {'xmlns': 'jabber:iq:register'});
_converse.connection._dataRecv(mock.createRequest(result)); _converse.connection._dataRecv(mock.createRequest(result));
done();
})); }));
}); });
}); });

View File

@ -9,7 +9,7 @@ describe("XMPP Ping", function () {
describe("An IQ stanza", function () { describe("An IQ stanza", function () {
it("is returned when converse.js gets pinged", it("is returned when converse.js gets pinged",
mock.initConverse(['statusInitialized'], {}, (done, _converse) => { mock.initConverse(['statusInitialized'], {}, (_converse) => {
const ping = u.toStanza(` const ping = u.toStanza(`
<iq from="${_converse.domain}" <iq from="${_converse.domain}"
to="${_converse.jid}" id="s2c1" type="get"> to="${_converse.jid}" id="s2c1" type="get">
@ -19,17 +19,15 @@ describe("XMPP Ping", function () {
const sent_stanza = _converse.connection.IQ_stanzas.pop(); const sent_stanza = _converse.connection.IQ_stanzas.pop();
expect(Strophe.serialize(sent_stanza)).toBe( expect(Strophe.serialize(sent_stanza)).toBe(
`<iq id="s2c1" to="${_converse.domain}" type="result" xmlns="jabber:client"/>`); `<iq id="s2c1" to="${_converse.domain}" type="result" xmlns="jabber:client"/>`);
done();
})); }));
it("is sent out when converse.js pings a server", mock.initConverse((done, _converse) => { it("is sent out when converse.js pings a server", mock.initConverse((_converse) => {
_converse.api.ping(); _converse.api.ping();
const sent_stanza = _converse.connection.IQ_stanzas.pop(); const sent_stanza = _converse.connection.IQ_stanzas.pop();
expect(Strophe.serialize(sent_stanza)).toBe( expect(Strophe.serialize(sent_stanza)).toBe(
`<iq id="${sent_stanza.getAttribute('id')}" to="montague.lit" type="get" xmlns="jabber:client">`+ `<iq id="${sent_stanza.getAttribute('id')}" to="montague.lit" type="get" xmlns="jabber:client">`+
`<ping xmlns="urn:xmpp:ping"/>`+ `<ping xmlns="urn:xmpp:ping"/>`+
`</iq>`); `</iq>`);
done();
})); }));
}); });
}); });

View File

@ -5,7 +5,7 @@
describe("A received presence stanza", function () { describe("A received presence stanza", function () {
it("has its priority taken into account", it("has its priority taken into account",
mock.initConverse([], {}, async (done, _converse) => { mock.initConverse([], {}, async (_converse) => {
const u = converse.env.utils; const u = converse.env.utils;
mock.openControlBox(_converse); mock.openControlBox(_converse);
@ -177,6 +177,5 @@ describe("A received presence stanza", function () {
_converse.connection._dataRecv(mock.createRequest(stanza)); _converse.connection._dataRecv(mock.createRequest(stanza));
expect(_converse.roster.get(contact_jid).presence.get('show')).toBe('offline'); expect(_converse.roster.get(contact_jid).presence.get('show')).toBe('offline');
expect(contact.presence.resources.length).toBe(0); expect(contact.presence.resources.length).toBe(0);
done();
})); }));
}); });

View File

@ -16,7 +16,7 @@ describe("XEP-0198 Stream Management", function () {
'show_controlbox_by_default': true, 'show_controlbox_by_default': true,
'smacks_max_unacked_stanzas': 2 'smacks_max_unacked_stanzas': 2
}, },
async function (done, _converse) { async function (_converse) {
await _converse.api.user.login('romeo@montague.lit/orchard', 'secret'); await _converse.api.user.login('romeo@montague.lit/orchard', 'secret');
const sent_stanzas = _converse.connection.sent_stanzas; const sent_stanzas = _converse.connection.sent_stanzas;
@ -119,7 +119,6 @@ describe("XEP-0198 Stream Management", function () {
expect(Strophe.serialize(iq)).toBe(`<iq id="${iq.getAttribute('id')}" type="get" xmlns="jabber:client"><query xmlns="jabber:iq:roster"/></iq>`); expect(Strophe.serialize(iq)).toBe(`<iq id="${iq.getAttribute('id')}" type="get" xmlns="jabber:client"><query xmlns="jabber:iq:roster"/></iq>`);
expect(IQ_stanzas.filter(iq => sizzle('query[xmlns="jabber:iq:roster"]', iq).pop()).length).toBe(0); expect(IQ_stanzas.filter(iq => sizzle('query[xmlns="jabber:iq:roster"]', iq).pop()).length).toBe(0);
done();
})); }));
@ -131,7 +130,7 @@ describe("XEP-0198 Stream Management", function () {
'show_controlbox_by_default': true, 'show_controlbox_by_default': true,
'smacks_max_unacked_stanzas': 2 'smacks_max_unacked_stanzas': 2
}, },
async function (done, _converse) { async function (_converse) {
await _converse.api.user.login('romeo@montague.lit/orchard', 'secret'); await _converse.api.user.login('romeo@montague.lit/orchard', 'secret');
const sent_stanzas = _converse.connection.sent_stanzas; const sent_stanzas = _converse.connection.sent_stanzas;
@ -173,7 +172,6 @@ describe("XEP-0198 Stream Management", function () {
// Check that the roster gets fetched // Check that the roster gets fetched
await mock.waitForRoster(_converse, 'current', 1); await mock.waitForRoster(_converse, 'current', 1);
await new Promise(resolve => _converse.api.listen.once('reconnected', resolve)); await new Promise(resolve => _converse.api.listen.once('reconnected', resolve));
done();
})); }));
@ -187,7 +185,7 @@ describe("XEP-0198 Stream Management", function () {
'show_controlbox_by_default': true, 'show_controlbox_by_default': true,
'smacks_max_unacked_stanzas': 2 'smacks_max_unacked_stanzas': 2
}, },
async function (done, _converse) { async function (_converse) {
const key = "converse-test-session/converse.session-romeo@montague.lit-converse.session-romeo@montague.lit"; const key = "converse-test-session/converse.session-romeo@montague.lit-converse.session-romeo@montague.lit";
sessionStorage.setItem( sessionStorage.setItem(
@ -266,6 +264,5 @@ describe("XEP-0198 Stream Management", function () {
await u.waitUntil(() => muc.messages.length); await u.waitUntil(() => muc.messages.length);
expect(muc.messages.at(0).get('message')).toBe('First message') expect(muc.messages.at(0).get('message')).toBe('First message')
delete _converse.no_connection_on_bind; delete _converse.no_connection_on_bind;
done();
})); }));
}); });

View File

@ -5,7 +5,7 @@ const u = converse.env.utils;
describe("The XMPPStatus model", function () { describe("The XMPPStatus model", function () {
it("won't send <show>online</show> when setting a custom status message", it("won't send <show>online</show> when setting a custom status message",
mock.initConverse(async (done, _converse) => { mock.initConverse(async (_converse) => {
const sent_stanzas = _converse.connection.sent_stanzas; const sent_stanzas = _converse.connection.sent_stanzas;
await _converse.api.user.status.set('online'); await _converse.api.user.status.set('online');
@ -18,6 +18,5 @@ describe("The XMPPStatus model", function () {
expect(stanza.querySelectorAll('show').length).toBe(0); expect(stanza.querySelectorAll('show').length).toBe(0);
expect(stanza.querySelectorAll('priority').length).toBe(1); expect(stanza.querySelectorAll('priority').length).toBe(1);
expect(stanza.querySelector('priority').textContent).toBe('0'); expect(stanza.querySelector('priority').textContent).toBe('0');
done();
})); }));
}); });

View File

@ -6,7 +6,7 @@ describe("Converse", function() {
describe("Authentication", function () { describe("Authentication", function () {
it("needs either a bosh_service_url a websocket_url or both", mock.initConverse(async (done, _converse) => { it("needs either a bosh_service_url a websocket_url or both", mock.initConverse(async (_converse) => {
const url = _converse.bosh_service_url; const url = _converse.bosh_service_url;
const connection = _converse.connection; const connection = _converse.connection;
_converse.api.settings.set('bosh_service_url', undefined); _converse.api.settings.set('bosh_service_url', undefined);
@ -17,7 +17,6 @@ describe("Converse", function() {
_converse.api.settings.set('bosh_service_url', url); _converse.api.settings.set('bosh_service_url', url);
_converse.connection = connection; _converse.connection = connection;
expect(e.message).toBe("initConnection: you must supply a value for either the bosh_service_url or websocket_url or both."); expect(e.message).toBe("initConnection: you must supply a value for either the bosh_service_url or websocket_url or both.");
done();
} }
})); }));
}); });
@ -25,7 +24,7 @@ describe("Converse", function() {
describe("A chat state indication", function () { describe("A chat state indication", function () {
it("are sent out when the client becomes or stops being idle", it("are sent out when the client becomes or stops being idle",
mock.initConverse(['discoInitialized'], {}, (done, _converse) => { mock.initConverse(['discoInitialized'], {}, (_converse) => {
spyOn(_converse, 'sendCSI').and.callThrough(); spyOn(_converse, 'sendCSI').and.callThrough();
let sent_stanza; let sent_stanza;
@ -47,14 +46,13 @@ describe("Converse", function() {
_converse.onUserActivity(); _converse.onUserActivity();
expect(_converse.sendCSI).toHaveBeenCalledWith('active'); expect(_converse.sendCSI).toHaveBeenCalledWith('active');
expect(Strophe.serialize(sent_stanza)).toBe('<active xmlns="urn:xmpp:csi:0"/>'); expect(Strophe.serialize(sent_stanza)).toBe('<active xmlns="urn:xmpp:csi:0"/>');
done();
})); }));
}); });
describe("Automatic status change", function () { describe("Automatic status change", function () {
it("happens when the client is idle for long enough", it("happens when the client is idle for long enough",
mock.initConverse(['initialized'], {}, async (done, _converse) => { mock.initConverse(['initialized'], {}, async (_converse) => {
let i = 0; let i = 0;
// Usually initialized by registerIntervalHandler // Usually initialized by registerIntervalHandler
_converse.idle_seconds = 0; _converse.idle_seconds = 0;
@ -120,7 +118,6 @@ describe("Converse", function() {
_converse.onUserActivity(); _converse.onUserActivity();
expect(await _converse.api.user.status.get()).toBe('dnd'); expect(await _converse.api.user.status.get()).toBe('dnd');
expect(_converse.auto_changed_status).toBe(false); expect(_converse.auto_changed_status).toBe(false);
done();
})); }));
}); });
@ -129,15 +126,14 @@ describe("Converse", function() {
describe("The \"status\" API", function () { describe("The \"status\" API", function () {
it("has a method for getting the user's availability", it("has a method for getting the user's availability",
mock.initConverse(['statusInitialized'], {}, async(done, _converse) => { mock.initConverse(['statusInitialized'], {}, async(_converse) => {
_converse.xmppstatus.set('status', 'online'); _converse.xmppstatus.set('status', 'online');
expect(await _converse.api.user.status.get()).toBe('online'); expect(await _converse.api.user.status.get()).toBe('online');
_converse.xmppstatus.set('status', 'dnd'); _converse.xmppstatus.set('status', 'dnd');
expect(await _converse.api.user.status.get()).toBe('dnd'); expect(await _converse.api.user.status.get()).toBe('dnd');
done();
})); }));
it("has a method for setting the user's availability", mock.initConverse(async (done, _converse) => { it("has a method for setting the user's availability", mock.initConverse(async (_converse) => {
await _converse.api.user.status.set('away'); await _converse.api.user.status.set('away');
expect(await _converse.xmppstatus.get('status')).toBe('away'); expect(await _converse.xmppstatus.get('status')).toBe('away');
await _converse.api.user.status.set('dnd'); await _converse.api.user.status.set('dnd');
@ -149,39 +145,35 @@ describe("Converse", function() {
const promise = _converse.api.user.status.set('invalid') const promise = _converse.api.user.status.set('invalid')
promise.catch(e => { promise.catch(e => {
expect(e.message).toBe('Invalid availability value. See https://xmpp.org/rfcs/rfc3921.html#rfc.section.2.2.2.1'); expect(e.message).toBe('Invalid availability value. See https://xmpp.org/rfcs/rfc3921.html#rfc.section.2.2.2.1');
done();
}); });
})); }));
it("allows setting the status message as well", mock.initConverse(async (done, _converse) => { it("allows setting the status message as well", mock.initConverse(async (_converse) => {
await _converse.api.user.status.set('away', "I'm in a meeting"); await _converse.api.user.status.set('away', "I'm in a meeting");
expect(_converse.xmppstatus.get('status')).toBe('away'); expect(_converse.xmppstatus.get('status')).toBe('away');
expect(_converse.xmppstatus.get('status_message')).toBe("I'm in a meeting"); expect(_converse.xmppstatus.get('status_message')).toBe("I'm in a meeting");
done();
})); }));
it("has a method for getting the user's status message", it("has a method for getting the user's status message",
mock.initConverse(['statusInitialized'], {}, async (done, _converse) => { mock.initConverse(['statusInitialized'], {}, async (_converse) => {
await _converse.xmppstatus.set('status_message', undefined); await _converse.xmppstatus.set('status_message', undefined);
expect(await _converse.api.user.status.message.get()).toBe(undefined); expect(await _converse.api.user.status.message.get()).toBe(undefined);
await _converse.xmppstatus.set('status_message', "I'm in a meeting"); await _converse.xmppstatus.set('status_message', "I'm in a meeting");
expect(await _converse.api.user.status.message.get()).toBe("I'm in a meeting"); expect(await _converse.api.user.status.message.get()).toBe("I'm in a meeting");
done();
})); }));
it("has a method for setting the user's status message", it("has a method for setting the user's status message",
mock.initConverse(['statusInitialized'], {}, async (done, _converse) => { mock.initConverse(['statusInitialized'], {}, async (_converse) => {
_converse.xmppstatus.set('status_message', undefined); _converse.xmppstatus.set('status_message', undefined);
await _converse.api.user.status.message.set("I'm in a meeting"); await _converse.api.user.status.message.set("I'm in a meeting");
expect(_converse.xmppstatus.get('status_message')).toBe("I'm in a meeting"); expect(_converse.xmppstatus.get('status_message')).toBe("I'm in a meeting");
done();
})); }));
}); });
}); });
describe("The \"tokens\" API", function () { describe("The \"tokens\" API", function () {
it("has a method for retrieving the next RID", mock.initConverse((done, _converse) => { it("has a method for retrieving the next RID", mock.initConverse((_converse) => {
mock.createContacts(_converse, 'current'); mock.createContacts(_converse, 'current');
const old_connection = _converse.connection; const old_connection = _converse.connection;
_converse.connection._proto.rid = '1234'; _converse.connection._proto.rid = '1234';
@ -190,10 +182,9 @@ describe("Converse", function() {
expect(_converse.api.tokens.get('rid')).toBe(null); expect(_converse.api.tokens.get('rid')).toBe(null);
// Restore the connection // Restore the connection
_converse.connection = old_connection; _converse.connection = old_connection;
done();
})); }));
it("has a method for retrieving the SID", mock.initConverse((done, _converse) => { it("has a method for retrieving the SID", mock.initConverse((_converse) => {
mock.createContacts(_converse, 'current'); mock.createContacts(_converse, 'current');
const old_connection = _converse.connection; const old_connection = _converse.connection;
_converse.connection._proto.sid = '1234'; _converse.connection._proto.sid = '1234';
@ -202,14 +193,13 @@ describe("Converse", function() {
expect(_converse.api.tokens.get('sid')).toBe(null); expect(_converse.api.tokens.get('sid')).toBe(null);
// Restore the connection // Restore the connection
_converse.connection = old_connection; _converse.connection = old_connection;
done();
})); }));
}); });
describe("The \"contacts\" API", function () { describe("The \"contacts\" API", function () {
it("has a method 'get' which returns wrapped contacts", it("has a method 'get' which returns wrapped contacts",
mock.initConverse([], {}, async function (done, _converse) { mock.initConverse([], {}, async function (_converse) {
await mock.waitForRoster(_converse, 'current'); await mock.waitForRoster(_converse, 'current');
let contact = await _converse.api.contacts.get('non-existing@jabber.org'); let contact = await _converse.api.contacts.get('non-existing@jabber.org');
@ -228,11 +218,10 @@ describe("Converse", function() {
// Check that all JIDs are returned if you call without any parameters // Check that all JIDs are returned if you call without any parameters
list = await _converse.api.contacts.get(); list = await _converse.api.contacts.get();
expect(list.length).toBe(mock.cur_names.length); expect(list.length).toBe(mock.cur_names.length);
done();
})); }));
it("has a method 'add' with which contacts can be added", it("has a method 'add' with which contacts can be added",
mock.initConverse(['rosterInitialized'], {}, async (done, _converse) => { mock.initConverse(['rosterInitialized'], {}, async (_converse) => {
await mock.waitForRoster(_converse, 'current', 0); await mock.waitForRoster(_converse, 'current', 0);
try { try {
@ -251,13 +240,12 @@ describe("Converse", function() {
spyOn(_converse.roster, 'addAndSubscribe'); spyOn(_converse.roster, 'addAndSubscribe');
await _converse.api.contacts.add("newcontact@example.org"); await _converse.api.contacts.add("newcontact@example.org");
expect(_converse.roster.addAndSubscribe).toHaveBeenCalled(); expect(_converse.roster.addAndSubscribe).toHaveBeenCalled();
done();
})); }));
}); });
describe("The \"settings\" API", function() { describe("The \"settings\" API", function() {
it("has methods 'get' and 'set' to set configuration settings", it("has methods 'get' and 'set' to set configuration settings",
mock.initConverse(null, {'play_sounds': true}, (done, _converse) => { mock.initConverse(null, {'play_sounds': true}, (_converse) => {
expect(Object.keys(_converse.api.settings)).toEqual(["extend", "update", "get", "set"]); expect(Object.keys(_converse.api.settings)).toEqual(["extend", "update", "get", "set"]);
expect(_converse.api.settings.get("play_sounds")).toBe(true); expect(_converse.api.settings.get("play_sounds")).toBe(true);
@ -269,11 +257,10 @@ describe("Converse", function() {
expect(typeof _converse.api.settings.get("non_existing")).toBe("undefined"); expect(typeof _converse.api.settings.get("non_existing")).toBe("undefined");
_converse.api.settings.set("non_existing", true); _converse.api.settings.set("non_existing", true);
expect(typeof _converse.api.settings.get("non_existing")).toBe("undefined"); expect(typeof _converse.api.settings.get("non_existing")).toBe("undefined");
done();
})); }));
it("extended via settings.extend don't override settings passed in via converse.initialize", it("extended via settings.extend don't override settings passed in via converse.initialize",
mock.initConverse([], {'emoji_categories': {"travel": ":rocket:"}}, (done, _converse) => { mock.initConverse([], {'emoji_categories': {"travel": ":rocket:"}}, (_converse) => {
expect(_converse.api.settings.get('emoji_categories')?.travel).toBe(':rocket:'); expect(_converse.api.settings.get('emoji_categories')?.travel).toBe(':rocket:');
@ -283,7 +270,6 @@ describe("Converse", function() {
expect(_converse.api.settings.get('emoji_categories')?.travel).toBe(':rocket:'); expect(_converse.api.settings.get('emoji_categories')?.travel).toBe(':rocket:');
expect(_converse.api.settings.get('emoji_categories')?.food).toBe(undefined); expect(_converse.api.settings.get('emoji_categories')?.food).toBe(undefined);
done();
})); }));
it("only overrides the passed in properties", it("only overrides the passed in properties",
@ -292,7 +278,7 @@ describe("Converse", function() {
'root': document.createElement('div').attachShadow({ 'mode': 'open' }), 'root': document.createElement('div').attachShadow({ 'mode': 'open' }),
'emoji_categories': { 'travel': ':rocket:' }, 'emoji_categories': { 'travel': ':rocket:' },
}, },
(done, _converse) => { (_converse) => {
expect(_converse.api.settings.get('emoji_categories')?.travel).toBe(':rocket:'); expect(_converse.api.settings.get('emoji_categories')?.travel).toBe(':rocket:');
// Test that the extend command doesn't override user-provided site // Test that the extend command doesn't override user-provided site
@ -303,7 +289,6 @@ describe("Converse", function() {
expect(_converse.api.settings.get('emoji_categories').travel).toBe(':rocket:'); expect(_converse.api.settings.get('emoji_categories').travel).toBe(':rocket:');
expect(_converse.api.settings.get('emoji_categories').food).toBe(undefined); expect(_converse.api.settings.get('emoji_categories').food).toBe(undefined);
done();
} }
) )
); );
@ -311,7 +296,7 @@ describe("Converse", function() {
}); });
describe("The \"plugins\" API", function() { describe("The \"plugins\" API", function() {
it("only has a method 'add' for registering plugins", mock.initConverse((done, _converse) => { it("only has a method 'add' for registering plugins", mock.initConverse((_converse) => {
expect(Object.keys(converse.plugins)).toEqual(["add"]); expect(Object.keys(converse.plugins)).toEqual(["add"]);
// Cheating a little bit. We clear the plugins to test more easily. // Cheating a little bit. We clear the plugins to test more easily.
const _old_plugins = _converse.pluggable.plugins; const _old_plugins = _converse.pluggable.plugins;
@ -321,17 +306,15 @@ describe("Converse", function() {
converse.plugins.add('plugin2', {}); converse.plugins.add('plugin2', {});
expect(Object.keys(_converse.pluggable.plugins)).toEqual(['plugin1', 'plugin2']); expect(Object.keys(_converse.pluggable.plugins)).toEqual(['plugin1', 'plugin2']);
_converse.pluggable.plugins = _old_plugins; _converse.pluggable.plugins = _old_plugins;
done();
})); }));
describe("The \"plugins.add\" method", function() { describe("The \"plugins.add\" method", function() {
it("throws an error when multiple plugins attempt to register with the same name", it("throws an error when multiple plugins attempt to register with the same name",
mock.initConverse((done, _converse) => { // eslint-disable-line no-unused-vars mock.initConverse((_converse) => { // eslint-disable-line no-unused-vars
converse.plugins.add('myplugin', {}); converse.plugins.add('myplugin', {});
const error = new TypeError('Error: plugin with name "myplugin" has already been registered!'); const error = new TypeError('Error: plugin with name "myplugin" has already been registered!');
expect(() => converse.plugins.add('myplugin', {})).toThrow(error); expect(() => converse.plugins.add('myplugin', {})).toThrow(error);
done();
})); }));
}); });
}); });

View File

@ -2,7 +2,7 @@
describe("The _converse Event Emitter", function() { describe("The _converse Event Emitter", function() {
it("allows you to subscribe to emitted events", mock.initConverse((done, _converse) => { it("allows you to subscribe to emitted events", mock.initConverse((_converse) => {
this.callback = function () {}; this.callback = function () {};
spyOn(this, 'callback'); spyOn(this, 'callback');
_converse.on('connected', this.callback); _converse.on('connected', this.callback);
@ -12,10 +12,9 @@ describe("The _converse Event Emitter", function() {
expect(this.callback.calls.count(), 2); expect(this.callback.calls.count(), 2);
_converse.api.trigger('connected'); _converse.api.trigger('connected');
expect(this.callback.calls.count(), 3); expect(this.callback.calls.count(), 3);
done();
})); }));
it("allows you to listen once for an emitted event", mock.initConverse((done, _converse) => { it("allows you to listen once for an emitted event", mock.initConverse((_converse) => {
this.callback = function () {}; this.callback = function () {};
spyOn(this, 'callback'); spyOn(this, 'callback');
_converse.once('connected', this.callback); _converse.once('connected', this.callback);
@ -25,10 +24,9 @@ describe("The _converse Event Emitter", function() {
expect(this.callback.calls.count(), 1); expect(this.callback.calls.count(), 1);
_converse.api.trigger('connected'); _converse.api.trigger('connected');
expect(this.callback.calls.count(), 1); expect(this.callback.calls.count(), 1);
done();
})); }));
it("allows you to stop listening or subscribing to an event", mock.initConverse((done, _converse) => { it("allows you to stop listening or subscribing to an event", mock.initConverse((_converse) => {
this.callback = function () {}; this.callback = function () {};
this.anotherCallback = function () {}; this.anotherCallback = function () {};
this.neverCalled = function () {}; this.neverCalled = function () {};
@ -56,6 +54,5 @@ describe("The _converse Event Emitter", function() {
expect(this.callback.calls.count(), 1); expect(this.callback.calls.count(), 1);
expect(this.anotherCallback.calls.count(), 3); expect(this.anotherCallback.calls.count(), 3);
expect(this.neverCalled).not.toHaveBeenCalled(); expect(this.neverCalled).not.toHaveBeenCalled();
done();
})); }));
}); });

View File

@ -3,10 +3,9 @@
describe("The persistent store", function() { describe("The persistent store", function() {
it("is unique to the user based on their JID", it("is unique to the user based on their JID",
mock.initConverse([], {'persistent_store': 'IndexedDB'}, (done, _converse) => { mock.initConverse([], {'persistent_store': 'IndexedDB'}, (_converse) => {
expect(_converse.storage.persistent.config().storeName).toBe(_converse.bare_jid); expect(_converse.storage.persistent.config().storeName).toBe(_converse.bare_jid);
expect(_converse.storage.persistent.config().description).toBe('indexedDB instance'); expect(_converse.storage.persistent.config().description).toBe('indexedDB instance');
done();
})); }));
}); });

View File

@ -6,7 +6,7 @@ const { Strophe, u, sizzle, $iq } = converse.env;
describe("A chat room", function () { describe("A chat room", function () {
it("can be bookmarked", mock.initConverse( it("can be bookmarked", mock.initConverse(
['chatBoxesFetched'], {}, async function (done, _converse) { ['chatBoxesFetched'], {}, async function (_converse) {
await mock.waitForRoster(_converse, 'current', 0); await mock.waitForRoster(_converse, 'current', 0);
await mock.waitUntilDiscoConfirmed( await mock.waitUntilDiscoConfirmed(
@ -128,12 +128,11 @@ describe("A chat room", function () {
expect(u.hasClass('on-button', view.querySelector('.toggle-bookmark')), true); expect(u.hasClass('on-button', view.querySelector('.toggle-bookmark')), true);
// We ignore this IQ stanza... (unless it's an error stanza), so // We ignore this IQ stanza... (unless it's an error stanza), so
// nothing to test for here. // nothing to test for here.
done();
})); }));
it("will be automatically opened if 'autojoin' is set on the bookmark", mock.initConverse( it("will be automatically opened if 'autojoin' is set on the bookmark", mock.initConverse(
['chatBoxesFetched'], {}, async function (done, _converse) { ['chatBoxesFetched'], {}, async function (_converse) {
const { u } = converse.env; const { u } = converse.env;
await mock.waitForRoster(_converse, 'current', 0); await mock.waitForRoster(_converse, 'current', 0);
@ -172,13 +171,12 @@ describe("A chat room", function () {
'nick': ' Othello' 'nick': ' Othello'
}); });
expect(_converse.chatboxviews.get(jid) === undefined).toBe(true); expect(_converse.chatboxviews.get(jid) === undefined).toBe(true);
done();
})); }));
describe("when bookmarked", function () { describe("when bookmarked", function () {
it("will use the nickname from the bookmark", mock.initConverse([], {}, async function (done, _converse) { it("will use the nickname from the bookmark", mock.initConverse([], {}, async function (_converse) {
const { u } = converse.env; const { u } = converse.env;
await mock.waitForRoster(_converse, 'current', 0); await mock.waitForRoster(_converse, 'current', 0);
await mock.waitUntilBookmarksReturned(_converse); await mock.waitUntilBookmarksReturned(_converse);
@ -195,10 +193,9 @@ describe("A chat room", function () {
const room = await room_creation_promise; const room = await room_creation_promise;
await u.waitUntil(() => room.getAndPersistNickname.calls.count()); await u.waitUntil(() => room.getAndPersistNickname.calls.count());
expect(room.get('nick')).toBe('Othello'); expect(room.get('nick')).toBe('Othello');
done();
})); }));
it("displays that it's bookmarked through its bookmark icon", mock.initConverse([], {}, async function (done, _converse) { it("displays that it's bookmarked through its bookmark icon", mock.initConverse([], {}, async function (_converse) {
const { u } = converse.env; const { u } = converse.env;
await mock.waitForRoster(_converse, 'current', 0); await mock.waitForRoster(_converse, 'current', 0);
@ -220,10 +217,9 @@ describe("A chat room", function () {
await u.waitUntil(() => view.querySelector('.chatbox-title__text .fa-bookmark') !== null); await u.waitUntil(() => view.querySelector('.chatbox-title__text .fa-bookmark') !== null);
view.model.set('bookmarked', false); view.model.set('bookmarked', false);
await u.waitUntil(() => view.querySelector('.chatbox-title__text .fa-bookmark') === null); await u.waitUntil(() => view.querySelector('.chatbox-title__text .fa-bookmark') === null);
done();
})); }));
it("can be unbookmarked", mock.initConverse([], {}, async function (done, _converse) { it("can be unbookmarked", mock.initConverse([], {}, async function (_converse) {
const { u, Strophe } = converse.env; const { u, Strophe } = converse.env;
await mock.waitForRoster(_converse, 'current', 0); await mock.waitForRoster(_converse, 'current', 0);
@ -282,14 +278,13 @@ describe("A chat room", function () {
`</pubsub>`+ `</pubsub>`+
`</iq>` `</iq>`
); );
done();
})); }));
}); });
describe("and when autojoin is set", function () { describe("and when autojoin is set", function () {
it("will be be opened and joined automatically upon login", mock.initConverse( it("will be be opened and joined automatically upon login", mock.initConverse(
[], {}, async function (done, _converse) { [], {}, async function (_converse) {
await mock.waitForRoster(_converse, 'current', 0); await mock.waitForRoster(_converse, 'current', 0);
await mock.waitUntilBookmarksReturned(_converse); await mock.waitUntilBookmarksReturned(_converse);
@ -310,7 +305,6 @@ describe("A chat room", function () {
'nick': '' 'nick': ''
}); });
expect(_converse.api.rooms.create).toHaveBeenCalled(); expect(_converse.api.rooms.create).toHaveBeenCalled();
done();
})); }));
}); });
}); });
@ -318,7 +312,7 @@ describe("A chat room", function () {
describe("Bookmarks", function () { describe("Bookmarks", function () {
it("can be pushed from the XMPP server", mock.initConverse( it("can be pushed from the XMPP server", mock.initConverse(
['connected', 'chatBoxesFetched'], {}, async function (done, _converse) { ['connected', 'chatBoxesFetched'], {}, async function (_converse) {
const { $msg, u } = converse.env; const { $msg, u } = converse.env;
await mock.waitForRoster(_converse, 'current', 0); await mock.waitForRoster(_converse, 'current', 0);
@ -403,13 +397,12 @@ describe("Bookmarks", function () {
expect(_converse.bookmarks.map(b => b.get('name'))).toEqual(['Second bookmark', 'The Play&apos;s the Thing', 'Yet another bookmark']); expect(_converse.bookmarks.map(b => b.get('name'))).toEqual(['Second bookmark', 'The Play&apos;s the Thing', 'Yet another bookmark']);
expect(_converse.chatboxviews.get('theplay@conference.shakespeare.lit')).not.toBeUndefined(); expect(_converse.chatboxviews.get('theplay@conference.shakespeare.lit')).not.toBeUndefined();
expect(Object.keys(_converse.chatboxviews.getAll()).length).toBe(2); expect(Object.keys(_converse.chatboxviews.getAll()).length).toBe(2);
done();
})); }));
it("can be retrieved from the XMPP server", mock.initConverse( it("can be retrieved from the XMPP server", mock.initConverse(
['chatBoxesFetched'], {}, ['chatBoxesFetched'], {},
async function (done, _converse) { async function (_converse) {
const { Strophe, sizzle, u, $iq } = converse.env; const { Strophe, sizzle, u, $iq } = converse.env;
await mock.waitForRoster(_converse, 'current', 0); await mock.waitForRoster(_converse, 'current', 0);
@ -483,13 +476,12 @@ describe("Bookmarks", function () {
expect(_converse.bookmarks.models.length).toBe(2); 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': 'theplay@conference.shakespeare.lit'}).get('autojoin')).toBe(true);
expect(_converse.bookmarks.findWhere({'jid': 'another@conference.shakespeare.lit'}).get('autojoin')).toBe(false); expect(_converse.bookmarks.findWhere({'jid': 'another@conference.shakespeare.lit'}).get('autojoin')).toBe(false);
done();
})); }));
describe("The bookmarks list", function () { describe("The bookmarks list", function () {
it("shows a list of bookmarks", mock.initConverse( it("shows a list of bookmarks", mock.initConverse(
[], {}, async function (done, _converse) { [], {}, async function (_converse) {
await mock.waitUntilDiscoConfirmed( await mock.waitUntilDiscoConfirmed(
_converse, _converse.bare_jid, _converse, _converse.bare_jid,
@ -560,11 +552,10 @@ describe("Bookmarks", function () {
expect(els[1].textContent).toBe("Bookmark with a very very long name that will be shortened"); 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[2].textContent).toBe("noname@conference.shakespeare.lit");
expect(els[3].textContent).toBe("The Play's the Thing"); expect(els[3].textContent).toBe("The Play's the Thing");
done();
})); }));
it("can be used to open a MUC from a bookmark", mock.initConverse( it("can be used to open a MUC from a bookmark", mock.initConverse(
[], {'view_mode': 'fullscreen'}, async function (done, _converse) { [], {'view_mode': 'fullscreen'}, async function (_converse) {
const api = _converse.api; const api = _converse.api;
await mock.waitUntilDiscoConfirmed( await mock.waitUntilDiscoConfirmed(
@ -610,11 +601,10 @@ describe("Bookmarks", function () {
await u.waitUntil(() => view.querySelector('.list-item.open').getAttribute('data-room-jid') === 'first@conference.shakespeare.lit'); await u.waitUntil(() => view.querySelector('.list-item.open').getAttribute('data-room-jid') === 'first@conference.shakespeare.lit');
expect((await api.rooms.get('first@conference.shakespeare.lit')).get('hidden')).toBe(false); expect((await api.rooms.get('first@conference.shakespeare.lit')).get('hidden')).toBe(false);
expect((await api.rooms.get('theplay@conference.shakespeare.lit')).get('hidden')).toBe(true); expect((await api.rooms.get('theplay@conference.shakespeare.lit')).get('hidden')).toBe(true);
done();
})); }));
it("remembers the toggle state of the bookmarks list", mock.initConverse( it("remembers the toggle state of the bookmarks list", mock.initConverse(
[], {}, async function (done, _converse) { [], {}, async function (_converse) {
await mock.waitForRoster(_converse, 'current', 0); await mock.waitForRoster(_converse, 'current', 0);
await mock.openControlBox(_converse); await mock.openControlBox(_converse);
@ -665,7 +655,6 @@ describe("Bookmarks", function () {
expect(u.hasClass('collapsed', sizzle('#chatrooms .bookmarks.rooms-list', chats_el).pop())).toBeFalsy(); expect(u.hasClass('collapsed', sizzle('#chatrooms .bookmarks.rooms-list', chats_el).pop())).toBeFalsy();
expect(sizzle(selector, chats_el).filter(u.isVisible).length).toBe(1); expect(sizzle(selector, chats_el).filter(u.isVisible).length).toBe(1);
expect(bookmarks_el.model.get('toggle-state')).toBe(_converse.OPENED); expect(bookmarks_el.model.get('toggle-state')).toBe(_converse.OPENED);
done();
})); }));
}); });
}); });
@ -673,7 +662,7 @@ describe("Bookmarks", function () {
describe("When hide_open_bookmarks is true and a bookmarked room is opened", function () { describe("When hide_open_bookmarks is true and a bookmarked room is opened", function () {
it("can be closed", mock.initConverse( it("can be closed", mock.initConverse(
[], { hide_open_bookmarks: true }, async function (done, _converse) { [], { hide_open_bookmarks: true }, async function (_converse) {
await mock.waitForRoster(_converse, 'current', 0); await mock.waitForRoster(_converse, 'current', 0);
await mock.openControlBox(_converse); await mock.openControlBox(_converse);
@ -704,6 +693,5 @@ describe("When hide_open_bookmarks is true and a bookmarked room is opened", fun
const view = _converse.chatboxviews.get(jid); const view = _converse.chatboxviews.get(jid);
view.close(); view.close();
await u.waitUntil(() => !u.hasClass('hidden', bookmarks_el.querySelector(".available-chatroom"))); await u.waitUntil(() => !u.hasClass('hidden', bookmarks_el.querySelector(".available-chatroom")));
done();
})); }));
}); });

View File

@ -13,7 +13,7 @@ describe("Chatboxes", function () {
describe("A Chatbox", function () { describe("A Chatbox", function () {
it("has a /help command to show the available commands", mock.initConverse(['chatBoxesFetched'], {}, async function (done, _converse) { it("has a /help command to show the available commands", mock.initConverse(['chatBoxesFetched'], {}, async function (_converse) {
await mock.waitForRoster(_converse, 'current', 1); await mock.waitForRoster(_converse, 'current', 1);
await mock.openControlBox(_converse); await mock.openControlBox(_converse);
@ -40,11 +40,10 @@ describe("Chatboxes", function () {
await u.waitUntil(() => view.querySelectorAll('.chat-msg').length); await u.waitUntil(() => view.querySelectorAll('.chat-msg').length);
const msg_txt_sel = 'converse-chat-message:last-child .chat-msg__body'; const msg_txt_sel = 'converse-chat-message:last-child .chat-msg__body';
await u.waitUntil(() => view.querySelector(msg_txt_sel).textContent.trim() === 'hello world'); await u.waitUntil(() => view.querySelector(msg_txt_sel).textContent.trim() === 'hello world');
done();
})); }));
it("has a /clear command", mock.initConverse(['chatBoxesFetched'], {}, async function (done, _converse) { it("has a /clear command", mock.initConverse(['chatBoxesFetched'], {}, async function (_converse) {
await mock.waitForRoster(_converse, 'current', 1); await mock.waitForRoster(_converse, 'current', 1);
await mock.openControlBox(_converse); await mock.openControlBox(_converse);
const contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit'; const contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit';
@ -67,12 +66,11 @@ describe("Chatboxes", function () {
}); });
expect(window.confirm).toHaveBeenCalled(); expect(window.confirm).toHaveBeenCalled();
await u.waitUntil(() => sizzle('converse-chat-message', view).length === 0); await u.waitUntil(() => sizzle('converse-chat-message', view).length === 0);
done();
})); }));
it("is created when you click on a roster item", mock.initConverse( it("is created when you click on a roster item", mock.initConverse(
['chatBoxesFetched'], {}, async function (done, _converse) { ['chatBoxesFetched'], {}, async function (_converse) {
await mock.waitForRoster(_converse, 'current'); await mock.waitForRoster(_converse, 'current');
await mock.openControlBox(_converse); await mock.openControlBox(_converse);
@ -98,12 +96,11 @@ describe("Chatboxes", function () {
// Check that new chat boxes are created to the left of the // Check that new chat boxes are created to the left of the
// controlbox (but to the right of all existing chat boxes) // controlbox (but to the right of all existing chat boxes)
expect(document.querySelectorAll("#conversejs .chatbox").length).toBe(3); expect(document.querySelectorAll("#conversejs .chatbox").length).toBe(3);
done();
})); }));
it("opens when a new message is received", mock.initConverse( it("opens when a new message is received", mock.initConverse(
[], {'allow_non_roster_messaging': true}, [], {'allow_non_roster_messaging': true},
async function (done, _converse) { async function (_converse) {
await mock.waitForRoster(_converse, 'current', 0); await mock.waitForRoster(_converse, 'current', 0);
const sender_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit'; const sender_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit';
@ -120,10 +117,9 @@ describe("Chatboxes", function () {
await u.waitUntil(() => message_promise); await u.waitUntil(() => message_promise);
expect(_converse.chatboxviews.keys().length).toBe(2); expect(_converse.chatboxviews.keys().length).toBe(2);
expect(_converse.chatboxviews.keys().pop()).toBe(sender_jid); expect(_converse.chatboxviews.keys().pop()).toBe(sender_jid);
done();
})); }));
it("doesn't open when a message without body is received", mock.initConverse([], {}, async function (done, _converse) { it("doesn't open when a message without body is received", mock.initConverse([], {}, async function (_converse) {
await mock.waitForRoster(_converse, 'current', 1); await mock.waitForRoster(_converse, 'current', 1);
const sender_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit'; const sender_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit';
const stanza = u.toStanza(` const stanza = u.toStanza(`
@ -136,11 +132,10 @@ describe("Chatboxes", function () {
_converse.connection._dataRecv(mock.createRequest(stanza)); _converse.connection._dataRecv(mock.createRequest(stanza));
await u.waitUntil(() => message_promise); await u.waitUntil(() => message_promise);
expect(_converse.chatboxviews.keys().length).toBe(1); expect(_converse.chatboxviews.keys().length).toBe(1);
done();
})); }));
it("is focused if its already open and you click on its corresponding roster item", it("is focused if its already open and you click on its corresponding roster item",
mock.initConverse(['chatBoxesFetched'], {'auto_focus': true}, async function (done, _converse) { mock.initConverse(['chatBoxesFetched'], {'auto_focus': true}, async function (_converse) {
await mock.waitForRoster(_converse, 'current'); await mock.waitForRoster(_converse, 'current');
await mock.openControlBox(_converse); await mock.openControlBox(_converse);
@ -159,11 +154,10 @@ describe("Chatboxes", function () {
await u.waitUntil(() => view.focus.calls.count(), 1000); await u.waitUntil(() => view.focus.calls.count(), 1000);
expect(view.focus).toHaveBeenCalled(); expect(view.focus).toHaveBeenCalled();
expect(_converse.chatboxes.length).toEqual(2); expect(_converse.chatboxes.length).toEqual(2);
done();
})); }));
it("can be saved to, and retrieved from, browserStorage", it("can be saved to, and retrieved from, browserStorage",
mock.initConverse([], {}, async function (done, _converse) { mock.initConverse([], {}, async function (_converse) {
spyOn(_converse.minimize, 'trimChats'); spyOn(_converse.minimize, 'trimChats');
await mock.waitForRoster(_converse, 'current'); await mock.waitForRoster(_converse, 'current');
@ -192,11 +186,10 @@ describe("Chatboxes", function () {
old_attrs = _converse.chatboxes.models.map(m => m.attributes[i]); old_attrs = _converse.chatboxes.models.map(m => m.attributes[i]);
expect(new_attrs).toEqual(old_attrs); expect(new_attrs).toEqual(old_attrs);
} }
done();
})); }));
it("can be closed by clicking a DOM element with class 'close-chatbox-button'", it("can be closed by clicking a DOM element with class 'close-chatbox-button'",
mock.initConverse(['chatBoxesFetched'], {}, async function (done, _converse) { mock.initConverse(['chatBoxesFetched'], {}, async function (_converse) {
await mock.waitForRoster(_converse, 'current'); await mock.waitForRoster(_converse, 'current');
await mock.openControlBox(_converse); await mock.openControlBox(_converse);
@ -211,11 +204,10 @@ describe("Chatboxes", function () {
expect(chatview.model.close).toHaveBeenCalled(); expect(chatview.model.close).toHaveBeenCalled();
await new Promise(resolve => _converse.api.listen.once('chatBoxClosed', resolve)); await new Promise(resolve => _converse.api.listen.once('chatBoxClosed', resolve));
expect(_converse.api.trigger).toHaveBeenCalledWith('chatBoxClosed', jasmine.any(Object)); expect(_converse.api.trigger).toHaveBeenCalledWith('chatBoxClosed', jasmine.any(Object));
done();
})); }));
it("will be removed from browserStorage when closed", it("will be removed from browserStorage when closed",
mock.initConverse(['chatBoxesFetched'], {}, async function (done, _converse) { mock.initConverse(['chatBoxesFetched'], {}, async function (_converse) {
await mock.waitForRoster(_converse, 'current'); await mock.waitForRoster(_converse, 'current');
await mock.openControlBox(_converse); await mock.openControlBox(_converse);
@ -248,13 +240,12 @@ describe("Chatboxes", function () {
await new Promise(resolve => _converse.api.listen.on('chatBoxesFetched', resolve)); await new Promise(resolve => _converse.api.listen.on('chatBoxesFetched', resolve));
expect(newchatboxes.length).toEqual(1); expect(newchatboxes.length).toEqual(1);
expect(newchatboxes.models[0].id).toBe("controlbox"); expect(newchatboxes.models[0].id).toBe("controlbox");
done();
})); }));
describe("A chat toolbar", function () { describe("A chat toolbar", function () {
it("shows the remaining character count if a message_limit is configured", it("shows the remaining character count if a message_limit is configured",
mock.initConverse(['chatBoxesFetched'], {'message_limit': 200}, async function (done, _converse) { mock.initConverse(['chatBoxesFetched'], {'message_limit': 200}, async function (_converse) {
await mock.waitForRoster(_converse, 'current', 3); await mock.waitForRoster(_converse, 'current', 3);
await mock.openControlBox(_converse); await mock.openControlBox(_converse);
@ -288,12 +279,11 @@ describe("Chatboxes", function () {
textarea.value = 'hello world'; textarea.value = 'hello world';
message_form.onKeyUp(ev); message_form.onKeyUp(ev);
await u.waitUntil(() => counter.textContent === '189'); await u.waitUntil(() => counter.textContent === '189');
done();
})); }));
it("does not show a remaining character count if message_limit is zero", it("does not show a remaining character count if message_limit is zero",
mock.initConverse(['chatBoxesFetched'], {'message_limit': 0}, async function (done, _converse) { mock.initConverse(['chatBoxesFetched'], {'message_limit': 0}, async function (_converse) {
await mock.waitForRoster(_converse, 'current', 3); await mock.waitForRoster(_converse, 'current', 3);
await mock.openControlBox(_converse); await mock.openControlBox(_converse);
@ -302,12 +292,11 @@ describe("Chatboxes", function () {
const view = _converse.chatboxviews.get(contact_jid); const view = _converse.chatboxviews.get(contact_jid);
const counter = view.querySelector('.chat-toolbar .message-limit'); const counter = view.querySelector('.chat-toolbar .message-limit');
expect(counter).toBe(null); expect(counter).toBe(null);
done();
})); }));
it("can contain a button for starting a call", it("can contain a button for starting a call",
mock.initConverse(['chatBoxesFetched'], {}, async function (done, _converse) { mock.initConverse(['chatBoxesFetched'], {}, async function (_converse) {
await mock.waitForRoster(_converse, 'current'); await mock.waitForRoster(_converse, 'current');
await mock.openControlBox(_converse); await mock.openControlBox(_converse);
@ -333,13 +322,12 @@ describe("Chatboxes", function () {
call_button = toolbar.querySelector('.toggle-call'); call_button = toolbar.querySelector('.toggle-call');
call_button.click(); call_button.click();
expect(_converse.api.trigger).toHaveBeenCalledWith('callButtonClicked', jasmine.any(Object)); expect(_converse.api.trigger).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", mock.initConverse([], {}, async function (done, _converse) { it("does not open a new chatbox", mock.initConverse([], {}, async function (_converse) {
await mock.waitForRoster(_converse, 'current'); await mock.waitForRoster(_converse, 'current');
await mock.openControlBox(_converse); await mock.openControlBox(_converse);
@ -357,13 +345,12 @@ describe("Chatboxes", function () {
await u.waitUntil(() => _converse.api.trigger.calls.count()); await u.waitUntil(() => _converse.api.trigger.calls.count());
expect(_converse.api.trigger).toHaveBeenCalledWith('message', jasmine.any(Object)); expect(_converse.api.trigger).toHaveBeenCalledWith('message', jasmine.any(Object));
expect(_converse.chatboxviews.keys().length).toBe(1); expect(_converse.chatboxviews.keys().length).toBe(1);
done();
})); }));
describe("An active notification", function () { describe("An active notification", function () {
it("is sent when the user opens a chat box", it("is sent when the user opens a chat box",
mock.initConverse(['chatBoxesFetched'], {}, async function (done, _converse) { mock.initConverse(['chatBoxesFetched'], {}, async function (_converse) {
await mock.waitForRoster(_converse, 'current'); await mock.waitForRoster(_converse, 'current');
const contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit'; const contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit';
@ -381,11 +368,10 @@ describe("Chatboxes", function () {
expect(stanza.childNodes[0].tagName).toBe('active'); expect(stanza.childNodes[0].tagName).toBe('active');
expect(stanza.childNodes[1].tagName).toBe('no-store'); expect(stanza.childNodes[1].tagName).toBe('no-store');
expect(stanza.childNodes[2].tagName).toBe('no-permanent-store'); expect(stanza.childNodes[2].tagName).toBe('no-permanent-store');
done();
})); }));
it("is sent when the user maximizes a minimized a chat box", mock.initConverse( it("is sent when the user maximizes a minimized a chat box", mock.initConverse(
['chatBoxesFetched'], {}, async function (done, _converse) { ['chatBoxesFetched'], {}, async function (_converse) {
await mock.waitForRoster(_converse, 'current', 1); await mock.waitForRoster(_converse, 'current', 1);
await mock.openControlBox(_converse); await mock.openControlBox(_converse);
@ -409,14 +395,13 @@ describe("Chatboxes", function () {
`<no-permanent-store xmlns="urn:xmpp:hints"/>`+ `<no-permanent-store xmlns="urn:xmpp:hints"/>`+
`</message>` `</message>`
); );
done();
})); }));
}); });
describe("A composing notification", function () { describe("A composing notification", function () {
it("is sent as soon as the user starts typing a message which is not a command", it("is sent as soon as the user starts typing a message which is not a command",
mock.initConverse(['chatBoxesFetched'], {}, async function (done, _converse) { mock.initConverse(['chatBoxesFetched'], {}, async function (_converse) {
await mock.waitForRoster(_converse, 'current'); await mock.waitForRoster(_converse, 'current');
await mock.openControlBox(_converse); await mock.openControlBox(_converse);
@ -452,12 +437,11 @@ describe("Chatboxes", function () {
}); });
expect(view.model.get('chat_state')).toBe('composing'); expect(view.model.get('chat_state')).toBe('composing');
expect(_converse.api.trigger.calls.count(), 1); expect(_converse.api.trigger.calls.count(), 1);
done();
})); }));
it("is NOT sent out if send_chat_state_notifications doesn't allow it", it("is NOT sent out if send_chat_state_notifications doesn't allow it",
mock.initConverse(['chatBoxesFetched'], {'send_chat_state_notifications': []}, mock.initConverse(['chatBoxesFetched'], {'send_chat_state_notifications': []},
async function (done, _converse) { async function (_converse) {
await mock.waitForRoster(_converse, 'current'); await mock.waitForRoster(_converse, 'current');
await mock.openControlBox(_converse); await mock.openControlBox(_converse);
@ -477,10 +461,9 @@ describe("Chatboxes", function () {
}); });
expect(view.model.get('chat_state')).toBe('composing'); expect(view.model.get('chat_state')).toBe('composing');
expect(_converse.connection.send).not.toHaveBeenCalled(); expect(_converse.connection.send).not.toHaveBeenCalled();
done();
})); }));
it("will be shown if received", mock.initConverse([], {}, async function (done, _converse) { it("will be shown if received", mock.initConverse([], {}, async function (_converse) {
await mock.waitForRoster(_converse, 'current'); await mock.waitForRoster(_converse, 'current');
await mock.openControlBox(_converse); await mock.openControlBox(_converse);
@ -525,11 +508,10 @@ describe("Chatboxes", function () {
const msg_el = await u.waitUntil(() => view.querySelector('.chat-msg')); const msg_el = await u.waitUntil(() => view.querySelector('.chat-msg'));
await u.waitUntil( () => view.querySelector('.chat-content__notifications').innerText === ''); await u.waitUntil( () => view.querySelector('.chat-content__notifications').innerText === '');
expect(msg_el.querySelector('.chat-msg__text').textContent).toBe('hello world'); expect(msg_el.querySelector('.chat-msg__text').textContent).toBe('hello world');
done();
})); }));
it("is ignored if it's a composing carbon message sent by this user from a different client", it("is ignored if it's a composing carbon message sent by this user from a different client",
mock.initConverse(['chatBoxesFetched'], {}, async function (done, _converse) { mock.initConverse(['chatBoxesFetched'], {}, async function (_converse) {
await mock.waitUntilDiscoConfirmed(_converse, 'montague.lit', [], ['vcard-temp']); await mock.waitUntilDiscoConfirmed(_converse, 'montague.lit', [], ['vcard-temp']);
await u.waitUntil(() => _converse.xmppstatus.vcard.get('fullname')); await u.waitUntil(() => _converse.xmppstatus.vcard.get('fullname'));
@ -560,14 +542,13 @@ describe("Chatboxes", function () {
expect(view.model.messages.length).toEqual(0); expect(view.model.messages.length).toEqual(0);
const el = view.querySelector('.chat-content__notifications'); const el = view.querySelector('.chat-content__notifications');
expect(el.textContent).toBe(''); expect(el.textContent).toBe('');
done();
})); }));
}); });
describe("A paused notification", function () { describe("A paused notification", function () {
it("is sent if the user has stopped typing since 30 seconds", it("is sent if the user has stopped typing since 30 seconds",
mock.initConverse(['chatBoxesFetched'], {}, async function (done, _converse) { mock.initConverse(['chatBoxesFetched'], {}, async function (_converse) {
await mock.waitForRoster(_converse, 'current'); await mock.waitForRoster(_converse, 'current');
const contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit'; const contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit';
@ -624,10 +605,9 @@ describe("Chatboxes", function () {
keyCode: 1 keyCode: 1
}); });
expect(view.model.get('chat_state')).toBe('composing'); expect(view.model.get('chat_state')).toBe('composing');
done();
})); }));
it("will be shown if received", mock.initConverse([], {}, async function (done, _converse) { it("will be shown if received", mock.initConverse([], {}, async function (_converse) {
await mock.waitForRoster(_converse, 'current'); await mock.waitForRoster(_converse, 'current');
await mock.openControlBox(_converse); await mock.openControlBox(_converse);
const rosterview = document.querySelector('converse-roster'); const rosterview = document.querySelector('converse-roster');
@ -649,11 +629,10 @@ describe("Chatboxes", function () {
const csn = mock.cur_names[1] + ' has stopped typing'; const csn = mock.cur_names[1] + ' has stopped typing';
await u.waitUntil( () => view.querySelector('.chat-content__notifications').innerText === csn); await u.waitUntil( () => view.querySelector('.chat-content__notifications').innerText === csn);
expect(view.model.messages.length).toEqual(0); expect(view.model.messages.length).toEqual(0);
done();
})); }));
it("will not be shown if it's a paused carbon message that this user sent from a different client", it("will not be shown if it's a paused carbon message that this user sent from a different client",
mock.initConverse(['chatBoxesFetched'], {}, async function (done, _converse) { mock.initConverse(['chatBoxesFetched'], {}, async function (_converse) {
await mock.waitUntilDiscoConfirmed(_converse, 'montague.lit', [], ['vcard-temp']); await mock.waitUntilDiscoConfirmed(_converse, 'montague.lit', [], ['vcard-temp']);
await u.waitUntil(() => _converse.xmppstatus.vcard.get('fullname')); await u.waitUntil(() => _converse.xmppstatus.vcard.get('fullname'));
@ -681,15 +660,13 @@ describe("Chatboxes", function () {
expect(view.model.messages.length).toEqual(0); expect(view.model.messages.length).toEqual(0);
const el = view.querySelector('.chat-content__notifications'); const el = view.querySelector('.chat-content__notifications');
expect(el.textContent).toBe(''); expect(el.textContent).toBe('');
done();
done();
})); }));
}); });
describe("An inactive notification", function () { describe("An inactive notification", function () {
it("is sent if the user has stopped typing since 2 minutes", it("is sent if the user has stopped typing since 2 minutes",
mock.initConverse(['chatBoxesFetched'], {}, async function (done, _converse) { mock.initConverse(['chatBoxesFetched'], {}, async function (_converse) {
const sent_stanzas = _converse.connection.sent_stanzas; const sent_stanzas = _converse.connection.sent_stanzas;
// Make the timeouts shorter so that we can test // Make the timeouts shorter so that we can test
@ -750,11 +727,10 @@ describe("Chatboxes", function () {
`<no-permanent-store xmlns="urn:xmpp:hints"/>`+ `<no-permanent-store xmlns="urn:xmpp:hints"/>`+
`</message>`); `</message>`);
done();
})); }));
it("is sent when the user a minimizes a chat box", it("is sent when the user a minimizes a chat box",
mock.initConverse(['chatBoxesFetched'], {}, async function (done, _converse) { mock.initConverse(['chatBoxesFetched'], {}, async function (_converse) {
await mock.waitForRoster(_converse, 'current'); await mock.waitForRoster(_converse, 'current');
await mock.openControlBox(_converse); await mock.openControlBox(_converse);
@ -769,11 +745,10 @@ describe("Chatboxes", function () {
var stanza = _converse.connection.send.calls.argsFor(0)[0]; var stanza = _converse.connection.send.calls.argsFor(0)[0];
expect(stanza.getAttribute('to')).toBe(contact_jid); expect(stanza.getAttribute('to')).toBe(contact_jid);
expect(stanza.childNodes[0].tagName).toBe('inactive'); expect(stanza.childNodes[0].tagName).toBe('inactive');
done();
})); }));
it("is sent if the user closes a chat box", it("is sent if the user closes a chat box",
mock.initConverse(['chatBoxesFetched'], {}, async function (done, _converse) { mock.initConverse(['chatBoxesFetched'], {}, async function (_converse) {
await mock.waitForRoster(_converse, 'current'); await mock.waitForRoster(_converse, 'current');
const contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit'; const contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit';
@ -792,11 +767,10 @@ describe("Chatboxes", function () {
expect(stanza.childNodes[0].tagName).toBe('inactive'); expect(stanza.childNodes[0].tagName).toBe('inactive');
expect(stanza.childNodes[1].tagName).toBe('no-store'); expect(stanza.childNodes[1].tagName).toBe('no-store');
expect(stanza.childNodes[2].tagName).toBe('no-permanent-store'); expect(stanza.childNodes[2].tagName).toBe('no-permanent-store');
done();
})); }));
it("will clear any other chat status notifications", it("will clear any other chat status notifications",
mock.initConverse(['chatBoxesFetched'], {}, async function (done, _converse) { mock.initConverse(['chatBoxesFetched'], {}, async function (_converse) {
await mock.waitForRoster(_converse, 'current'); await mock.waitForRoster(_converse, 'current');
await mock.openControlBox(_converse); await mock.openControlBox(_converse);
@ -829,13 +803,12 @@ describe("Chatboxes", function () {
_converse.connection._dataRecv(mock.createRequest(msg)); _converse.connection._dataRecv(mock.createRequest(msg));
await u.waitUntil(() => !view.querySelector('.chat-content__notifications').textContent); await u.waitUntil(() => !view.querySelector('.chat-content__notifications').textContent);
done();
})); }));
}); });
describe("A gone notification", function () { describe("A gone notification", function () {
it("will be shown if received", mock.initConverse([], {}, async function (done, _converse) { it("will be shown if received", mock.initConverse([], {}, async function (_converse) {
await mock.waitForRoster(_converse, 'current', 3); await mock.waitForRoster(_converse, 'current', 3);
await mock.openControlBox(_converse); await mock.openControlBox(_converse);
const sender_jid = mock.cur_names[1].replace(/ /g,'.').toLowerCase() + '@montague.lit'; const sender_jid = mock.cur_names[1].replace(/ /g,'.').toLowerCase() + '@montague.lit';
@ -852,13 +825,12 @@ describe("Chatboxes", function () {
const view = _converse.chatboxviews.get(sender_jid); const view = _converse.chatboxviews.get(sender_jid);
const csntext = await u.waitUntil(() => view.querySelector('.chat-content__notifications').textContent); const csntext = await u.waitUntil(() => view.querySelector('.chat-content__notifications').textContent);
expect(csntext).toEqual(mock.cur_names[1] + ' has gone away'); expect(csntext).toEqual(mock.cur_names[1] + ' has gone away');
done();
})); }));
}); });
describe("On receiving a message correction", function () { describe("On receiving a message correction", function () {
it("will be removed", mock.initConverse([], {}, async function (done, _converse) { it("will be removed", mock.initConverse([], {}, async function (_converse) {
await mock.waitForRoster(_converse, 'current'); await mock.waitForRoster(_converse, 'current');
await mock.openControlBox(_converse); await mock.openControlBox(_converse);
@ -910,7 +882,6 @@ describe("Chatboxes", function () {
await _converse.handleMessageStanza(edited); await _converse.handleMessageStanza(edited);
await u.waitUntil(() => !view.querySelector('.chat-content__notifications').textContent); await u.waitUntil(() => !view.querySelector('.chat-content__notifications').textContent);
done();
})); }));
}); });
}); });
@ -919,7 +890,7 @@ describe("Chatboxes", function () {
describe("Special Messages", function () { describe("Special Messages", function () {
it("'/clear' can be used to clear messages in a conversation", it("'/clear' can be used to clear messages in a conversation",
mock.initConverse(['chatBoxesFetched'], {}, async function (done, _converse) { mock.initConverse(['chatBoxesFetched'], {}, async function (_converse) {
await mock.waitForRoster(_converse, 'current'); await mock.waitForRoster(_converse, 'current');
await mock.openControlBox(_converse); await mock.openControlBox(_converse);
@ -948,7 +919,6 @@ describe("Chatboxes", function () {
expect(window.confirm).toHaveBeenCalledWith('Are you sure you want to clear the messages from this conversation?'); expect(window.confirm).toHaveBeenCalledWith('Are you sure you want to clear the messages from this conversation?');
await u.waitUntil(() => view.model.messages.length === 0); await u.waitUntil(() => view.model.messages.length === 0);
await u.waitUntil(() => !view.querySelectorAll('.chat-msg__body').length); await u.waitUntil(() => !view.querySelectorAll('.chat-msg__body').length);
done();
})); }));
}); });
@ -956,7 +926,7 @@ describe("Chatboxes", function () {
describe("A RosterView's Unread Message Count", function () { describe("A RosterView's Unread Message Count", function () {
it("is updated when message is received and chatbox is scrolled up", it("is updated when message is received and chatbox is scrolled up",
mock.initConverse(['chatBoxesFetched'], {}, async function (done, _converse) { mock.initConverse(['chatBoxesFetched'], {}, async function (_converse) {
await mock.waitForRoster(_converse, 'current', 1); await mock.waitForRoster(_converse, 'current', 1);
let msg, indicator_el; let msg, indicator_el;
@ -977,11 +947,10 @@ describe("Chatboxes", function () {
await u.waitUntil(() => chatbox.messages.length > 1); await u.waitUntil(() => chatbox.messages.length > 1);
indicator_el = sizzle(selector, rosterview).pop(); indicator_el = sizzle(selector, rosterview).pop();
expect(indicator_el.textContent).toBe('2'); expect(indicator_el.textContent).toBe('2');
done();
})); }));
it("is updated when message is received and chatbox is minimized", it("is updated when message is received and chatbox is minimized",
mock.initConverse(['chatBoxesFetched'], {}, async function (done, _converse) { mock.initConverse(['chatBoxesFetched'], {}, async function (_converse) {
await mock.waitForRoster(_converse, 'current', 1); await mock.waitForRoster(_converse, 'current', 1);
const sender_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit'; const sender_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit';
@ -1005,11 +974,10 @@ describe("Chatboxes", function () {
await u.waitUntil(() => chatbox.messages.length === 2); await u.waitUntil(() => chatbox.messages.length === 2);
indicator_el = sizzle(selector, rosterview).pop(); indicator_el = sizzle(selector, rosterview).pop();
expect(indicator_el.textContent).toBe('2'); expect(indicator_el.textContent).toBe('2');
done();
})); }));
it("is cleared when chatbox is maximzied after receiving messages in minimized mode", it("is cleared when chatbox is maximzied after receiving messages in minimized mode",
mock.initConverse(['chatBoxesFetched'], {}, async function (done, _converse) { mock.initConverse(['chatBoxesFetched'], {}, async function (_converse) {
await mock.waitForRoster(_converse, 'current', 1); await mock.waitForRoster(_converse, 'current', 1);
const sender_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit'; const sender_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit';
@ -1030,11 +998,10 @@ describe("Chatboxes", function () {
expect(select_msgs_indicator().textContent).toBe('2'); expect(select_msgs_indicator().textContent).toBe('2');
_converse.minimize.maximize(view.model); _converse.minimize.maximize(view.model);
u.waitUntil(() => typeof select_msgs_indicator() === 'undefined'); u.waitUntil(() => typeof select_msgs_indicator() === 'undefined');
done();
})); }));
it("is cleared when unread messages are viewed which were received in scrolled-up chatbox", it("is cleared when unread messages are viewed which were received in scrolled-up chatbox",
mock.initConverse(['chatBoxesFetched'], {}, async function (done, _converse) { mock.initConverse(['chatBoxesFetched'], {}, async function (_converse) {
await mock.openControlBox(_converse); await mock.openControlBox(_converse);
await mock.waitForRoster(_converse, 'current', 1); await mock.waitForRoster(_converse, 'current', 1);
@ -1054,11 +1021,10 @@ describe("Chatboxes", function () {
const chat_new_msgs_indicator = await u.waitUntil(() => view.querySelector('.new-msgs-indicator')); const chat_new_msgs_indicator = await u.waitUntil(() => view.querySelector('.new-msgs-indicator'));
chat_new_msgs_indicator.click(); chat_new_msgs_indicator.click();
await u.waitUntil(() => select_msgs_indicator() === undefined); await u.waitUntil(() => select_msgs_indicator() === undefined);
done();
})); }));
it("is not cleared after user clicks on roster view when chatbox is already opened and scrolled up", it("is not cleared after user clicks on roster view when chatbox is already opened and scrolled up",
mock.initConverse(['chatBoxesFetched'], {}, async function (done, _converse) { mock.initConverse(['chatBoxesFetched'], {}, async function (_converse) {
await mock.waitForRoster(_converse, 'current', 1); await mock.waitForRoster(_converse, 'current', 1);
const sender_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit'; const sender_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit';
@ -1077,7 +1043,6 @@ describe("Chatboxes", function () {
expect(select_msgs_indicator().textContent).toBe('1'); expect(select_msgs_indicator().textContent).toBe('1');
await mock.openChatBoxFor(_converse, sender_jid); await mock.openChatBoxFor(_converse, sender_jid);
expect(select_msgs_indicator().textContent).toBe('1'); expect(select_msgs_indicator().textContent).toBe('1');
done();
})); }));
}); });
}); });

View File

@ -5,7 +5,7 @@ const { Promise, $msg, Strophe, sizzle, u } = converse.env;
describe("A Chat Message", function () { describe("A Chat Message", function () {
it("can be sent as a correction by using the up arrow", it("can be sent as a correction by using the up arrow",
mock.initConverse(['chatBoxesFetched'], {}, async function (done, _converse) { mock.initConverse(['chatBoxesFetched'], {}, async function (_converse) {
await mock.waitForRoster(_converse, 'current', 1); await mock.waitForRoster(_converse, 'current', 1);
await mock.openControlBox(_converse); await mock.openControlBox(_converse);
@ -161,12 +161,11 @@ describe("A Chat Message", function () {
expect(view.model.messages.at(0).get('correcting')).toBeFalsy(); expect(view.model.messages.at(0).get('correcting')).toBeFalsy();
expect(view.model.messages.at(1).get('correcting')).toBeFalsy(); expect(view.model.messages.at(1).get('correcting')).toBeFalsy();
expect(view.model.messages.at(2).get('correcting')).toBeFalsy(); expect(view.model.messages.at(2).get('correcting')).toBeFalsy();
done();
})); }));
it("can be sent as a correction by clicking the pencil icon", it("can be sent as a correction by clicking the pencil icon",
mock.initConverse(['chatBoxesFetched'], {}, async function (done, _converse) { mock.initConverse(['chatBoxesFetched'], {}, async function (_converse) {
await mock.waitForRoster(_converse, 'current', 1); await mock.waitForRoster(_converse, 'current', 1);
await mock.openControlBox(_converse); await mock.openControlBox(_converse);
@ -285,14 +284,13 @@ describe("A Chat Message", function () {
['You have an unsent message which will be lost if you continue. Are you sure?']); ['You have an unsent message which will be lost if you continue. Are you sure?']);
expect(window.confirm.calls.argsFor(1)).toEqual( expect(window.confirm.calls.argsFor(1)).toEqual(
['You have an unsent message which will be lost if you continue. Are you sure?']); ['You have an unsent message which will be lost if you continue. Are you sure?']);
done();
})); }));
describe("when received from someone else", function () { describe("when received from someone else", function () {
it("can be replaced with a correction", it("can be replaced with a correction",
mock.initConverse(['chatBoxesFetched'], {}, async function (done, _converse) { mock.initConverse(['chatBoxesFetched'], {}, async function (_converse) {
await mock.waitForRoster(_converse, 'current', 1); await mock.waitForRoster(_converse, 'current', 1);
await mock.openControlBox(_converse); await mock.openControlBox(_converse);
@ -346,7 +344,6 @@ describe("A Chat Message", function () {
expect(older_msgs.length).toBe(2); expect(older_msgs.length).toBe(2);
expect(older_msgs[0].textContent.includes('But soft, what light through yonder airlock breaks?')).toBe(true); expect(older_msgs[0].textContent.includes('But soft, what light through yonder airlock breaks?')).toBe(true);
expect(view.model.messages.models.length).toBe(1); expect(view.model.messages.models.length).toBe(1);
done();
})); }));
}); });
}); });

View File

@ -11,7 +11,7 @@ describe("Emojis", function () {
afterEach(() => (jasmine.DEFAULT_TIMEOUT_INTERVAL = original_timeout)); afterEach(() => (jasmine.DEFAULT_TIMEOUT_INTERVAL = original_timeout));
it("can be opened by clicking a button in the chat toolbar", it("can be opened by clicking a button in the chat toolbar",
mock.initConverse(['chatBoxesFetched'], {}, async function (done, _converse) { mock.initConverse(['chatBoxesFetched'], {}, async function (_converse) {
const contact_jid = mock.cur_names[2].replace(/ /g,'.').toLowerCase() + '@montague.lit'; const contact_jid = mock.cur_names[2].replace(/ /g,'.').toLowerCase() + '@montague.lit';
await mock.waitForRoster(_converse, 'current'); await mock.waitForRoster(_converse, 'current');
@ -25,14 +25,13 @@ describe("Emojis", function () {
item.click() item.click()
expect(view.querySelector('textarea.chat-textarea').value).toBe(':smiley: '); expect(view.querySelector('textarea.chat-textarea').value).toBe(':smiley: ');
toolbar.querySelector('.toggle-emojis').click(); // Close the panel again toolbar.querySelector('.toggle-emojis').click(); // Close the panel again
done();
})); }));
}); });
describe("A Chat Message", function () { describe("A Chat Message", function () {
it("will display larger if it's only emojis", it("will display larger if it's only emojis",
mock.initConverse(['chatBoxesFetched'], {'use_system_emojis': true}, async function (done, _converse) { mock.initConverse(['chatBoxesFetched'], {'use_system_emojis': true}, async function (_converse) {
await mock.waitForRoster(_converse, 'current'); await mock.waitForRoster(_converse, 'current');
const sender_jid = mock.cur_names[1].replace(/ /g,'.').toLowerCase() + '@montague.lit'; const sender_jid = mock.cur_names[1].replace(/ /g,'.').toLowerCase() + '@montague.lit';
@ -114,13 +113,12 @@ describe("Emojis", function () {
message = view.querySelector('.message:last-child .chat-msg__text'); message = view.querySelector('.message:last-child .chat-msg__text');
expect(u.hasClass('chat-msg__text--larger', message)).toBe(true); expect(u.hasClass('chat-msg__text--larger', message)).toBe(true);
done()
})); }));
it("can render emojis as images", it("can render emojis as images",
mock.initConverse( mock.initConverse(
['chatBoxesFetched'], {'use_system_emojis': false}, ['chatBoxesFetched'], {'use_system_emojis': false},
async function (done, _converse) { async function (_converse) {
await mock.waitForRoster(_converse, 'current'); await mock.waitForRoster(_converse, 'current');
const contact_jid = mock.cur_names[1].replace(/ /g,'.').toLowerCase() + '@montague.lit'; const contact_jid = mock.cur_names[1].replace(/ /g,'.').toLowerCase() + '@montague.lit';
@ -163,8 +161,7 @@ describe("Emojis", function () {
const sent_stanzas = _converse.connection.sent_stanzas; const sent_stanzas = _converse.connection.sent_stanzas;
const sent_stanza = sent_stanzas.filter(s => s.nodeName === 'message').pop(); const sent_stanza = sent_stanzas.filter(s => s.nodeName === 'message').pop();
expect(sent_stanza.querySelector('body').innerHTML).toBe('💩 😇'); expect(sent_stanza.querySelector('body').innerHTML).toBe('💩 😇');
done() }));
}));
it("can show custom emojis", it("can show custom emojis",
mock.initConverse( mock.initConverse(
@ -181,7 +178,7 @@ describe("Emojis", function () {
"flags": ":flag_ac:", "flags": ":flag_ac:",
"custom": ':xmpp:' "custom": ':xmpp:'
} }, } },
async function (done, _converse) { async function (_converse) {
await mock.waitForRoster(_converse, 'current', 1); await mock.waitForRoster(_converse, 'current', 1);
const contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit'; const contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit';
@ -208,7 +205,6 @@ describe("Emojis", function () {
const body = view.querySelector('converse-chat-message-body'); const body = view.querySelector('converse-chat-message-body');
await u.waitUntil(() => body.innerHTML.replace(/<!-.*?->/g, '').trim() === await u.waitUntil(() => body.innerHTML.replace(/<!-.*?->/g, '').trim() ===
'Running tests for <img class="emoji" draggable="false" title=":converse:" alt=":converse:" src="/dist/images/custom_emojis/converse.png">'); 'Running tests for <img class="emoji" draggable="false" title=":converse:" alt=":converse:" src="/dist/images/custom_emojis/converse.png">');
done();
})); }));
}); });
}); });

View File

@ -8,7 +8,7 @@ describe("XEP-0363: HTTP File Upload", function () {
describe("Discovering support", function () { describe("Discovering support", function () {
it("is done automatically", mock.initConverse(['chatBoxesFetched'], {}, async function (done, _converse) { it("is done automatically", mock.initConverse(['chatBoxesFetched'], {}, async function (_converse) {
const IQ_stanzas = _converse.connection.IQ_stanzas; const IQ_stanzas = _converse.connection.IQ_stanzas;
await mock.waitUntilDiscoConfirmed(_converse, _converse.bare_jid, [], []); await mock.waitUntilDiscoConfirmed(_converse, _converse.bare_jid, [], []);
let selector = 'iq[to="montague.lit"] query[xmlns="http://jabber.org/protocol/disco#info"]'; let selector = 'iq[to="montague.lit"] query[xmlns="http://jabber.org/protocol/disco#info"]';
@ -133,7 +133,6 @@ describe("XEP-0363: HTTP File Upload", function () {
expect(features.length).toBe(1); expect(features.length).toBe(1);
expect(features[0].get('jid')).toBe('upload.montague.lit'); expect(features[0].get('jid')).toBe('upload.montague.lit');
expect(features[0].dataforms.where({'FORM_TYPE': {value: "urn:xmpp:http:upload:0", type: "hidden"}}).length).toBe(1); expect(features[0].dataforms.where({'FORM_TYPE': {value: "urn:xmpp:http:upload:0", type: "hidden"}}).length).toBe(1);
done();
})); }));
}); });
@ -141,7 +140,7 @@ describe("XEP-0363: HTTP File Upload", function () {
describe("A file upload toolbar button", function () { describe("A file upload toolbar button", function () {
it("does not appear in private chats", it("does not appear in private chats",
mock.initConverse([], {}, async function (done, _converse) { mock.initConverse([], {}, async function (_converse) {
await mock.waitForRoster(_converse, 'current', 3); await mock.waitForRoster(_converse, 'current', 3);
mock.openControlBox(_converse); mock.openControlBox(_converse);
@ -155,7 +154,6 @@ describe("XEP-0363: HTTP File Upload", function () {
await mock.waitUntilDiscoConfirmed(_converse, _converse.domain, [], [], [], 'items'); await mock.waitUntilDiscoConfirmed(_converse, _converse.domain, [], [], [], 'items');
const view = _converse.chatboxviews.get(contact_jid); const view = _converse.chatboxviews.get(contact_jid);
expect(view.querySelector('.chat-toolbar .fileupload')).toBe(null); expect(view.querySelector('.chat-toolbar .fileupload')).toBe(null);
done();
})); }));
}); });
}); });
@ -164,7 +162,7 @@ describe("XEP-0363: HTTP File Upload", function () {
describe("A file upload toolbar button", function () { describe("A file upload toolbar button", function () {
it("appears in private chats", mock.initConverse(async (done, _converse) => { it("appears in private chats", mock.initConverse(async (_converse) => {
await mock.waitUntilDiscoConfirmed( await mock.waitUntilDiscoConfirmed(
_converse, _converse.domain, _converse, _converse.domain,
[{'category': 'server', 'type':'IM'}], [{'category': 'server', 'type':'IM'}],
@ -178,12 +176,11 @@ describe("XEP-0363: HTTP File Upload", function () {
const view = _converse.chatboxviews.get(contact_jid); const view = _converse.chatboxviews.get(contact_jid);
const el = await u.waitUntil(() => view.querySelector('.chat-toolbar .fileupload')); const el = await u.waitUntil(() => view.querySelector('.chat-toolbar .fileupload'));
expect(el).not.toEqual(null); expect(el).not.toEqual(null);
done();
})); }));
describe("when clicked and a file chosen", function () { describe("when clicked and a file chosen", function () {
it("is uploaded and sent out", mock.initConverse(['chatBoxesFetched'], {} ,async (done, _converse) => { it("is uploaded and sent out", mock.initConverse(['chatBoxesFetched'], {} ,async (_converse) => {
const base_url = 'https://conversejs.org'; const base_url = 'https://conversejs.org';
await mock.waitUntilDiscoConfirmed( await mock.waitUntilDiscoConfirmed(
_converse, _converse.domain, _converse, _converse.domain,
@ -282,11 +279,10 @@ describe("XEP-0363: HTTP File Upload", function () {
`<a target="_blank" rel="noopener" href="${base_url}/logo/conversejs-filled.svg">`+ `<a target="_blank" rel="noopener" href="${base_url}/logo/conversejs-filled.svg">`+
`Download file "conversejs-filled.svg"</a>`); `Download file "conversejs-filled.svg"</a>`);
XMLHttpRequest.prototype.send = send_backup; XMLHttpRequest.prototype.send = send_backup;
done();
})); }));
it("shows an error message if the file is too large", it("shows an error message if the file is too large",
mock.initConverse(['chatBoxesFetched'], {}, async function (done, _converse) { mock.initConverse(['chatBoxesFetched'], {}, async function (_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;
@ -398,14 +394,13 @@ describe("XEP-0363: HTTP File Upload", function () {
expect(messages.length).toBe(1); expect(messages.length).toBe(1);
expect(messages[0].textContent.trim()).toBe( expect(messages[0].textContent.trim()).toBe(
'The size of your file, my-juliet.jpg, exceeds the maximum allowed by your server, which is 5 MB.'); 'The size of your file, my-juliet.jpg, exceeds the maximum allowed by your server, which is 5 MB.');
done();
})); }));
}); });
}); });
describe("While a file is being uploaded", function () { describe("While a file is being uploaded", function () {
it("shows a progress bar", mock.initConverse(['chatBoxesFetched'], {}, async function (done, _converse) { it("shows a progress bar", mock.initConverse(['chatBoxesFetched'], {}, async function (_converse) {
await mock.waitUntilDiscoConfirmed( await mock.waitUntilDiscoConfirmed(
_converse, _converse.domain, _converse, _converse.domain,
[{'category': 'server', 'type':'IM'}], [{'category': 'server', 'type':'IM'}],
@ -466,7 +461,6 @@ describe("XEP-0363: HTTP File Upload", function () {
message.set('progress', 1); message.set('progress', 1);
await u.waitUntil(() => view.querySelector('.chat-content progress').getAttribute('value') === '1'); await u.waitUntil(() => view.querySelector('.chat-content progress').getAttribute('value') === '1');
expect(view.querySelector('.chat-content .chat-msg__text').textContent).toBe('Uploading file: my-juliet.jpg, 22.91 KB'); expect(view.querySelector('.chat-content .chat-msg__text').textContent).toBe('Uploading file: my-juliet.jpg, 22.91 KB');
done();
}); });
_converse.connection._dataRecv(mock.createRequest(stanza)); _converse.connection._dataRecv(mock.createRequest(stanza));
})); }));

View File

@ -8,7 +8,7 @@ const u = converse.env.utils;
describe("A XEP-0333 Chat Marker", function () { describe("A XEP-0333 Chat Marker", function () {
it("is sent when a markable message is received from a roster contact", it("is sent when a markable message is received from a roster contact",
mock.initConverse([], {}, async function (done, _converse) { mock.initConverse([], {}, async function (_converse) {
await mock.waitForRoster(_converse, 'current', 1); await mock.waitForRoster(_converse, 'current', 1);
const contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit'; const contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit';
@ -33,11 +33,10 @@ describe("A XEP-0333 Chat Marker", function () {
`to="${contact_jid}" type="chat" xmlns="jabber:client">`+ `to="${contact_jid}" type="chat" xmlns="jabber:client">`+
`<received id="${msgid}" xmlns="urn:xmpp:chat-markers:0"/>`+ `<received id="${msgid}" xmlns="urn:xmpp:chat-markers:0"/>`+
`</message>`); `</message>`);
done();
})); }));
it("is not sent when a markable message is received from someone not on the roster", it("is not sent when a markable message is received from someone not on the roster",
mock.initConverse([], {'allow_non_roster_messaging': true}, async function (done, _converse) { mock.initConverse([], {'allow_non_roster_messaging': true}, async function (_converse) {
await mock.waitForRoster(_converse, 'current', 0); await mock.waitForRoster(_converse, 'current', 0);
const contact_jid = 'someone@montague.lit'; const contact_jid = 'someone@montague.lit';
@ -66,11 +65,10 @@ describe("A XEP-0333 Chat Marker", function () {
`<no-permanent-store xmlns="urn:xmpp:hints"/>`+ `<no-permanent-store xmlns="urn:xmpp:hints"/>`+
`</message>` `</message>`
); );
done();
})); }));
it("is ignored if it's a carbon copy of one that I sent from a different client", it("is ignored if it's a carbon copy of one that I sent from a different client",
mock.initConverse([], {}, async function (done, _converse) { mock.initConverse([], {}, async function (_converse) {
await mock.waitForRoster(_converse, 'current', 1); await mock.waitForRoster(_converse, 'current', 1);
await mock.waitUntilDiscoConfirmed(_converse, _converse.bare_jid, [], [Strophe.NS.SID]); await mock.waitUntilDiscoConfirmed(_converse, _converse.bare_jid, [], [Strophe.NS.SID]);
@ -112,6 +110,5 @@ describe("A XEP-0333 Chat Marker", function () {
await u.waitUntil(() => _converse.api.trigger.calls.count(), 500); await u.waitUntil(() => _converse.api.trigger.calls.count(), 500);
expect(view.querySelectorAll('.chat-msg').length).toBe(1); expect(view.querySelectorAll('.chat-msg').length).toBe(1);
expect(view.model.messages.length).toBe(1); expect(view.model.messages.length).toBe(1);
done();
})); }));
}); });

View File

@ -4,7 +4,7 @@ const { u, sizzle, $msg } = converse.env;
describe("A Groupchat Message", function () { describe("A Groupchat Message", function () {
it("supports the /me command", mock.initConverse([], {}, async function (done, _converse) { it("supports the /me command", mock.initConverse([], {}, async function (_converse) {
await mock.waitUntilDiscoConfirmed(_converse, 'montague.lit', [], ['vcard-temp']); await mock.waitUntilDiscoConfirmed(_converse, 'montague.lit', [], ['vcard-temp']);
await u.waitUntil(() => _converse.xmppstatus.vcard.get('fullname')); await u.waitUntil(() => _converse.xmppstatus.vcard.get('fullname'));
await mock.waitForRoster(_converse, 'current'); await mock.waitForRoster(_converse, 'current');
@ -51,13 +51,12 @@ describe("A Groupchat Message", function () {
await u.waitUntil(() => view.querySelectorAll('.chat-msg__text').length === 3); await u.waitUntil(() => view.querySelectorAll('.chat-msg__text').length === 3);
await u.waitUntil(() => sizzle('.chat-msg__text:last', view).pop().innerHTML.replace(/<!-.*?->/g, '') === await u.waitUntil(() => sizzle('.chat-msg__text:last', view).pop().innerHTML.replace(/<!-.*?->/g, '') ===
'mentions <span class="mention mention--self badge badge-info">romeo</span>'); 'mentions <span class="mention mention--self badge badge-info">romeo</span>');
done();
})); }));
}); });
describe("A Message", function () { describe("A Message", function () {
it("supports the /me command", mock.initConverse([], {}, async function (done, _converse) { it("supports the /me command", mock.initConverse([], {}, async function (_converse) {
await mock.waitForRoster(_converse, 'current'); await mock.waitForRoster(_converse, 'current');
await mock.waitUntilDiscoConfirmed(_converse, 'montague.lit', [], ['vcard-temp']); await mock.waitUntilDiscoConfirmed(_converse, 'montague.lit', [], ['vcard-temp']);
await u.waitUntil(() => _converse.xmppstatus.vcard.get('fullname')); await u.waitUntil(() => _converse.xmppstatus.vcard.get('fullname'));
@ -105,6 +104,5 @@ describe("A Message", function () {
expect(sizzle('.chat-msg__text:last', view).pop().textContent).toBe('wrote a 3rd person message'); expect(sizzle('.chat-msg__text:last', view).pop().textContent).toBe('wrote a 3rd person message');
expect(u.isVisible(sizzle('.chat-msg__author:last', view).pop())).toBeTruthy(); expect(u.isVisible(sizzle('.chat-msg__author:last', view).pop())).toBeTruthy();
done();
})); }));
}); });

View File

@ -6,7 +6,7 @@ describe("A Chat Message", function () {
it("will render audio files from their URLs", it("will render audio files from their URLs",
mock.initConverse(['chatBoxesFetched'], {}, mock.initConverse(['chatBoxesFetched'], {},
async function (done, _converse) { async function (_converse) {
await mock.waitForRoster(_converse, 'current'); await mock.waitForRoster(_converse, 'current');
const base_url = 'https://conversejs.org'; const base_url = 'https://conversejs.org';
const message = base_url+"/logo/audio.mp3"; const message = base_url+"/logo/audio.mp3";
@ -20,6 +20,5 @@ describe("A Chat Message", function () {
expect(msg.innerHTML.replace(/<!-.*?->/g, '').replace(/(\r\n|\n|\r)/gm, "").trim()).toEqual( expect(msg.innerHTML.replace(/<!-.*?->/g, '').replace(/(\r\n|\n|\r)/gm, "").trim()).toEqual(
`<audio controls="" src="${message}"></audio>`+ `<audio controls="" src="${message}"></audio>`+
`<a target="_blank" rel="noopener" href="${message}">${message}</a>`); `<a target="_blank" rel="noopener" href="${message}">${message}</a>`);
done();
})); }));
}); });

View File

@ -4,7 +4,7 @@ const { sizzle, u } = converse.env;
describe("A Chat Message", function () { describe("A Chat Message", function () {
it("will render images from their URLs", mock.initConverse(['chatBoxesFetched'], {}, async function (done, _converse) { it("will render images from their URLs", mock.initConverse(['chatBoxesFetched'], {}, async function (_converse) {
await mock.waitForRoster(_converse, 'current'); await mock.waitForRoster(_converse, 'current');
const base_url = 'https://conversejs.org'; const base_url = 'https://conversejs.org';
let message = base_url+"/logo/conversejs-filled.svg"; let message = base_url+"/logo/conversejs-filled.svg";
@ -49,11 +49,10 @@ describe("A Chat Message", function () {
// Check that the Imgur URL gets a .png attached to make it render // Check that the Imgur URL gets a .png attached to make it render
await u.waitUntil(() => Array.from(view.querySelectorAll('.chat-content .chat-image')).pop().src.endsWith('png'), 1000); await u.waitUntil(() => Array.from(view.querySelectorAll('.chat-content .chat-image')).pop().src.endsWith('png'), 1000);
done();
})); }));
it("will not render images if show_images_inline is false", it("will not render images if show_images_inline is false",
mock.initConverse(['chatBoxesFetched'], {'show_images_inline': false}, async function (done, _converse) { mock.initConverse(['chatBoxesFetched'], {'show_images_inline': false}, async function (_converse) {
await mock.waitForRoster(_converse, 'current'); await mock.waitForRoster(_converse, 'current');
const base_url = 'https://conversejs.org'; const base_url = 'https://conversejs.org';
const message = base_url+"/logo/conversejs-filled.svg"; const message = base_url+"/logo/conversejs-filled.svg";
@ -65,13 +64,12 @@ describe("A Chat Message", function () {
const sel = '.chat-content .chat-msg:last .chat-msg__text'; const sel = '.chat-content .chat-msg:last .chat-msg__text';
await u.waitUntil(() => sizzle(sel).pop().innerHTML.replace(/<!-.*?->/g, '').trim() === message); await u.waitUntil(() => sizzle(sel).pop().innerHTML.replace(/<!-.*?->/g, '').trim() === message);
expect(true).toBe(true); expect(true).toBe(true);
done();
})); }));
it("will render images from approved URLs only", it("will render images from approved URLs only",
mock.initConverse( mock.initConverse(
['chatBoxesFetched'], {'show_images_inline': ['conversejs.org']}, ['chatBoxesFetched'], {'show_images_inline': ['conversejs.org']},
async function (done, _converse) { async function (_converse) {
await mock.waitForRoster(_converse, 'current'); await mock.waitForRoster(_converse, 'current');
const base_url = 'https://conversejs.org'; const base_url = 'https://conversejs.org';
@ -88,13 +86,12 @@ describe("A Chat Message", function () {
await u.waitUntil(() => view.querySelectorAll('.chat-content .chat-msg').length === 2, 1000); await u.waitUntil(() => view.querySelectorAll('.chat-content .chat-msg').length === 2, 1000);
await u.waitUntil(() => view.querySelectorAll('.chat-content .chat-image').length === 1, 1000) await u.waitUntil(() => view.querySelectorAll('.chat-content .chat-image').length === 1, 1000)
expect(view.querySelectorAll('.chat-content .chat-image').length).toBe(1); expect(view.querySelectorAll('.chat-content .chat-image').length).toBe(1);
done();
})); }));
it("will fall back to rendering images as URLs", it("will fall back to rendering images as URLs",
mock.initConverse( mock.initConverse(
['chatBoxesFetched'], {}, ['chatBoxesFetched'], {},
async function (done, _converse) { async function (_converse) {
await mock.waitForRoster(_converse, 'current'); await mock.waitForRoster(_converse, 'current');
const base_url = 'https://conversejs.org'; const base_url = 'https://conversejs.org';
@ -109,7 +106,6 @@ describe("A Chat Message", function () {
const msg = sizzle('.chat-content .chat-msg:last .chat-msg__text').pop(); const msg = sizzle('.chat-content .chat-msg:last .chat-msg__text').pop();
await u.waitUntil(() => msg.innerHTML.replace(/<!-.*?->/g, '').trim() == await u.waitUntil(() => msg.innerHTML.replace(/<!-.*?->/g, '').trim() ==
`<a target="_blank" rel="noopener" href="https://conversejs.org/logo/non-existing.svg">https://conversejs.org/logo/non-existing.svg</a>`, 1000); `<a target="_blank" rel="noopener" href="https://conversejs.org/logo/non-existing.svg">https://conversejs.org/logo/non-existing.svg</a>`, 1000);
done();
})); }));
it("will fall back to rendering URLs that match image_urls_regex as URLs", it("will fall back to rendering URLs that match image_urls_regex as URLs",
@ -118,7 +114,7 @@ describe("A Chat Message", function () {
'show_images_inline': ['twimg.com'], 'show_images_inline': ['twimg.com'],
'image_urls_regex': /^https?:\/\/(www.)?(pbs\.twimg\.com\/)/i 'image_urls_regex': /^https?:\/\/(www.)?(pbs\.twimg\.com\/)/i
}, },
async function (done, _converse) { async function (_converse) {
await mock.waitForRoster(_converse, 'current'); await mock.waitForRoster(_converse, 'current');
const message = "https://pbs.twimg.com/media/string?format=jpg&name=small"; const message = "https://pbs.twimg.com/media/string?format=jpg&name=small";
@ -132,13 +128,12 @@ describe("A Chat Message", function () {
const msg = view.querySelector('.chat-content .chat-msg .chat-msg__text'); const msg = view.querySelector('.chat-content .chat-msg .chat-msg__text');
await u.waitUntil(() => msg.innerHTML.replace(/<!-.*?->/g, '').trim() == await u.waitUntil(() => msg.innerHTML.replace(/<!-.*?->/g, '').trim() ==
`<a target="_blank" rel="noopener" href="https://pbs.twimg.com/media/string?format=jpg&amp;name=small">https://pbs.twimg.com/media/string?format=jpg&amp;name=small</a>`, 1000); `<a target="_blank" rel="noopener" href="https://pbs.twimg.com/media/string?format=jpg&amp;name=small">https://pbs.twimg.com/media/string?format=jpg&amp;name=small</a>`, 1000);
done();
})); }));
it("will respect a changed setting when re-rendered", it("will respect a changed setting when re-rendered",
mock.initConverse( mock.initConverse(
['chatBoxesFetched'], {'show_images_inline': true}, ['chatBoxesFetched'], {'show_images_inline': true},
async function (done, _converse) { async function (_converse) {
const { api } = _converse; const { api } = _converse;
await mock.waitForRoster(_converse, 'current'); await mock.waitForRoster(_converse, 'current');
@ -152,6 +147,5 @@ describe("A Chat Message", function () {
view.querySelector('converse-chat-message').requestUpdate(); view.querySelector('converse-chat-message').requestUpdate();
await u.waitUntil(() => view.querySelector('converse-chat-message-body .chat-image') === null); await u.waitUntil(() => view.querySelector('converse-chat-message-body .chat-image') === null);
expect(true).toBe(true); expect(true).toBe(true);
done();
})); }));
}); });

View File

@ -4,7 +4,7 @@ const { Strophe, sizzle, u } = converse.env;
describe("A Chat Message", function () { describe("A Chat Message", function () {
it("will render videos from their URLs", mock.initConverse(['chatBoxesFetched'], {}, async function (done, _converse) { it("will render videos from their URLs", mock.initConverse(['chatBoxesFetched'], {}, async function (_converse) {
await mock.waitForRoster(_converse, 'current'); await mock.waitForRoster(_converse, 'current');
// let message = "https://i.imgur.com/Py9ifJE.mp4"; // let message = "https://i.imgur.com/Py9ifJE.mp4";
const base_url = 'https://conversejs.org'; const base_url = 'https://conversejs.org';
@ -27,11 +27,10 @@ describe("A Chat Message", function () {
expect(msg.innerHTML.replace(/<!-.*?->/g, '').trim()).toEqual( expect(msg.innerHTML.replace(/<!-.*?->/g, '').trim()).toEqual(
`<video controls="" preload="metadata" src="${Strophe.xmlescape(message)}"></video>`+ `<video controls="" preload="metadata" src="${Strophe.xmlescape(message)}"></video>`+
`<a target="_blank" rel="noopener" href="${Strophe.xmlescape(message)}">${Strophe.xmlescape(message)}</a>`); `<a target="_blank" rel="noopener" href="${Strophe.xmlescape(message)}">${Strophe.xmlescape(message)}</a>`);
done();
})); }));
it("will not render videos if embed_videos is false", it("will not render videos if embed_videos is false",
mock.initConverse(['chatBoxesFetched'], {'embed_videos': false}, async function (done, _converse) { mock.initConverse(['chatBoxesFetched'], {'embed_videos': false}, async function (_converse) {
await mock.waitForRoster(_converse, 'current'); await mock.waitForRoster(_converse, 'current');
// let message = "https://i.imgur.com/Py9ifJE.mp4"; // let message = "https://i.imgur.com/Py9ifJE.mp4";
const base_url = 'https://conversejs.org'; const base_url = 'https://conversejs.org';
@ -44,13 +43,12 @@ describe("A Chat Message", function () {
const sel = '.chat-content .chat-msg:last .chat-msg__text'; const sel = '.chat-content .chat-msg:last .chat-msg__text';
await u.waitUntil(() => sizzle(sel).pop().innerHTML.replace(/<!-.*?->/g, '').trim() === message); await u.waitUntil(() => sizzle(sel).pop().innerHTML.replace(/<!-.*?->/g, '').trim() === message);
expect(true).toBe(true); expect(true).toBe(true);
done();
})); }));
it("will render videos from approved URLs only", it("will render videos from approved URLs only",
mock.initConverse( mock.initConverse(
['chatBoxesFetched'], {'embed_videos': ['conversejs.org']}, ['chatBoxesFetched'], {'embed_videos': ['conversejs.org']},
async function (done, _converse) { async function (_converse) {
await mock.waitForRoster(_converse, 'current'); await mock.waitForRoster(_converse, 'current');
let message = "https://i.imgur.com/Py9ifJE.mp4"; let message = "https://i.imgur.com/Py9ifJE.mp4";
@ -69,6 +67,5 @@ describe("A Chat Message", function () {
expect(msg.innerHTML.replace(/<!-.*?->/g, '').trim()).toEqual( expect(msg.innerHTML.replace(/<!-.*?->/g, '').trim()).toEqual(
`<video controls="" preload="metadata" src="${message}"></video>`+ `<video controls="" preload="metadata" src="${message}"></video>`+
`<a target="_blank" rel="noopener" href="${message}">${message}</a>`); `<a target="_blank" rel="noopener" href="${message}">${message}</a>`);
done();
})); }));
}); });

View File

@ -7,7 +7,7 @@ describe("A Chat Message", function () {
it("will be demarcated if it's the first newly received message", it("will be demarcated if it's the first newly received message",
mock.initConverse(['chatBoxesFetched'], {}, mock.initConverse(['chatBoxesFetched'], {},
async function (done, _converse) { async function (_converse) {
await mock.waitForRoster(_converse, 'current', 1); await mock.waitForRoster(_converse, 'current', 1);
const contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit'; const contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit';
@ -28,14 +28,13 @@ describe("A Chat Message", function () {
await u.waitUntil(() => view.querySelector('converse-chat-message:last-child .chat-msg__text')?.textContent === 'This message will be new'); await u.waitUntil(() => view.querySelector('converse-chat-message:last-child .chat-msg__text')?.textContent === 'This message will be new');
const last_msg_el = view.querySelector('converse-chat-message:last-child'); const last_msg_el = view.querySelector('converse-chat-message:last-child');
expect(last_msg_el.firstElementChild?.textContent).toBe('New messages'); expect(last_msg_el.firstElementChild?.textContent).toBe('New messages');
done();
})); }));
it("is rejected if it's an unencapsulated forwarded message", it("is rejected if it's an unencapsulated forwarded message",
mock.initConverse( mock.initConverse(
['chatBoxesFetched'], {}, ['chatBoxesFetched'], {},
async function (done, _converse) { async function (_converse) {
await mock.waitForRoster(_converse, 'current', 2); await mock.waitForRoster(_converse, 'current', 2);
const contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit'; const contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit';
@ -74,11 +73,10 @@ describe("A Chat Message", function () {
'</message>'); '</message>');
models = await _converse.api.chats.get(); models = await _converse.api.chats.get();
expect(models.length).toBe(1); expect(models.length).toBe(1);
done();
})); }));
it("can be received out of order, and will still be displayed in the right order", it("can be received out of order, and will still be displayed in the right order",
mock.initConverse([], {}, async function (done, _converse) { mock.initConverse([], {}, async function (_converse) {
await mock.waitForRoster(_converse, 'current'); await mock.waitForRoster(_converse, 'current');
await mock.openControlBox(_converse); await mock.openControlBox(_converse);
@ -238,11 +236,10 @@ describe("A Chat Message", function () {
expect(day.getAttribute('data-isodate')).toEqual(dayjs().startOf('day').toISOString()); expect(day.getAttribute('data-isodate')).toEqual(dayjs().startOf('day').toISOString());
expect(day.nextElementSibling.querySelector('.chat-msg__text').textContent).toBe('latest message'); expect(day.nextElementSibling.querySelector('.chat-msg__text').textContent).toBe('latest message');
expect(u.hasClass('chat-msg--followup', el)).toBe(false); expect(u.hasClass('chat-msg--followup', el)).toBe(false);
done();
})); }));
it("is ignored if it's a malformed headline message", it("is ignored if it's a malformed headline message",
mock.initConverse([], {}, async function (done, _converse) { mock.initConverse([], {}, async function (_converse) {
await mock.waitForRoster(_converse, 'current'); await mock.waitForRoster(_converse, 'current');
await mock.openControlBox(_converse); await mock.openControlBox(_converse);
@ -262,12 +259,11 @@ describe("A Chat Message", function () {
"handleMessageStanza: Ignoring incoming server message from JID: montague.lit" "handleMessageStanza: Ignoring incoming server message from JID: montague.lit"
); );
expect(_converse.api.chatboxes.get).not.toHaveBeenCalled(); expect(_converse.api.chatboxes.get).not.toHaveBeenCalled();
done();
})); }));
it("can be a carbon message, as defined in XEP-0280", it("can be a carbon message, as defined in XEP-0280",
mock.initConverse([], {}, async function (done, _converse) { mock.initConverse([], {}, async function (_converse) {
const include_nick = false; const include_nick = false;
await mock.waitForRoster(_converse, 'current', 2, include_nick); await mock.waitForRoster(_converse, 'current', 2, include_nick);
@ -312,11 +308,10 @@ describe("A Chat Message", function () {
expect(view.querySelector('.chat-msg__time').textContent.match(/^[0-9][0-9]:[0-9][0-9]/)).toBeTruthy(); expect(view.querySelector('.chat-msg__time').textContent.match(/^[0-9][0-9]:[0-9][0-9]/)).toBeTruthy();
await u.waitUntil(() => chatbox.vcard.get('fullname') === 'Juliet Capulet') await u.waitUntil(() => chatbox.vcard.get('fullname') === 'Juliet Capulet')
expect(view.querySelector('span.chat-msg__author').textContent.trim()).toBe('Juliet Capulet'); expect(view.querySelector('span.chat-msg__author').textContent.trim()).toBe('Juliet Capulet');
done();
})); }));
it("can be a carbon message that this user sent from a different client, as defined in XEP-0280", it("can be a carbon message that this user sent from a different client, as defined in XEP-0280",
mock.initConverse([], {}, async function (done, _converse) { mock.initConverse([], {}, async function (_converse) {
await mock.waitUntilDiscoConfirmed(_converse, 'montague.lit', [], ['vcard-temp']); await mock.waitUntilDiscoConfirmed(_converse, 'montague.lit', [], ['vcard-temp']);
await mock.waitForRoster(_converse, 'current'); await mock.waitForRoster(_converse, 'current');
@ -357,11 +352,10 @@ describe("A Chat Message", function () {
// Now check that the message appears inside the chatbox in the DOM // Now check that the message appears inside the chatbox in the DOM
const msg_el = await u.waitUntil(() => view.querySelector('.chat-content .chat-msg .chat-msg__text')); const msg_el = await u.waitUntil(() => view.querySelector('.chat-content .chat-msg .chat-msg__text'));
expect(msg_el.textContent).toEqual(msgtext); expect(msg_el.textContent).toEqual(msgtext);
done();
})); }));
it("will be discarded if it's a malicious message meant to look like a carbon copy", it("will be discarded if it's a malicious message meant to look like a carbon copy",
mock.initConverse([], {}, async function (done, _converse) { mock.initConverse([], {}, async function (_converse) {
await mock.waitForRoster(_converse, 'current'); await mock.waitForRoster(_converse, 'current');
await mock.openControlBox(_converse); await mock.openControlBox(_converse);
@ -401,11 +395,10 @@ describe("A Chat Message", function () {
// Check that the chatbox for the malicous user is not created // Check that the chatbox for the malicous user is not created
chatbox = await _converse.api.chats.get(sender_jid); chatbox = await _converse.api.chats.get(sender_jid);
expect(chatbox).toBe(null); expect(chatbox).toBe(null);
done();
})); }));
it("will indicate when it has a time difference of more than a day between it and its predecessor", it("will indicate when it has a time difference of more than a day between it and its predecessor",
mock.initConverse(['chatBoxesFetched'], {}, async function (done, _converse) { mock.initConverse(['chatBoxesFetched'], {}, async function (_converse) {
const include_nick = false; const include_nick = false;
await mock.waitForRoster(_converse, 'current', 2, include_nick); await mock.waitForRoster(_converse, 'current', 2, include_nick);
@ -492,11 +485,10 @@ describe("A Chat Message", function () {
expect(view.querySelector('converse-chat-message:last-child .chat-msg__text').textContent).toEqual(message); expect(view.querySelector('converse-chat-message:last-child .chat-msg__text').textContent).toEqual(message);
expect(view.querySelector('converse-chat-message:last-child .chat-msg__time').textContent.match(/^[0-9][0-9]:[0-9][0-9]/)).toBeTruthy(); expect(view.querySelector('converse-chat-message:last-child .chat-msg__time').textContent.match(/^[0-9][0-9]:[0-9][0-9]/)).toBeTruthy();
expect(view.querySelector('converse-chat-message:last-child .chat-msg__author').textContent.trim()).toBe('Juliet Capulet'); expect(view.querySelector('converse-chat-message:last-child .chat-msg__author').textContent.trim()).toBe('Juliet Capulet');
done();
})); }));
it("is sanitized to prevent Javascript injection attacks", it("is sanitized to prevent Javascript injection attacks",
mock.initConverse(['chatBoxesFetched'], {}, async function (done, _converse) { mock.initConverse(['chatBoxesFetched'], {}, async function (_converse) {
await mock.waitForRoster(_converse, 'current'); await mock.waitForRoster(_converse, 'current');
await mock.openControlBox(_converse); await mock.openControlBox(_converse);
@ -510,11 +502,10 @@ describe("A Chat Message", function () {
const msg = sizzle('.chat-content .chat-msg:last .chat-msg__text', view).pop(); const msg = sizzle('.chat-content .chat-msg:last .chat-msg__text', view).pop();
expect(msg.textContent).toEqual(message); expect(msg.textContent).toEqual(message);
expect(msg.innerHTML.replace(/<!-.*?->/g, '')).toEqual('&lt;p&gt;This message contains &lt;em&gt;some&lt;/em&gt; &lt;b&gt;markup&lt;/b&gt;&lt;/p&gt;'); expect(msg.innerHTML.replace(/<!-.*?->/g, '')).toEqual('&lt;p&gt;This message contains &lt;em&gt;some&lt;/em&gt; &lt;b&gt;markup&lt;/b&gt;&lt;/p&gt;');
done();
})); }));
it("can contain hyperlinks, which will be clickable", it("can contain hyperlinks, which will be clickable",
mock.initConverse(['chatBoxesFetched'], {}, async function (done, _converse) { mock.initConverse(['chatBoxesFetched'], {}, async function (_converse) {
await mock.waitForRoster(_converse, 'current'); await mock.waitForRoster(_converse, 'current');
await mock.openControlBox(_converse); await mock.openControlBox(_converse);
@ -530,12 +521,11 @@ describe("A Chat Message", function () {
expect(msg.textContent).toEqual(message); expect(msg.textContent).toEqual(message);
await u.waitUntil(() => msg.innerHTML.replace(/<!-.*?->/g, '') === await u.waitUntil(() => msg.innerHTML.replace(/<!-.*?->/g, '') ===
'This message contains a hyperlink: <a target="_blank" rel="noopener" href="http://www.opkode.com">www.opkode.com</a>'); 'This message contains a hyperlink: <a target="_blank" rel="noopener" href="http://www.opkode.com">www.opkode.com</a>');
done();
})); }));
it("will remove url query parameters from hyperlinks as set", it("will remove url query parameters from hyperlinks as set",
mock.initConverse(['chatBoxesFetched'], {'filter_url_query_params': ['utm_medium', 'utm_content', 's']}, mock.initConverse(['chatBoxesFetched'], {'filter_url_query_params': ['utm_medium', 'utm_content', 's']},
async function (done, _converse) { async function (_converse) {
await mock.waitForRoster(_converse, 'current'); await mock.waitForRoster(_converse, 'current');
await mock.openControlBox(_converse); await mock.openControlBox(_converse);
@ -559,10 +549,9 @@ describe("A Chat Message", function () {
await u.waitUntil(() => msg.innerHTML.replace(/<!-.*?->/g, '') === await u.waitUntil(() => msg.innerHTML.replace(/<!-.*?->/g, '') ===
'Another message with a hyperlink with forbidden query params: '+ 'Another message with a hyperlink with forbidden query params: '+
'<a target="_blank" rel="noopener" href="https://www.opkode.com/?id=0&amp;utm_content=1&amp;s=1">https://www.opkode.com/?id=0&amp;utm_content=1&amp;s=1</a>'); '<a target="_blank" rel="noopener" href="https://www.opkode.com/?id=0&amp;utm_content=1&amp;s=1">https://www.opkode.com/?id=0&amp;utm_content=1&amp;s=1</a>');
done();
})); }));
it("will render newlines", mock.initConverse(['chatBoxesFetched'], {}, async function (done, _converse) { it("will render newlines", mock.initConverse(['chatBoxesFetched'], {}, async function (_converse) {
await mock.waitForRoster(_converse, 'current'); await mock.waitForRoster(_converse, 'current');
const contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit'; const contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit';
const view = await mock.openChatBoxFor(_converse, contact_jid); const view = await mock.openChatBoxFor(_converse, contact_jid);
@ -607,13 +596,12 @@ describe("A Chat Message", function () {
const text = view.querySelector('converse-chat-message:last-child .chat-msg__text').innerHTML.replace(/<!-.*?->/g, ''); const text = view.querySelector('converse-chat-message:last-child .chat-msg__text').innerHTML.replace(/<!-.*?->/g, '');
return text === 'Hey\nHave you heard\n\u200B\nthe news?\n<a target="_blank" rel="noopener" href="https://conversejs.org/">https://conversejs.org</a>'; return text === 'Hey\nHave you heard\n\u200B\nthe news?\n<a target="_blank" rel="noopener" href="https://conversejs.org/">https://conversejs.org</a>';
}); });
done();
})); }));
it("will render the message time as configured", it("will render the message time as configured",
mock.initConverse( mock.initConverse(
['chatBoxesFetched'], {}, ['chatBoxesFetched'], {},
async function (done, _converse) { async function (_converse) {
const { api } = _converse; const { api } = _converse;
await mock.waitForRoster(_converse, 'current'); await mock.waitForRoster(_converse, 'current');
@ -634,13 +622,12 @@ describe("A Chat Message", function () {
const msg_time = view.querySelector('.chat-content .chat-msg:last-child .chat-msg__time'); const msg_time = view.querySelector('.chat-content .chat-msg:last-child .chat-msg__time');
const time = dayjs(msg_object.get('time')).format(api.settings.get('time_format')); const time = dayjs(msg_object.get('time')).format(api.settings.get('time_format'));
expect(msg_time.textContent).toBe(time); expect(msg_time.textContent).toBe(time);
done();
})); }));
it("will be correctly identified and rendered as a followup message", it("will be correctly identified and rendered as a followup message",
mock.initConverse( mock.initConverse(
[], {'debounced_content_rendering': false}, [], {'debounced_content_rendering': false},
async function (done, _converse) { async function (_converse) {
await mock.waitForRoster(_converse, 'current'); await mock.waitForRoster(_converse, 'current');
await mock.openControlBox(_converse); await mock.openControlBox(_converse);
@ -793,7 +780,6 @@ describe("A Chat Message", function () {
"Another message within 10 minutes, but from a different person"); "Another message within 10 minutes, but from a different person");
jasmine.clock().uninstall(); jasmine.clock().uninstall();
done();
})); }));
@ -802,7 +788,7 @@ describe("A Chat Message", function () {
it("will appear inside the chatbox it was sent from", it("will appear inside the chatbox it was sent from",
mock.initConverse( mock.initConverse(
['chatBoxesFetched'], {}, ['chatBoxesFetched'], {},
async function (done, _converse) { async function (_converse) {
await mock.waitForRoster(_converse, 'current'); await mock.waitForRoster(_converse, 'current');
await mock.openControlBox(_converse); await mock.openControlBox(_converse);
@ -816,14 +802,13 @@ describe("A Chat Message", function () {
expect(view.model.sendMessage).toHaveBeenCalled(); expect(view.model.sendMessage).toHaveBeenCalled();
expect(view.model.messages.length, 2); expect(view.model.messages.length, 2);
expect(sizzle('.chat-content .chat-msg:last .chat-msg__text', view).pop().textContent).toEqual(message); expect(sizzle('.chat-content .chat-msg:last .chat-msg__text', view).pop().textContent).toEqual(message);
done();
})); }));
it("will be trimmed of leading and trailing whitespace", it("will be trimmed of leading and trailing whitespace",
mock.initConverse( mock.initConverse(
['chatBoxesFetched'], {}, ['chatBoxesFetched'], {},
async function (done, _converse) { async function (_converse) {
await mock.waitForRoster(_converse, 'current', 1); await mock.waitForRoster(_converse, 'current', 1);
const contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit'; const contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit';
@ -834,7 +819,6 @@ describe("A Chat Message", function () {
expect(view.model.messages.at(0).get('message')).toEqual(message.trim()); expect(view.model.messages.at(0).get('message')).toEqual(message.trim());
const message_el = sizzle('.chat-content .chat-msg:last .chat-msg__text', view).pop(); const message_el = sizzle('.chat-content .chat-msg:last .chat-msg__text', view).pop();
expect(message_el.textContent).toEqual(message.trim()); expect(message_el.textContent).toEqual(message.trim());
done();
})); }));
}); });
@ -842,7 +826,7 @@ describe("A Chat Message", function () {
describe("when received from someone else", function () { describe("when received from someone else", function () {
it("will open a chatbox and be displayed inside it", it("will open a chatbox and be displayed inside it",
mock.initConverse([], {}, async function (done, _converse) { mock.initConverse([], {}, async function (_converse) {
const include_nick = false; const include_nick = false;
await mock.waitForRoster(_converse, 'current', 1, include_nick); await mock.waitForRoster(_converse, 'current', 1, include_nick);
@ -883,11 +867,10 @@ describe("A Chat Message", function () {
expect(view.querySelector('.chat-msg__time').textContent.match(/^[0-9][0-9]:[0-9][0-9]/)).toBeTruthy(); expect(view.querySelector('.chat-msg__time').textContent.match(/^[0-9][0-9]:[0-9][0-9]/)).toBeTruthy();
await u.waitUntil(() => chatbox.vcard.get('fullname') === mock.cur_names[0]); await u.waitUntil(() => chatbox.vcard.get('fullname') === mock.cur_names[0]);
expect(view.querySelector('span.chat-msg__author').textContent.trim()).toBe('Mercutio'); expect(view.querySelector('span.chat-msg__author').textContent.trim()).toBe('Mercutio');
done();
})); }));
it("will be trimmed of leading and trailing whitespace", it("will be trimmed of leading and trailing whitespace",
mock.initConverse([], {}, async function (done, _converse) { mock.initConverse([], {}, async function (_converse) {
await mock.waitForRoster(_converse, 'current', 1, false); await mock.waitForRoster(_converse, 'current', 1, false);
const rosterview = document.querySelector('converse-roster'); const rosterview = document.querySelector('converse-roster');
@ -910,7 +893,6 @@ describe("A Chat Message", function () {
expect(msg_obj.get('message')).toEqual(message.trim()); expect(msg_obj.get('message')).toEqual(message.trim());
const mel = await u.waitUntil(() => view.querySelector('.chat-msg .chat-msg__text')); const mel = await u.waitUntil(() => view.querySelector('.chat-msg .chat-msg__text'));
expect(mel.textContent).toEqual(message.trim()); expect(mel.textContent).toEqual(message.trim());
done();
})); }));
@ -918,7 +900,7 @@ describe("A Chat Message", function () {
it("the VCard for that user is fetched and the chatbox updated with the results", it("the VCard for that user is fetched and the chatbox updated with the results",
mock.initConverse([], {'allow_non_roster_messaging': true}, mock.initConverse([], {'allow_non_roster_messaging': true},
async function (done, _converse) { async function (_converse) {
await mock.waitForRoster(_converse, 'current', 0); await mock.waitForRoster(_converse, 'current', 0);
spyOn(_converse.api, "trigger").and.callThrough(); spyOn(_converse.api, "trigger").and.callThrough();
@ -962,7 +944,6 @@ describe("A Chat Message", function () {
await u.waitUntil(() => chatbox.vcard.get('fullname') === mock.cur_names[0]) await u.waitUntil(() => chatbox.vcard.get('fullname') === mock.cur_names[0])
author_el = view.querySelector('.chat-msg__author'); author_el = view.querySelector('.chat-msg__author');
expect(author_el.textContent.trim().includes('Mercutio')).toBeTruthy(); expect(author_el.textContent.trim().includes('Mercutio')).toBeTruthy();
done();
})); }));
}); });
@ -972,7 +953,7 @@ describe("A Chat Message", function () {
it("will open a chatbox and be displayed inside it if allow_non_roster_messaging is true", it("will open a chatbox and be displayed inside it if allow_non_roster_messaging is true",
mock.initConverse( mock.initConverse(
[], {'allow_non_roster_messaging': false}, [], {'allow_non_roster_messaging': false},
async function (done, _converse) { async function (_converse) {
await mock.waitForRoster(_converse, 'current', 0); await mock.waitForRoster(_converse, 'current', 0);
@ -1019,7 +1000,6 @@ describe("A Chat Message", function () {
expect(view.querySelector('.chat-msg .chat-msg__text').textContent).toEqual(message); expect(view.querySelector('.chat-msg .chat-msg__text').textContent).toEqual(message);
expect(view.querySelector('.chat-msg__time').textContent.match(/^[0-9][0-9]:[0-9][0-9]/)).toBeTruthy(); expect(view.querySelector('.chat-msg__time').textContent.match(/^[0-9][0-9]:[0-9][0-9]/)).toBeTruthy();
expect(view.querySelector('span.chat-msg__author').textContent.trim()).toBe('Mercutio'); expect(view.querySelector('span.chat-msg__author').textContent.trim()).toBe('Mercutio');
done();
})); }));
}); });
@ -1027,7 +1007,7 @@ describe("A Chat Message", function () {
describe("and for which then an error message is received from the server", function () { describe("and for which then an error message is received from the server", function () {
it("will have the error message displayed after itself", it("will have the error message displayed after itself",
mock.initConverse(['chatBoxesFetched'], {}, async function (done, _converse) { mock.initConverse(['chatBoxesFetched'], {}, async function (_converse) {
await mock.waitForRoster(_converse, 'current', 1); await mock.waitForRoster(_converse, 'current', 1);
@ -1142,13 +1122,12 @@ describe("A Chat Message", function () {
expect(el.querySelector('.chat-msg__action-edit')).toBe(null) expect(el.querySelector('.chat-msg__action-edit')).toBe(null)
expect(el.querySelector('.chat-msg__action-retract')).toBe(null) expect(el.querySelector('.chat-msg__action-retract')).toBe(null)
}) })
done();
})); }));
it("will not show to the user an error message for a CSI message", it("will not show to the user an error message for a CSI message",
mock.initConverse( mock.initConverse(
['chatBoxesFetched'], {}, ['chatBoxesFetched'], {},
async function (done, _converse) { async function (_converse) {
// See #1317 // See #1317
// https://github.com/conversejs/converse.js/issues/1317 // https://github.com/conversejs/converse.js/issues/1317
@ -1181,12 +1160,11 @@ describe("A Chat Message", function () {
await view.model.sendMessage(msg_text); await view.model.sendMessage(msg_text);
await u.waitUntil(() => view.querySelectorAll('.chat-msg__text').length); await u.waitUntil(() => view.querySelectorAll('.chat-msg__text').length);
expect(view.querySelectorAll('.chat-error').length).toEqual(0); expect(view.querySelectorAll('.chat-error').length).toEqual(0);
done();
})); }));
}); });
it("will cause the chat area to be scrolled down only if it was at the bottom originally", it("will cause the chat area to be scrolled down only if it was at the bottom originally",
mock.initConverse(['chatBoxesFetched'], {}, async function (done, _converse) { mock.initConverse(['chatBoxesFetched'], {}, async function (_converse) {
await mock.waitForRoster(_converse, 'current'); await mock.waitForRoster(_converse, 'current');
const sender_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit'; const sender_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit';
@ -1216,11 +1194,10 @@ describe("A Chat Message", function () {
indicator_el.click(); indicator_el.click();
await u.waitUntil(() => !view.querySelector('.new-msgs-indicator')); await u.waitUntil(() => !view.querySelector('.new-msgs-indicator'));
await u.waitUntil(() => !view.model.get('scrolled')); await u.waitUntil(() => !view.model.get('scrolled'));
done();
})); }));
it("is ignored if it's intended for a different resource and filter_by_resource is set to true", it("is ignored if it's intended for a different resource and filter_by_resource is set to true",
mock.initConverse([], {}, async function (done, _converse) { mock.initConverse([], {}, async function (_converse) {
const { api } = _converse; const { api } = _converse;
await mock.waitForRoster(_converse, 'current'); await mock.waitForRoster(_converse, 'current');
@ -1262,7 +1239,6 @@ describe("A Chat Message", function () {
const last_message = await u.waitUntil(() => sizzle('.chat-content:last .chat-msg__text', view).pop()); const last_message = await u.waitUntil(() => sizzle('.chat-content:last .chat-msg__text', view).pop());
const msg_txt = last_message.textContent; const msg_txt = last_message.textContent;
expect(msg_txt).toEqual(message); expect(msg_txt).toEqual(message);
done();
})); }));
}); });
}); });

View File

@ -8,7 +8,7 @@ describe("A Chat Message", function () {
it("will render audio from oob mp3 URLs", it("will render audio from oob mp3 URLs",
mock.initConverse( mock.initConverse(
['chatBoxesFetched'], {}, ['chatBoxesFetched'], {},
async function (done, _converse) { async function (_converse) {
await mock.waitForRoster(_converse, 'current', 1); await mock.waitForRoster(_converse, 'current', 1);
const contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit'; const contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit';
@ -52,13 +52,12 @@ describe("A Chat Message", function () {
expect(media.innerHTML.replace(/<!-.*?->/g, '').replace(/(\r\n|\n|\r)/gm, "").trim()).toEqual( expect(media.innerHTML.replace(/<!-.*?->/g, '').replace(/(\r\n|\n|\r)/gm, "").trim()).toEqual(
`<audio controls="" src="https://montague.lit/audio.mp3"></audio>`+ `<audio controls="" src="https://montague.lit/audio.mp3"></audio>`+
`<a target="_blank" rel="noopener" href="${url}">${url}</a>`); `<a target="_blank" rel="noopener" href="${url}">${url}</a>`);
done();
})); }));
it("will render video from oob mp4 URLs", it("will render video from oob mp4 URLs",
mock.initConverse( mock.initConverse(
['chatBoxesFetched'], {}, ['chatBoxesFetched'], {},
async function (done, _converse) { async function (_converse) {
await mock.waitForRoster(_converse, 'current', 1); await mock.waitForRoster(_converse, 'current', 1);
const contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit'; const contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit';
@ -100,13 +99,12 @@ describe("A Chat Message", function () {
expect(media.innerHTML.replace(/(\r\n|\n|\r)/gm, "").replace(/<!-.*?->/g, '')).toEqual( expect(media.innerHTML.replace(/(\r\n|\n|\r)/gm, "").replace(/<!-.*?->/g, '')).toEqual(
`<video controls="" preload="metadata" src="${Strophe.xmlescape(url)}"></video>`+ `<video controls="" preload="metadata" src="${Strophe.xmlescape(url)}"></video>`+
`<a target="_blank" rel="noopener" href="${Strophe.xmlescape(url)}">${Strophe.xmlescape(url)}</a>`); `<a target="_blank" rel="noopener" href="${Strophe.xmlescape(url)}">${Strophe.xmlescape(url)}</a>`);
done();
})); }));
it("will render download links for files from oob URLs", it("will render download links for files from oob URLs",
mock.initConverse( mock.initConverse(
['chatBoxesFetched'], {}, ['chatBoxesFetched'], {},
async function (done, _converse) { async function (_converse) {
await mock.waitForRoster(_converse, 'current', 1); await mock.waitForRoster(_converse, 'current', 1);
const contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit'; const contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit';
@ -129,13 +127,12 @@ describe("A Chat Message", function () {
const media = view.querySelector('.chat-msg .chat-msg__media'); const media = view.querySelector('.chat-msg .chat-msg__media');
expect(media.innerHTML.replace(/(\r\n|\n|\r)/gm, "").replace(/<!-.*?->/g, '')).toEqual( expect(media.innerHTML.replace(/(\r\n|\n|\r)/gm, "").replace(/<!-.*?->/g, '')).toEqual(
`<a target="_blank" rel="noopener" href="https://montague.lit/funny.pdf">Download file "funny.pdf"</a>`); `<a target="_blank" rel="noopener" href="https://montague.lit/funny.pdf">Download file "funny.pdf"</a>`);
done();
})); }));
it("will render images from oob URLs", it("will render images from oob URLs",
mock.initConverse( mock.initConverse(
['chatBoxesFetched'], {}, ['chatBoxesFetched'], {},
async function (done, _converse) { async function (_converse) {
const base_url = 'https://conversejs.org'; const base_url = 'https://conversejs.org';
await mock.waitForRoster(_converse, 'current', 1); await mock.waitForRoster(_converse, 'current', 1);
@ -163,7 +160,6 @@ describe("A Chat Message", function () {
expect(media.innerHTML.replace(/<!-.*?->/g, '').replace(/(\r\n|\n|\r)/gm, "")).toEqual( expect(media.innerHTML.replace(/<!-.*?->/g, '').replace(/(\r\n|\n|\r)/gm, "")).toEqual(
`<a target="_blank" rel="noopener" href="${base_url}/logo/conversejs-filled.svg">`+ `<a target="_blank" rel="noopener" href="${base_url}/logo/conversejs-filled.svg">`+
`Download file "conversejs-filled.svg"</a>`); `Download file "conversejs-filled.svg"</a>`);
done();
})); }));
}); });
}); });

View File

@ -9,7 +9,7 @@ describe("A delivery receipt", function () {
it("is emitted for a received message which requests it", it("is emitted for a received message which requests it",
mock.initConverse( mock.initConverse(
['chatBoxesFetched'], {}, ['chatBoxesFetched'], {},
async function (done, _converse) { async function (_converse) {
await mock.waitForRoster(_converse, 'current'); await mock.waitForRoster(_converse, 'current');
const sender_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit'; const sender_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit';
@ -29,13 +29,12 @@ describe("A delivery receipt", function () {
expect(sent_messages.length).toBe(2); expect(sent_messages.length).toBe(2);
const receipt = sizzle(`received[xmlns="${Strophe.NS.RECEIPTS}"]`, sent_messages[1]).pop(); const receipt = sizzle(`received[xmlns="${Strophe.NS.RECEIPTS}"]`, sent_messages[1]).pop();
expect(Strophe.serialize(receipt)).toBe(`<received id="${msg_id}" xmlns="${Strophe.NS.RECEIPTS}"/>`); expect(Strophe.serialize(receipt)).toBe(`<received id="${msg_id}" xmlns="${Strophe.NS.RECEIPTS}"/>`);
done();
})); }));
it("is not emitted for a carbon message", it("is not emitted for a carbon message",
mock.initConverse( mock.initConverse(
['chatBoxesFetched'], {}, ['chatBoxesFetched'], {},
async function (done, _converse) { async function (_converse) {
await mock.waitForRoster(_converse, 'current', 1); await mock.waitForRoster(_converse, 'current', 1);
const sender_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit'; const sender_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit';
@ -59,13 +58,12 @@ describe("A delivery receipt", function () {
.c('request', {'xmlns': Strophe.NS.RECEIPTS}).tree(); .c('request', {'xmlns': Strophe.NS.RECEIPTS}).tree();
await _converse.handleMessageStanza(msg); await _converse.handleMessageStanza(msg);
expect(view.model.sendReceiptStanza).not.toHaveBeenCalled(); expect(view.model.sendReceiptStanza).not.toHaveBeenCalled();
done();
})); }));
it("is not emitted for an archived message", it("is not emitted for an archived message",
mock.initConverse( mock.initConverse(
['chatBoxesFetched'], {}, ['chatBoxesFetched'], {},
async function (done, _converse) { async function (_converse) {
await mock.waitForRoster(_converse, 'current', 1); await mock.waitForRoster(_converse, 'current', 1);
const sender_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit'; const sender_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit';
@ -96,13 +94,12 @@ describe("A delivery receipt", function () {
expect(message_attrs.is_archived).toBe(true); expect(message_attrs.is_archived).toBe(true);
expect(message_attrs.is_valid_receipt_request).toBe(false); expect(message_attrs.is_valid_receipt_request).toBe(false);
expect(view.model.sendReceiptStanza).not.toHaveBeenCalled(); expect(view.model.sendReceiptStanza).not.toHaveBeenCalled();
done();
})); }));
it("can be received for a sent message", it("can be received for a sent message",
mock.initConverse( mock.initConverse(
['chatBoxesFetched'], {}, ['chatBoxesFetched'], {},
async function (done, _converse) { async function (_converse) {
await mock.waitForRoster(_converse, 'current', 1); await mock.waitForRoster(_converse, 'current', 1);
const contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit'; const contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit';
@ -150,6 +147,5 @@ describe("A delivery receipt", function () {
_converse.connection._dataRecv(mock.createRequest(msg)); _converse.connection._dataRecv(mock.createRequest(msg));
await u.waitUntil(() => view.querySelectorAll('.chat-msg__receipt').length === 2); await u.waitUntil(() => view.querySelectorAll('.chat-msg__receipt').length === 2);
expect(_converse.handleMessageStanza.calls.count()).toBe(1); expect(_converse.handleMessageStanza.calls.count()).toBe(1);
done();
})); }));
}); });

View File

@ -8,7 +8,7 @@ describe("A spoiler message", function () {
afterEach(() => (jasmine.DEFAULT_TIMEOUT_INTERVAL = original_timeout)); afterEach(() => (jasmine.DEFAULT_TIMEOUT_INTERVAL = original_timeout));
it("can be received with a hint", it("can be received with a hint",
mock.initConverse(['chatBoxesFetched'], {}, async (done, _converse) => { mock.initConverse(['chatBoxesFetched'], {}, async (_converse) => {
await mock.waitForRoster(_converse, 'current'); await mock.waitForRoster(_converse, 'current');
const sender_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit'; const sender_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit';
@ -42,11 +42,10 @@ describe("A spoiler message", function () {
await u.waitUntil(() => message_content.textContent === spoiler); await u.waitUntil(() => message_content.textContent === spoiler);
const spoiler_hint_el = view.querySelector('.spoiler-hint'); const spoiler_hint_el = view.querySelector('.spoiler-hint');
expect(spoiler_hint_el.textContent).toBe(spoiler_hint); expect(spoiler_hint_el.textContent).toBe(spoiler_hint);
done();
})); }));
it("can be received without a hint", it("can be received without a hint",
mock.initConverse(['chatBoxesFetched'], {}, async (done, _converse) => { mock.initConverse(['chatBoxesFetched'], {}, async (_converse) => {
await mock.waitForRoster(_converse, 'current'); await mock.waitForRoster(_converse, 'current');
const sender_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit'; const sender_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit';
@ -79,11 +78,10 @@ describe("A spoiler message", function () {
await u.waitUntil(() => message_content.textContent === spoiler); await u.waitUntil(() => message_content.textContent === spoiler);
const spoiler_hint_el = view.querySelector('.spoiler-hint'); const spoiler_hint_el = view.querySelector('.spoiler-hint');
expect(spoiler_hint_el.textContent).toBe(''); expect(spoiler_hint_el.textContent).toBe('');
done();
})); }));
it("can be sent without a hint", it("can be sent without a hint",
mock.initConverse(['chatBoxesFetched'], {}, async (done, _converse) => { mock.initConverse(['chatBoxesFetched'], {}, async (_converse) => {
await mock.waitForRoster(_converse, 'current', 1); await mock.waitForRoster(_converse, 'current', 1);
mock.openControlBox(_converse); mock.openControlBox(_converse);
@ -156,11 +154,10 @@ describe("A spoiler message", function () {
expect(spoiler_toggle.textContent.trim()).toBe('Show less'); expect(spoiler_toggle.textContent.trim()).toBe('Show less');
spoiler_toggle.click(); spoiler_toggle.click();
await u.waitUntil(() => Array.from(spoiler_msg_el.classList).includes('hidden')); await u.waitUntil(() => Array.from(spoiler_msg_el.classList).includes('hidden'));
done();
})); }));
it("can be sent with a hint", it("can be sent with a hint",
mock.initConverse(['chatBoxesFetched'], {}, async (done, _converse) => { mock.initConverse(['chatBoxesFetched'], {}, async (_converse) => {
await mock.waitForRoster(_converse, 'current', 1); await mock.waitForRoster(_converse, 'current', 1);
mock.openControlBox(_converse); mock.openControlBox(_converse);
@ -237,6 +234,5 @@ describe("A spoiler message", function () {
expect(spoiler_toggle.textContent.trim()).toBe('Show less'); expect(spoiler_toggle.textContent.trim()).toBe('Show less');
spoiler_toggle.click(); spoiler_toggle.click();
await u.waitUntil(() => Array.from(spoiler_msg_el.classList).includes('hidden')); await u.waitUntil(() => Array.from(spoiler_msg_el.classList).includes('hidden'));
done();
})); }));
}); });

View File

@ -6,7 +6,7 @@ describe("An incoming chat Message", function () {
it("can have styling disabled via an \"unstyled\" element", it("can have styling disabled via an \"unstyled\" element",
mock.initConverse(['chatBoxesFetched'], {}, mock.initConverse(['chatBoxesFetched'], {},
async function (done, _converse) { async function (_converse) {
const include_nick = false; const include_nick = false;
await mock.waitForRoster(_converse, 'current', 2, include_nick); await mock.waitForRoster(_converse, 'current', 2, include_nick);
@ -31,14 +31,13 @@ describe("An incoming chat Message", function () {
setTimeout(() => { setTimeout(() => {
const msg_el = view.querySelector('converse-chat-message-body'); const msg_el = view.querySelector('converse-chat-message-body');
expect(msg_el.innerText).toBe(msg_text); expect(msg_el.innerText).toBe(msg_text);
done();
}, 500); }, 500);
})); }));
it("can have styling disabled via the allow_message_styling setting", it("can have styling disabled via the allow_message_styling setting",
mock.initConverse(['chatBoxesFetched'], {'allow_message_styling': false}, mock.initConverse(['chatBoxesFetched'], {'allow_message_styling': false},
async function (done, _converse) { async function (_converse) {
const include_nick = false; const include_nick = false;
await mock.waitForRoster(_converse, 'current', 2, include_nick); await mock.waitForRoster(_converse, 'current', 2, include_nick);
@ -62,13 +61,12 @@ describe("An incoming chat Message", function () {
setTimeout(() => { setTimeout(() => {
const msg_el = view.querySelector('converse-chat-message-body'); const msg_el = view.querySelector('converse-chat-message-body');
expect(msg_el.innerText).toBe(msg_text); expect(msg_el.innerText).toBe(msg_text);
done();
}, 500); }, 500);
})); }));
it("can be styled with span XEP-0393 message styling hints", it("can be styled with span XEP-0393 message styling hints",
mock.initConverse(['chatBoxesFetched'], {}, mock.initConverse(['chatBoxesFetched'], {},
async function (done, _converse) { async function (_converse) {
let msg_text, msg, msg_el; let msg_text, msg, msg_el;
await mock.waitForRoster(_converse, 'current', 1); await mock.waitForRoster(_converse, 'current', 1);
@ -187,12 +185,11 @@ describe("An incoming chat Message", function () {
'<i><a target="_blank" rel="noopener" href="https://converse_js.org/">https://converse_js.org</a></i>'+ '<i><a target="_blank" rel="noopener" href="https://converse_js.org/">https://converse_js.org</a></i>'+
'<span class="styling-directive">_</span> <span class="styling-directive">_</span><i>please</i><span class="styling-directive">_</span>'); '<span class="styling-directive">_</span> <span class="styling-directive">_</span><i>please</i><span class="styling-directive">_</span>');
done();
})); }));
it("can be styled with block XEP-0393 message styling hints", it("can be styled with block XEP-0393 message styling hints",
mock.initConverse(['chatBoxesFetched'], {}, mock.initConverse(['chatBoxesFetched'], {},
async function (done, _converse) { async function (_converse) {
let msg_text, msg, msg_el; let msg_text, msg, msg_el;
await mock.waitForRoster(_converse, 'current', 1); await mock.waitForRoster(_converse, 'current', 1);
@ -233,12 +230,11 @@ describe("An incoming chat Message", function () {
'```ignored\n (println "Hello, world!")\n ```\n\n'+ '```ignored\n (println "Hello, world!")\n ```\n\n'+
' This should not show up as monospace, '+ ' This should not show up as monospace, '+
'<span class="styling-directive">*</span><b>preformatted</b><span class="styling-directive">*</span> text ^'); '<span class="styling-directive">*</span><b>preformatted</b><span class="styling-directive">*</span> text ^');
done();
})); }));
it("can be styled with quote XEP-0393 message styling hints", it("can be styled with quote XEP-0393 message styling hints",
mock.initConverse(['chatBoxesFetched'], {}, mock.initConverse(['chatBoxesFetched'], {},
async function (done, _converse) { async function (_converse) {
let msg_text, msg, msg_el; let msg_text, msg, msg_el;
await mock.waitForRoster(_converse, 'current', 1); await mock.waitForRoster(_converse, 'current', 1);
@ -371,12 +367,11 @@ describe("An incoming chat Message", function () {
`<blockquote>What do you think of it <span class="mention">romeo</span>?</blockquote>\n Did you see this <span class="mention">romeo</span>?`); `<blockquote>What do you think of it <span class="mention">romeo</span>?</blockquote>\n Did you see this <span class="mention">romeo</span>?`);
expect(true).toBe(true); expect(true).toBe(true);
done();
})); }));
it("won't style invalid block quotes", it("won't style invalid block quotes",
mock.initConverse(['chatBoxesFetched'], {}, mock.initConverse(['chatBoxesFetched'], {},
async function (done, _converse) { async function (_converse) {
await mock.waitForRoster(_converse, 'current', 1); await mock.waitForRoster(_converse, 'current', 1);
const contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit'; const contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit';
@ -409,6 +404,5 @@ describe("An incoming chat Message", function () {
const msg_el = Array.from(view.querySelectorAll('converse-chat-message-body')).pop(); const msg_el = Array.from(view.querySelectorAll('converse-chat-message-body')).pop();
await u.waitUntil(() => msg_el.innerHTML.replace(/<!-.*?->/g, '') === '```\ncode```'); await u.waitUntil(() => msg_el.innerHTML.replace(/<!-.*?->/g, '') === '```\ncode```');
expect(true).toBe(true); expect(true).toBe(true);
done();
})); }));
}); });

View File

@ -6,7 +6,7 @@ const { u } = converse.env;
describe("A ChatBox's Unread Message Count", function () { describe("A ChatBox's Unread Message Count", function () {
it("is incremented when the message is received and ChatBoxView is scrolled up", it("is incremented when the message is received and ChatBoxView is scrolled up",
mock.initConverse(['chatBoxesFetched'], {}, async function (done, _converse) { mock.initConverse(['chatBoxesFetched'], {}, async function (_converse) {
await mock.waitForRoster(_converse, 'current', 1); await mock.waitForRoster(_converse, 'current', 1);
const sender_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit', const sender_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit',
@ -23,11 +23,10 @@ describe("A ChatBox's Unread Message Count", function () {
expect(view.model.get('first_unread_id')).toBe(msgid); expect(view.model.get('first_unread_id')).toBe(msgid);
await u.waitUntil(() => sent_stanzas.length); await u.waitUntil(() => sent_stanzas.length);
expect(sent_stanzas[0].querySelector('received')).toBeDefined(); expect(sent_stanzas[0].querySelector('received')).toBeDefined();
done();
})); }));
it("is not incremented when the message is received and ChatBoxView is scrolled down", it("is not incremented when the message is received and ChatBoxView is scrolled down",
mock.initConverse(['chatBoxesFetched'], {}, async function (done, _converse) { mock.initConverse(['chatBoxesFetched'], {}, async function (_converse) {
await mock.waitForRoster(_converse, 'current', 1); await mock.waitForRoster(_converse, 'current', 1);
const sender_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit'; const sender_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit';
@ -40,11 +39,10 @@ describe("A ChatBox's Unread Message Count", function () {
expect(chatbox.get('num_unread')).toBe(0); expect(chatbox.get('num_unread')).toBe(0);
await u.waitUntil(() => sent_stanzas.filter(s => s.nodeName === 'message').length === 2); await u.waitUntil(() => sent_stanzas.filter(s => s.nodeName === 'message').length === 2);
expect(sent_stanzas[1].querySelector('displayed')).toBeDefined(); expect(sent_stanzas[1].querySelector('displayed')).toBeDefined();
done();
})); }));
it("is incremented when message is received, chatbox is scrolled down and the window is not focused", it("is incremented when message is received, chatbox is scrolled down and the window is not focused",
mock.initConverse(['chatBoxesFetched'], {}, async function (done, _converse) { mock.initConverse(['chatBoxesFetched'], {}, async function (_converse) {
await mock.waitForRoster(_converse, 'current'); await mock.waitForRoster(_converse, 'current');
const sender_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit'; const sender_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit';
@ -64,11 +62,10 @@ describe("A ChatBox's Unread Message Count", function () {
expect(chatbox.get('first_unread_id')).toBe(msgid); expect(chatbox.get('first_unread_id')).toBe(msgid);
await u.waitUntil(() => sent_stanzas.filter(s => s.nodeName === 'message').length); await u.waitUntil(() => sent_stanzas.filter(s => s.nodeName === 'message').length);
expect(sent_stanzas[0].querySelector('received')).toBeDefined(); expect(sent_stanzas[0].querySelector('received')).toBeDefined();
done();
})); }));
it("is incremented when message is received, chatbox is scrolled up and the window is not focused", it("is incremented when message is received, chatbox is scrolled up and the window is not focused",
mock.initConverse(['chatBoxesFetched'], {}, async function (done, _converse) { mock.initConverse(['chatBoxesFetched'], {}, async function (_converse) {
await mock.waitForRoster(_converse, 'current', 1); await mock.waitForRoster(_converse, 'current', 1);
const sender_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit'; const sender_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit';
@ -87,11 +84,10 @@ describe("A ChatBox's Unread Message Count", function () {
expect(chatbox.get('first_unread_id')).toBe(msgid); expect(chatbox.get('first_unread_id')).toBe(msgid);
await u.waitUntil(() => sent_stanzas.filter(s => s.nodeName === 'message').length === 1); await u.waitUntil(() => sent_stanzas.filter(s => s.nodeName === 'message').length === 1);
expect(sent_stanzas[0].querySelector('received')).toBeDefined(); expect(sent_stanzas[0].querySelector('received')).toBeDefined();
done();
})); }));
it("is cleared when the chat was scrolled down and the window become focused", it("is cleared when the chat was scrolled down and the window become focused",
mock.initConverse(['chatBoxesFetched'], {}, async function (done, _converse) { mock.initConverse(['chatBoxesFetched'], {}, async function (_converse) {
await mock.waitForRoster(_converse, 'current', 1); await mock.waitForRoster(_converse, 'current', 1);
const sender_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit'; const sender_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit';
@ -113,12 +109,11 @@ describe("A ChatBox's Unread Message Count", function () {
await u.waitUntil(() => sent_stanzas.filter(s => s.nodeName === 'message').length === 2); await u.waitUntil(() => sent_stanzas.filter(s => s.nodeName === 'message').length === 2);
expect(sent_stanzas[1].querySelector('displayed')).toBeDefined(); expect(sent_stanzas[1].querySelector('displayed')).toBeDefined();
expect(chatbox.get('num_unread')).toBe(0); expect(chatbox.get('num_unread')).toBe(0);
done();
})); }));
it("is cleared when the chat was hidden in fullscreen mode and then becomes visible", it("is cleared when the chat was hidden in fullscreen mode and then becomes visible",
mock.initConverse(['chatBoxesFetched'], {'view_mode': 'fullscreen'}, mock.initConverse(['chatBoxesFetched'], {'view_mode': 'fullscreen'},
async function (done, _converse) { async function (_converse) {
await mock.waitForRoster(_converse, 'current', 1); await mock.waitForRoster(_converse, 'current', 1);
const sender_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit'; const sender_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit';
@ -131,11 +126,10 @@ describe("A ChatBox's Unread Message Count", function () {
chatbox.save({'hidden': false}); chatbox.save({'hidden': false});
await u.waitUntil(() => chatbox.get('num_unread') === 0); await u.waitUntil(() => chatbox.get('num_unread') === 0);
chatbox.close(); chatbox.close();
done();
})); }));
it("is not cleared when ChatBoxView was scrolled up and the windows become focused", it("is not cleared when ChatBoxView was scrolled up and the windows become focused",
mock.initConverse(['chatBoxesFetched'], {}, async function (done, _converse) { mock.initConverse(['chatBoxesFetched'], {}, async function (_converse) {
await mock.waitForRoster(_converse, 'current', 1); await mock.waitForRoster(_converse, 'current', 1);
const sender_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit'; const sender_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit';
@ -158,6 +152,5 @@ describe("A ChatBox's Unread Message Count", function () {
await u.waitUntil(() => chatbox.get('num_unread') === 1); await u.waitUntil(() => chatbox.get('num_unread') === 1);
expect(chatbox.get('first_unread_id')).toBe(msgid); expect(chatbox.get('first_unread_id')).toBe(msgid);
expect(sent_stanzas[0].querySelector('received')).toBeDefined(); expect(sent_stanzas[0].querySelector('received')).toBeDefined();
done();
})); }));
}); });

View File

@ -6,7 +6,7 @@ const u = converse.env.utils;
describe("XSS", function () { describe("XSS", function () {
describe("A Chat Message", function () { describe("A Chat Message", function () {
it("will escape IMG payload XSS attempts", mock.initConverse(['chatBoxesFetched'], {}, async function (done, _converse) { it("will escape IMG payload XSS attempts", mock.initConverse(['chatBoxesFetched'], {}, async function (_converse) {
spyOn(window, 'alert').and.callThrough(); spyOn(window, 'alert').and.callThrough();
await mock.waitForRoster(_converse, 'current'); await mock.waitForRoster(_converse, 'current');
await mock.openControlBox(_converse); await mock.openControlBox(_converse);
@ -59,10 +59,9 @@ describe("XSS", function () {
expect(msg.innerHTML.replace(/<!-.*?->/g, '')).toEqual("&gt;&lt;img src=x onerror=alert(String.fromCharCode(88,83,83));&gt;"); expect(msg.innerHTML.replace(/<!-.*?->/g, '')).toEqual("&gt;&lt;img src=x onerror=alert(String.fromCharCode(88,83,83));&gt;");
expect(window.alert).not.toHaveBeenCalled(); expect(window.alert).not.toHaveBeenCalled();
done();
})); }));
it("will escape SVG payload XSS attempts", mock.initConverse(['chatBoxesFetched'], {}, async function (done, _converse) { it("will escape SVG payload XSS attempts", mock.initConverse(['chatBoxesFetched'], {}, async function (_converse) {
spyOn(window, 'alert').and.callThrough(); spyOn(window, 'alert').and.callThrough();
await mock.waitForRoster(_converse, 'current'); await mock.waitForRoster(_converse, 'current');
await mock.openControlBox(_converse); await mock.openControlBox(_converse);
@ -114,11 +113,10 @@ describe("XSS", function () {
expect(msg.innerHTML.replace(/<!-.*?->/g, '')).toEqual('"&gt;&lt;svg/onload=alert(/XSS/)'); expect(msg.innerHTML.replace(/<!-.*?->/g, '')).toEqual('"&gt;&lt;svg/onload=alert(/XSS/)');
expect(window.alert).not.toHaveBeenCalled(); expect(window.alert).not.toHaveBeenCalled();
done();
})); }));
it("will have properly escaped URLs", it("will have properly escaped URLs",
mock.initConverse(['chatBoxesFetched'], {}, async function (done, _converse) { mock.initConverse(['chatBoxesFetched'], {}, async function (_converse) {
await mock.waitForRoster(_converse, 'current'); await mock.waitForRoster(_converse, 'current');
await mock.openControlBox(_converse); await mock.openControlBox(_converse);
@ -170,11 +168,10 @@ describe("XSS", function () {
expect(msg.textContent).toEqual(message); expect(msg.textContent).toEqual(message);
await u.waitUntil(() => msg.innerHTML.replace(/<!-.*?->/g, '') === await u.waitUntil(() => msg.innerHTML.replace(/<!-.*?->/g, '') ===
`<a target="_blank" rel="noopener" href="https://www.google.com/maps/place/Kochstraat+6,+2041+CE+Zandvoort/@52.3775999,4.548971,3a,15y,170.85h,88.39t/data=%213m6%211e1%213m4%211sQ7SdHo_bPLPlLlU8GSGWaQ%212e0%217i13312%218i6656%214m5%213m4%211s0x47c5ec1e56f845ad:0x1de0bc4a5771fb08%218m2%213d52.3773668%214d4.5489388%215m1%211e2">https://www.google.com/maps/place/Kochstraat+6,+2041+CE+Zandvoort/@52.3775999,4.548971,3a,15y,170.85h,88.39t/data=!3m6!1e1!3m4!1sQ7SdHo_bPLPlLlU8GSGWaQ!2e0!7i13312!8i6656!4m5!3m4!1s0x47c5ec1e56f845ad:0x1de0bc4a5771fb08!8m2!3d52.3773668!4d4.5489388!5m1!1e2</a>`); `<a target="_blank" rel="noopener" href="https://www.google.com/maps/place/Kochstraat+6,+2041+CE+Zandvoort/@52.3775999,4.548971,3a,15y,170.85h,88.39t/data=%213m6%211e1%213m4%211sQ7SdHo_bPLPlLlU8GSGWaQ%212e0%217i13312%218i6656%214m5%213m4%211s0x47c5ec1e56f845ad:0x1de0bc4a5771fb08%218m2%213d52.3773668%214d4.5489388%215m1%211e2">https://www.google.com/maps/place/Kochstraat+6,+2041+CE+Zandvoort/@52.3775999,4.548971,3a,15y,170.85h,88.39t/data=!3m6!1e1!3m4!1sQ7SdHo_bPLPlLlU8GSGWaQ!2e0!7i13312!8i6656!4m5!3m4!1s0x47c5ec1e56f845ad:0x1de0bc4a5771fb08!8m2!3d52.3773668!4d4.5489388!5m1!1e2</a>`);
done();
})); }));
it("will avoid malformed and unsafe urls urls from rendering as anchors", it("will avoid malformed and unsafe urls urls from rendering as anchors",
mock.initConverse(['chatBoxesFetched'], {}, async function (done, _converse) { mock.initConverse(['chatBoxesFetched'], {}, async function (_converse) {
await mock.waitForRoster(_converse, 'current'); await mock.waitForRoster(_converse, 'current');
await mock.openControlBox(_converse); await mock.openControlBox(_converse);
@ -250,7 +247,6 @@ describe("XSS", function () {
await mock.sendMessage(view, good_urls[5].entered); await mock.sendMessage(view, good_urls[5].entered);
await checkParsedURL(good_urls[5]); await checkParsedURL(good_urls[5]);
done();
})); }));
}); });
}); });

View File

@ -9,19 +9,18 @@ const sizzle = converse.env.sizzle;
describe("The Controlbox", function () { describe("The Controlbox", function () {
it("can be opened by clicking a DOM element with class 'toggle-controlbox'", it("can be opened by clicking a DOM element with class 'toggle-controlbox'",
mock.initConverse([], {}, function (done, _converse) { mock.initConverse([], {}, function (_converse) {
spyOn(_converse.api, "trigger").and.callThrough(); spyOn(_converse.api, "trigger").and.callThrough();
document.querySelector('.toggle-controlbox').click(); document.querySelector('.toggle-controlbox').click();
expect(_converse.api.trigger).toHaveBeenCalledWith('controlBoxOpened', jasmine.any(Object)); expect(_converse.api.trigger).toHaveBeenCalledWith('controlBoxOpened', jasmine.any(Object));
const el = document.querySelector("#controlbox"); const el = document.querySelector("#controlbox");
expect(u.isVisible(el)).toBe(true); expect(u.isVisible(el)).toBe(true);
done();
})); }));
it("can be closed by clicking a DOM element with class 'close-chatbox-button'", it("can be closed by clicking a DOM element with class 'close-chatbox-button'",
mock.initConverse(['chatBoxesFetched'], {}, async function (done, _converse) { mock.initConverse(['chatBoxesFetched'], {}, async function (_converse) {
await mock.openControlBox(_converse); await mock.openControlBox(_converse);
const view = _converse.chatboxviews.get('controlbox'); const view = _converse.chatboxviews.get('controlbox');
@ -32,14 +31,13 @@ describe("The Controlbox", function () {
view.querySelector('.close-chatbox-button').click(); view.querySelector('.close-chatbox-button').click();
expect(view.close).toHaveBeenCalled(); expect(view.close).toHaveBeenCalled();
expect(_converse.api.trigger).toHaveBeenCalledWith('controlBoxClosed', jasmine.any(Object)); expect(_converse.api.trigger).toHaveBeenCalledWith('controlBoxClosed', jasmine.any(Object));
done();
})); }));
describe("The \"Contacts\" section", function () { describe("The \"Contacts\" section", function () {
it("can be used to add contact and it checks for case-sensivity", it("can be used to add contact and it checks for case-sensivity",
mock.initConverse([], {}, async function (done, _converse) { mock.initConverse([], {}, async function (_converse) {
spyOn(_converse.api, "trigger").and.callThrough(); spyOn(_converse.api, "trigger").and.callThrough();
await mock.waitForRoster(_converse, 'all', 0); await mock.waitForRoster(_converse, 'all', 0);
@ -61,11 +59,10 @@ describe("The Controlbox", function () {
await u.waitUntil(() => Array.from(rosterview.querySelectorAll('.roster-group li')).filter(u.isVisible).length, 700); await u.waitUntil(() => Array.from(rosterview.querySelectorAll('.roster-group li')).filter(u.isVisible).length, 700);
// Checking that only one entry is created because both JID is same (Case sensitive check) // Checking that only one entry is created because both JID is same (Case sensitive check)
expect(Array.from(rosterview.querySelectorAll('li')).filter(u.isVisible).length).toBe(1); expect(Array.from(rosterview.querySelectorAll('li')).filter(u.isVisible).length).toBe(1);
done();
})); }));
it("shows the number of unread mentions received", it("shows the number of unread mentions received",
mock.initConverse(['chatBoxesFetched'], {}, async function (done, _converse) { mock.initConverse(['chatBoxesFetched'], {}, async function (_converse) {
await mock.waitForRoster(_converse, 'all'); await mock.waitForRoster(_converse, 'all');
await mock.openControlBox(_converse); await mock.openControlBox(_converse);
@ -108,23 +105,21 @@ describe("The Controlbox", function () {
chatview.model.set({'minimized': false}); chatview.model.set({'minimized': false});
expect(el.querySelector('.restore-chat .message-count')).toBe(null); expect(el.querySelector('.restore-chat .message-count')).toBe(null);
await u.waitUntil(() => rosterview.querySelector('.msgs-indicator') === null); await u.waitUntil(() => rosterview.querySelector('.msgs-indicator') === null);
done();
})); }));
}); });
describe("The Status Widget", function () { describe("The Status Widget", function () {
it("shows the user's chat status, which is online by default", it("shows the user's chat status, which is online by default",
mock.initConverse([], {}, async function (done, _converse) { mock.initConverse([], {}, async function (_converse) {
mock.openControlBox(_converse); mock.openControlBox(_converse);
const view = await u.waitUntil(() => document.querySelector('converse-user-profile')); const view = await u.waitUntil(() => document.querySelector('converse-user-profile'));
expect(u.hasClass('online', view.querySelector('.xmpp-status span:first-child'))).toBe(true); expect(u.hasClass('online', view.querySelector('.xmpp-status span:first-child'))).toBe(true);
expect(view.querySelector('.xmpp-status span.online').textContent.trim()).toBe('I am online'); expect(view.querySelector('.xmpp-status span.online').textContent.trim()).toBe('I am online');
done();
})); }));
it("can be used to set the current user's chat status", it("can be used to set the current user's chat status",
mock.initConverse([], {}, async function (done, _converse) { mock.initConverse([], {}, async function (_converse) {
await mock.openControlBox(_converse); await mock.openControlBox(_converse);
var cbview = _converse.chatboxviews.get('controlbox'); var cbview = _converse.chatboxviews.get('controlbox');
@ -146,11 +141,10 @@ describe("The Controlbox", function () {
expect(u.hasClass('online', first_child)).toBe(false); expect(u.hasClass('online', first_child)).toBe(false);
expect(u.hasClass('dnd', first_child)).toBe(true); expect(u.hasClass('dnd', first_child)).toBe(true);
expect(view.querySelector('.xmpp-status span:first-child').textContent.trim()).toBe('I am busy'); expect(view.querySelector('.xmpp-status span:first-child').textContent.trim()).toBe('I am busy');
done();
})); }));
it("can be used to set a custom status message", it("can be used to set a custom status message",
mock.initConverse([], {}, async function (done, _converse) { mock.initConverse([], {}, async function (_converse) {
await mock.openControlBox(_converse); await mock.openControlBox(_converse);
const cbview = _converse.chatboxviews.get('controlbox'); const cbview = _converse.chatboxviews.get('controlbox');
@ -174,7 +168,6 @@ describe("The Controlbox", function () {
const first_child = view.querySelector('.xmpp-status span:first-child'); const first_child = view.querySelector('.xmpp-status span:first-child');
expect(u.hasClass('online', first_child)).toBe(true); expect(u.hasClass('online', first_child)).toBe(true);
expect(view.querySelector('.xmpp-status span:first-child').textContent.trim()).toBe(msg); expect(view.querySelector('.xmpp-status span:first-child').textContent.trim()).toBe(msg);
done();
})); }));
}); });
}); });
@ -182,7 +175,7 @@ describe("The Controlbox", function () {
describe("The 'Add Contact' widget", function () { describe("The 'Add Contact' widget", function () {
it("opens up an add modal when you click on it", it("opens up an add modal when you click on it",
mock.initConverse([], {}, async function (done, _converse) { mock.initConverse([], {}, async function (_converse) {
await mock.waitForRoster(_converse, 'all'); await mock.waitForRoster(_converse, 'all');
await mock.openControlBox(_converse); await mock.openControlBox(_converse);
@ -210,11 +203,10 @@ describe("The 'Add Contact' widget", function () {
`<iq id="${sent_stanza.getAttribute('id')}" type="set" xmlns="jabber:client">`+ `<iq id="${sent_stanza.getAttribute('id')}" type="set" xmlns="jabber:client">`+
`<query xmlns="jabber:iq:roster"><item jid="someone@montague.lit" name="Someone"/></query>`+ `<query xmlns="jabber:iq:roster"><item jid="someone@montague.lit" name="Someone"/></query>`+
`</iq>`); `</iq>`);
done();
})); }));
it("can be configured to not provide search suggestions", it("can be configured to not provide search suggestions",
mock.initConverse([], {'autocomplete_add_contact': false}, async function (done, _converse) { mock.initConverse([], {'autocomplete_add_contact': false}, async function (_converse) {
await mock.waitForRoster(_converse, 'all', 0); await mock.waitForRoster(_converse, 'all', 0);
await mock.openControlBox(_converse); await mock.openControlBox(_converse);
@ -239,13 +231,12 @@ describe("The 'Add Contact' widget", function () {
`<query xmlns="jabber:iq:roster"><item jid="someone@montague.lit"/></query>`+ `<query xmlns="jabber:iq:roster"><item jid="someone@montague.lit"/></query>`+
`</iq>` `</iq>`
); );
done();
})); }));
it("integrates with xhr_user_search_url to search for contacts", it("integrates with xhr_user_search_url to search for contacts",
mock.initConverse([], { 'xhr_user_search_url': 'http://example.org/?' }, mock.initConverse([], { 'xhr_user_search_url': 'http://example.org/?' },
async function (done, _converse) { async function (_converse) {
await mock.waitForRoster(_converse, 'all', 0); await mock.waitForRoster(_converse, 'all', 0);
@ -296,14 +287,13 @@ describe("The 'Add Contact' widget", function () {
`<query xmlns="jabber:iq:roster"><item jid="marty@mcfly.net" name="Marty McFly"/></query>`+ `<query xmlns="jabber:iq:roster"><item jid="marty@mcfly.net" name="Marty McFly"/></query>`+
`</iq>`); `</iq>`);
window.XMLHttpRequest = XMLHttpRequestBackup; window.XMLHttpRequest = XMLHttpRequestBackup;
done();
})); }));
it("can be configured to not provide search suggestions for XHR search results", it("can be configured to not provide search suggestions for XHR search results",
mock.initConverse([], mock.initConverse([],
{ 'autocomplete_add_contact': false, { 'autocomplete_add_contact': false,
'xhr_user_search_url': 'http://example.org/?' }, 'xhr_user_search_url': 'http://example.org/?' },
async function (done, _converse) { async function (_converse) {
await mock.waitForRoster(_converse, 'all'); await mock.waitForRoster(_converse, 'all');
await mock.openControlBox(_converse); await mock.openControlBox(_converse);
@ -371,6 +361,5 @@ describe("The 'Add Contact' widget", function () {
`<query xmlns="jabber:iq:roster"><item jid="marty@mcfly.net" name="Marty McFly"/></query>`+ `<query xmlns="jabber:iq:roster"><item jid="marty@mcfly.net" name="Marty McFly"/></query>`+
`</iq>`); `</iq>`);
window.XMLHttpRequest = XMLHttpRequestBackup; window.XMLHttpRequest = XMLHttpRequestBackup;
done();
})); }));
}); });

View File

@ -9,7 +9,7 @@ describe("The Login Form", function () {
['chatBoxesInitialized'], ['chatBoxesInitialized'],
{ auto_login: false, { auto_login: false,
allow_registration: false }, allow_registration: false },
async function (done, _converse) { async function (_converse) {
const cbview = await u.waitUntil(() => _converse.chatboxviews.get('controlbox')); const cbview = await u.waitUntil(() => _converse.chatboxviews.get('controlbox'));
mock.toggleControlBox(); mock.toggleControlBox();
@ -34,7 +34,6 @@ describe("The Login Form", function () {
cbview.querySelector('input[type="submit"]').click(); cbview.querySelector('input[type="submit"]').click();
expect(_converse.config.get('trusted')).toBe(false); expect(_converse.config.get('trusted')).toBe(false);
expect(_converse.getDefaultStore()).toBe('session'); expect(_converse.getDefaultStore()).toBe('session');
done();
})); }));
it("checkbox can be set to false by default", it("checkbox can be set to false by default",
@ -43,7 +42,7 @@ describe("The Login Form", function () {
{ auto_login: false, { auto_login: false,
allow_user_trust_override: 'off', allow_user_trust_override: 'off',
allow_registration: false }, allow_registration: false },
async function (done, _converse) { async function (_converse) {
await u.waitUntil(() => _converse.chatboxviews.get('controlbox')) await u.waitUntil(() => _converse.chatboxviews.get('controlbox'))
const cbview = _converse.chatboxviews.get('controlbox'); const cbview = _converse.chatboxviews.get('controlbox');
@ -67,6 +66,5 @@ describe("The Login Form", function () {
cbview.querySelector('input[type="submit"]').click(); cbview.querySelector('input[type="submit"]').click();
expect(_converse.config.get('trusted')).toBe(true); expect(_converse.config.get('trusted')).toBe(true);
expect(_converse.getDefaultStore()).toBe('persistent'); expect(_converse.getDefaultStore()).toBe('persistent');
done();
})); }));
}); });

View File

@ -3,7 +3,7 @@
describe("A headlines box", function () { describe("A headlines box", function () {
it("will not open nor display non-headline messages", it("will not open nor display non-headline messages",
mock.initConverse(['chatBoxesFetched'], {}, async function (done, _converse) { mock.initConverse(['chatBoxesFetched'], {}, async function (_converse) {
await mock.waitForRoster(_converse, 'current', 0); await mock.waitForRoster(_converse, 'current', 0);
const { $msg } = converse.env; const { $msg } = converse.env;
@ -27,11 +27,10 @@ describe("A headlines box", function () {
.c('body').t('SORRY FOR THIS ADVERT'); .c('body').t('SORRY FOR THIS ADVERT');
_converse.connection._dataRecv(mock.createRequest(stanza)); _converse.connection._dataRecv(mock.createRequest(stanza));
expect(_converse.api.headlines.get().length === 0); expect(_converse.api.headlines.get().length === 0);
done();
})); }));
it("will open and display headline messages", mock.initConverse( it("will open and display headline messages", mock.initConverse(
[], {}, async function (done, _converse) { [], {}, async function (_converse) {
await mock.waitForRoster(_converse, 'current', 0); await mock.waitForRoster(_converse, 'current', 0);
const { u, $msg} = converse.env; const { u, $msg} = converse.env;
@ -64,11 +63,10 @@ describe("A headlines box", function () {
const view = _converse.chatboxviews.get('notify.example.com'); const view = _converse.chatboxviews.get('notify.example.com');
expect(view.model.get('show_avatar')).toBeFalsy(); expect(view.model.get('show_avatar')).toBeFalsy();
expect(view.querySelector('img.avatar')).toBe(null); expect(view.querySelector('img.avatar')).toBe(null);
done();
})); }));
it("will show headline messages in the controlbox", mock.initConverse( it("will show headline messages in the controlbox", mock.initConverse(
[], {}, async function (done, _converse) { [], {}, async function (_converse) {
await mock.waitForRoster(_converse, 'current', 0); await mock.waitForRoster(_converse, 'current', 0);
const { u, $msg} = converse.env; const { u, $msg} = converse.env;
@ -101,11 +99,10 @@ describe("A headlines box", function () {
await u.waitUntil(() => view.querySelectorAll(".open-headline").length); await u.waitUntil(() => view.querySelectorAll(".open-headline").length);
expect(view.querySelectorAll('.open-headline').length).toBe(1); expect(view.querySelectorAll('.open-headline').length).toBe(1);
expect(view.querySelector('.open-headline').text).toBe('notify.example.com'); expect(view.querySelector('.open-headline').text).toBe('notify.example.com');
done();
})); }));
it("will remove headline messages from the controlbox if closed", mock.initConverse( it("will remove headline messages from the controlbox if closed", mock.initConverse(
[], {}, async function (done, _converse) { [], {}, async function (_converse) {
const { u, $msg} = converse.env; const { u, $msg} = converse.env;
await mock.waitForRoster(_converse, 'current', 0); await mock.waitForRoster(_converse, 'current', 0);
@ -143,12 +140,11 @@ describe("A headlines box", function () {
close_el.click(); close_el.click();
await u.waitUntil(() => cbview.querySelectorAll(".open-headline").length === 0); await u.waitUntil(() => cbview.querySelectorAll(".open-headline").length === 0);
expect(cbview.querySelectorAll('.open-headline').length).toBe(0); expect(cbview.querySelectorAll('.open-headline').length).toBe(0);
done();
})); }));
it("will not show a headline messages from a full JID if allow_non_roster_messaging is false", it("will not show a headline messages from a full JID if allow_non_roster_messaging is false",
mock.initConverse( mock.initConverse(
['chatBoxesFetched'], {}, async function (done, _converse) { ['chatBoxesFetched'], {}, async function (_converse) {
await mock.waitForRoster(_converse, 'current', 0); await mock.waitForRoster(_converse, 'current', 0);
const { $msg } = converse.env; const { $msg } = converse.env;
@ -163,6 +159,5 @@ describe("A headlines box", function () {
.c('body').t('Здравствуйте друзья'); .c('body').t('Здравствуйте друзья');
_converse.connection._dataRecv(mock.createRequest(stanza)); _converse.connection._dataRecv(mock.createRequest(stanza));
expect(_.without('controlbox', _converse.chatboxviews.keys()).length).toBe(0); expect(_.without('controlbox', _converse.chatboxviews.keys()).length).toBe(0);
done();
})); }));
}); });

View File

@ -19,7 +19,7 @@ describe("Message Archive Management", function () {
describe("The XEP-0313 Archive", function () { describe("The XEP-0313 Archive", function () {
it("is queried when the user scrolls up", it("is queried when the user scrolls up",
mock.initConverse(['discoInitialized'], {'archived_messages_page_size': 2}, async function (done, _converse) { mock.initConverse(['discoInitialized'], {'archived_messages_page_size': 2}, async function (_converse) {
await mock.waitForRoster(_converse, 'current', 1); await mock.waitForRoster(_converse, 'current', 1);
const contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit'; const contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit';
@ -78,7 +78,6 @@ describe("Message Archive Management", function () {
`<set xmlns="http://jabber.org/protocol/rsm"><before>${view.model.messages.at(0).get('stanza_id romeo@montague.lit')}</before><max>2</max></set></query>`+ `<set xmlns="http://jabber.org/protocol/rsm"><before>${view.model.messages.at(0).get('stanza_id romeo@montague.lit')}</before><max>2</max></set></query>`+
`</iq>` `</iq>`
); );
done();
})); }));
it("is queried when the user enters a new MUC", it("is queried when the user enters a new MUC",
@ -86,7 +85,7 @@ describe("Message Archive Management", function () {
{ {
'archived_messages_page_size': 2, 'archived_messages_page_size': 2,
'muc_clear_messages_on_leave': false, 'muc_clear_messages_on_leave': false,
}, async function (done, _converse) { }, async function (_converse) {
const sent_IQs = _converse.connection.IQ_stanzas; const sent_IQs = _converse.connection.IQ_stanzas;
const muc_jid = 'orchard@chat.shakespeare.lit'; const muc_jid = 'orchard@chat.shakespeare.lit';
@ -269,7 +268,6 @@ describe("Message Archive Management", function () {
await u.waitUntil(() => view.querySelectorAll('.chat-msg__text').length); await u.waitUntil(() => view.querySelectorAll('.chat-msg__text').length);
await u.waitUntil(() => Array.from(view.querySelectorAll('.chat-msg__text')) await u.waitUntil(() => Array.from(view.querySelectorAll('.chat-msg__text'))
.map(e => e.textContent).join(' ') === "2nd Message 3rd Message 4th Message 5th Message 6th Message", 1000); .map(e => e.textContent).join(' ') === "2nd Message 3rd Message 4th Message 5th Message 6th Message", 1000);
done();
})); }));
it("queries for messages since the most recent cached message in a newly entered MUC", it("queries for messages since the most recent cached message in a newly entered MUC",
@ -278,7 +276,7 @@ describe("Message Archive Management", function () {
'archived_messages_page_size': 2, 'archived_messages_page_size': 2,
'muc_nickname_from_jid': false, 'muc_nickname_from_jid': false,
'muc_clear_messages_on_leave': false, 'muc_clear_messages_on_leave': false,
}, async function (done, _converse) { }, async function (_converse) {
const { api } = _converse; const { api } = _converse;
const sent_IQs = _converse.connection.IQ_stanzas; const sent_IQs = _converse.connection.IQ_stanzas;
@ -322,7 +320,6 @@ describe("Message Archive Management", function () {
`<set xmlns="http://jabber.org/protocol/rsm"><max>2</max></set>`+ `<set xmlns="http://jabber.org/protocol/rsm"><max>2</max></set>`+
`</query>`+ `</query>`+
`</iq>`); `</iq>`);
return done();
})); }));
}); });
@ -332,7 +329,7 @@ describe("Message Archive Management", function () {
it("is discarded if it doesn't come from the right sender", it("is discarded if it doesn't come from the right sender",
mock.initConverse( mock.initConverse(
['discoInitialized'], {}, ['discoInitialized'], {},
async function (done, _converse) { async function (_converse) {
await mock.waitForRoster(_converse, 'current', 1); await mock.waitForRoster(_converse, 'current', 1);
const contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit'; const contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit';
@ -382,13 +379,12 @@ describe("Message Archive Management", function () {
.filter(el => el.textContent === "Thrice the brinded cat hath mew'd.").length, 1000); .filter(el => el.textContent === "Thrice the brinded cat hath mew'd.").length, 1000);
expect(view.model.messages.length).toBe(1); expect(view.model.messages.length).toBe(1);
expect(view.model.messages.at(0).get('message')).toBe("Thrice the brinded cat hath mew'd."); expect(view.model.messages.at(0).get('message')).toBe("Thrice the brinded cat hath mew'd.");
done();
})); }));
it("is not discarded if it comes from the right sender", it("is not discarded if it comes from the right sender",
mock.initConverse( mock.initConverse(
['discoInitialized'], {}, ['discoInitialized'], {},
async function (done, _converse) { async function (_converse) {
await mock.waitForRoster(_converse, 'current', 1); await mock.waitForRoster(_converse, 'current', 1);
const contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit'; const contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit';
@ -437,13 +433,12 @@ describe("Message Archive Management", function () {
expect(view.model.messages.length).toBe(2); expect(view.model.messages.length).toBe(2);
expect(view.model.messages.at(0).get('message')).toBe("Meet me at the dance"); expect(view.model.messages.at(0).get('message')).toBe("Meet me at the dance");
expect(view.model.messages.at(1).get('message')).toBe("Thrice the brinded cat hath mew'd."); expect(view.model.messages.at(1).get('message')).toBe("Thrice the brinded cat hath mew'd.");
done();
})); }));
it("updates the is_archived value of an already cached version", it("updates the is_archived value of an already cached version",
mock.initConverse( mock.initConverse(
['discoInitialized'], {}, ['discoInitialized'], {},
async function (done, _converse) { async function (_converse) {
await mock.openAndEnterChatRoom(_converse, 'trek-radio@conference.lightwitch.org', 'romeo'); await mock.openAndEnterChatRoom(_converse, 'trek-radio@conference.lightwitch.org', 'romeo');
@ -485,13 +480,12 @@ describe("Message Archive Management", function () {
expect(view.model.messages.length).toBe(1); expect(view.model.messages.length).toBe(1);
expect(view.model.messages.at(0).get('is_archived')).toBe(true); expect(view.model.messages.at(0).get('is_archived')).toBe(true);
expect(view.model.messages.at(0).get('stanza_id trek-radio@conference.lightwitch.org')).toBe('45fbbf2a-1059-479d-9283-c8effaf05621'); expect(view.model.messages.at(0).get('stanza_id trek-radio@conference.lightwitch.org')).toBe('45fbbf2a-1059-479d-9283-c8effaf05621');
done();
})); }));
it("isn't shown as duplicate by comparing its stanza id or archive id", it("isn't shown as duplicate by comparing its stanza id or archive id",
mock.initConverse( mock.initConverse(
['discoInitialized'], {}, ['discoInitialized'], {},
async function (done, _converse) { async function (_converse) {
await mock.openAndEnterChatRoom(_converse, 'trek-radio@conference.lightwitch.org', 'jcbrand'); await mock.openAndEnterChatRoom(_converse, 'trek-radio@conference.lightwitch.org', 'jcbrand');
const view = _converse.chatboxviews.get('trek-radio@conference.lightwitch.org'); const view = _converse.chatboxviews.get('trek-radio@conference.lightwitch.org');
@ -524,13 +518,12 @@ describe("Message Archive Management", function () {
const result = await view.model.getDuplicateMessage.calls.all()[0].returnValue const result = await view.model.getDuplicateMessage.calls.all()[0].returnValue
expect(result instanceof _converse.Message).toBe(true); expect(result instanceof _converse.Message).toBe(true);
expect(view.querySelectorAll('.chat-msg').length).toBe(1); expect(view.querySelectorAll('.chat-msg').length).toBe(1);
done();
})); }));
it("isn't shown as duplicate by comparing only the archive id", it("isn't shown as duplicate by comparing only the archive id",
mock.initConverse( mock.initConverse(
['discoInitialized'], {}, ['discoInitialized'], {},
async function (done, _converse) { async function (_converse) {
await mock.openAndEnterChatRoom(_converse, 'discuss@conference.conversejs.org', 'romeo'); await mock.openAndEnterChatRoom(_converse, 'discuss@conference.conversejs.org', 'romeo');
const view = _converse.chatboxviews.get('discuss@conference.conversejs.org'); const view = _converse.chatboxviews.get('discuss@conference.conversejs.org');
@ -574,7 +567,6 @@ describe("Message Archive Management", function () {
const result = await view.model.getDuplicateMessage.calls.all()[0].returnValue const result = await view.model.getDuplicateMessage.calls.all()[0].returnValue
expect(result instanceof _converse.Message).toBe(true); expect(result instanceof _converse.Message).toBe(true);
expect(view.querySelectorAll('.chat-msg').length).toBe(1); expect(view.querySelectorAll('.chat-msg').length).toBe(1);
done();
})) }))
}); });
}); });
@ -582,7 +574,7 @@ describe("Message Archive Management", function () {
describe("The archive.query API", function () { describe("The archive.query API", function () {
it("can be used to query for all archived messages", it("can be used to query for all archived messages",
mock.initConverse(['discoInitialized'], {}, async function (done, _converse) { mock.initConverse(['discoInitialized'], {}, async function (_converse) {
const sendIQ = _converse.connection.sendIQ; const sendIQ = _converse.connection.sendIQ;
await mock.waitUntilDiscoConfirmed(_converse, _converse.bare_jid, null, [Strophe.NS.MAM]); await mock.waitUntilDiscoConfirmed(_converse, _converse.bare_jid, null, [Strophe.NS.MAM]);
@ -596,11 +588,10 @@ describe("Message Archive Management", function () {
const queryid = sent_stanza.querySelector('query').getAttribute('queryid'); const queryid = sent_stanza.querySelector('query').getAttribute('queryid');
expect(Strophe.serialize(sent_stanza)).toBe( expect(Strophe.serialize(sent_stanza)).toBe(
`<iq id="${IQ_id}" type="set" xmlns="jabber:client"><query queryid="${queryid}" xmlns="urn:xmpp:mam:2"/></iq>`); `<iq id="${IQ_id}" type="set" xmlns="jabber:client"><query queryid="${queryid}" xmlns="urn:xmpp:mam:2"/></iq>`);
done();
})); }));
it("can be used to query for all messages to/from a particular JID", it("can be used to query for all messages to/from a particular JID",
mock.initConverse([], {}, async function (done, _converse) { mock.initConverse([], {}, async function (_converse) {
await mock.waitUntilDiscoConfirmed(_converse, _converse.bare_jid, null, [Strophe.NS.MAM]); await mock.waitUntilDiscoConfirmed(_converse, _converse.bare_jid, null, [Strophe.NS.MAM]);
let sent_stanza, IQ_id; let sent_stanza, IQ_id;
@ -625,11 +616,10 @@ describe("Message Archive Management", function () {
`</x>`+ `</x>`+
`</query>`+ `</query>`+
`</iq>`); `</iq>`);
done();
})); }));
it("can be used to query for archived messages from a chat room", it("can be used to query for archived messages from a chat room",
mock.initConverse(['statusInitialized'], {}, async function (done, _converse) { mock.initConverse(['statusInitialized'], {}, async function (_converse) {
const room_jid = 'coven@chat.shakespeare.lit'; const room_jid = 'coven@chat.shakespeare.lit';
_converse.api.archive.query({'with': room_jid, 'groupchat': true}); _converse.api.archive.query({'with': room_jid, 'groupchat': true});
@ -650,11 +640,10 @@ describe("Message Archive Management", function () {
`</x>`+ `</x>`+
`</query>`+ `</query>`+
`</iq>`); `</iq>`);
done();
})); }));
it("checks whether returned MAM messages from a MUC room are from the right JID", it("checks whether returned MAM messages from a MUC room are from the right JID",
mock.initConverse(['statusInitialized'], {}, async function (done, _converse) { mock.initConverse(['statusInitialized'], {}, async function (_converse) {
const room_jid = 'coven@chat.shakespeare.lit'; const room_jid = 'coven@chat.shakespeare.lit';
const promise = _converse.api.archive.query({'with': room_jid, 'groupchat': true, 'max':'10'}); const promise = _converse.api.archive.query({'with': room_jid, 'groupchat': true, 'max':'10'});
@ -719,11 +708,10 @@ describe("Message Archive Management", function () {
const result = await promise; const result = await promise;
expect(result.messages.length).toBe(0); expect(result.messages.length).toBe(0);
done();
})); }));
it("can be used to query for all messages in a certain timespan", it("can be used to query for all messages in a certain timespan",
mock.initConverse([], {}, async function (done, _converse) { mock.initConverse([], {}, async function (_converse) {
await mock.waitUntilDiscoConfirmed(_converse, _converse.bare_jid, null, [Strophe.NS.MAM]); await mock.waitUntilDiscoConfirmed(_converse, _converse.bare_jid, null, [Strophe.NS.MAM]);
let sent_stanza, IQ_id; let sent_stanza, IQ_id;
@ -757,11 +745,10 @@ describe("Message Archive Management", function () {
`</query>`+ `</query>`+
`</iq>` `</iq>`
); );
done();
})); }));
it("throws a TypeError if an invalid date is provided", it("throws a TypeError if an invalid date is provided",
mock.initConverse([], {}, async function (done, _converse) { mock.initConverse([], {}, async function (_converse) {
await mock.waitUntilDiscoConfirmed(_converse, _converse.bare_jid, null, [Strophe.NS.MAM]); await mock.waitUntilDiscoConfirmed(_converse, _converse.bare_jid, null, [Strophe.NS.MAM]);
try { try {
@ -769,11 +756,10 @@ describe("Message Archive Management", function () {
} catch (e) { } catch (e) {
expect(() => {throw e}).toThrow(new TypeError('archive.query: invalid date provided for: start')); expect(() => {throw e}).toThrow(new TypeError('archive.query: invalid date provided for: start'));
} }
done();
})); }));
it("can be used to query for all messages after a certain time", it("can be used to query for all messages after a certain time",
mock.initConverse([], {}, async function (done, _converse) { mock.initConverse([], {}, async function (_converse) {
await mock.waitUntilDiscoConfirmed(_converse, _converse.bare_jid, null, [Strophe.NS.MAM]); await mock.waitUntilDiscoConfirmed(_converse, _converse.bare_jid, null, [Strophe.NS.MAM]);
let sent_stanza, IQ_id; let sent_stanza, IQ_id;
@ -803,11 +789,10 @@ describe("Message Archive Management", function () {
`</query>`+ `</query>`+
`</iq>` `</iq>`
); );
done();
})); }));
it("can be used to query for a limited set of results", it("can be used to query for a limited set of results",
mock.initConverse([], {}, async function (done, _converse) { mock.initConverse([], {}, async function (_converse) {
await mock.waitUntilDiscoConfirmed(_converse, _converse.bare_jid, null, [Strophe.NS.MAM]); await mock.waitUntilDiscoConfirmed(_converse, _converse.bare_jid, null, [Strophe.NS.MAM]);
let sent_stanza, IQ_id; let sent_stanza, IQ_id;
@ -837,11 +822,10 @@ describe("Message Archive Management", function () {
`</query>`+ `</query>`+
`</iq>` `</iq>`
); );
done();
})); }));
it("can be used to page through results", it("can be used to page through results",
mock.initConverse([], {}, async function (done, _converse) { mock.initConverse([], {}, async function (_converse) {
await mock.waitUntilDiscoConfirmed(_converse, _converse.bare_jid, null, [Strophe.NS.MAM]); await mock.waitUntilDiscoConfirmed(_converse, _converse.bare_jid, null, [Strophe.NS.MAM]);
let sent_stanza, IQ_id; let sent_stanza, IQ_id;
@ -875,11 +859,10 @@ describe("Message Archive Management", function () {
`</set>`+ `</set>`+
`</query>`+ `</query>`+
`</iq>`); `</iq>`);
done();
})); }));
it("accepts \"before\" with an empty string as value to reverse the order", it("accepts \"before\" with an empty string as value to reverse the order",
mock.initConverse([], {}, async function (done, _converse) { mock.initConverse([], {}, async function (_converse) {
await mock.waitUntilDiscoConfirmed(_converse, _converse.bare_jid, null, [Strophe.NS.MAM]); await mock.waitUntilDiscoConfirmed(_converse, _converse.bare_jid, null, [Strophe.NS.MAM]);
let sent_stanza, IQ_id; let sent_stanza, IQ_id;
@ -905,11 +888,10 @@ describe("Message Archive Management", function () {
`</set>`+ `</set>`+
`</query>`+ `</query>`+
`</iq>`); `</iq>`);
done();
})); }));
it("returns an object which includes the messages and a _converse.RSM object", it("returns an object which includes the messages and a _converse.RSM object",
mock.initConverse([], {}, async function (done, _converse) { mock.initConverse([], {}, async function (_converse) {
await mock.waitUntilDiscoConfirmed(_converse, _converse.bare_jid, null, [Strophe.NS.MAM]); await mock.waitUntilDiscoConfirmed(_converse, _converse.bare_jid, null, [Strophe.NS.MAM]);
let sent_stanza, IQ_id; let sent_stanza, IQ_id;
@ -988,14 +970,13 @@ describe("Message Archive Management", function () {
expect(result.rsm.result.count).toBe(16); expect(result.rsm.result.count).toBe(16);
expect(result.rsm.result.first).toBe('23452-4534-1'); expect(result.rsm.result.first).toBe('23452-4534-1');
expect(result.rsm.result.last).toBe('09af3-cc343-b409f'); expect(result.rsm.result.last).toBe('09af3-cc343-b409f');
done()
})); }));
}); });
describe("The default preference", function () { describe("The default preference", function () {
it("is set once server support for MAM has been confirmed", it("is set once server support for MAM has been confirmed",
mock.initConverse([], {}, async function (done, _converse) { mock.initConverse([], {}, async function (_converse) {
const { api } = _converse; const { api } = _converse;
@ -1065,7 +1046,6 @@ describe("Message Archive Management", function () {
await u.waitUntil(() => feature.save.calls.count()); await u.waitUntil(() => feature.save.calls.count());
expect(feature.save).toHaveBeenCalled(); expect(feature.save).toHaveBeenCalled();
expect(feature.get('preferences')['default']).toBe('never'); // eslint-disable-line dot-notation expect(feature.get('preferences')['default']).toBe('never'); // eslint-disable-line dot-notation
done();
})); }));
}); });
}); });
@ -1074,7 +1054,7 @@ describe("Chatboxes", function () {
describe("A Chatbox", function () { describe("A Chatbox", function () {
it("will fetch archived messages once it's opened", it("will fetch archived messages once it's opened",
mock.initConverse(['discoInitialized'], {}, async function (done, _converse) { mock.initConverse(['discoInitialized'], {}, async function (_converse) {
await mock.waitForRoster(_converse, 'current', 1); await mock.waitForRoster(_converse, 'current', 1);
const contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit'; const contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit';
@ -1130,11 +1110,10 @@ describe("Chatboxes", function () {
.c('last').t('09af3-cc343-b409f').up() .c('last').t('09af3-cc343-b409f').up()
.c('count').t('16'); .c('count').t('16');
_converse.connection._dataRecv(mock.createRequest(stanza)); _converse.connection._dataRecv(mock.createRequest(stanza));
done();
})); }));
it("will show an error message if the MAM query times out", it("will show an error message if the MAM query times out",
mock.initConverse(['discoInitialized'], {}, async function (done, _converse) { mock.initConverse(['discoInitialized'], {}, async function (_converse) {
const sendIQ = _converse.connection.sendIQ; const sendIQ = _converse.connection.sendIQ;
@ -1231,7 +1210,6 @@ describe("Chatboxes", function () {
await u.waitUntil(() => view.model.messages.length === 2, 500); await u.waitUntil(() => view.model.messages.length === 2, 500);
err_message = view.querySelector('.message.chat-error'); err_message = view.querySelector('.message.chat-error');
expect(err_message).toBe(null); expect(err_message).toBe(null);
done();
})); }));
}); });
}); });

View File

@ -14,7 +14,7 @@ describe("Message Archive Management", function () {
'persistent_store': 'localStorage', 'persistent_store': 'localStorage',
'mam_request_all_pages': false 'mam_request_all_pages': false
}, },
async function (done, _converse) { async function (_converse) {
const sent_IQs = _converse.connection.IQ_stanzas; const sent_IQs = _converse.connection.IQ_stanzas;
const muc_jid = 'orchard@chat.shakespeare.lit'; const muc_jid = 'orchard@chat.shakespeare.lit';
@ -152,12 +152,11 @@ describe("Message Archive Management", function () {
_converse.connection._dataRecv(mock.createRequest(result)); _converse.connection._dataRecv(mock.createRequest(result));
await u.waitUntil(() => view.model.messages.length === 4); await u.waitUntil(() => view.model.messages.length === 4);
await u.waitUntil(() => view.querySelector('converse-mam-placeholder') === null); await u.waitUntil(() => view.querySelector('converse-mam-placeholder') === null);
done();
})); }));
it("is not created when there isn't a gap because the cached history is empty", it("is not created when there isn't a gap because the cached history is empty",
mock.initConverse(['discoInitialized'], {'archived_messages_page_size': 2}, mock.initConverse(['discoInitialized'], {'archived_messages_page_size': 2},
async function (done, _converse) { async function (_converse) {
const sent_IQs = _converse.connection.IQ_stanzas; const sent_IQs = _converse.connection.IQ_stanzas;
const muc_jid = 'orchard@chat.shakespeare.lit'; const muc_jid = 'orchard@chat.shakespeare.lit';
@ -213,7 +212,6 @@ describe("Message Archive Management", function () {
_converse.connection._dataRecv(mock.createRequest(result)); _converse.connection._dataRecv(mock.createRequest(result));
await u.waitUntil(() => view.model.messages.length === 2); await u.waitUntil(() => view.model.messages.length === 2);
expect(true).toBe(true); expect(true).toBe(true);
done();
})); }));
}); });
}); });

View File

@ -8,11 +8,8 @@ const sizzle = converse.env.sizzle;
describe("A chat message", function () { describe("A chat message", function () {
it("received for a minimized chat box will increment a counter on its header", it("received for a minimized chat box will increment a counter on its header",
mock.initConverse(['chatBoxesFetched'], {}, async function (done, _converse) { mock.initConverse(['chatBoxesFetched'], {'view_mode': 'overlayed'}, async function (_converse) {
if (_converse.view_mode === 'fullscreen') {
return done();
}
await mock.waitForRoster(_converse, 'current'); await mock.waitForRoster(_converse, 'current');
const contact_name = mock.cur_names[0]; const contact_name = mock.cur_names[0];
const contact_jid = contact_name.replace(/ /g,'.').toLowerCase() + '@montague.lit'; const contact_jid = contact_name.replace(/ /g,'.').toLowerCase() + '@montague.lit';
@ -65,7 +62,6 @@ describe("A chat message", function () {
expect(count.textContent).toBe('2'); expect(count.textContent).toBe('2');
document.querySelector("converse-minimized-chat a.restore-chat").click(); document.querySelector("converse-minimized-chat a.restore-chat").click();
expect(_converse.chatboxes.filter('minimized').length).toBe(0); expect(_converse.chatboxes.filter('minimized').length).toBe(0);
done();
})); }));
}); });
@ -73,7 +69,7 @@ describe("A chat message", function () {
describe("A Groupchat", function () { describe("A Groupchat", function () {
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.initConverse(['chatBoxesFetched'], {}, async function (done, _converse) { mock.initConverse(['chatBoxesFetched'], {}, async function (_converse) {
await mock.openChatRoom(_converse, 'lounge', 'montague.lit', 'romeo'); await mock.openChatRoom(_converse, 'lounge', 'montague.lit', 'romeo');
const view = _converse.chatboxviews.get('lounge@montague.lit'); const view = _converse.chatboxviews.get('lounge@montague.lit');
@ -89,7 +85,6 @@ describe("A Groupchat", function () {
expect(_converse.api.trigger).toHaveBeenCalledWith('chatBoxMaximized', jasmine.any(Object)); expect(_converse.api.trigger).toHaveBeenCalledWith('chatBoxMaximized', jasmine.any(Object));
expect(view.model.get('minimized')).toBeFalsy(); expect(view.model.get('minimized')).toBeFalsy();
expect(_converse.api.trigger.calls.count(), 3); expect(_converse.api.trigger.calls.count(), 3);
done();
})); }));
}); });
@ -97,7 +92,7 @@ describe("A Groupchat", function () {
describe("A Chatbox", function () { describe("A Chatbox", function () {
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.initConverse(['chatBoxesFetched'], {}, async function (done, _converse) { mock.initConverse(['chatBoxesFetched'], {}, async function (_converse) {
await mock.waitForRoster(_converse, 'current'); await mock.waitForRoster(_converse, 'current');
await mock.openControlBox(_converse); await mock.openControlBox(_converse);
@ -121,11 +116,10 @@ describe("A Chatbox", function () {
minimized_chats.querySelector("a.restore-chat").click(); minimized_chats.querySelector("a.restore-chat").click();
expect(_converse.api.trigger).toHaveBeenCalledWith('chatBoxMaximized', jasmine.any(Object)); expect(_converse.api.trigger).toHaveBeenCalledWith('chatBoxMaximized', jasmine.any(Object));
expect(chatview.model.get('minimized')).toBeFalsy(); expect(chatview.model.get('minimized')).toBeFalsy();
done();
})); }));
it("can be opened in minimized mode initially", mock.initConverse([], {}, async function (done, _converse) { it("can be opened in minimized mode initially", mock.initConverse([], {}, async function (_converse) {
await mock.waitForRoster(_converse, 'current'); await mock.waitForRoster(_converse, 'current');
const sender_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit'; const sender_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit';
const minimized_chats = document.querySelector("converse-minimized-chats") const minimized_chats = document.querySelector("converse-minimized-chats")
@ -136,11 +130,10 @@ describe("A Chatbox", function () {
expect(u.isVisible(minimized_chats.firstElementChild)).toBe(true); expect(u.isVisible(minimized_chats.firstElementChild)).toBe(true);
expect(minimized_chats.firstElementChild.querySelectorAll('converse-minimized-chat').length).toBe(1); expect(minimized_chats.firstElementChild.querySelectorAll('converse-minimized-chat').length).toBe(1);
expect(_converse.chatboxes.filter('minimized').length).toBe(1); expect(_converse.chatboxes.filter('minimized').length).toBe(1);
done();
})); }));
it("can be trimmed to conserve space", mock.initConverse([], {}, async function (done, _converse) { it("can be trimmed to conserve space", mock.initConverse([], {}, async function (_converse) {
spyOn(_converse.minimize, 'trimChats'); spyOn(_converse.minimize, 'trimChats');
await mock.waitForRoster(_converse, 'current'); await mock.waitForRoster(_converse, 'current');
await mock.openControlBox(_converse); await mock.openControlBox(_converse);
@ -173,7 +166,6 @@ describe("A Chatbox", function () {
const minimized_chats = document.querySelector("converse-minimized-chats") const minimized_chats = document.querySelector("converse-minimized-chats")
minimized_chats.querySelector("a.restore-chat").click(); minimized_chats.querySelector("a.restore-chat").click();
expect(_converse.minimize.trimChats.calls.count()).toBe(17); expect(_converse.minimize.trimChats.calls.count()).toBe(17);
done();
})); }));
}); });
@ -181,7 +173,7 @@ describe("A Chatbox", function () {
describe("A Minimized ChatBoxView's Unread Message Count", function () { describe("A Minimized ChatBoxView's Unread Message Count", function () {
it("is displayed when scrolled up chatbox is minimized after receiving unread messages", it("is displayed when scrolled up chatbox is minimized after receiving unread messages",
mock.initConverse(['chatBoxesFetched'], {}, async function (done, _converse) { mock.initConverse(['chatBoxesFetched'], {}, async function (_converse) {
await mock.waitForRoster(_converse, 'current', 1); await mock.waitForRoster(_converse, 'current', 1);
const sender_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit'; const sender_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit';
@ -199,11 +191,10 @@ describe("A Minimized ChatBoxView's Unread Message Count", function () {
const unread_count = selectUnreadMsgCount(); const unread_count = selectUnreadMsgCount();
expect(u.isVisible(unread_count)).toBeTruthy(); expect(u.isVisible(unread_count)).toBeTruthy();
expect(unread_count.innerHTML.replace(/<!-.*?->/g, '')).toBe('1'); expect(unread_count.innerHTML.replace(/<!-.*?->/g, '')).toBe('1');
done();
})); }));
it("is incremented when message is received and windows is not focused", it("is incremented when message is received and windows is not focused",
mock.initConverse(['chatBoxesFetched'], {}, async function (done, _converse) { mock.initConverse(['chatBoxesFetched'], {}, async function (_converse) {
await mock.waitForRoster(_converse, 'current', 1); await mock.waitForRoster(_converse, 'current', 1);
const sender_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit'; const sender_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit';
@ -217,11 +208,10 @@ describe("A Minimized ChatBoxView's Unread Message Count", function () {
const unread_count = selectUnreadMsgCount(); const unread_count = selectUnreadMsgCount();
expect(u.isVisible(unread_count)).toBeTruthy(); expect(u.isVisible(unread_count)).toBeTruthy();
expect(unread_count.innerHTML.replace(/<!-.*?->/g, '')).toBe('1'); expect(unread_count.innerHTML.replace(/<!-.*?->/g, '')).toBe('1');
done();
})); }));
it("will render Openstreetmap-URL from geo-URI", it("will render Openstreetmap-URL from geo-URI",
mock.initConverse(['chatBoxesFetched'], {}, async function (done, _converse) { mock.initConverse(['chatBoxesFetched'], {}, async function (_converse) {
await mock.waitForRoster(_converse, 'current', 1); await mock.waitForRoster(_converse, 'current', 1);
const message = "geo:37.786971,-122.399677"; const message = "geo:37.786971,-122.399677";
@ -236,7 +226,6 @@ describe("A Minimized ChatBoxView's Unread Message Count", function () {
await u.waitUntil(() => msg.innerHTML.replace(/\<!-.*?-\>/g, '') === await u.waitUntil(() => msg.innerHTML.replace(/\<!-.*?-\>/g, '') ===
'<a target="_blank" rel="noopener" href="https://www.openstreetmap.org/?mlat=37.786971&amp;'+ '<a target="_blank" rel="noopener" href="https://www.openstreetmap.org/?mlat=37.786971&amp;'+
'mlon=-122.399677#map=18/37.786971/-122.399677">https://www.openstreetmap.org/?mlat=37.786971&amp;mlon=-122.399677#map=18/37.786971/-122.399677</a>'); 'mlon=-122.399677#map=18/37.786971/-122.399677">https://www.openstreetmap.org/?mlat=37.786971&amp;mlon=-122.399677#map=18/37.786971/-122.399677</a>');
done();
})); }));
}); });
@ -244,7 +233,7 @@ describe("A Minimized ChatBoxView's Unread Message Count", function () {
describe("The Minimized Chats Widget", function () { describe("The Minimized Chats Widget", function () {
it("shows chats that have been minimized", it("shows chats that have been minimized",
mock.initConverse([], {}, async function (done, _converse) { mock.initConverse([], {}, async function (_converse) {
await mock.waitForRoster(_converse, 'current'); await mock.waitForRoster(_converse, 'current');
await mock.openControlBox(_converse); await mock.openControlBox(_converse);
@ -271,11 +260,10 @@ describe("The Minimized Chats Widget", function () {
expect(u.isVisible(minimized_chats)).toBe(true); expect(u.isVisible(minimized_chats)).toBe(true);
expect(_converse.chatboxes.filter('minimized').length).toBe(2); expect(_converse.chatboxes.filter('minimized').length).toBe(2);
expect(_converse.chatboxes.filter('minimized').map(c => c.get('jid')).includes(contact_jid)).toBeTruthy(); expect(_converse.chatboxes.filter('minimized').map(c => c.get('jid')).includes(contact_jid)).toBeTruthy();
done();
})); }));
it("can be toggled to hide or show minimized chats", it("can be toggled to hide or show minimized chats",
mock.initConverse([], {}, async function (done, _converse) { mock.initConverse([], {}, async function (_converse) {
await mock.waitForRoster(_converse, 'current'); await mock.waitForRoster(_converse, 'current');
await mock.openControlBox(_converse); await mock.openControlBox(_converse);
@ -297,11 +285,10 @@ describe("The Minimized Chats Widget", function () {
minimized_chats.querySelector('#toggle-minimized-chats').click(); minimized_chats.querySelector('#toggle-minimized-chats').click();
await u.waitUntil(() => u.isVisible(minimized_chats.querySelector('.minimized-chats-flyout'))); await u.waitUntil(() => u.isVisible(minimized_chats.querySelector('.minimized-chats-flyout')));
expect(minimized_chats.minchats.get('collapsed')).toBeTruthy(); expect(minimized_chats.minchats.get('collapsed')).toBeTruthy();
done();
})); }));
it("shows the number messages received to minimized chats", it("shows the number messages received to minimized chats",
mock.initConverse(['chatBoxesFetched'], {}, async function (done, _converse) { mock.initConverse(['chatBoxesFetched'], {}, async function (_converse) {
await mock.waitForRoster(_converse, 'current', 4); await mock.waitForRoster(_converse, 'current', 4);
await mock.openControlBox(_converse); await mock.openControlBox(_converse);
@ -372,11 +359,10 @@ describe("The Minimized Chats Widget", function () {
id: u.getUniqueId() id: u.getUniqueId()
}).c('inactive', {'xmlns': 'http://jabber.org/protocol/chatstates'}).tree()); }).c('inactive', {'xmlns': 'http://jabber.org/protocol/chatstates'}).tree());
expect(minimized_chats.querySelector('.unread-message-count').textContent).toBe((i).toString()); expect(minimized_chats.querySelector('.unread-message-count').textContent).toBe((i).toString());
done();
})); }));
it("shows the number messages received to minimized groupchats", it("shows the number messages received to minimized groupchats",
mock.initConverse([], {}, async function (done, _converse) { mock.initConverse([], {}, async function (_converse) {
const muc_jid = 'kitchen@conference.shakespeare.lit'; const muc_jid = 'kitchen@conference.shakespeare.lit';
await mock.openAndEnterChatRoom(_converse, 'kitchen@conference.shakespeare.lit', 'fires'); await mock.openAndEnterChatRoom(_converse, 'kitchen@conference.shakespeare.lit', 'fires');
@ -395,6 +381,5 @@ describe("The Minimized Chats Widget", function () {
const minimized_chats = document.querySelector("converse-minimized-chats") const minimized_chats = document.querySelector("converse-minimized-chats")
expect(u.isVisible(minimized_chats.querySelector('.unread-message-count'))).toBeTruthy(); expect(u.isVisible(minimized_chats.querySelector('.unread-message-count'))).toBeTruthy();
expect(minimized_chats.querySelector('.unread-message-count').textContent).toBe('1'); expect(minimized_chats.querySelector('.unread-message-count').textContent).toBe('1');
done();
})); }));
}); });

View File

@ -9,7 +9,7 @@ describe("The nickname autocomplete feature", function () {
it("shows all autocompletion options when the user presses @", it("shows all autocompletion options when the user presses @",
mock.initConverse(['chatBoxesFetched'], {}, mock.initConverse(['chatBoxesFetched'], {},
async function (done, _converse) { async function (_converse) {
await mock.openAndEnterChatRoom(_converse, 'lounge@montague.lit', 'tom'); await mock.openAndEnterChatRoom(_converse, 'lounge@montague.lit', 'tom');
const view = _converse.chatboxviews.get('lounge@montague.lit'); const view = _converse.chatboxviews.get('lounge@montague.lit');
@ -58,12 +58,11 @@ describe("The nickname autocomplete feature", function () {
expect(view.querySelector('.suggestion-box__results li:nth-child(2)').textContent).toBe('harry'); expect(view.querySelector('.suggestion-box__results li:nth-child(2)').textContent).toBe('harry');
expect(view.querySelector('.suggestion-box__results li:nth-child(3)').textContent).toBe('jane'); expect(view.querySelector('.suggestion-box__results li:nth-child(3)').textContent).toBe('jane');
expect(view.querySelector('.suggestion-box__results li:nth-child(4)').textContent).toBe('tom'); expect(view.querySelector('.suggestion-box__results li:nth-child(4)').textContent).toBe('tom');
done();
})); }));
it("shows all autocompletion options when the user presses @ right after a new line", it("shows all autocompletion options when the user presses @ right after a new line",
mock.initConverse(['chatBoxesFetched'], {}, mock.initConverse(['chatBoxesFetched'], {},
async function (done, _converse) { async function (_converse) {
await mock.openAndEnterChatRoom(_converse, 'lounge@montague.lit', 'tom'); await mock.openAndEnterChatRoom(_converse, 'lounge@montague.lit', 'tom');
const view = _converse.chatboxviews.get('lounge@montague.lit'); const view = _converse.chatboxviews.get('lounge@montague.lit');
@ -113,13 +112,12 @@ describe("The nickname autocomplete feature", function () {
expect(view.querySelector('.suggestion-box__results li:nth-child(2)').textContent).toBe('harry'); expect(view.querySelector('.suggestion-box__results li:nth-child(2)').textContent).toBe('harry');
expect(view.querySelector('.suggestion-box__results li:nth-child(3)').textContent).toBe('jane'); expect(view.querySelector('.suggestion-box__results li:nth-child(3)').textContent).toBe('jane');
expect(view.querySelector('.suggestion-box__results li:nth-child(4)').textContent).toBe('tom'); expect(view.querySelector('.suggestion-box__results li:nth-child(4)').textContent).toBe('tom');
done();
})); }));
it("shows all autocompletion options when the user presses @ right after an allowed character", it("shows all autocompletion options when the user presses @ right after an allowed character",
mock.initConverse( mock.initConverse(
['chatBoxesFetched'], {'opening_mention_characters':['(']}, ['chatBoxesFetched'], {'opening_mention_characters':['(']},
async function (done, _converse) { async function (_converse) {
await mock.openAndEnterChatRoom(_converse, 'lounge@montague.lit', 'tom'); await mock.openAndEnterChatRoom(_converse, 'lounge@montague.lit', 'tom');
const view = _converse.chatboxviews.get('lounge@montague.lit'); const view = _converse.chatboxviews.get('lounge@montague.lit');
@ -169,11 +167,10 @@ describe("The nickname autocomplete feature", function () {
expect(view.querySelector('.suggestion-box__results li:nth-child(2)').textContent).toBe('harry'); expect(view.querySelector('.suggestion-box__results li:nth-child(2)').textContent).toBe('harry');
expect(view.querySelector('.suggestion-box__results li:nth-child(3)').textContent).toBe('jane'); expect(view.querySelector('.suggestion-box__results li:nth-child(3)').textContent).toBe('jane');
expect(view.querySelector('.suggestion-box__results li:nth-child(4)').textContent).toBe('tom'); expect(view.querySelector('.suggestion-box__results li:nth-child(4)').textContent).toBe('tom');
done();
})); }));
it("should order by query index position and length", mock.initConverse( it("should order by query index position and length", mock.initConverse(
['chatBoxesFetched'], {}, async function (done, _converse) { ['chatBoxesFetched'], {}, async function (_converse) {
await mock.openAndEnterChatRoom(_converse, 'lounge@montague.lit', 'tom'); await mock.openAndEnterChatRoom(_converse, 'lounge@montague.lit', 'tom');
const view = _converse.chatboxviews.get('lounge@montague.lit'); const view = _converse.chatboxviews.get('lounge@montague.lit');
@ -217,11 +214,10 @@ describe("The nickname autocomplete feature", function () {
await u.waitUntil(() => view.querySelectorAll('.suggestion-box__results li').length === 2); await u.waitUntil(() => view.querySelectorAll('.suggestion-box__results li').length === 2);
expect(view.querySelector('.suggestion-box__results li:first-child').textContent).toBe('john'); expect(view.querySelector('.suggestion-box__results li:first-child').textContent).toBe('john');
expect(view.querySelector('.suggestion-box__results li:nth-child(2)').textContent).toBe('jones'); expect(view.querySelector('.suggestion-box__results li:nth-child(2)').textContent).toBe('jones');
done();
})); }));
it("autocompletes when the user presses tab", it("autocompletes when the user presses tab",
mock.initConverse(['chatBoxesFetched'], {}, async function (done, _converse) { mock.initConverse(['chatBoxesFetched'], {}, async function (_converse) {
await mock.openAndEnterChatRoom(_converse, 'lounge@montague.lit', 'romeo'); await mock.openAndEnterChatRoom(_converse, 'lounge@montague.lit', 'romeo');
const view = _converse.chatboxviews.get('lounge@montague.lit'); const view = _converse.chatboxviews.get('lounge@montague.lit');
@ -328,11 +324,10 @@ describe("The nickname autocomplete feature", function () {
message_form.onKeyDown(tab_event); message_form.onKeyDown(tab_event);
message_form.onKeyUp(tab_event); message_form.onKeyUp(tab_event);
await u.waitUntil(() => textarea.value === 'hello @z3r0 '); await u.waitUntil(() => textarea.value === 'hello @z3r0 ');
done();
})); }));
it("autocompletes when the user presses backspace", it("autocompletes when the user presses backspace",
mock.initConverse([], {}, async function (done, _converse) { mock.initConverse([], {}, async function (_converse) {
await mock.openAndEnterChatRoom(_converse, 'lounge@montague.lit', 'romeo'); await mock.openAndEnterChatRoom(_converse, 'lounge@montague.lit', 'romeo');
const view = _converse.chatboxviews.get('lounge@montague.lit'); const view = _converse.chatboxviews.get('lounge@montague.lit');
@ -368,6 +363,5 @@ describe("The nickname autocomplete feature", function () {
await u.waitUntil(() => view.querySelector('.suggestion-box__results').hidden === false); await u.waitUntil(() => view.querySelector('.suggestion-box__results').hidden === false);
expect(view.querySelectorAll('.suggestion-box__results li').length).toBe(1); expect(view.querySelectorAll('.suggestion-box__results li').length).toBe(1);
expect(view.querySelector('.suggestion-box__results li').textContent).toBe('some1'); expect(view.querySelector('.suggestion-box__results li').textContent).toBe('some1');
done();
})); }));
}); });

View File

@ -6,7 +6,7 @@ const u = converse.env.utils;
describe("The <converse-muc> component", function () { describe("The <converse-muc> component", function () {
it("can be rendered as a standalone component", it("can be rendered as a standalone component",
mock.initConverse([], {'auto_insert': false}, async function (done, _converse) { mock.initConverse([], {'auto_insert': false}, async function (_converse) {
const { api } = _converse; const { api } = _converse;
const muc_jid = 'lounge@montague.lit'; const muc_jid = 'lounge@montague.lit';
@ -33,11 +33,10 @@ describe("The <converse-muc> component", function () {
await u.waitUntil(() => muc_el.querySelector('converse-muc-bottom-panel')); await u.waitUntil(() => muc_el.querySelector('converse-muc-bottom-panel'));
body.removeChild(span_el); body.removeChild(span_el);
expect(true).toBe(true); expect(true).toBe(true);
done();
})); }));
it("will update correctly when the jid property changes", it("will update correctly when the jid property changes",
mock.initConverse([], {'auto_insert': false}, async function (done, _converse) { mock.initConverse([], {'auto_insert': false}, async function (_converse) {
const { api } = _converse; const { api } = _converse;
const muc_jid = 'lounge@montague.lit'; const muc_jid = 'lounge@montague.lit';
@ -89,6 +88,5 @@ describe("The <converse-muc> component", function () {
await u.waitUntil(() => muc_el.querySelector('converse-chat-message-body').textContent.trim() === 'hello from the bar!'); await u.waitUntil(() => muc_el.querySelector('converse-chat-message-body').textContent.trim() === 'hello from the bar!');
body.removeChild(span_el); body.removeChild(span_el);
done();
})); }));
}); });

View File

@ -5,7 +5,7 @@ const { $msg, $pres, Strophe, u } = converse.env;
describe("A Groupchat Message", function () { describe("A Groupchat Message", function () {
it("can be replaced with a correction", it("can be replaced with a correction",
mock.initConverse([], {}, async function (done, _converse) { mock.initConverse([], {}, async function (_converse) {
const muc_jid = 'lounge@montague.lit'; const muc_jid = 'lounge@montague.lit';
await mock.openAndEnterChatRoom(_converse, muc_jid, 'romeo'); await mock.openAndEnterChatRoom(_converse, muc_jid, 'romeo');
@ -66,11 +66,10 @@ describe("A Groupchat Message", function () {
expect(older_msgs.length).toBe(2); expect(older_msgs.length).toBe(2);
expect(older_msgs[0].textContent.includes('But soft, what light through yonder airlock breaks?')).toBe(true); expect(older_msgs[0].textContent.includes('But soft, what light through yonder airlock breaks?')).toBe(true);
expect(older_msgs[1].textContent.includes('But soft, what light through yonder chimney breaks?')).toBe(true); expect(older_msgs[1].textContent.includes('But soft, what light through yonder chimney breaks?')).toBe(true);
done();
})); }));
it("keeps the same position in history after a correction", it("keeps the same position in history after a correction",
mock.initConverse([], {}, async function (done, _converse) { mock.initConverse([], {}, async function (_converse) {
const muc_jid = 'lounge@montague.lit'; const muc_jid = 'lounge@montague.lit';
await mock.openAndEnterChatRoom(_converse, muc_jid, 'romeo'); await mock.openAndEnterChatRoom(_converse, muc_jid, 'romeo');
@ -158,11 +157,10 @@ describe("A Groupchat Message", function () {
expect(older_msgs.length).toBe(2); expect(older_msgs.length).toBe(2);
expect(older_msgs[0].textContent.includes('But soft, what light through yonder airlock breaks?')).toBe(true); expect(older_msgs[0].textContent.includes('But soft, what light through yonder airlock breaks?')).toBe(true);
expect(older_msgs[1].textContent.includes('But soft, what light through yonder chimney breaks?')).toBe(true); expect(older_msgs[1].textContent.includes('But soft, what light through yonder chimney breaks?')).toBe(true);
done();
})); }));
it("can be sent as a correction by using the up arrow", it("can be sent as a correction by using the up arrow",
mock.initConverse([], {}, async function (done, _converse) { mock.initConverse([], {}, async function (_converse) {
const muc_jid = 'lounge@montague.lit'; const muc_jid = 'lounge@montague.lit';
await mock.openAndEnterChatRoom(_converse, muc_jid, 'romeo'); await mock.openAndEnterChatRoom(_converse, muc_jid, 'romeo');
@ -262,6 +260,5 @@ describe("A Groupchat Message", function () {
expect(view.model.messages.at(0).get('correcting')).toBe(false); expect(view.model.messages.at(0).get('correcting')).toBe(false);
expect(view.querySelectorAll('.chat-msg').length).toBe(2); expect(view.querySelectorAll('.chat-msg').length).toBe(2);
await u.waitUntil(() => !u.hasClass('correcting', view.querySelector('.chat-msg')), 500); await u.waitUntil(() => !u.hasClass('correcting', view.querySelector('.chat-msg')), 500);
done();
})); }));
}); });

View File

@ -6,7 +6,7 @@ const u = converse.env.utils;
describe("Emojis", function () { describe("Emojis", function () {
describe("The emoji picker", function () { describe("The emoji picker", function () {
it("is opened to autocomplete emojis in the textarea", it("is opened to autocomplete emojis in the textarea",
mock.initConverse(['chatBoxesFetched'], {}, async function (done, _converse) { mock.initConverse(['chatBoxesFetched'], {}, async function (_converse) {
await mock.waitForRoster(_converse, 'current', 0); await mock.waitForRoster(_converse, 'current', 0);
const muc_jid = 'lounge@montague.lit'; const muc_jid = 'lounge@montague.lit';
@ -70,11 +70,10 @@ describe("Emojis", function () {
await u.waitUntil(() => input.value === ':use'); await u.waitUntil(() => input.value === ':use');
visible_emojis = sizzle('.insert-emoji:not(.hidden)', picker); visible_emojis = sizzle('.insert-emoji:not(.hidden)', picker);
expect(visible_emojis.length).toBe(0); expect(visible_emojis.length).toBe(0);
done();
})); }));
it("is focused to autocomplete emojis in the textarea", it("is focused to autocomplete emojis in the textarea",
mock.initConverse(['chatBoxesFetched'], {}, async function (done, _converse) { mock.initConverse(['chatBoxesFetched'], {}, async function (_converse) {
const muc_jid = 'lounge@montague.lit'; const muc_jid = 'lounge@montague.lit';
await mock.waitForRoster(_converse, 'current', 0); await mock.waitForRoster(_converse, 'current', 0);
@ -119,12 +118,11 @@ describe("Emojis", function () {
emoji = sizzle('.emojis-lists__container--search .insert-emoji:not(.hidden) a', view).pop(); emoji = sizzle('.emojis-lists__container--search .insert-emoji:not(.hidden) a', view).pop();
emoji.click(); emoji.click();
await u.waitUntil(() => textarea.value === ':grinning: :grimacing: '); await u.waitUntil(() => textarea.value === ':grinning: :grimacing: ');
done();
})); }));
it("properly inserts emojis into the chat textarea", it("properly inserts emojis into the chat textarea",
mock.initConverse(['chatBoxesFetched'], {}, async function (done, _converse) { mock.initConverse(['chatBoxesFetched'], {}, async function (_converse) {
const muc_jid = 'lounge@montague.lit'; const muc_jid = 'lounge@montague.lit';
await mock.waitForRoster(_converse, 'current', 0); await mock.waitForRoster(_converse, 'current', 0);
@ -164,12 +162,11 @@ describe("Emojis", function () {
const emoji = sizzle('.emojis-lists__container--search .insert-emoji:not(.hidden) a', view).pop(); const emoji = sizzle('.emojis-lists__container--search .insert-emoji:not(.hidden) a', view).pop();
emoji.click(); emoji.click();
expect(textarea.value).toBe(':100: '); expect(textarea.value).toBe(':100: ');
done();
})); }));
it("allows you to search for particular emojis", it("allows you to search for particular emojis",
mock.initConverse(['chatBoxesFetched'], {}, async function (done, _converse) { mock.initConverse(['chatBoxesFetched'], {}, async function (_converse) {
const muc_jid = 'lounge@montague.lit'; const muc_jid = 'lounge@montague.lit';
await mock.waitForRoster(_converse, 'current', 0); await mock.waitForRoster(_converse, 'current', 0);
@ -222,7 +219,6 @@ describe("Emojis", function () {
input.dispatchEvent(new KeyboardEvent('keydown', enter_event)); input.dispatchEvent(new KeyboardEvent('keydown', enter_event));
await u.waitUntil(() => input.value === ''); await u.waitUntil(() => input.value === '');
expect(view.querySelector('textarea.chat-textarea').value).toBe(':smiley: '); expect(view.querySelector('textarea.chat-textarea').value).toBe(':smiley: ');
done();
})); }));
}); });
}); });

View File

@ -5,7 +5,7 @@ const u = converse.env.utils;
describe("A XEP-0317 MUC Hat", function () { describe("A XEP-0317 MUC Hat", function () {
it("can be included in a presence stanza", it("can be included in a presence stanza",
mock.initConverse(['chatBoxesFetched'], {}, async function (done, _converse) { mock.initConverse(['chatBoxesFetched'], {}, async function (_converse) {
const muc_jid = 'lounge@montague.lit'; const muc_jid = 'lounge@montague.lit';
await mock.openAndEnterChatRoom(_converse, muc_jid, 'romeo'); await mock.openAndEnterChatRoom(_converse, muc_jid, 'romeo');
const view = _converse.chatboxviews.get(muc_jid); const view = _converse.chatboxviews.get(muc_jid);
@ -70,6 +70,5 @@ describe("A XEP-0317 MUC Hat", function () {
`))); `)));
await u.waitUntil(() => view.model.getOccupant("Terry").get('hats').length === 0); await u.waitUntil(() => view.model.getOccupant("Terry").get('hats').length === 0);
await u.waitUntil(() => view.querySelectorAll('.chat-msg .badge').length === 0); await u.waitUntil(() => view.querySelectorAll('.chat-msg .badge').length === 0);
done();
})); }));
}) })

View File

@ -8,7 +8,7 @@ describe("XEP-0363: HTTP File Upload", function () {
describe("When not supported", function () { describe("When not supported", function () {
describe("A file upload toolbar button", function () { describe("A file upload toolbar button", function () {
it("does not appear in MUC chats", mock.initConverse([], {}, async (done, _converse) => { it("does not appear in MUC chats", mock.initConverse([], {}, async (_converse) => {
await mock.openAndEnterChatRoom(_converse, 'lounge@montague.lit', 'romeo'); await mock.openAndEnterChatRoom(_converse, 'lounge@montague.lit', 'romeo');
mock.waitUntilDiscoConfirmed( mock.waitUntilDiscoConfirmed(
_converse, _converse.domain, _converse, _converse.domain,
@ -19,7 +19,6 @@ describe("XEP-0363: HTTP File Upload", function () {
const view = _converse.chatboxviews.get('lounge@montague.lit'); const view = _converse.chatboxviews.get('lounge@montague.lit');
await u.waitUntil(() => view.querySelector('.chat-toolbar .fileupload') === null); await u.waitUntil(() => view.querySelector('.chat-toolbar .fileupload') === null);
expect(1).toBe(1); expect(1).toBe(1);
done();
})); }));
}); });
@ -29,7 +28,7 @@ describe("XEP-0363: HTTP File Upload", function () {
describe("A file upload toolbar button", function () { describe("A file upload toolbar button", function () {
it("appears in MUC chats", mock.initConverse(['chatBoxesFetched'], {}, async (done, _converse) => { it("appears in MUC chats", mock.initConverse(['chatBoxesFetched'], {}, async (_converse) => {
await mock.waitUntilDiscoConfirmed( await mock.waitUntilDiscoConfirmed(
_converse, _converse.domain, _converse, _converse.domain,
[{'category': 'server', 'type':'IM'}], [{'category': 'server', 'type':'IM'}],
@ -41,12 +40,11 @@ describe("XEP-0363: HTTP File Upload", function () {
await u.waitUntil(() => _converse.chatboxviews.get('lounge@montague.lit').querySelector('.fileupload')); await u.waitUntil(() => _converse.chatboxviews.get('lounge@montague.lit').querySelector('.fileupload'));
const view = _converse.chatboxviews.get('lounge@montague.lit'); const view = _converse.chatboxviews.get('lounge@montague.lit');
expect(view.querySelector('.chat-toolbar .fileupload')).not.toBe(null); expect(view.querySelector('.chat-toolbar .fileupload')).not.toBe(null);
done();
})); }));
describe("when clicked and a file chosen", function () { describe("when clicked and a file chosen", function () {
it("is uploaded and sent out from a groupchat", mock.initConverse(['chatBoxesFetched'], {} ,async (done, _converse) => { it("is uploaded and sent out from a groupchat", mock.initConverse(['chatBoxesFetched'], {} ,async (_converse) => {
const base_url = 'https://conversejs.org'; const base_url = 'https://conversejs.org';
await mock.waitUntilDiscoConfirmed( await mock.waitUntilDiscoConfirmed(
_converse, _converse.domain, _converse, _converse.domain,
@ -148,7 +146,6 @@ describe("XEP-0363: HTTP File Upload", function () {
`Download file "conversejs-filled.svg"</a>`); `Download file "conversejs-filled.svg"</a>`);
XMLHttpRequest.prototype.send = send_backup; XMLHttpRequest.prototype.send = send_backup;
done();
})); }));

View File

@ -6,7 +6,7 @@ const u = converse.env.utils;
describe("A XEP-0333 Chat Marker", function () { describe("A XEP-0333 Chat Marker", function () {
it("may be returned for a MUC message", it("may be returned for a MUC message",
mock.initConverse([], {}, async function (done, _converse) { mock.initConverse([], {}, async function (_converse) {
await mock.waitForRoster(_converse, 'current'); await mock.waitForRoster(_converse, 'current');
const muc_jid = 'lounge@montague.lit'; const muc_jid = 'lounge@montague.lit';
@ -64,6 +64,5 @@ describe("A XEP-0333 Chat Marker", function () {
_converse.connection._dataRecv(mock.createRequest(stanza)); _converse.connection._dataRecv(mock.createRequest(stanza));
await u.waitUntil(() => view.querySelectorAll('.chat-msg').length === 2); await u.waitUntil(() => view.querySelectorAll('.chat-msg').length === 2);
expect(view.querySelectorAll('.chat-msg__receipt').length).toBe(0); expect(view.querySelectorAll('.chat-msg__receipt').length).toBe(0);
done();
})); }));
}); });

View File

@ -7,7 +7,7 @@ const u = converse.env.utils;
describe("An incoming groupchat message", function () { describe("An incoming groupchat message", function () {
it("is specially marked when you are mentioned in it", it("is specially marked when you are mentioned in it",
mock.initConverse(['chatBoxesFetched'], {}, async function (done, _converse) { mock.initConverse(['chatBoxesFetched'], {}, async function (_converse) {
const muc_jid = 'lounge@montague.lit'; const muc_jid = 'lounge@montague.lit';
await mock.openAndEnterChatRoom(_converse, muc_jid, 'romeo'); await mock.openAndEnterChatRoom(_converse, muc_jid, 'romeo');
@ -24,12 +24,11 @@ describe("An incoming groupchat message", function () {
await view.model.handleMessageStanza(msg); await view.model.handleMessageStanza(msg);
await u.waitUntil(() => view.querySelectorAll('.chat-msg__text').length); await u.waitUntil(() => view.querySelectorAll('.chat-msg__text').length);
expect(u.hasClass('mentioned', view.querySelector('.chat-msg'))).toBeTruthy(); expect(u.hasClass('mentioned', view.querySelector('.chat-msg'))).toBeTruthy();
done();
})); }));
it("highlights all users mentioned via XEP-0372 references", it("highlights all users mentioned via XEP-0372 references",
mock.initConverse([], {}, async function (done, _converse) { mock.initConverse([], {}, async function (_converse) {
const muc_jid = 'lounge@montague.lit'; const muc_jid = 'lounge@montague.lit';
await mock.openAndEnterChatRoom(_converse, muc_jid, 'tom'); await mock.openAndEnterChatRoom(_converse, muc_jid, 'tom');
@ -79,11 +78,10 @@ describe("An incoming groupchat message", function () {
'hello <span class="mention">z3r0</span> '+ 'hello <span class="mention">z3r0</span> '+
'<span class="mention mention--self badge badge-info">tom</span> '+ '<span class="mention mention--self badge badge-info">tom</span> '+
'<span class="mention">mr.robot</span>, how are you?'); '<span class="mention">mr.robot</span>, how are you?');
done();
})); }));
it("properly renders mentions that contain the pipe character", it("properly renders mentions that contain the pipe character",
mock.initConverse([], {}, async function (done, _converse) { mock.initConverse([], {}, async function (_converse) {
const muc_jid = 'lounge@montague.lit'; const muc_jid = 'lounge@montague.lit';
const nick = 'romeo'; const nick = 'romeo';
@ -128,11 +126,10 @@ describe("An incoming groupchat message", function () {
const message = await u.waitUntil(() => view.querySelector('.chat-msg__text')); const message = await u.waitUntil(() => view.querySelector('.chat-msg__text'));
expect(message.innerHTML.replace(/<!-.*?->/g, '')).toBe('hello <span class="mention">ThUnD3r|Gr33n</span>'); expect(message.innerHTML.replace(/<!-.*?->/g, '')).toBe('hello <span class="mention">ThUnD3r|Gr33n</span>');
done();
})); }));
it("highlights all users mentioned via XEP-0372 references in a quoted message", it("highlights all users mentioned via XEP-0372 references in a quoted message",
mock.initConverse([], {}, async function (done, _converse) { mock.initConverse([], {}, async function (_converse) {
const muc_jid = 'lounge@montague.lit'; const muc_jid = 'lounge@montague.lit';
await mock.openAndEnterChatRoom(_converse, muc_jid, 'tom'); await mock.openAndEnterChatRoom(_converse, muc_jid, 'tom');
@ -166,7 +163,6 @@ describe("An incoming groupchat message", function () {
'<blockquote>hello <span class="mention">z3r0</span> <span class="mention mention--self badge badge-info">tom</span> <span class="mention">mr.robot</span>, how are you?</blockquote>'); '<blockquote>hello <span class="mention">z3r0</span> <span class="mention mention--self badge badge-info">tom</span> <span class="mention">mr.robot</span>, how are you?</blockquote>');
const message = view.querySelector('.chat-msg__text'); const message = view.querySelector('.chat-msg__text');
expect(message.classList.length).toEqual(1); expect(message.classList.length).toEqual(1);
done();
})); }));
}); });
@ -176,7 +172,7 @@ describe("A sent groupchat message", function () {
describe("in which someone is mentioned", function () { describe("in which someone is mentioned", function () {
it("gets parsed for mentions which get turned into references", it("gets parsed for mentions which get turned into references",
mock.initConverse([], {}, async function (done, _converse) { mock.initConverse([], {}, async function (_converse) {
const muc_jid = 'lounge@montague.lit'; const muc_jid = 'lounge@montague.lit';
@ -302,11 +298,10 @@ describe("A sent groupchat message", function () {
expect(references.length).toBe(1); expect(references.length).toBe(1);
expect(references) expect(references)
.toEqual([{"begin":0,"end":5,"value":"gh0st","type":"mention","uri":"xmpp:lounge@montague.lit/gh0st"}]); .toEqual([{"begin":0,"end":5,"value":"gh0st","type":"mention","uri":"xmpp:lounge@montague.lit/gh0st"}]);
done();
})); }));
it("gets parsed for mentions as indicated with an @ preceded by a space or at the start of the text", it("gets parsed for mentions as indicated with an @ preceded by a space or at the start of the text",
mock.initConverse([], {}, async function (done, _converse) { mock.initConverse([], {}, async function (_converse) {
const muc_jid = 'lounge@montague.lit'; const muc_jid = 'lounge@montague.lit';
await mock.openAndEnterChatRoom(_converse, muc_jid, 'tom'); await mock.openAndEnterChatRoom(_converse, muc_jid, 'tom');
@ -334,11 +329,10 @@ describe("A sent groupchat message", function () {
[text, references] = view.model.parseTextForReferences('nice website https://darnuria.eu/@darnuria'); [text, references] = view.model.parseTextForReferences('nice website https://darnuria.eu/@darnuria');
expect(references.length).toBe(0); expect(references.length).toBe(0);
expect(text).toBe('nice website https://darnuria.eu/@darnuria'); expect(text).toBe('nice website https://darnuria.eu/@darnuria');
done();
})); }));
it("properly encodes the URIs in sent out references", it("properly encodes the URIs in sent out references",
mock.initConverse([], {}, async function (done, _converse) { mock.initConverse([], {}, async function (_converse) {
const muc_jid = 'lounge@montague.lit'; const muc_jid = 'lounge@montague.lit';
await mock.openAndEnterChatRoom(_converse, muc_jid, 'tom'); await mock.openAndEnterChatRoom(_converse, muc_jid, 'tom');
@ -377,11 +371,10 @@ describe("A sent groupchat message", function () {
`<reference begin="6" end="16" type="mention" uri="xmpp:lounge@montague.lit/Link%20Mauve" xmlns="urn:xmpp:reference:0"/>`+ `<reference begin="6" end="16" type="mention" uri="xmpp:lounge@montague.lit/Link%20Mauve" xmlns="urn:xmpp:reference:0"/>`+
`<origin-id id="${msg.querySelector('origin-id').getAttribute("id")}" xmlns="urn:xmpp:sid:0"/>`+ `<origin-id id="${msg.querySelector('origin-id').getAttribute("id")}" xmlns="urn:xmpp:sid:0"/>`+
`</message>`); `</message>`);
done();
})); }));
it("can get corrected and given new references", it("can get corrected and given new references",
mock.initConverse([], {}, async function (done, _converse) { mock.initConverse([], {}, async function (_converse) {
const muc_jid = 'lounge@montague.lit'; const muc_jid = 'lounge@montague.lit';
@ -474,11 +467,10 @@ describe("A sent groupchat message", function () {
`<replace id="${msg.getAttribute("id")}" xmlns="urn:xmpp:message-correct:0"/>`+ `<replace id="${msg.getAttribute("id")}" xmlns="urn:xmpp:message-correct:0"/>`+
`<origin-id id="${correction.querySelector('origin-id').getAttribute("id")}" xmlns="urn:xmpp:sid:0"/>`+ `<origin-id id="${correction.querySelector('origin-id').getAttribute("id")}" xmlns="urn:xmpp:sid:0"/>`+
`</message>`); `</message>`);
done();
})); }));
it("includes a XEP-0372 references to that person", it("includes a XEP-0372 references to that person",
mock.initConverse([], {}, async function (done, _converse) { mock.initConverse([], {}, async function (_converse) {
const muc_jid = 'lounge@montague.lit'; const muc_jid = 'lounge@montague.lit';
await mock.openAndEnterChatRoom(_converse, muc_jid, 'romeo'); await mock.openAndEnterChatRoom(_converse, muc_jid, 'romeo');
@ -523,12 +515,11 @@ describe("A sent groupchat message", function () {
`<reference begin="18" end="26" type="mention" uri="xmpp:${muc_jid}/mr.robot" xmlns="urn:xmpp:reference:0"/>`+ `<reference begin="18" end="26" type="mention" uri="xmpp:${muc_jid}/mr.robot" xmlns="urn:xmpp:reference:0"/>`+
`<origin-id id="${msg.querySelector('origin-id').getAttribute("id")}" xmlns="urn:xmpp:sid:0"/>`+ `<origin-id id="${msg.querySelector('origin-id').getAttribute("id")}" xmlns="urn:xmpp:sid:0"/>`+
`</message>`); `</message>`);
done();
})); }));
}); });
it("highlights all users mentioned via XEP-0372 references in a quoted message", it("highlights all users mentioned via XEP-0372 references in a quoted message",
mock.initConverse([], {}, async function (done, _converse) { mock.initConverse([], {}, async function (_converse) {
const members = [{'jid': 'gibson@gibson.net', 'nick': 'gibson', 'affiliation': 'member'}]; const members = [{'jid': 'gibson@gibson.net', 'nick': 'gibson', 'affiliation': 'member'}];
const muc_jid = 'lounge@montague.lit'; const muc_jid = 'lounge@montague.lit';
@ -549,6 +540,5 @@ describe("A sent groupchat message", function () {
`Welcome <span class="mention">gibson</span> <span title=":poop:">💩</span> `+ `Welcome <span class="mention">gibson</span> <span title=":poop:">💩</span> `+
`We have a guide on how to do that here: `+ `We have a guide on how to do that here: `+
`<a target="_blank" rel="noopener" href="https://conversejs.org/docs/html/index.html">https://conversejs.org/docs/html/index.html</a>`); `<a target="_blank" rel="noopener" href="https://conversejs.org/docs/html/index.html">https://conversejs.org/docs/html/index.html</a>`);
done();
})); }));
}); });

View File

@ -21,7 +21,7 @@ async function openModtools (_converse, view) {
describe("The groupchat moderator tool", function () { describe("The groupchat moderator tool", function () {
it("allows you to set affiliations and roles", it("allows you to set affiliations and roles",
mock.initConverse([], {}, async function (done, _converse) { mock.initConverse([], {}, async function (_converse) {
const muc_jid = 'lounge@montague.lit'; const muc_jid = 'lounge@montague.lit';
@ -135,11 +135,10 @@ describe("The groupchat moderator tool", function () {
user_els = roles_panel.querySelectorAll('.list-group--users > li') user_els = roles_panel.querySelectorAll('.list-group--users > li')
expect(user_els.length).toBe(1); expect(user_els.length).toBe(1);
expect(user_els[0].textContent.trim()).toBe('No users with that role found.'); expect(user_els[0].textContent.trim()).toBe('No users with that role found.');
done();
})); }));
it("allows you to filter affiliation search results", it("allows you to filter affiliation search results",
mock.initConverse([], {}, async function (done, _converse) { mock.initConverse([], {}, async function (_converse) {
const muc_jid = 'lounge@montague.lit'; const muc_jid = 'lounge@montague.lit';
const members = [ const members = [
@ -188,11 +187,10 @@ describe("The groupchat moderator tool", function () {
u.triggerEvent(filter, "keyup", "KeyboardEvent"); u.triggerEvent(filter, "keyup", "KeyboardEvent");
await u.waitUntil(() => ( modal.el.querySelectorAll('.list-group--users > li').length === 1)); await u.waitUntil(() => ( modal.el.querySelectorAll('.list-group--users > li').length === 1));
done();
})); }));
it("allows you to filter role search results", it("allows you to filter role search results",
mock.initConverse([], {}, async function (done, _converse) { mock.initConverse([], {}, async function (_converse) {
const muc_jid = 'lounge@montague.lit'; const muc_jid = 'lounge@montague.lit';
await mock.openAndEnterChatRoom(_converse, muc_jid, 'romeo', []); await mock.openAndEnterChatRoom(_converse, muc_jid, 'romeo', []);
@ -295,11 +293,10 @@ describe("The groupchat moderator tool", function () {
filter.value = 'crone'; filter.value = 'crone';
u.triggerEvent(filter, "keyup", "KeyboardEvent"); u.triggerEvent(filter, "keyup", "KeyboardEvent");
await u.waitUntil(() => ( modal.el.querySelectorAll('.list-group--users > li').length === 1)); await u.waitUntil(() => ( modal.el.querySelectorAll('.list-group--users > li').length === 1));
done();
})); }));
it("shows an error message if a particular affiliation list may not be retrieved", it("shows an error message if a particular affiliation list may not be retrieved",
mock.initConverse([], {}, async function (done, _converse) { mock.initConverse([], {}, async function (_converse) {
const muc_jid = 'lounge@montague.lit'; const muc_jid = 'lounge@montague.lit';
const members = [ const members = [
@ -344,11 +341,10 @@ describe("The groupchat moderator tool", function () {
const user_els = modal.el.querySelectorAll('.list-group--users > li'); const user_els = modal.el.querySelectorAll('.list-group--users > li');
expect(user_els.length).toBe(1); expect(user_els.length).toBe(1);
expect(user_els[0].textContent.trim()).toBe('Error: not allowed to fetch outcast list for MUC lounge@montague.lit'); expect(user_els[0].textContent.trim()).toBe('Error: not allowed to fetch outcast list for MUC lounge@montague.lit');
done();
})); }));
it("shows an error message if a particular affiliation may not be set", it("shows an error message if a particular affiliation may not be set",
mock.initConverse([], {}, async function (done, _converse) { mock.initConverse([], {}, async function (_converse) {
const muc_jid = 'lounge@montague.lit'; const muc_jid = 'lounge@montague.lit';
const members = [ const members = [
@ -407,12 +403,11 @@ describe("The groupchat moderator tool", function () {
</iq>`); </iq>`);
_converse.connection._dataRecv(mock.createRequest(error)); _converse.connection._dataRecv(mock.createRequest(error));
done();
})); }));
it("doesn't allow admins to make more admins", it("doesn't allow admins to make more admins",
mock.initConverse([], {}, async function (done, _converse) { mock.initConverse([], {}, async function (_converse) {
const muc_jid = 'lounge@montague.lit'; const muc_jid = 'lounge@montague.lit';
const members = [ const members = [
@ -442,11 +437,10 @@ describe("The groupchat moderator tool", function () {
change_affiliation_dropdown = user_els[1].querySelector('.select-affiliation'); change_affiliation_dropdown = user_els[1].querySelector('.select-affiliation');
expect(Array.from(change_affiliation_dropdown.options).map(o => o.value)).toEqual(['member', 'outcast', 'none']); expect(Array.from(change_affiliation_dropdown.options).map(o => o.value)).toEqual(['member', 'outcast', 'none']);
done();
})); }));
it("lets the assignable affiliations and roles be configured via modtools_disable_assign", it("lets the assignable affiliations and roles be configured via modtools_disable_assign",
mock.initConverse([], {}, async function (done, _converse) { mock.initConverse([], {}, async function (_converse) {
const muc_jid = 'lounge@montague.lit'; const muc_jid = 'lounge@montague.lit';
const members = [{'jid': 'romeo@montague.lit', 'nick': 'romeo', 'affiliation': 'owner'}]; const members = [{'jid': 'romeo@montague.lit', 'nick': 'romeo', 'affiliation': 'owner'}];
@ -476,6 +470,5 @@ describe("The groupchat moderator tool", function () {
_converse.api.settings.set('modtools_disable_assign', ['admin', 'moderator']); _converse.api.settings.set('modtools_disable_assign', ['admin', 'moderator']);
expect(modal.getAssignableRoles(occupant)).toEqual(['participant', 'visitor']); expect(modal.getAssignableRoles(occupant)).toEqual(['participant', 'visitor']);
done();
})); }));
}); });

View File

@ -8,7 +8,7 @@ describe("Groupchats", function () {
describe("The \"rooms\" API", function () { describe("The \"rooms\" API", function () {
it("has a method 'close' which closes rooms by JID or all rooms when called with no arguments", it("has a method 'close' which closes rooms by JID or all rooms when called with no arguments",
mock.initConverse([], {}, async function (done, _converse) { mock.initConverse([], {}, async function (_converse) {
await mock.openAndEnterChatRoom(_converse, 'lounge@montague.lit', 'romeo'); await mock.openAndEnterChatRoom(_converse, 'lounge@montague.lit', 'romeo');
@ -50,11 +50,10 @@ describe("Groupchats", function () {
expect(_converse.chatboxviews.get('lounge@montague.lit')).toBeUndefined(); expect(_converse.chatboxviews.get('lounge@montague.lit')).toBeUndefined();
expect(_converse.chatboxviews.get('leisure@montague.lit')).toBeUndefined(); expect(_converse.chatboxviews.get('leisure@montague.lit')).toBeUndefined();
done();
})); }));
it("has a method 'get' which returns a wrapped groupchat (if it exists)", it("has a method 'get' which returns a wrapped groupchat (if it exists)",
mock.initConverse([], {}, async function (done, _converse) { mock.initConverse([], {}, async function (_converse) {
await mock.waitForRoster(_converse, 'current'); await mock.waitForRoster(_converse, 'current');
const rosterview = document.querySelector('converse-roster'); const rosterview = document.querySelector('converse-roster');
@ -95,11 +94,10 @@ describe("Groupchats", function () {
muc_jid = 'chillout2@montague.lit'; muc_jid = 'chillout2@montague.lit';
room = await _converse.api.rooms.get(muc_jid); room = await _converse.api.rooms.get(muc_jid);
expect(room).toBe(null); expect(room).toBe(null);
done();
})); }));
it("has a method 'open' which opens (optionally configures) and returns a wrapped chat box", it("has a method 'open' which opens (optionally configures) and returns a wrapped chat box",
mock.initConverse(['chatBoxesFetched'], {}, async function (done, _converse) { mock.initConverse(['chatBoxesFetched'], {}, async function (_converse) {
// Mock 'getDiscoInfo', otherwise the room won't be // Mock 'getDiscoInfo', otherwise the room won't be
// displayed as it waits first for the features to be returned // displayed as it waits first for the features to be returned
@ -261,7 +259,6 @@ describe("Groupchats", function () {
expect(sizzle('field[var="muc#roomconfig_whois"] value ', sent_stanza).pop().textContent.trim()).toBe('anyone'); expect(sizzle('field[var="muc#roomconfig_whois"] value ', sent_stanza).pop().textContent.trim()).toBe('anyone');
expect(sizzle('field[var="muc#roomconfig_membersonly"] value', sent_stanza).pop().textContent.trim()).toBe('1'); expect(sizzle('field[var="muc#roomconfig_membersonly"] value', sent_stanza).pop().textContent.trim()).toBe('1');
expect(sizzle('field[var="muc#roomconfig_historylength"] value', sent_stanza).pop().textContent.trim()).toBe('20'); expect(sizzle('field[var="muc#roomconfig_historylength"] value', sent_stanza).pop().textContent.trim()).toBe('20');
done();
})); }));
}); });
}); });

View File

@ -12,7 +12,7 @@ describe("MUC Mention Notfications", function () {
'allow_bookmarks': false, // Hack to get the rooms list to render 'allow_bookmarks': false, // Hack to get the rooms list to render
'muc_subscribe_to_rai': true, 'muc_subscribe_to_rai': true,
'view_mode': 'fullscreen'}, 'view_mode': 'fullscreen'},
async function (done, _converse) { async function (_converse) {
const { api } = _converse; const { api } = _converse;
@ -81,6 +81,5 @@ describe("MUC Mention Notfications", function () {
_converse.connection._dataRecv(mock.createRequest(message)); _converse.connection._dataRecv(mock.createRequest(message));
expect(Array.from(room_el.classList).includes('unread-msgs')).toBeTruthy(); expect(Array.from(room_el.classList).includes('unread-msgs')).toBeTruthy();
expect(room_el.querySelector('.msgs-indicator')?.textContent.trim()).toBe('2'); expect(room_el.querySelector('.msgs-indicator')?.textContent.trim()).toBe('2');
done();
})); }));
}); });

View File

@ -12,7 +12,7 @@ describe("A Groupchat Message", function () {
describe("which is succeeded by an error message", function () { describe("which is succeeded by an error message", function () {
it("will have the error displayed below it", it("will have the error displayed below it",
mock.initConverse([], {}, async function (done, _converse) { mock.initConverse([], {}, async function (_converse) {
const muc_jid = 'lounge@montague.lit'; const muc_jid = 'lounge@montague.lit';
await mock.openAndEnterChatRoom(_converse, muc_jid, 'romeo'); await mock.openAndEnterChatRoom(_converse, muc_jid, 'romeo');
@ -48,7 +48,6 @@ describe("A Groupchat Message", function () {
expect(message.get('body')).toBe('hello world'); expect(message.get('body')).toBe('hello world');
expect(message.get('error_text')).toBe(err_msg_text); expect(message.get('error_text')).toBe(err_msg_text);
expect(message.get('editable')).toBe(false); expect(message.get('editable')).toBe(false);
done();
})); }));
}); });
@ -56,7 +55,7 @@ describe("A Groupchat Message", function () {
describe("an info message", function () { describe("an info message", function () {
it("is not rendered as a followup message", it("is not rendered as a followup message",
mock.initConverse(['chatBoxesFetched'], {}, async function (done, _converse) { mock.initConverse(['chatBoxesFetched'], {}, async function (_converse) {
const muc_jid = 'lounge@montague.lit'; const muc_jid = 'lounge@montague.lit';
const nick = 'romeo'; const nick = 'romeo';
@ -89,11 +88,10 @@ describe("A Groupchat Message", function () {
const messages = view.querySelectorAll('.chat-info'); const messages = view.querySelectorAll('.chat-info');
expect(u.hasClass('chat-msg--followup', messages[0])).toBe(false); expect(u.hasClass('chat-msg--followup', messages[0])).toBe(false);
expect(u.hasClass('chat-msg--followup', messages[1])).toBe(false); expect(u.hasClass('chat-msg--followup', messages[1])).toBe(false);
done();
})); }));
it("is not shown if its a duplicate", it("is not shown if its a duplicate",
mock.initConverse(['chatBoxesFetched'], {}, async function (done, _converse) { mock.initConverse(['chatBoxesFetched'], {}, async function (_converse) {
const muc_jid = 'lounge@montague.lit'; const muc_jid = 'lounge@montague.lit';
await mock.openAndEnterChatRoom(_converse, muc_jid, 'romeo'); await mock.openAndEnterChatRoom(_converse, muc_jid, 'romeo');
@ -120,13 +118,12 @@ describe("A Groupchat Message", function () {
_converse.connection._dataRecv(mock.createRequest(presence)); _converse.connection._dataRecv(mock.createRequest(presence));
await u.waitUntil(() => view.model.createInfoMessages.calls.count() === 2); await u.waitUntil(() => view.model.createInfoMessages.calls.count() === 2);
expect(view.querySelectorAll('.chat-info').length).toBe(1); expect(view.querySelectorAll('.chat-info').length).toBe(1);
done();
})); }));
}); });
it("is rejected if it's an unencapsulated forwarded message", it("is rejected if it's an unencapsulated forwarded message",
mock.initConverse(['chatBoxesFetched'], {}, async function (done, _converse) { mock.initConverse(['chatBoxesFetched'], {}, async function (_converse) {
const muc_jid = 'lounge@montague.lit'; const muc_jid = 'lounge@montague.lit';
await mock.openAndEnterChatRoom(_converse, muc_jid, 'romeo'); await mock.openAndEnterChatRoom(_converse, muc_jid, 'romeo');
@ -155,11 +152,10 @@ describe("A Groupchat Message", function () {
); );
expect(view.querySelectorAll('.chat-msg').length).toBe(0); expect(view.querySelectorAll('.chat-msg').length).toBe(0);
expect(view.model.messages.length).toBe(0); expect(view.model.messages.length).toBe(0);
done();
})); }));
it("can contain a chat state notification and will still be shown", it("can contain a chat state notification and will still be shown",
mock.initConverse(['chatBoxesFetched'], {}, async function (done, _converse) { mock.initConverse(['chatBoxesFetched'], {}, async function (_converse) {
const muc_jid = 'lounge@montague.lit'; const muc_jid = 'lounge@montague.lit';
await mock.openAndEnterChatRoom(_converse, muc_jid, 'romeo'); await mock.openAndEnterChatRoom(_converse, muc_jid, 'romeo');
@ -178,11 +174,10 @@ describe("A Groupchat Message", function () {
await view.model.handleMessageStanza(msg); await view.model.handleMessageStanza(msg);
const el = await u.waitUntil(() => view.querySelector('.chat-msg__text')); const el = await u.waitUntil(() => view.querySelector('.chat-msg__text'));
expect(el.textContent).toBe(message); expect(el.textContent).toBe(message);
done();
})); }));
it("can not be expected to have a unique id attribute", it("can not be expected to have a unique id attribute",
mock.initConverse(['chatBoxesFetched'], {}, async function (done, _converse) { mock.initConverse(['chatBoxesFetched'], {}, async function (_converse) {
const muc_jid = 'lounge@montague.lit'; const muc_jid = 'lounge@montague.lit';
await mock.openAndEnterChatRoom(_converse, muc_jid, 'romeo'); await mock.openAndEnterChatRoom(_converse, muc_jid, 'romeo');
@ -207,11 +202,10 @@ describe("A Groupchat Message", function () {
await view.model.handleMessageStanza(msg); await view.model.handleMessageStanza(msg);
await u.waitUntil(() => view.querySelectorAll('.chat-msg').length === 2); await u.waitUntil(() => view.querySelectorAll('.chat-msg').length === 2);
expect(view.model.messages.length).toBe(2); expect(view.model.messages.length).toBe(2);
done();
})); }));
it("is ignored if it has the same archive-id of an already received one", it("is ignored if it has the same archive-id of an already received one",
mock.initConverse([], {}, async function (done, _converse) { mock.initConverse([], {}, async function (_converse) {
const muc_jid = 'room@muc.example.com'; const muc_jid = 'room@muc.example.com';
await mock.openAndEnterChatRoom(_converse, muc_jid, 'romeo'); await mock.openAndEnterChatRoom(_converse, muc_jid, 'romeo');
@ -254,11 +248,10 @@ describe("A Groupchat Message", function () {
expect(result instanceof _converse.Message).toBe(true); expect(result instanceof _converse.Message).toBe(true);
expect(view.model.messages.length).toBe(1); expect(view.model.messages.length).toBe(1);
await u.waitUntil(() => view.model.updateMessage.calls.count()); await u.waitUntil(() => view.model.updateMessage.calls.count());
done();
})); }));
it("is ignored if it has the same stanza-id of an already received one", it("is ignored if it has the same stanza-id of an already received one",
mock.initConverse([], {}, async function (done, _converse) { mock.initConverse([], {}, async function (_converse) {
const muc_jid = 'room@muc.example.com'; const muc_jid = 'room@muc.example.com';
await mock.openAndEnterChatRoom(_converse, muc_jid, 'romeo'); await mock.openAndEnterChatRoom(_converse, muc_jid, 'romeo');
@ -300,11 +293,10 @@ describe("A Groupchat Message", function () {
expect(result instanceof _converse.Message).toBe(true); expect(result instanceof _converse.Message).toBe(true);
expect(view.model.messages.length).toBe(1); expect(view.model.messages.length).toBe(1);
await u.waitUntil(() => view.model.updateMessage.calls.count()); await u.waitUntil(() => view.model.updateMessage.calls.count());
done();
})); }));
it("will be discarded if it's a malicious message meant to look like a carbon copy", it("will be discarded if it's a malicious message meant to look like a carbon copy",
mock.initConverse([], {}, async function (done, _converse) { mock.initConverse([], {}, async function (_converse) {
await mock.waitForRoster(_converse, 'current'); await mock.waitForRoster(_converse, 'current');
await mock.openControlBox(_converse); await mock.openControlBox(_converse);
@ -357,11 +349,10 @@ describe("A Groupchat Message", function () {
); );
expect(view.querySelectorAll('.chat-msg').length).toBe(0); expect(view.querySelectorAll('.chat-msg').length).toBe(0);
expect(view.model.messages.length).toBe(0); expect(view.model.messages.length).toBe(0);
done();
})); }));
it("keeps track of the sender's role and affiliation", it("keeps track of the sender's role and affiliation",
mock.initConverse([], {}, async function (done, _converse) { mock.initConverse([], {}, async function (_converse) {
const muc_jid = 'lounge@montague.lit'; const muc_jid = 'lounge@montague.lit';
await mock.openAndEnterChatRoom(_converse, muc_jid, 'romeo'); await mock.openAndEnterChatRoom(_converse, muc_jid, 'romeo');
@ -483,12 +474,11 @@ describe("A Groupchat Message", function () {
expect(view.model.messages.last().occupant.get('nick')).toBe('some1'); expect(view.model.messages.last().occupant.get('nick')).toBe('some1');
// Check that the "add" event handler was removed. // Check that the "add" event handler was removed.
expect(view.model.occupants._events.add.length).toBe(add_events); expect(view.model.occupants._events.add.length).toBe(add_events);
done();
})); }));
it("keeps track whether you are the sender or not", it("keeps track whether you are the sender or not",
mock.initConverse([], {}, async function (done, _converse) { mock.initConverse([], {}, async function (_converse) {
const muc_jid = 'lounge@montague.lit'; const muc_jid = 'lounge@montague.lit';
await mock.openAndEnterChatRoom(_converse, muc_jid, 'romeo'); await mock.openAndEnterChatRoom(_converse, muc_jid, 'romeo');
@ -502,11 +492,10 @@ describe("A Groupchat Message", function () {
await view.model.handleMessageStanza(msg); await view.model.handleMessageStanza(msg);
await u.waitUntil(() => view.model.messages.last()?.get('received')); await u.waitUntil(() => view.model.messages.last()?.get('received'));
expect(view.model.messages.last().get('sender')).toBe('me'); expect(view.model.messages.last().get('sender')).toBe('me');
done();
})); }));
it("will be shown as received upon MUC reflection", it("will be shown as received upon MUC reflection",
mock.initConverse([], {}, async function (done, _converse) { mock.initConverse([], {}, async function (_converse) {
await mock.waitForRoster(_converse, 'current'); await mock.waitForRoster(_converse, 'current');
const muc_jid = 'lounge@montague.lit'; const muc_jid = 'lounge@montague.lit';
@ -544,11 +533,10 @@ describe("A Groupchat Message", function () {
const message = view.model.messages.at(0); const message = view.model.messages.at(0);
expect(message.get('stanza_id lounge@montague.lit')).toBe('5f3dbc5e-e1d3-4077-a492-693f3769c7ad'); expect(message.get('stanza_id lounge@montague.lit')).toBe('5f3dbc5e-e1d3-4077-a492-693f3769c7ad');
expect(message.get('origin_id')).toBe(msg_obj.get('origin_id')); expect(message.get('origin_id')).toBe(msg_obj.get('origin_id'));
done();
})); }));
it("gets updated with its stanza-id upon MUC reflection", it("gets updated with its stanza-id upon MUC reflection",
mock.initConverse([], {}, async function (done, _converse) { mock.initConverse([], {}, async function (_converse) {
const muc_jid = 'room@muc.example.com'; const muc_jid = 'room@muc.example.com';
await mock.openAndEnterChatRoom(_converse, muc_jid, 'romeo'); await mock.openAndEnterChatRoom(_converse, muc_jid, 'romeo');
@ -577,11 +565,10 @@ describe("A Groupchat Message", function () {
expect(view.model.messages.length).toBe(1); expect(view.model.messages.length).toBe(1);
expect(view.model.messages.at(0).get('stanza_id room@muc.example.com')).toBe("5f3dbc5e-e1d3-4077-a492-693f3769c7ad"); expect(view.model.messages.at(0).get('stanza_id room@muc.example.com')).toBe("5f3dbc5e-e1d3-4077-a492-693f3769c7ad");
expect(view.model.messages.at(0).get('origin_id')).toBe(msg.get('origin_id')); expect(view.model.messages.at(0).get('origin_id')).toBe(msg.get('origin_id'));
done();
})); }));
it("can cause a delivery receipt to be returned", it("can cause a delivery receipt to be returned",
mock.initConverse([], {}, async function (done, _converse) { mock.initConverse([], {}, async function (_converse) {
await mock.waitForRoster(_converse, 'current'); await mock.waitForRoster(_converse, 'current');
const muc_jid = 'lounge@montague.lit'; const muc_jid = 'lounge@montague.lit';
@ -621,6 +608,5 @@ describe("A Groupchat Message", function () {
</message>`); </message>`);
_converse.connection._dataRecv(mock.createRequest(stanza)); _converse.connection._dataRecv(mock.createRequest(stanza));
expect(view.querySelectorAll('.chat-msg').length).toBe(1); expect(view.querySelectorAll('.chat-msg').length).toBe(1);
done();
})); }));
}); });

View File

@ -8,7 +8,7 @@ describe("Chatrooms", function () {
it("allows you to register your nickname in a room", it("allows you to register your nickname in a room",
mock.initConverse(['chatBoxesFetched'], {'auto_register_muc_nickname': true}, mock.initConverse(['chatBoxesFetched'], {'auto_register_muc_nickname': true},
async function (done, _converse) { async function (_converse) {
const muc_jid = 'coven@chat.shakespeare.lit'; const muc_jid = 'coven@chat.shakespeare.lit';
await mock.openAndEnterChatRoom(_converse, muc_jid, 'romeo') await mock.openAndEnterChatRoom(_converse, muc_jid, 'romeo')
@ -54,7 +54,6 @@ describe("Chatrooms", function () {
`</x>`+ `</x>`+
`</query>`+ `</query>`+
`</iq>`); `</iq>`);
done();
})); }));
}); });
}); });

File diff suppressed because it is too large Load Diff

View File

@ -9,7 +9,7 @@ describe("A list of open groupchats", function () {
['chatBoxesFetched'], ['chatBoxesFetched'],
{ allow_bookmarks: false // Makes testing easier, otherwise we { allow_bookmarks: false // Makes testing easier, otherwise we
// have to mock stanza traffic. // have to mock stanza traffic.
}, async function (done, _converse) { }, async function (_converse) {
await mock.waitForRoster(_converse, 'current', 0); await mock.waitForRoster(_converse, 'current', 0);
await mock.openControlBox(_converse); await mock.openControlBox(_converse);
@ -44,14 +44,13 @@ describe("A list of open groupchats", function () {
list = controlbox.querySelector('.list-container--openrooms'); list = controlbox.querySelector('.list-container--openrooms');
expect(Array.from(list.classList).includes('hidden')).toBeTruthy(); expect(Array.from(list.classList).includes('hidden')).toBeTruthy();
done();
})); }));
it("uses bookmarks to determine groupchat names", it("uses bookmarks to determine groupchat names",
mock.initConverse( mock.initConverse(
['chatBoxesFetched'], ['chatBoxesFetched'],
{'view_mode': 'fullscreen'}, {'view_mode': 'fullscreen'},
async function (done, _converse) { async function (_converse) {
const { Strophe, $iq, $pres, sizzle } = converse.env; const { Strophe, $iq, $pres, sizzle } = converse.env;
const u = converse.env.utils; const u = converse.env.utils;
@ -106,7 +105,6 @@ describe("A list of open groupchats", function () {
expect(items.length).toBe(1); expect(items.length).toBe(1);
await u.waitUntil(() => list.querySelector('.list-item').textContent.trim() === 'Bookmarked Lounge'); await u.waitUntil(() => list.querySelector('.list-item').textContent.trim() === 'Bookmarked Lounge');
expect(_converse.bookmarks.fetchBookmarks).toHaveBeenCalled(); expect(_converse.bookmarks.fetchBookmarks).toHaveBeenCalled();
done();
})); }));
}); });
@ -116,7 +114,7 @@ describe("A groupchat shown in the groupchats list", function () {
['chatBoxesFetched'], ['chatBoxesFetched'],
{ view_mode: 'fullscreen', { view_mode: 'fullscreen',
allow_bookmarks: false // Makes testing easier, otherwise we have to mock stanza traffic. allow_bookmarks: false // Makes testing easier, otherwise we have to mock stanza traffic.
}, async function (done, _converse) { }, async function (_converse) {
await mock.waitForRoster(_converse, 'current', 0); await mock.waitForRoster(_converse, 'current', 0);
const controlbox = _converse.chatboxviews.get('controlbox'); const controlbox = _converse.chatboxviews.get('controlbox');
@ -141,7 +139,6 @@ describe("A groupchat shown in the groupchats list", function () {
expect(room_els.length).toBe(1); expect(room_els.length).toBe(1);
item = room_els[0]; item = room_els[0];
expect(item.textContent.trim()).toBe('balcony@chat.shakespeare.lit'); expect(item.textContent.trim()).toBe('balcony@chat.shakespeare.lit');
done();
})); }));
it("has an info icon which opens a details modal when clicked", mock.initConverse( it("has an info icon which opens a details modal when clicked", mock.initConverse(
@ -149,7 +146,7 @@ describe("A groupchat shown in the groupchats list", function () {
{ whitelisted_plugins: ['converse-roomslist'], { whitelisted_plugins: ['converse-roomslist'],
allow_bookmarks: false // Makes testing easier, otherwise we allow_bookmarks: false // Makes testing easier, otherwise we
// have to mock stanza traffic. // have to mock stanza traffic.
}, async function (done, _converse) { }, async function (_converse) {
const { Strophe, $iq, $pres } = converse.env; const { Strophe, $iq, $pres } = converse.env;
const u = converse.env.utils; const u = converse.env.utils;
@ -250,7 +247,6 @@ describe("A groupchat shown in the groupchats list", function () {
expect(els[3].textContent).toBe("Topic: Hatching dark plots") expect(els[3].textContent).toBe("Topic: Hatching dark plots")
expect(els[4].textContent).toBe("Topic author: someone") expect(els[4].textContent).toBe("Topic author: someone")
expect(els[5].textContent).toBe("Online users: 2") expect(els[5].textContent).toBe("Online users: 2")
done();
})); }));
it("can be closed", mock.initConverse( it("can be closed", mock.initConverse(
@ -258,7 +254,7 @@ describe("A groupchat shown in the groupchats list", function () {
{ whitelisted_plugins: ['converse-roomslist'], { whitelisted_plugins: ['converse-roomslist'],
allow_bookmarks: false // Makes testing easier, otherwise we have to mock stanza traffic. allow_bookmarks: false // Makes testing easier, otherwise we have to mock stanza traffic.
}, },
async function (done, _converse) { async function (_converse) {
const u = converse.env.utils; const u = converse.env.utils;
spyOn(window, 'confirm').and.callFake(() => true); spyOn(window, 'confirm').and.callFake(() => true);
@ -281,14 +277,13 @@ describe("A groupchat shown in the groupchats list", function () {
await u.waitUntil(() => rooms_list.querySelectorAll(".open-room").length === 0); await u.waitUntil(() => rooms_list.querySelectorAll(".open-room").length === 0);
expect(_converse.chatboxes.length).toBe(1); expect(_converse.chatboxes.length).toBe(1);
done();
})); }));
it("shows unread messages directed at the user", mock.initConverse( it("shows unread messages directed at the user", mock.initConverse(
null, null,
{ whitelisted_plugins: ['converse-roomslist'], { whitelisted_plugins: ['converse-roomslist'],
allow_bookmarks: false // Makes testing easier, otherwise we have to mock stanza traffic. allow_bookmarks: false // Makes testing easier, otherwise we have to mock stanza traffic.
}, async (done, _converse) => { }, async (_converse) => {
const { $msg } = converse.env; const { $msg } = converse.env;
const u = converse.env.utils; const u = converse.env.utils;
@ -345,6 +340,5 @@ describe("A groupchat shown in the groupchats list", function () {
expect(indicator_el === null); expect(indicator_el === null);
room_el = lview.querySelector(".available-chatroom"); room_el = lview.querySelector(".available-chatroom");
expect(Array.from(room_el.classList).includes('unread-msgs')).toBeFalsy(); expect(Array.from(room_el.classList).includes('unread-msgs')).toBeFalsy();
done();
})); }));
}); });

View File

@ -13,7 +13,7 @@ describe("XEP-0437 Room Activity Indicators", function () {
'allow_bookmarks': false, // Hack to get the rooms list to render 'allow_bookmarks': false, // Hack to get the rooms list to render
'muc_subscribe_to_rai': true, 'muc_subscribe_to_rai': true,
'view_mode': 'fullscreen'}, 'view_mode': 'fullscreen'},
async function (done, _converse) { async function (_converse) {
expect(_converse.session.get('rai_enabled_domains')).toBe(undefined); expect(_converse.session.get('rai_enabled_domains')).toBe(undefined);
@ -110,7 +110,6 @@ describe("XEP-0437 Room Activity Indicators", function () {
await u.waitUntil(() => view.model.get('has_activity')); await u.waitUntil(() => view.model.get('has_activity'));
expect(Array.from(room_el.classList).includes('unread-msgs')).toBeTruthy(); expect(Array.from(room_el.classList).includes('unread-msgs')).toBeTruthy();
done();
})); }));
it("will be activated for a MUC that starts out hidden", it("will be activated for a MUC that starts out hidden",
@ -119,7 +118,7 @@ describe("XEP-0437 Room Activity Indicators", function () {
'allow_bookmarks': false, // Hack to get the rooms list to render 'allow_bookmarks': false, // Hack to get the rooms list to render
'muc_subscribe_to_rai': true, 'muc_subscribe_to_rai': true,
'view_mode': 'fullscreen'}, 'view_mode': 'fullscreen'},
async function (done, _converse) { async function (_converse) {
const { api } = _converse; const { api } = _converse;
expect(_converse.session.get('rai_enabled_domains')).toBe(undefined); expect(_converse.session.get('rai_enabled_domains')).toBe(undefined);
@ -173,7 +172,6 @@ describe("XEP-0437 Room Activity Indicators", function () {
await u.waitUntil(() => model.get('has_activity')); await u.waitUntil(() => model.get('has_activity'));
expect(Array.from(room_el.classList).includes('unread-msgs')).toBeTruthy(); expect(Array.from(room_el.classList).includes('unread-msgs')).toBeTruthy();
done();
})); }));
@ -183,7 +181,7 @@ describe("XEP-0437 Room Activity Indicators", function () {
'allow_bookmarks': false, // Hack to get the rooms list to render 'allow_bookmarks': false, // Hack to get the rooms list to render
'muc_subscribe_to_rai': true, 'muc_subscribe_to_rai': true,
'view_mode': 'fullscreen'}, 'view_mode': 'fullscreen'},
async function (done, _converse) { async function (_converse) {
expect(_converse.session.get('rai_enabled_domains')).toBe(undefined); expect(_converse.session.get('rai_enabled_domains')).toBe(undefined);
@ -218,7 +216,6 @@ describe("XEP-0437 Room Activity Indicators", function () {
_converse.connection._dataRecv(mock.createRequest(activity_stanza)); _converse.connection._dataRecv(mock.createRequest(activity_stanza));
await u.waitUntil(() => view.model.session.get('connection_status') === converse.ROOMSTATUS.CONNECTING); await u.waitUntil(() => view.model.session.get('connection_status') === converse.ROOMSTATUS.CONNECTING);
done();
})); }));
}); });

View File

@ -37,7 +37,7 @@ describe("Message Retractions", function () {
describe("A groupchat message retraction", function () { describe("A groupchat message retraction", function () {
it("is not applied if it's not from the right author", it("is not applied if it's not from the right author",
mock.initConverse(['chatBoxesFetched'], {}, async function (done, _converse) { mock.initConverse(['chatBoxesFetched'], {}, async function (_converse) {
const muc_jid = 'lounge@montague.lit'; const muc_jid = 'lounge@montague.lit';
const features = [...mock.default_muc_features, Strophe.NS.MODERATE]; const features = [...mock.default_muc_features, Strophe.NS.MODERATE];
@ -75,11 +75,10 @@ describe("Message Retractions", function () {
expect(view.model.messages.at(0).get('retracted')).toBeFalsy(); expect(view.model.messages.at(0).get('retracted')).toBeFalsy();
expect(view.model.messages.at(0).get('is_ephemeral')).toBeFalsy(); expect(view.model.messages.at(0).get('is_ephemeral')).toBeFalsy();
done();
})); }));
it("can be received before the message it pertains to", it("can be received before the message it pertains to",
mock.initConverse(['chatBoxesFetched'], {}, async function (done, _converse) { mock.initConverse(['chatBoxesFetched'], {}, async function (_converse) {
const date = (new Date()).toISOString(); const date = (new Date()).toISOString();
const muc_jid = 'lounge@montague.lit'; const muc_jid = 'lounge@montague.lit';
@ -126,14 +125,13 @@ describe("Message Retractions", function () {
expect(message.get('time')).toBe(date); expect(message.get('time')).toBe(date);
expect(message.get('type')).toBe('groupchat'); expect(message.get('type')).toBe('groupchat');
expect(await view.model.handleRetraction.calls.all().pop().returnValue).toBe(true); expect(await view.model.handleRetraction.calls.all().pop().returnValue).toBe(true);
done();
})); }));
}); });
describe("A groupchat message moderator retraction", function () { describe("A groupchat message moderator retraction", function () {
it("can be received before the message it pertains to", it("can be received before the message it pertains to",
mock.initConverse(['chatBoxesFetched'], {}, async function (done, _converse) { mock.initConverse(['chatBoxesFetched'], {}, async function (_converse) {
const date = (new Date()).toISOString(); const date = (new Date()).toISOString();
const muc_jid = 'lounge@montague.lit'; const muc_jid = 'lounge@montague.lit';
@ -184,7 +182,6 @@ describe("Message Retractions", function () {
expect(message.get('time')).toBe(date); expect(message.get('time')).toBe(date);
expect(message.get('type')).toBe('groupchat'); expect(message.get('type')).toBe('groupchat');
expect(await view.model.handleModeration.calls.all().pop().returnValue).toBe(true); expect(await view.model.handleModeration.calls.all().pop().returnValue).toBe(true);
done();
})); }));
}); });
@ -192,7 +189,7 @@ describe("Message Retractions", function () {
describe("A message retraction", function () { describe("A message retraction", function () {
it("can be received before the message it pertains to", it("can be received before the message it pertains to",
mock.initConverse(['chatBoxesFetched'], {}, async function (done, _converse) { mock.initConverse(['chatBoxesFetched'], {}, async function (_converse) {
const date = (new Date()).toISOString(); const date = (new Date()).toISOString();
await mock.waitForRoster(_converse, 'current', 1); await mock.waitForRoster(_converse, 'current', 1);
@ -241,13 +238,12 @@ describe("Message Retractions", function () {
expect(message.get('origin_id')).toBe('2e972ea0-0050-44b7-a830-f6638a2595b3'); expect(message.get('origin_id')).toBe('2e972ea0-0050-44b7-a830-f6638a2595b3');
expect(message.get('time')).toBe(date); expect(message.get('time')).toBe(date);
expect(message.get('type')).toBe('chat'); expect(message.get('type')).toBe('chat');
done();
})); }));
}); });
describe("A Received Chat Message", function () { describe("A Received Chat Message", function () {
it("can be followed up by a retraction", mock.initConverse(['chatBoxesFetched'], {}, async function (done, _converse) { it("can be followed up by a retraction", mock.initConverse(['chatBoxesFetched'], {}, async function (_converse) {
await mock.waitForRoster(_converse, 'current', 1); await mock.waitForRoster(_converse, 'current', 1);
await mock.waitUntilDiscoConfirmed(_converse, _converse.bare_jid, [], [Strophe.NS.SID]); await mock.waitUntilDiscoConfirmed(_converse, _converse.bare_jid, [], [Strophe.NS.SID]);
const contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit'; const contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit';
@ -307,13 +303,12 @@ describe("Message Retractions", function () {
const msg_el = view.querySelector('.chat-msg--retracted .chat-msg__message'); const msg_el = view.querySelector('.chat-msg--retracted .chat-msg__message');
expect(msg_el.textContent.trim()).toBe('Mercutio has removed this message'); expect(msg_el.textContent.trim()).toBe('Mercutio has removed this message');
expect(u.hasClass('chat-msg--followup', view.querySelector('.chat-msg--retracted'))).toBe(true); expect(u.hasClass('chat-msg--followup', view.querySelector('.chat-msg--retracted'))).toBe(true);
done();
})); }));
}); });
describe("A Sent Chat Message", function () { describe("A Sent Chat Message", function () {
it("can be retracted by its author", mock.initConverse(['chatBoxesFetched'], {}, async function (done, _converse) { it("can be retracted by its author", mock.initConverse(['chatBoxesFetched'], {}, async function (_converse) {
await mock.waitForRoster(_converse, 'current', 1); await mock.waitForRoster(_converse, 'current', 1);
const contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit'; const contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit';
const view = await mock.openChatBoxFor(_converse, contact_jid); const view = await mock.openChatBoxFor(_converse, contact_jid);
@ -352,14 +347,13 @@ describe("Message Retractions", function () {
expect(view.querySelectorAll('.chat-msg--retracted').length).toBe(1); expect(view.querySelectorAll('.chat-msg--retracted').length).toBe(1);
const el = view.querySelector('.chat-msg--retracted .chat-msg__message'); const el = view.querySelector('.chat-msg--retracted .chat-msg__message');
expect(el.textContent.trim()).toBe('Romeo Montague has removed this message'); expect(el.textContent.trim()).toBe('Romeo Montague has removed this message');
done();
})); }));
}); });
describe("A Received Groupchat Message", function () { describe("A Received Groupchat Message", function () {
it("can be followed up by a retraction by the author", mock.initConverse(['chatBoxesFetched'], {}, async function (done, _converse) { it("can be followed up by a retraction by the author", mock.initConverse(['chatBoxesFetched'], {}, async function (_converse) {
const muc_jid = 'lounge@montague.lit'; const muc_jid = 'lounge@montague.lit';
const features = [...mock.default_muc_features, Strophe.NS.MODERATE]; const features = [...mock.default_muc_features, Strophe.NS.MODERATE];
await mock.openAndEnterChatRoom(_converse, muc_jid, 'romeo', features); await mock.openAndEnterChatRoom(_converse, muc_jid, 'romeo', features);
@ -395,12 +389,11 @@ describe("Message Retractions", function () {
const msg_el = view.querySelector('.chat-msg--retracted .chat-msg__message'); const msg_el = view.querySelector('.chat-msg--retracted .chat-msg__message');
expect(msg_el.textContent.trim()).toBe('eve has removed this message'); expect(msg_el.textContent.trim()).toBe('eve has removed this message');
expect(msg_el.querySelector('.chat-msg--retracted q')).toBe(null); expect(msg_el.querySelector('.chat-msg--retracted q')).toBe(null);
done();
})); }));
it("can be retracted by a moderator, with the IQ response received before the retraction message", it("can be retracted by a moderator, with the IQ response received before the retraction message",
mock.initConverse(['chatBoxesFetched'], {}, async function (done, _converse) { mock.initConverse(['chatBoxesFetched'], {}, async function (_converse) {
const muc_jid = 'lounge@montague.lit'; const muc_jid = 'lounge@montague.lit';
const features = [...mock.default_muc_features, Strophe.NS.MODERATE]; const features = [...mock.default_muc_features, Strophe.NS.MODERATE];
@ -480,11 +473,10 @@ describe("Message Retractions", function () {
expect(view.model.messages.at(0).get('moderation_reason')).toBe(reason); expect(view.model.messages.at(0).get('moderation_reason')).toBe(reason);
expect(view.model.messages.at(0).get('is_ephemeral')).toBe(false); expect(view.model.messages.at(0).get('is_ephemeral')).toBe(false);
expect(view.model.messages.at(0).get('editable')).toBe(false); expect(view.model.messages.at(0).get('editable')).toBe(false);
done();
})); }));
it("can not be retracted if the MUC doesn't support message moderation", it("can not be retracted if the MUC doesn't support message moderation",
mock.initConverse(['chatBoxesFetched'], {}, async function (done, _converse) { mock.initConverse(['chatBoxesFetched'], {}, async function (_converse) {
const muc_jid = 'lounge@montague.lit'; const muc_jid = 'lounge@montague.lit';
await mock.openAndEnterChatRoom(_converse, muc_jid, 'romeo'); await mock.openAndEnterChatRoom(_converse, muc_jid, 'romeo');
@ -503,12 +495,11 @@ describe("Message Retractions", function () {
expect(view.querySelector('.chat-msg__content .chat-msg__action-retract')).toBe(null); expect(view.querySelector('.chat-msg__content .chat-msg__action-retract')).toBe(null);
const result = await view.model.canModerateMessages(); const result = await view.model.canModerateMessages();
expect(result).toBe(false); expect(result).toBe(false);
done();
})); }));
it("can be retracted by a moderator, with the retraction message received before the IQ response", it("can be retracted by a moderator, with the retraction message received before the IQ response",
mock.initConverse(['chatBoxesFetched'], {}, async function (done, _converse) { mock.initConverse(['chatBoxesFetched'], {}, async function (_converse) {
const muc_jid = 'lounge@montague.lit'; const muc_jid = 'lounge@montague.lit';
const features = [...mock.default_muc_features, Strophe.NS.MODERATE]; const features = [...mock.default_muc_features, Strophe.NS.MODERATE];
@ -569,14 +560,13 @@ describe("Message Retractions", function () {
expect(view.model.messages.at(0).get('moderated_by')).toBe(_converse.bare_jid); expect(view.model.messages.at(0).get('moderated_by')).toBe(_converse.bare_jid);
expect(view.model.messages.at(0).get('moderation_reason')).toBe(reason); expect(view.model.messages.at(0).get('moderation_reason')).toBe(reason);
expect(view.model.messages.at(0).get('editable')).toBe(false); expect(view.model.messages.at(0).get('editable')).toBe(false);
done();
})); }));
}); });
describe("A Sent Groupchat Message", function () { describe("A Sent Groupchat Message", function () {
it("can be retracted by its author", mock.initConverse(['chatBoxesFetched'], {}, async function (done, _converse) { it("can be retracted by its author", mock.initConverse(['chatBoxesFetched'], {}, async function (_converse) {
const muc_jid = 'lounge@montague.lit'; const muc_jid = 'lounge@montague.lit';
const features = [...mock.default_muc_features, Strophe.NS.MODERATE]; const features = [...mock.default_muc_features, Strophe.NS.MODERATE];
await mock.openAndEnterChatRoom(_converse, muc_jid, 'romeo', features); await mock.openAndEnterChatRoom(_converse, muc_jid, 'romeo', features);
@ -627,11 +617,10 @@ describe("Message Retractions", function () {
expect(view.querySelectorAll('.chat-msg--retracted').length).toBe(1); expect(view.querySelectorAll('.chat-msg--retracted').length).toBe(1);
const el = view.querySelector('.chat-msg--retracted .chat-msg__message div'); const el = view.querySelector('.chat-msg--retracted .chat-msg__message div');
expect(el.textContent).toBe('romeo has removed this message'); expect(el.textContent).toBe('romeo has removed this message');
done();
})); }));
it("can be retracted by its author, causing an error message in response", it("can be retracted by its author, causing an error message in response",
mock.initConverse(['chatBoxesFetched'], {}, async function (done, _converse) { mock.initConverse(['chatBoxesFetched'], {}, async function (_converse) {
const muc_jid = 'lounge@montague.lit'; const muc_jid = 'lounge@montague.lit';
const features = [...mock.default_muc_features, Strophe.NS.MODERATE]; const features = [...mock.default_muc_features, Strophe.NS.MODERATE];
@ -674,11 +663,10 @@ describe("Message Retractions", function () {
const errmsg = view.querySelector('.chat-msg__error'); const errmsg = view.querySelector('.chat-msg__error');
expect(errmsg.textContent.trim()).toBe("You're not allowed to retract your message."); expect(errmsg.textContent.trim()).toBe("You're not allowed to retract your message.");
done();
})); }));
it("can be retracted by its author, causing a timeout error in response", it("can be retracted by its author, causing a timeout error in response",
mock.initConverse(['chatBoxesFetched'], {}, async function (done, _converse) { mock.initConverse(['chatBoxesFetched'], {}, async function (_converse) {
_converse.STANZA_TIMEOUT = 1; _converse.STANZA_TIMEOUT = 1;
@ -708,11 +696,10 @@ describe("Message Retractions", function () {
const error_messages = view.querySelectorAll('.chat-msg__error'); const error_messages = view.querySelectorAll('.chat-msg__error');
expect(error_messages.length).toBe(1); expect(error_messages.length).toBe(1);
expect(error_messages[0].textContent.trim()).toBe('A timeout happened while while trying to retract your message.'); expect(error_messages[0].textContent.trim()).toBe('A timeout happened while while trying to retract your message.');
done();
})); }));
it("can be retracted by a moderator", mock.initConverse(['chatBoxesFetched'], {}, async function (done, _converse) { it("can be retracted by a moderator", mock.initConverse(['chatBoxesFetched'], {}, async function (_converse) {
const muc_jid = 'lounge@montague.lit'; const muc_jid = 'lounge@montague.lit';
const features = [...mock.default_muc_features, Strophe.NS.MODERATE]; const features = [...mock.default_muc_features, Strophe.NS.MODERATE];
await mock.openAndEnterChatRoom(_converse, muc_jid, 'romeo', features); await mock.openAndEnterChatRoom(_converse, muc_jid, 'romeo', features);
@ -757,11 +744,10 @@ describe("Message Retractions", function () {
expect(view.model.messages.at(0).get('moderation_reason')).toBe(reason); expect(view.model.messages.at(0).get('moderation_reason')).toBe(reason);
expect(view.model.messages.at(0).get('is_ephemeral')).toBe(false); expect(view.model.messages.at(0).get('is_ephemeral')).toBe(false);
expect(view.model.messages.at(0).get('editable')).toBe(false); expect(view.model.messages.at(0).get('editable')).toBe(false);
done();
})); }));
it("can be retracted by the sender if they're a moderator", it("can be retracted by the sender if they're a moderator",
mock.initConverse(['chatBoxesFetched'], {'allow_message_retraction': 'moderator'}, async function (done, _converse) { mock.initConverse(['chatBoxesFetched'], {'allow_message_retraction': 'moderator'}, async function (_converse) {
const muc_jid = 'lounge@montague.lit'; const muc_jid = 'lounge@montague.lit';
const features = [...mock.default_muc_features, Strophe.NS.MODERATE]; const features = [...mock.default_muc_features, Strophe.NS.MODERATE];
@ -840,7 +826,6 @@ describe("Message Retractions", function () {
expect(view.model.messages.at(0).get('moderation_reason')).toBe(undefined); expect(view.model.messages.at(0).get('moderation_reason')).toBe(undefined);
expect(view.model.messages.at(0).get('is_ephemeral')).toBe(false); expect(view.model.messages.at(0).get('is_ephemeral')).toBe(false);
expect(view.model.messages.at(0).get('editable')).toBe(false); expect(view.model.messages.at(0).get('editable')).toBe(false);
done();
})); }));
}); });
@ -850,7 +835,7 @@ describe("Message Retractions", function () {
it("may be returned as a tombstone message", it("may be returned as a tombstone message",
mock.initConverse( mock.initConverse(
['discoInitialized'], {}, ['discoInitialized'], {},
async function (done, _converse) { async function (_converse) {
await mock.waitForRoster(_converse, 'current', 1); await mock.waitForRoster(_converse, 'current', 1);
const contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit'; const contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit';
@ -932,13 +917,12 @@ describe("Message Retractions", function () {
const el = view.querySelector('.chat-msg--retracted .chat-msg__message div'); const el = view.querySelector('.chat-msg--retracted .chat-msg__message div');
expect(el.textContent.trim()).toBe('Mercutio has removed this message'); expect(el.textContent.trim()).toBe('Mercutio has removed this message');
expect(u.hasClass('chat-msg--followup', el.parentElement)).toBe(false); expect(u.hasClass('chat-msg--followup', el.parentElement)).toBe(false);
done();
})); }));
it("may be returned as a tombstone groupchat message", it("may be returned as a tombstone groupchat message",
mock.initConverse( mock.initConverse(
['discoInitialized'], {}, ['discoInitialized'], {},
async function (done, _converse) { async function (_converse) {
const muc_jid = 'lounge@montague.lit'; const muc_jid = 'lounge@montague.lit';
const features = [...mock.default_muc_features, Strophe.NS.MODERATE]; const features = [...mock.default_muc_features, Strophe.NS.MODERATE];
@ -1008,13 +992,12 @@ describe("Message Retractions", function () {
expect(view.querySelectorAll('.chat-msg--retracted').length).toBe(1); expect(view.querySelectorAll('.chat-msg--retracted').length).toBe(1);
const el = view.querySelector('.chat-msg--retracted .chat-msg__message div'); const el = view.querySelector('.chat-msg--retracted .chat-msg__message div');
expect(el.textContent.trim()).toBe('eve has removed this message'); expect(el.textContent.trim()).toBe('eve has removed this message');
done();
})); }));
it("may be returned as a tombstone moderated groupchat message", it("may be returned as a tombstone moderated groupchat message",
mock.initConverse( mock.initConverse(
['discoInitialized', 'chatBoxesFetched'], {}, ['discoInitialized', 'chatBoxesFetched'], {},
async function (done, _converse) { async function (_converse) {
const muc_jid = 'lounge@montague.lit'; const muc_jid = 'lounge@montague.lit';
const features = [...mock.default_muc_features, Strophe.NS.MODERATE]; const features = [...mock.default_muc_features, Strophe.NS.MODERATE];
@ -1096,7 +1079,6 @@ describe("Message Retractions", function () {
expect(el.textContent.trim()).toBe('A moderator has removed this message'); expect(el.textContent.trim()).toBe('A moderator has removed this message');
const qel = view.querySelector('.chat-msg--retracted .chat-msg__message q'); const qel = view.querySelector('.chat-msg--retracted .chat-msg__message q');
expect(qel.textContent.trim()).toBe('This message contains inappropriate content'); expect(qel.textContent.trim()).toBe('This message contains inappropriate content');
done();
})); }));
}); });
}) })

View File

@ -6,7 +6,7 @@ describe("An incoming groupchat Message", function () {
it("can be styled with span XEP-0393 message styling hints that contain mentions", it("can be styled with span XEP-0393 message styling hints that contain mentions",
mock.initConverse(['chatBoxesFetched'], {}, mock.initConverse(['chatBoxesFetched'], {},
async function (done, _converse) { async function (_converse) {
const muc_jid = 'lounge@montague.lit'; const muc_jid = 'lounge@montague.lit';
await mock.openAndEnterChatRoom(_converse, muc_jid, 'romeo'); await mock.openAndEnterChatRoom(_converse, muc_jid, 'romeo');
@ -27,12 +27,11 @@ describe("An incoming groupchat Message", function () {
expect(msg_el.innerText).toBe(msg_text); expect(msg_el.innerText).toBe(msg_text);
await u.waitUntil(() => msg_el.innerHTML.replace(/<!-.*?->/g, '') === await u.waitUntil(() => msg_el.innerHTML.replace(/<!-.*?->/g, '') ===
'This <span class="styling-directive">*</span><b>message mentions <span class="mention mention--self badge badge-info">romeo</span></b><span class="styling-directive">*</span>'); 'This <span class="styling-directive">*</span><b>message mentions <span class="mention mention--self badge badge-info">romeo</span></b><span class="styling-directive">*</span>');
done();
})); }));
it("will not have styling applied to mentioned nicknames themselves", it("will not have styling applied to mentioned nicknames themselves",
mock.initConverse(['chatBoxesFetched'], {}, mock.initConverse(['chatBoxesFetched'], {},
async function (done, _converse) { async function (_converse) {
const muc_jid = 'lounge@montague.lit'; const muc_jid = 'lounge@montague.lit';
await mock.openAndEnterChatRoom(_converse, muc_jid, 'romeo'); await mock.openAndEnterChatRoom(_converse, muc_jid, 'romeo');
@ -53,6 +52,5 @@ describe("An incoming groupchat Message", function () {
expect(msg_el.innerText).toBe(msg_text); expect(msg_el.innerText).toBe(msg_text);
await u.waitUntil(() => msg_el.innerHTML.replace(/<!-.*?->/g, '') === await u.waitUntil(() => msg_el.innerHTML.replace(/<!-.*?->/g, '') ===
'<span class="mention">x_y_z_</span> hello'); '<span class="mention">x_y_z_</span> hello');
done();
})); }));
}); });

View File

@ -6,14 +6,13 @@ describe('The visible_toolbar_buttons configuration setting', function () {
it("can be used to show a participants toggle in a MUC's toolbar", it("can be used to show a participants toggle in a MUC's toolbar",
mock.initConverse([], { 'visible_toolbar_buttons': { 'toggle_occupants': true } }, mock.initConverse([], { 'visible_toolbar_buttons': { 'toggle_occupants': true } },
async (done, _converse) => { async (_converse) => {
const muc_jid = 'lounge@montague.lit'; const muc_jid = 'lounge@montague.lit';
await mock.openAndEnterChatRoom(_converse, muc_jid, 'romeo'); await mock.openAndEnterChatRoom(_converse, muc_jid, 'romeo');
const view = _converse.chatboxviews.get(muc_jid); const view = _converse.chatboxviews.get(muc_jid);
await u.waitUntil(() => view.querySelector('converse-chat-toolbar .toggle_occupants')); await u.waitUntil(() => view.querySelector('converse-chat-toolbar .toggle_occupants'));
expect(1).toBe(1); expect(1).toBe(1);
done();
}) })
); );
}); });

View File

@ -4,7 +4,7 @@ const { u } = converse.env;
describe("A Groupchat Message", function () { describe("A Groupchat Message", function () {
it("will render an unfurl based on OGP data", mock.initConverse(['chatBoxesFetched'], {}, async function (done, _converse) { it("will render an unfurl based on OGP data", mock.initConverse(['chatBoxesFetched'], {}, async function (_converse) {
const nick = 'romeo'; const nick = 'romeo';
const muc_jid = 'lounge@montague.lit'; const muc_jid = 'lounge@montague.lit';
await mock.openAndEnterChatRoom(_converse, muc_jid, nick); await mock.openAndEnterChatRoom(_converse, muc_jid, nick);
@ -44,10 +44,9 @@ describe("A Groupchat Message", function () {
const unfurl = await u.waitUntil(() => view.querySelector('converse-message-unfurl')); const unfurl = await u.waitUntil(() => view.querySelector('converse-message-unfurl'));
expect(unfurl.querySelector('.card-img-top').getAttribute('src')).toBe('https://i.ytimg.com/vi/dQw4w9WgXcQ/maxresdefault.jpg'); expect(unfurl.querySelector('.card-img-top').getAttribute('src')).toBe('https://i.ytimg.com/vi/dQw4w9WgXcQ/maxresdefault.jpg');
done();
})); }));
it("will render an unfurl with limited OGP data", mock.initConverse(['chatBoxesFetched'], {}, async function (done, _converse) { it("will render an unfurl with limited OGP data", mock.initConverse(['chatBoxesFetched'], {}, async function (_converse) {
/* Some sites don't include ogp data such as title, description and /* Some sites don't include ogp data such as title, description and
* url. This test is to check that we fall back gracefully */ * url. This test is to check that we fall back gracefully */
const nick = 'romeo'; const nick = 'romeo';
@ -82,10 +81,9 @@ describe("A Groupchat Message", function () {
expect(unfurl.querySelector('.card-img-top').getAttribute('src')).toBe('https://conversejs.org/dist/images/custom_emojis/converse.png'); expect(unfurl.querySelector('.card-img-top').getAttribute('src')).toBe('https://conversejs.org/dist/images/custom_emojis/converse.png');
expect(unfurl.querySelector('.card-body')).toBe(null); expect(unfurl.querySelector('.card-body')).toBe(null);
expect(unfurl.querySelector('a')).toBe(null); expect(unfurl.querySelector('a')).toBe(null);
done();
})); }));
it("will render multiple unfurls based on OGP data", mock.initConverse(['chatBoxesFetched'], {}, async function (done, _converse) { it("will render multiple unfurls based on OGP data", mock.initConverse(['chatBoxesFetched'], {}, async function (_converse) {
const nick = 'romeo'; const nick = 'romeo';
const muc_jid = 'lounge@montague.lit'; const muc_jid = 'lounge@montague.lit';
await mock.openAndEnterChatRoom(_converse, muc_jid, nick); await mock.openAndEnterChatRoom(_converse, muc_jid, nick);
@ -137,10 +135,9 @@ describe("A Groupchat Message", function () {
_converse.connection._dataRecv(mock.createRequest(metadata_stanza)); _converse.connection._dataRecv(mock.createRequest(metadata_stanza));
await u.waitUntil(() => view.querySelectorAll('converse-message-unfurl').length === 2); await u.waitUntil(() => view.querySelectorAll('converse-message-unfurl').length === 2);
done();
})); }));
it("will not render an unfurl received from a MUC participant", mock.initConverse(['chatBoxesFetched'], {}, async function (done, _converse) { it("will not render an unfurl received from a MUC participant", mock.initConverse(['chatBoxesFetched'], {}, async function (_converse) {
const nick = 'romeo'; const nick = 'romeo';
const muc_jid = 'lounge@montague.lit'; const muc_jid = 'lounge@montague.lit';
await mock.openAndEnterChatRoom(_converse, muc_jid, nick); await mock.openAndEnterChatRoom(_converse, muc_jid, nick);
@ -175,13 +172,12 @@ describe("A Groupchat Message", function () {
await u.waitUntil(() => view.model.handleMetadataFastening.calls.count()); await u.waitUntil(() => view.model.handleMetadataFastening.calls.count());
expect(view.model.handleMetadataFastening.calls.first().returnValue).toBe(false); expect(view.model.handleMetadataFastening.calls.first().returnValue).toBe(false);
expect(view.querySelector('converse-message-unfurl')).toBe(null); expect(view.querySelector('converse-message-unfurl')).toBe(null);
done();
})); }));
it("will not render an unfurl based on OGP data if muc_show_ogp_unfurls is false", it("will not render an unfurl based on OGP data if muc_show_ogp_unfurls is false",
mock.initConverse(['chatBoxesFetched'], mock.initConverse(['chatBoxesFetched'],
{'muc_show_ogp_unfurls': false}, {'muc_show_ogp_unfurls': false},
async function (done, _converse) { async function (_converse) {
const nick = 'romeo'; const nick = 'romeo';
const muc_jid = 'lounge@montague.lit'; const muc_jid = 'lounge@montague.lit';
await mock.openAndEnterChatRoom(_converse, muc_jid, nick); await mock.openAndEnterChatRoom(_converse, muc_jid, nick);
@ -216,11 +212,10 @@ describe("A Groupchat Message", function () {
await u.waitUntil(() => view.model.handleMetadataFastening.calls.count()); await u.waitUntil(() => view.model.handleMetadataFastening.calls.count());
expect(view.model.handleMetadataFastening.calls.first().returnValue).toBe(false); expect(view.model.handleMetadataFastening.calls.first().returnValue).toBe(false);
expect(view.querySelector('converse-message-unfurl')).toBe(null); expect(view.querySelector('converse-message-unfurl')).toBe(null);
done();
})); }));
it("will only render a single unfurl when receiving the same OGP data multiple times", it("will only render a single unfurl when receiving the same OGP data multiple times",
mock.initConverse(['chatBoxesFetched'], {}, async function (done, _converse) { mock.initConverse(['chatBoxesFetched'], {}, async function (_converse) {
const nick = 'romeo'; const nick = 'romeo';
const muc_jid = 'lounge@montague.lit'; const muc_jid = 'lounge@montague.lit';
await mock.openAndEnterChatRoom(_converse, muc_jid, nick); await mock.openAndEnterChatRoom(_converse, muc_jid, nick);
@ -257,13 +252,12 @@ describe("A Groupchat Message", function () {
await u.waitUntil(() => view.model.handleMetadataFastening.calls.count()); await u.waitUntil(() => view.model.handleMetadataFastening.calls.count());
const unfurls = await u.waitUntil(() => view.querySelectorAll('converse-message-unfurl')); const unfurls = await u.waitUntil(() => view.querySelectorAll('converse-message-unfurl'));
expect(unfurls.length).toBe(1); expect(unfurls.length).toBe(1);
done();
})); }));
it("will not render an unfurl image if the domain is not in show_images_inline", it("will not render an unfurl image if the domain is not in show_images_inline",
mock.initConverse(['chatBoxesFetched'], mock.initConverse(['chatBoxesFetched'],
{'show_images_inline': []}, {'show_images_inline': []},
async function (done, _converse) { async function (_converse) {
const nick = 'romeo'; const nick = 'romeo';
const muc_jid = 'lounge@montague.lit'; const muc_jid = 'lounge@montague.lit';
@ -296,13 +290,12 @@ describe("A Groupchat Message", function () {
const unfurl = await u.waitUntil(() => view.querySelector('converse-message-unfurl')); const unfurl = await u.waitUntil(() => view.querySelector('converse-message-unfurl'));
expect(unfurl.querySelector('.card-img-top')).toBe(null); expect(unfurl.querySelector('.card-img-top')).toBe(null);
done();
})); }));
it("lets the user hide an unfurl", it("lets the user hide an unfurl",
mock.initConverse(['chatBoxesFetched'], mock.initConverse(['chatBoxesFetched'],
{'show_images_inline': []}, {'show_images_inline': []},
async function (done, _converse) { async function (_converse) {
const nick = 'romeo'; const nick = 'romeo';
const muc_jid = 'lounge@montague.lit'; const muc_jid = 'lounge@montague.lit';
@ -339,6 +332,5 @@ describe("A Groupchat Message", function () {
await u.waitUntil(() => view.querySelector('converse-message-unfurl') === null, 750); await u.waitUntil(() => view.querySelector('converse-message-unfurl') === null, 750);
button.click(); button.click();
await u.waitUntil(() => view.querySelector('converse-message-unfurl'), 750); await u.waitUntil(() => view.querySelector('converse-message-unfurl'), 750);
done();
})); }));
}); });

View File

@ -7,7 +7,7 @@ describe("XSS", function () {
describe("A Groupchat", function () { describe("A Groupchat", function () {
it("escapes occupant nicknames when rendering them, to avoid JS-injection attacks", it("escapes occupant nicknames when rendering them, to avoid JS-injection attacks",
mock.initConverse([], {}, async function (done, _converse) { mock.initConverse([], {}, async function (_converse) {
await mock.openAndEnterChatRoom(_converse, 'lounge@montague.lit', 'romeo'); await mock.openAndEnterChatRoom(_converse, 'lounge@montague.lit', 'romeo');
/* <presence xmlns="jabber:client" to="jc@chat.example.org/converse.js-17184538" /* <presence xmlns="jabber:client" to="jc@chat.example.org/converse.js-17184538"
@ -34,11 +34,10 @@ describe("XSS", function () {
const occupants = view.querySelectorAll('.occupant-list li .occupant-nick'); const occupants = view.querySelectorAll('.occupant-list li .occupant-nick');
expect(occupants.length).toBe(2); expect(occupants.length).toBe(2);
expect(occupants[0].textContent.trim()).toBe("&lt;img src=&quot;x&quot; onerror=&quot;alert(123)&quot;/&gt;"); expect(occupants[0].textContent.trim()).toBe("&lt;img src=&quot;x&quot; onerror=&quot;alert(123)&quot;/&gt;");
done();
})); }));
it("escapes the subject before rendering it, to avoid JS-injection attacks", it("escapes the subject before rendering it, to avoid JS-injection attacks",
mock.initConverse([], {}, async function (done, _converse) { mock.initConverse([], {}, async function (_converse) {
await mock.openAndEnterChatRoom(_converse, 'jdev@conference.jabber.org', 'jc'); await mock.openAndEnterChatRoom(_converse, 'jdev@conference.jabber.org', 'jc');
spyOn(window, 'alert'); spyOn(window, 'alert');
@ -50,7 +49,6 @@ describe("XSS", function () {
}}); }});
const text = await u.waitUntil(() => view.querySelector('.chat-head__desc')?.textContent.trim()); const text = await u.waitUntil(() => view.querySelector('.chat-head__desc')?.textContent.trim());
expect(text).toBe(subject); expect(text).toBe(subject);
done();
})); }));
}); });
}); });

View File

@ -12,7 +12,7 @@ describe("Notifications", function () {
describe("an HTML5 Notification", function () { describe("an HTML5 Notification", function () {
it("is shown when a new private message is received", it("is shown when a new private message is received",
mock.initConverse([], {}, async (done, _converse) => { mock.initConverse([], {}, async (_converse) => {
await mock.waitForRoster(_converse, 'current'); await mock.waitForRoster(_converse, 'current');
const stub = jasmine.createSpyObj('MyNotification', ['onclick', 'close']); const stub = jasmine.createSpyObj('MyNotification', ['onclick', 'close']);
@ -30,11 +30,10 @@ describe("Notifications", function () {
await _converse.handleMessageStanza(msg); // This will emit 'message' await _converse.handleMessageStanza(msg); // This will emit 'message'
await u.waitUntil(() => _converse.chatboxviews.get(sender_jid)); await u.waitUntil(() => _converse.chatboxviews.get(sender_jid));
expect(window.Notification).toHaveBeenCalled(); expect(window.Notification).toHaveBeenCalled();
done();
})); }));
it("is shown when you are mentioned in a groupchat", it("is shown when you are mentioned in a groupchat",
mock.initConverse([], {}, async (done, _converse) => { mock.initConverse([], {}, async (_converse) => {
await mock.waitForRoster(_converse, 'current'); await mock.waitForRoster(_converse, 'current');
await mock.openAndEnterChatRoom(_converse, 'lounge@montague.lit', 'romeo'); await mock.openAndEnterChatRoom(_converse, 'lounge@montague.lit', 'romeo');
@ -75,10 +74,9 @@ describe("Notifications", function () {
_converse.connection._dataRecv(mock.createRequest(makeMsg('romeo: this will show a notification'))); _converse.connection._dataRecv(mock.createRequest(makeMsg('romeo: this will show a notification')));
await new Promise(resolve => view.model.messages.once('rendered', resolve)); await new Promise(resolve => view.model.messages.once('rendered', resolve));
expect(window.Notification.calls.count()).toBe(2); expect(window.Notification.calls.count()).toBe(2);
done();
})); }));
it("is shown for headline messages", mock.initConverse([], {}, async (done, _converse) => { it("is shown for headline messages", mock.initConverse([], {}, async (_converse) => {
const stub = jasmine.createSpyObj('MyNotification', ['onclick', 'close']); const stub = jasmine.createSpyObj('MyNotification', ['onclick', 'close']);
spyOn(window, 'Notification').and.returnValue(stub); spyOn(window, 'Notification').and.returnValue(stub);
@ -100,10 +98,9 @@ describe("Notifications", function () {
await new Promise(resolve => view.model.messages.once('rendered', resolve)); await new Promise(resolve => view.model.messages.once('rendered', resolve));
expect(_converse.chatboxviews.keys().includes('notify.example.com')).toBeTruthy(); expect(_converse.chatboxviews.keys().includes('notify.example.com')).toBeTruthy();
expect(window.Notification).toHaveBeenCalled(); expect(window.Notification).toHaveBeenCalled();
done();
})); }));
it("is not shown for full JID headline messages if allow_non_roster_messaging is false", mock.initConverse((done, _converse) => { it("is not shown for full JID headline messages if allow_non_roster_messaging is false", mock.initConverse((_converse) => {
_converse.allow_non_roster_messaging = false; _converse.allow_non_roster_messaging = false;
const stub = jasmine.createSpyObj('MyNotification', ['onclick', 'close']); const stub = jasmine.createSpyObj('MyNotification', ['onclick', 'close']);
spyOn(window, 'Notification').and.returnValue(stub); spyOn(window, 'Notification').and.returnValue(stub);
@ -120,12 +117,11 @@ describe("Notifications", function () {
_converse.connection._dataRecv(mock.createRequest(stanza)); _converse.connection._dataRecv(mock.createRequest(stanza));
expect(_converse.chatboxviews.keys().includes('someone@notify.example.com')).toBeFalsy(); expect(_converse.chatboxviews.keys().includes('someone@notify.example.com')).toBeFalsy();
expect(window.Notification).not.toHaveBeenCalled(); expect(window.Notification).not.toHaveBeenCalled();
done();
})); }));
it("is shown when a user changes their chat state (if show_chat_state_notifications is true)", it("is shown when a user changes their chat state (if show_chat_state_notifications is true)",
mock.initConverse([], {show_chat_state_notifications: true}, mock.initConverse([], {show_chat_state_notifications: true},
async (done, _converse) => { async (_converse) => {
await mock.waitForRoster(_converse, 'current', 3); await mock.waitForRoster(_converse, 'current', 3);
const stub = jasmine.createSpyObj('MyNotification', ['onclick', 'close']); const stub = jasmine.createSpyObj('MyNotification', ['onclick', 'close']);
@ -133,18 +129,16 @@ describe("Notifications", function () {
const jid = mock.cur_names[2].replace(/ /g,'.').toLowerCase() + '@montague.lit'; const jid = mock.cur_names[2].replace(/ /g,'.').toLowerCase() + '@montague.lit';
_converse.roster.get(jid).presence.set('show', 'dnd'); _converse.roster.get(jid).presence.set('show', 'dnd');
expect(window.Notification).toHaveBeenCalled(); expect(window.Notification).toHaveBeenCalled();
done()
})); }));
}); });
}); });
describe("When a new contact request is received", function () { describe("When a new contact request is received", function () {
it("an HTML5 Notification is received", mock.initConverse((done, _converse) => { it("an HTML5 Notification is received", mock.initConverse((_converse) => {
const stub = jasmine.createSpyObj('MyNotification', ['onclick', 'close']); const stub = jasmine.createSpyObj('MyNotification', ['onclick', 'close']);
spyOn(window, 'Notification').and.returnValue(stub); spyOn(window, 'Notification').and.returnValue(stub);
_converse.api.trigger('contactRequest', {'getDisplayName': () => 'Peter Parker'}); _converse.api.trigger('contactRequest', {'getDisplayName': () => 'Peter Parker'});
expect(window.Notification).toHaveBeenCalled(); expect(window.Notification).toHaveBeenCalled();
done();
})); }));
}); });
}); });
@ -152,7 +146,7 @@ describe("Notifications", function () {
describe("When play_sounds is set to true", function () { describe("When play_sounds is set to true", function () {
describe("A notification sound", function () { describe("A notification sound", function () {
it("is played when the current user is mentioned in a groupchat", mock.initConverse([], {}, async (done, _converse) => { it("is played when the current user is mentioned in a groupchat", mock.initConverse([], {}, async (_converse) => {
await mock.waitForRoster(_converse, 'current'); await mock.waitForRoster(_converse, 'current');
await mock.openAndEnterChatRoom(_converse, 'lounge@montague.lit', 'romeo'); await mock.openAndEnterChatRoom(_converse, 'lounge@montague.lit', 'romeo');
@ -198,7 +192,6 @@ describe("Notifications", function () {
}).c('body').t(text); }).c('body').t(text);
await view.model.handleMessageStanza(message.nodeTree); await view.model.handleMessageStanza(message.nodeTree);
expect(window.Audio, 1); expect(window.Audio, 1);
done();
})); }));
}); });
}); });
@ -207,7 +200,7 @@ describe("Notifications", function () {
describe("A Favicon Message Counter", function () { describe("A Favicon Message Counter", function () {
it("is incremented when the message is received and the window is not focused", it("is incremented when the message is received and the window is not focused",
mock.initConverse([], {'show_tab_notifications': false}, async function (done, _converse) { mock.initConverse([], {'show_tab_notifications': false}, async function (_converse) {
await mock.waitForRoster(_converse, 'current'); await mock.waitForRoster(_converse, 'current');
await mock.openControlBox(_converse); await mock.openControlBox(_converse);
@ -257,11 +250,10 @@ describe("Notifications", function () {
expect(view.model.get('num_unread')).toBe(0); expect(view.model.get('num_unread')).toBe(0);
_converse.windowSate = previous_state; _converse.windowSate = previous_state;
done();
})); }));
it("is not incremented when the message is received and the window is focused", it("is not incremented when the message is received and the window is focused",
mock.initConverse([], {}, async function (done, _converse) { mock.initConverse([], {}, async function (_converse) {
await mock.waitForRoster(_converse, 'current'); await mock.waitForRoster(_converse, 'current');
await mock.openControlBox(_converse); await mock.openControlBox(_converse);
@ -285,12 +277,11 @@ describe("Notifications", function () {
const view = _converse.chatboxviews.get(sender_jid); const view = _converse.chatboxviews.get(sender_jid);
expect(view.model.get('num_unread')).toBe(0); expect(view.model.get('num_unread')).toBe(0);
expect(favico.badge.calls.count()).toBe(0); expect(favico.badge.calls.count()).toBe(0);
done();
}, 500); }, 500);
})); }));
it("is incremented from zero when chatbox was closed after viewing previously received messages and the window is not focused now", it("is incremented from zero when chatbox was closed after viewing previously received messages and the window is not focused now",
mock.initConverse([], {}, async function (done, _converse) { mock.initConverse([], {}, async function (_converse) {
await mock.waitForRoster(_converse, 'current'); await mock.waitForRoster(_converse, 'current');
const favico = jasmine.createSpyObj('favico', ['badge']); const favico = jasmine.createSpyObj('favico', ['badge']);
@ -335,7 +326,6 @@ describe("Notifications", function () {
await u.waitUntil(() => u.isVisible(view)); await u.waitUntil(() => u.isVisible(view));
await u.waitUntil(() => favico.badge.calls.count() === 3); await u.waitUntil(() => favico.badge.calls.count() === 3);
expect(favico.badge.calls.mostRecent().args.pop()).toBe(1); expect(favico.badge.calls.mostRecent().args.pop()).toBe(1);
done();
})); }));
}); });

View File

@ -73,18 +73,17 @@ async function initializedOMEMO (_converse) {
describe("The OMEMO module", function() { describe("The OMEMO module", function() {
it("adds methods for encrypting and decrypting messages via AES GCM", it("adds methods for encrypting and decrypting messages via AES GCM",
mock.initConverse(['chatBoxesFetched'], {}, async function (done, _converse) { mock.initConverse(['chatBoxesFetched'], {}, async function (_converse) {
const message = 'This message will be encrypted' const message = 'This message will be encrypted'
await mock.waitForRoster(_converse, 'current', 1); await mock.waitForRoster(_converse, 'current', 1);
const payload = await omemo.encryptMessage(message); const payload = await omemo.encryptMessage(message);
const result = await omemo.decryptMessage(payload); const result = await omemo.decryptMessage(payload);
expect(result).toBe(message); expect(result).toBe(message);
done();
})); }));
it("enables encrypted messages to be sent and received", it("enables encrypted messages to be sent and received",
mock.initConverse(['chatBoxesFetched'], {}, async function (done, _converse) { mock.initConverse(['chatBoxesFetched'], {}, async function (_converse) {
let sent_stanza; let sent_stanza;
await mock.waitForRoster(_converse, 'current', 1); await mock.waitForRoster(_converse, 'current', 1);
@ -217,11 +216,10 @@ describe("The OMEMO module", function() {
expect(view.model.messages.length).toBe(3); expect(view.model.messages.length).toBe(3);
expect(view.querySelectorAll('.chat-msg__body')[2].textContent.trim()) expect(view.querySelectorAll('.chat-msg__body')[2].textContent.trim())
.toBe('Another received encrypted message without fallback'); .toBe('Another received encrypted message without fallback');
done();
})); }));
it("enables encrypted groupchat messages to be sent and received", it("enables encrypted groupchat messages to be sent and received",
mock.initConverse(['chatBoxesFetched'], {}, async function (done, _converse) { mock.initConverse(['chatBoxesFetched'], {}, async function (_converse) {
// MEMO encryption works only in members only conferences // MEMO encryption works only in members only conferences
// that are non-anonymous. // that are non-anonymous.
@ -363,11 +361,10 @@ describe("The OMEMO module", function() {
`</encrypted>`+ `</encrypted>`+
`<store xmlns="urn:xmpp:hints"/>`+ `<store xmlns="urn:xmpp:hints"/>`+
`</message>`); `</message>`);
done();
})); }));
it("will create a new device based on a received carbon message", it("will create a new device based on a received carbon message",
mock.initConverse(['chatBoxesFetched'], {}, async function (done, _converse) { mock.initConverse(['chatBoxesFetched'], {}, async function (_converse) {
await mock.waitUntilDiscoConfirmed(_converse, _converse.bare_jid, [], [Strophe.NS.SID]); await mock.waitUntilDiscoConfirmed(_converse, _converse.bare_jid, [], [Strophe.NS.SID]);
await mock.waitForRoster(_converse, 'current', 1); await mock.waitForRoster(_converse, 'current', 1);
@ -472,11 +469,10 @@ describe("The OMEMO module", function() {
`<items node="eu.siacs.conversations.axolotl.bundles:988349631"/>`+ `<items node="eu.siacs.conversations.axolotl.bundles:988349631"/>`+
`</pubsub>`+ `</pubsub>`+
`</iq>`); `</iq>`);
done();
})); }));
it("gracefully handles auth errors when trying to send encrypted groupchat messages", it("gracefully handles auth errors when trying to send encrypted groupchat messages",
mock.initConverse(['chatBoxesFetched'], {}, async function (done, _converse) { mock.initConverse(['chatBoxesFetched'], {}, async function (_converse) {
// MEMO encryption works only in members only conferences // MEMO encryption works only in members only conferences
// that are non-anonymous. // that are non-anonymous.
@ -600,11 +596,10 @@ describe("The OMEMO module", function() {
expect(view.model.get('omemo_supported')).toBe(false); expect(view.model.get('omemo_supported')).toBe(false);
expect(view.querySelector('.chat-textarea').value).toBe('This message will be encrypted'); expect(view.querySelector('.chat-textarea').value).toBe('This message will be encrypted');
done();
})); }));
it("can receive a PreKeySignalMessage", it("can receive a PreKeySignalMessage",
mock.initConverse(['chatBoxesFetched'], {}, async function (done, _converse) { mock.initConverse(['chatBoxesFetched'], {}, async function (_converse) {
_converse.NUM_PREKEYS = 5; // Restrict to 5, otherwise the resulting stanza is too large to easily test _converse.NUM_PREKEYS = 5; // Restrict to 5, otherwise the resulting stanza is too large to easily test
await mock.waitForRoster(_converse, 'current', 1); await mock.waitForRoster(_converse, 'current', 1);
@ -695,11 +690,10 @@ describe("The OMEMO module", function() {
const own_device = _converse.devicelists.get(_converse.bare_jid).devices.get(_converse.omemo_store.get('device_id')); const own_device = _converse.devicelists.get(_converse.bare_jid).devices.get(_converse.omemo_store.get('device_id'));
expect(own_device.get('bundle').prekeys.length).toBe(5); expect(own_device.get('bundle').prekeys.length).toBe(5);
expect(_converse.omemo_store.generateMissingPreKeys).toHaveBeenCalled(); expect(_converse.omemo_store.generateMissingPreKeys).toHaveBeenCalled();
done();
})); }));
it("updates device lists based on PEP messages", it("updates device lists based on PEP messages",
mock.initConverse([], {'allow_non_roster_messaging': true}, async function (done, _converse) { mock.initConverse([], {'allow_non_roster_messaging': true}, async function (_converse) {
await mock.waitUntilDiscoConfirmed( await mock.waitUntilDiscoConfirmed(
_converse, _converse.bare_jid, _converse, _converse.bare_jid,
@ -866,12 +860,11 @@ describe("The OMEMO module", function() {
expect(devices.get('444').get('active')).toBe(true); expect(devices.get('444').get('active')).toBe(true);
expect(devices.get('555').get('active')).toBe(false); expect(devices.get('555').get('active')).toBe(false);
expect(devices.get('777').get('active')).toBe(false); expect(devices.get('777').get('active')).toBe(false);
done();
})); }));
it("updates device bundles based on PEP messages", it("updates device bundles based on PEP messages",
mock.initConverse([], {}, async function (done, _converse) { mock.initConverse([], {}, async function (_converse) {
await mock.waitUntilDiscoConfirmed( await mock.waitUntilDiscoConfirmed(
_converse, _converse.bare_jid, _converse, _converse.bare_jid,
@ -1015,11 +1008,10 @@ describe("The OMEMO module", function() {
expect(device.get('bundle').prekeys[0].id).toBe(3001); expect(device.get('bundle').prekeys[0].id).toBe(3001);
expect(device.get('bundle').prekeys[1].id).toBe(3002); expect(device.get('bundle').prekeys[1].id).toBe(3002);
expect(device.get('bundle').prekeys[2].id).toBe(3003); expect(device.get('bundle').prekeys[2].id).toBe(3003);
done();
})); }));
it("publishes a bundle with which an encrypted session can be created", it("publishes a bundle with which an encrypted session can be created",
mock.initConverse(['chatBoxesFetched'], {}, async function (done, _converse) { mock.initConverse(['chatBoxesFetched'], {}, async function (_converse) {
await mock.waitUntilDiscoConfirmed( await mock.waitUntilDiscoConfirmed(
_converse, _converse.bare_jid, _converse, _converse.bare_jid,
@ -1090,12 +1082,11 @@ describe("The OMEMO module", function() {
'type': 'result'}); 'type': 'result'});
_converse.connection._dataRecv(mock.createRequest(stanza)); _converse.connection._dataRecv(mock.createRequest(stanza));
await _converse.api.waitUntil('OMEMOInitialized'); await _converse.api.waitUntil('OMEMOInitialized');
done();
})); }));
it("adds a toolbar button for starting an encrypted chat session", it("adds a toolbar button for starting an encrypted chat session",
mock.initConverse(['chatBoxesFetched'], {}, async function (done, _converse) { mock.initConverse(['chatBoxesFetched'], {}, async function (_converse) {
await mock.waitUntilDiscoConfirmed( await mock.waitUntilDiscoConfirmed(
_converse, _converse.bare_jid, _converse, _converse.bare_jid,
@ -1250,11 +1241,10 @@ describe("The OMEMO module", function() {
icon = toolbar.querySelector('.toggle-omemo converse-icon'); icon = toolbar.querySelector('.toggle-omemo converse-icon');
expect(u.hasClass('fa-lock', icon)).toBe(false); expect(u.hasClass('fa-lock', icon)).toBe(false);
expect(u.hasClass('fa-unlock', icon)).toBe(true); expect(u.hasClass('fa-unlock', icon)).toBe(true);
done();
})); }));
it("adds a toolbar button for starting an encrypted groupchat session", it("adds a toolbar button for starting an encrypted groupchat session",
mock.initConverse(['chatBoxesFetched'], {}, async function (done, _converse) { mock.initConverse(['chatBoxesFetched'], {}, async function (_converse) {
await mock.waitForRoster(_converse, 'current', 0); await mock.waitForRoster(_converse, 'current', 0);
await mock.waitUntilDiscoConfirmed( await mock.waitUntilDiscoConfirmed(
@ -1421,12 +1411,11 @@ describe("The OMEMO module", function() {
expect(u.hasClass('fa-unlock', icon)).toBe(true); expect(u.hasClass('fa-unlock', icon)).toBe(true);
expect(u.hasClass('fa-lock', icon)).toBe(false); expect(u.hasClass('fa-lock', icon)).toBe(false);
expect(toolbar.querySelector('.toggle-omemo').title).toBe('This groupchat needs to be members-only and non-anonymous in order to support OMEMO encrypted messages'); expect(toolbar.querySelector('.toggle-omemo').title).toBe('This groupchat needs to be members-only and non-anonymous in order to support OMEMO encrypted messages');
done();
})); }));
it("shows OMEMO device fingerprints in the user details modal", it("shows OMEMO device fingerprints in the user details modal",
mock.initConverse(['chatBoxesFetched'], {}, async function (done, _converse) { mock.initConverse(['chatBoxesFetched'], {}, async function (_converse) {
await mock.waitUntilDiscoConfirmed( await mock.waitUntilDiscoConfirmed(
_converse, _converse.bare_jid, _converse, _converse.bare_jid,
@ -1516,6 +1505,5 @@ describe("The OMEMO module", function() {
trusted_radio.click(); trusted_radio.click();
expect(devicelist.devices.get('555').get('trusted')).toBe(1); expect(devicelist.devices.get('555').get('trusted')).toBe(1);
done();
})); }));
}); });

View File

@ -17,12 +17,11 @@ describe("The Registration Panel", function () {
['chatBoxesInitialized'], ['chatBoxesInitialized'],
{ auto_login: false, { auto_login: false,
allow_registration: false }, allow_registration: false },
async function (done, _converse) { async function (_converse) {
await u.waitUntil(() => _converse.chatboxviews.get('controlbox')); await u.waitUntil(() => _converse.chatboxviews.get('controlbox'));
const cbview = _converse.api.controlbox.get(); const cbview = _converse.api.controlbox.get();
expect(cbview.querySelectorAll('a.register-account').length).toBe(0); expect(cbview.querySelectorAll('a.register-account').length).toBe(0);
done();
})); }));
it("can be opened by clicking on the registration tab", it("can be opened by clicking on the registration tab",
@ -30,7 +29,7 @@ describe("The Registration Panel", function () {
['chatBoxesInitialized'], ['chatBoxesInitialized'],
{ auto_login: false, { auto_login: false,
allow_registration: true }, allow_registration: true },
async function (done, _converse) { async function (_converse) {
const toggle = await u.waitUntil(() => document.querySelector(".toggle-controlbox")); const toggle = await u.waitUntil(() => document.querySelector(".toggle-controlbox"));
if (!u.isVisible(document.querySelector("#controlbox"))) { if (!u.isVisible(document.querySelector("#controlbox"))) {
@ -47,7 +46,6 @@ describe("The Registration Panel", function () {
register_link.click(); register_link.click();
expect(cbview.querySelector('converse-register-panel')).toBeDefined(); expect(cbview.querySelector('converse-register-panel')).toBeDefined();
done();
})); }));
it("allows the user to choose an XMPP provider's domain", it("allows the user to choose an XMPP provider's domain",
@ -56,7 +54,7 @@ describe("The Registration Panel", function () {
{ auto_login: false, { auto_login: false,
discover_connection_methods: false, discover_connection_methods: false,
allow_registration: true }, allow_registration: true },
async function (done, _converse) { async function (_converse) {
const toggle = await u.waitUntil(() => document.querySelector(".toggle-controlbox")); const toggle = await u.waitUntil(() => document.querySelector(".toggle-controlbox"));
@ -88,7 +86,6 @@ describe("The Registration Panel", function () {
expect(registerview.onProviderChosen).toHaveBeenCalled(); expect(registerview.onProviderChosen).toHaveBeenCalled();
expect(registerview.fetchRegistrationForm).toHaveBeenCalled(); expect(registerview.fetchRegistrationForm).toHaveBeenCalled();
delete _converse.connection; delete _converse.connection;
done();
})); }));
it("will render a registration form as received from the XMPP provider", it("will render a registration form as received from the XMPP provider",
@ -97,7 +94,7 @@ describe("The Registration Panel", function () {
{ auto_login: false, { auto_login: false,
discover_connection_methods: false, discover_connection_methods: false,
allow_registration: true }, allow_registration: true },
async function (done, _converse) { async function (_converse) {
const toggle = await u.waitUntil(() => document.querySelector(".toggle-controlbox")); const toggle = await u.waitUntil(() => document.querySelector(".toggle-controlbox"));
toggle.click(); toggle.click();
@ -146,7 +143,6 @@ describe("The Registration Panel", function () {
expect(registerview.querySelectorAll('input').length).toBe(5); expect(registerview.querySelectorAll('input').length).toBe(5);
expect(registerview.querySelectorAll('input[type=submit]').length).toBe(1); expect(registerview.querySelectorAll('input[type=submit]').length).toBe(1);
expect(registerview.querySelectorAll('input[type=button]').length).toBe(1); expect(registerview.querySelectorAll('input[type=button]').length).toBe(1);
done();
})); }));
it("will set form_type to legacy and submit it as legacy", it("will set form_type to legacy and submit it as legacy",
@ -155,7 +151,7 @@ describe("The Registration Panel", function () {
{ auto_login: false, { auto_login: false,
discover_connection_methods: false, discover_connection_methods: false,
allow_registration: true }, allow_registration: true },
async function (done, _converse) { async function (_converse) {
const toggle = document.querySelector(".toggle-controlbox"); const toggle = document.querySelector(".toggle-controlbox");
if (!u.isVisible(document.querySelector("#controlbox"))) { if (!u.isVisible(document.querySelector("#controlbox"))) {
@ -209,7 +205,6 @@ describe("The Registration Panel", function () {
expect(stanza.querySelector('query').firstElementChild.tagName).toBe('username'); expect(stanza.querySelector('query').firstElementChild.tagName).toBe('username');
delete _converse.connection; delete _converse.connection;
done();
})); }));
it("will set form_type to xform and submit it as xform", it("will set form_type to xform and submit it as xform",
@ -218,7 +213,7 @@ describe("The Registration Panel", function () {
{ auto_login: false, { auto_login: false,
discover_connection_methods: false, discover_connection_methods: false,
allow_registration: true }, allow_registration: true },
async function (done, _converse) { async function (_converse) {
const toggle = document.querySelector(".toggle-controlbox"); const toggle = document.querySelector(".toggle-controlbox");
if (!u.isVisible(document.querySelector("#controlbox"))) { if (!u.isVisible(document.querySelector("#controlbox"))) {
@ -289,7 +284,6 @@ describe("The Registration Panel", function () {
); );
delete _converse.connection; delete _converse.connection;
done();
})); }));
it("renders the account registration form", it("renders the account registration form",
@ -298,7 +292,7 @@ describe("The Registration Panel", function () {
{ auto_login: false, { auto_login: false,
discover_connection_methods: false, discover_connection_methods: false,
allow_registration: true }, allow_registration: true },
async function (done, _converse) { async function (_converse) {
const toggle = document.querySelector(".toggle-controlbox"); const toggle = document.querySelector(".toggle-controlbox");
if (!u.isVisible(document.querySelector("#controlbox"))) { if (!u.isVisible(document.querySelector("#controlbox"))) {
@ -358,7 +352,6 @@ describe("The Registration Panel", function () {
// passed or failed // passed or failed
u.addClass('hidden', _converse.chatboxviews.get('controlbox').el); u.addClass('hidden', _converse.chatboxviews.get('controlbox').el);
delete _converse.connection; delete _converse.connection;
done();
})); }));
it("renders errors", it("renders errors",
@ -368,7 +361,7 @@ describe("The Registration Panel", function () {
view_mode: 'fullscreen', view_mode: 'fullscreen',
discover_connection_methods: false, discover_connection_methods: false,
allow_registration: true }, allow_registration: true },
async function (done, _converse) { async function (_converse) {
const toggle = document.querySelector(".toggle-controlbox"); const toggle = document.querySelector(".toggle-controlbox");
if (!u.isVisible(document.querySelector("#controlbox"))) { if (!u.isVisible(document.querySelector("#controlbox"))) {
@ -439,6 +432,5 @@ describe("The Registration Panel", function () {
_converse.connection._dataRecv(mock.createRequest(response_IQ)); _converse.connection._dataRecv(mock.createRequest(response_IQ));
expect(view.querySelector('.error')?.textContent.trim()).toBe('Too many CAPTCHA requests'); expect(view.querySelector('.error')?.textContent.trim()).toBe('Too many CAPTCHA requests');
delete _converse.connection; delete _converse.connection;
done();
})); }));
}); });

View File

@ -5,12 +5,11 @@ const u = converse.env.utils;
describe("Converse", function() { describe("Converse", function() {
it("Can be inserted into a converse-root custom element after having been initialized", it("Can be inserted into a converse-root custom element after having been initialized",
mock.initConverse([], {'root': new DocumentFragment()}, async (done, _converse) => { mock.initConverse([], {'root': new DocumentFragment()}, async (_converse) => {
expect(document.body.querySelector('#conversejs')).toBe(null); expect(document.body.querySelector('#conversejs')).toBe(null);
expect(_converse.root.firstElementChild.nodeName.toLowerCase()).toBe('converse-root'); expect(_converse.root.firstElementChild.nodeName.toLowerCase()).toBe('converse-root');
document.body.appendChild(document.createElement('converse-root')); document.body.appendChild(document.createElement('converse-root'));
await u.waitUntil(() => document.body.querySelector('#conversejs') !== null); await u.waitUntil(() => document.body.querySelector('#conversejs') !== null);
done();
})); }));
}); });

View File

@ -8,7 +8,7 @@ describe("A sent presence stanza", function () {
afterEach(() => (jasmine.DEFAULT_TIMEOUT_INTERVAL = original_timeout)); afterEach(() => (jasmine.DEFAULT_TIMEOUT_INTERVAL = original_timeout));
it("includes the saved status message", it("includes the saved status message",
mock.initConverse([], {}, async (done, _converse) => { mock.initConverse([], {}, async (_converse) => {
const { u, Strophe } = converse.env; const { u, Strophe } = converse.env;
mock.openControlBox(_converse); mock.openControlBox(_converse);
@ -49,6 +49,5 @@ describe("A sent presence stanza", function () {
`<priority>0</priority>`+ `<priority>0</priority>`+
`<c hash="sha-1" node="https://conversejs.org" ver="PxXfr6uz8ClMWIga0OB/MhKNH/M=" xmlns="http://jabber.org/protocol/caps"/>`+ `<c hash="sha-1" node="https://conversejs.org" ver="PxXfr6uz8ClMWIga0OB/MhKNH/M=" xmlns="http://jabber.org/protocol/caps"/>`+
`</presence>`) `</presence>`)
done();
})); }));
}); });

View File

@ -39,7 +39,7 @@ describe("The Protocol", function () {
* stanza of type "result". * stanza of type "result".
*/ */
it("Subscribe to contact, contact accepts and subscribes back", it("Subscribe to contact, contact accepts and subscribes back",
mock.initConverse([], { roster_groups: false }, async function (done, _converse) { mock.initConverse([], { roster_groups: false }, async function (_converse) {
const { u, $iq, $pres, sizzle, Strophe } = converse.env; const { u, $iq, $pres, sizzle, Strophe } = converse.env;
let contact, stanza; let contact, stanza;
@ -354,12 +354,11 @@ describe("The Protocol", function () {
// The class on the contact will now have switched. // The class on the contact will now have switched.
await u.waitUntil(() => !u.hasClass('to', contacts[0])); await u.waitUntil(() => !u.hasClass('to', contacts[0]));
expect(u.hasClass('both', contacts[0])).toBe(true); expect(u.hasClass('both', contacts[0])).toBe(true);
done();
})); }));
it("Alternate Flow: Contact Declines Subscription Request", it("Alternate Flow: Contact Declines Subscription Request",
mock.initConverse([], {}, async function (done, _converse) { mock.initConverse([], {}, async function (_converse) {
const { $iq, $pres } = converse.env; const { $iq, $pres } = converse.env;
/* The process by which a user subscribes to a contact, including /* The process by which a user subscribes to a contact, including
@ -438,11 +437,10 @@ describe("The Protocol", function () {
`</query>`+ `</query>`+
`</iq>` `</iq>`
); );
done();
})); }));
it("Unsubscribe to a contact when subscription is mutual", it("Unsubscribe to a contact when subscription is mutual",
mock.initConverse([], { roster_groups: false }, async function (done, _converse) { mock.initConverse([], { roster_groups: false }, async function (_converse) {
const { u, $iq, sizzle, Strophe } = converse.env; const { u, $iq, sizzle, Strophe } = converse.env;
const jid = 'abram@montague.lit'; const jid = 'abram@montague.lit';
@ -494,11 +492,10 @@ describe("The Protocol", function () {
_converse.connection._dataRecv(mock.createRequest(stanza)); _converse.connection._dataRecv(mock.createRequest(stanza));
// Our contact has now been removed // Our contact has now been removed
await u.waitUntil(() => typeof _converse.roster.get(jid) === "undefined"); await u.waitUntil(() => typeof _converse.roster.get(jid) === "undefined");
done();
})); }));
it("Receiving a subscription request", mock.initConverse( it("Receiving a subscription request", mock.initConverse(
[], {}, async function (done, _converse) { [], {}, async function (_converse) {
const { u, $pres, sizzle, Strophe } = converse.env; const { u, $pres, sizzle, Strophe } = converse.env;
spyOn(_converse.api, "trigger").and.callThrough(); spyOn(_converse.api, "trigger").and.callThrough();
@ -530,7 +527,6 @@ describe("The Protocol", function () {
expect(u.isVisible(header)).toBe(true); expect(u.isVisible(header)).toBe(true);
const contacts = header.nextElementSibling.querySelectorAll('li'); const contacts = header.nextElementSibling.querySelectorAll('li');
expect(contacts.length).toBe(1); expect(contacts.length).toBe(1);
done();
})); }));
}); });
}); });

View File

@ -26,7 +26,7 @@ const checkHeaderToggling = async function (group) {
describe("The Contacts Roster", function () { describe("The Contacts Roster", function () {
it("verifies the origin of roster pushes", mock.initConverse(['chatBoxesFetched'], {}, async function (done, _converse) { it("verifies the origin of roster pushes", mock.initConverse(['chatBoxesFetched'], {}, async function (_converse) {
// See: https://gultsch.de/gajim_roster_push_and_message_interception.html // See: https://gultsch.de/gajim_roster_push_and_message_interception.html
const contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit'; const contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit';
@ -59,10 +59,9 @@ describe("The Contacts Roster", function () {
); );
expect(_converse.roster.models.length).toBe(1); expect(_converse.roster.models.length).toBe(1);
expect(_converse.roster.at(0).get('jid')).toBe(contact_jid); expect(_converse.roster.at(0).get('jid')).toBe(contact_jid);
done();
})); }));
it("is populated once we have registered a presence handler", mock.initConverse([], {}, async function (done, _converse) { it("is populated once we have registered a presence handler", mock.initConverse([], {}, async function (_converse) {
const IQs = _converse.connection.IQ_stanzas; const IQs = _converse.connection.IQ_stanzas;
const stanza = await u.waitUntil( const stanza = await u.waitUntil(
() => _.filter(IQs, iq => iq.querySelector('iq query[xmlns="jabber:iq:roster"]')).pop()); () => _.filter(IQs, iq => iq.querySelector('iq query[xmlns="jabber:iq:roster"]')).pop());
@ -81,10 +80,9 @@ describe("The Contacts Roster", function () {
.c('item', {'jid': 'romeo@example.com'}) .c('item', {'jid': 'romeo@example.com'})
_converse.connection._dataRecv(mock.createRequest(result)); _converse.connection._dataRecv(mock.createRequest(result));
await u.waitUntil(() => _converse.promises['rosterContactsFetched'].isResolved === true); await u.waitUntil(() => _converse.promises['rosterContactsFetched'].isResolved === true);
done();
})); }));
it("supports roster versioning", mock.initConverse([], {}, async function (done, _converse) { it("supports roster versioning", mock.initConverse([], {}, async function (_converse) {
const IQ_stanzas = _converse.connection.IQ_stanzas; const IQ_stanzas = _converse.connection.IQ_stanzas;
let stanza = await u.waitUntil( let stanza = await u.waitUntil(
() => _.filter(IQ_stanzas, iq => iq.querySelector('iq query[xmlns="jabber:iq:roster"]')).pop() () => _.filter(IQ_stanzas, iq => iq.querySelector('iq query[xmlns="jabber:iq:roster"]')).pop()
@ -132,10 +130,9 @@ describe("The Contacts Roster", function () {
expect(_converse.roster.data.get('version')).toBe('ver34'); expect(_converse.roster.data.get('version')).toBe('ver34');
expect(_converse.roster.models.length).toBe(1); expect(_converse.roster.models.length).toBe(1);
expect(_converse.roster.at(0).get('jid')).toBe('nurse@example.com'); expect(_converse.roster.at(0).get('jid')).toBe('nurse@example.com');
done();
})); }));
it("will also show contacts added afterwards", mock.initConverse([], {}, async function (done, _converse) { it("will also show contacts added afterwards", mock.initConverse([], {}, async function (_converse) {
await mock.openControlBox(_converse); await mock.openControlBox(_converse);
await mock.waitForRoster(_converse, 'current'); await mock.waitForRoster(_converse, 'current');
@ -175,13 +172,12 @@ describe("The Contacts Roster", function () {
expect(visible_groups[3].textContent.trim()).toBe('newgroup'); expect(visible_groups[3].textContent.trim()).toBe('newgroup');
expect(visible_groups[4].textContent.trim()).toBe('ænemies'); expect(visible_groups[4].textContent.trim()).toBe('ænemies');
expect(roster.querySelectorAll('.roster-group').length).toBe(5); expect(roster.querySelectorAll('.roster-group').length).toBe(5);
done();
})); }));
describe("The live filter", function () { describe("The live filter", function () {
it("will only appear when roster contacts flow over the visible area", it("will only appear when roster contacts flow over the visible area",
mock.initConverse([], {}, async function (done, _converse) { mock.initConverse([], {}, async function (_converse) {
expect(document.querySelector('converse-roster')).toBe(null); expect(document.querySelector('converse-roster')).toBe(null);
await mock.waitForRoster(_converse, 'current'); await mock.waitForRoster(_converse, 'current');
@ -197,13 +193,12 @@ describe("The Contacts Roster", function () {
const filter = rosterview.querySelector('.roster-filter'); const filter = rosterview.querySelector('.roster-filter');
const el = rosterview.querySelector('.roster-contacts'); const el = rosterview.querySelector('.roster-contacts');
await u.waitUntil(() => hasScrollBar(el) ? u.isVisible(filter) : !u.isVisible(filter), 900); await u.waitUntil(() => hasScrollBar(el) ? u.isVisible(filter) : !u.isVisible(filter), 900);
done();
})); }));
it("can be used to filter the contacts shown", it("can be used to filter the contacts shown",
mock.initConverse( mock.initConverse(
[], {'roster_groups': true}, [], {'roster_groups': true},
async function (done, _converse) { async function (_converse) {
await mock.openControlBox(_converse); await mock.openControlBox(_converse);
await mock.waitForRoster(_converse, 'current'); await mock.waitForRoster(_converse, 'current');
@ -250,10 +245,9 @@ describe("The Contacts Roster", function () {
u.triggerEvent(filter, "keydown", "KeyboardEvent"); u.triggerEvent(filter, "keydown", "KeyboardEvent");
await u.waitUntil(() => (sizzle('li', roster).filter(u.isVisible).length === 17), 600); await u.waitUntil(() => (sizzle('li', roster).filter(u.isVisible).length === 17), 600);
expect(sizzle('ul.roster-group-contacts', roster).filter(u.isVisible).length).toBe(5); expect(sizzle('ul.roster-group-contacts', roster).filter(u.isVisible).length).toBe(5);
done();
})); }));
it("can be used to filter the groups shown", mock.initConverse([], {'roster_groups': true}, async function (done, _converse) { it("can be used to filter the groups shown", mock.initConverse([], {'roster_groups': true}, async function (_converse) {
await mock.openControlBox(_converse); await mock.openControlBox(_converse);
await mock.waitForRoster(_converse, 'current'); await mock.waitForRoster(_converse, 'current');
const rosterview = document.querySelector('converse-roster'); const rosterview = document.querySelector('converse-roster');
@ -287,11 +281,10 @@ describe("The Contacts Roster", function () {
u.triggerEvent(filter, "keydown", "KeyboardEvent"); u.triggerEvent(filter, "keydown", "KeyboardEvent");
await u.waitUntil(() => (roster.querySelectorAll('div.roster-group.collapsed').length === 0), 700); await u.waitUntil(() => (roster.querySelectorAll('div.roster-group.collapsed').length === 0), 700);
expect(sizzle('div.roster-group', roster).length).toBe(0); expect(sizzle('div.roster-group', roster).length).toBe(0);
done();
})); }));
it("has a button with which its contents can be cleared", it("has a button with which its contents can be cleared",
mock.initConverse([], {'roster_groups': true}, async function (done, _converse) { mock.initConverse([], {'roster_groups': true}, async function (_converse) {
await mock.openControlBox(_converse); await mock.openControlBox(_converse);
await mock.waitForRoster(_converse, 'current'); await mock.waitForRoster(_converse, 'current');
@ -307,7 +300,6 @@ describe("The Contacts Roster", function () {
await u.waitUntil(() => !isHidden(rosterview.querySelector('.roster-filter-form .clear-input')), 900); await u.waitUntil(() => !isHidden(rosterview.querySelector('.roster-filter-form .clear-input')), 900);
rosterview.querySelector('.clear-input').click(); rosterview.querySelector('.clear-input').click();
expect(document.querySelector('.roster-filter').value).toBe(""); expect(document.querySelector('.roster-filter').value).toBe("");
done();
})); }));
// Disabling for now, because since recently this test consistently // Disabling for now, because since recently this test consistently
@ -315,7 +307,7 @@ describe("The Contacts Roster", function () {
xit("can be used to filter contacts by their chat state", xit("can be used to filter contacts by their chat state",
mock.initConverse( mock.initConverse(
[], {}, [], {},
async function (done, _converse) { async function (_converse) {
mock.waitForRoster(_converse, 'all'); mock.waitForRoster(_converse, 'all');
let jid = mock.cur_names[3].replace(/ /g,'.').toLowerCase() + '@montague.lit'; let jid = mock.cur_names[3].replace(/ /g,'.').toLowerCase() + '@montague.lit';
@ -342,7 +334,6 @@ describe("The Contacts Roster", function () {
u.triggerEvent(filter, 'change'); u.triggerEvent(filter, 'change');
await u.waitUntil(() => sizzle('li', roster).filter(u.isVisible).pop().textContent.trim() === 'Friar Laurence', 900); await u.waitUntil(() => sizzle('li', roster).filter(u.isVisible).pop().textContent.trim() === 'Friar Laurence', 900);
expect(sizzle('ul.roster-group-contacts', roster).filter(u.isVisible).length).toBe(1); expect(sizzle('ul.roster-group-contacts', roster).filter(u.isVisible).length).toBe(1);
done();
})); }));
}); });
@ -351,7 +342,7 @@ describe("The Contacts Roster", function () {
it("is created to show contacts with unread messages", it("is created to show contacts with unread messages",
mock.initConverse( mock.initConverse(
[], {'roster_groups': true}, [], {'roster_groups': true},
async function (done, _converse) { async function (_converse) {
await mock.openControlBox(_converse); await mock.openControlBox(_converse);
await mock.waitForRoster(_converse, 'all'); await mock.waitForRoster(_converse, 'all');
@ -406,14 +397,13 @@ describe("The Contacts Roster", function () {
"Ungrouped", "Ungrouped",
"Pending contacts" "Pending contacts"
]); ]);
done();
})); }));
it("can be used to organize existing contacts", it("can be used to organize existing contacts",
mock.initConverse( mock.initConverse(
[], {'roster_groups': true}, [], {'roster_groups': true},
async function (done, _converse) { async function (_converse) {
await mock.openControlBox(_converse); await mock.openControlBox(_converse);
await mock.waitForRoster(_converse, 'all'); await mock.waitForRoster(_converse, 'all');
@ -438,11 +428,10 @@ describe("The Contacts Roster", function () {
const names = contacts.map(o => o.textContent.trim()); const names = contacts.map(o => o.textContent.trim());
expect(names).toEqual(_.clone(names).sort()); expect(names).toEqual(_.clone(names).sort());
}); });
done();
})); }));
it("gets created when a contact's \"groups\" attribute changes", it("gets created when a contact's \"groups\" attribute changes",
mock.initConverse([], {'roster_groups': true}, async function (done, _converse) { mock.initConverse([], {'roster_groups': true}, async function (_converse) {
await mock.openControlBox(_converse); await mock.openControlBox(_converse);
await mock.waitForRoster(_converse, 'current', 0); await mock.waitForRoster(_converse, 'current', 0);
@ -480,11 +469,10 @@ describe("The Contacts Roster", function () {
} }
}, 1000); }, 1000);
expect(group_titles).toEqual(['secondgroup']); expect(group_titles).toEqual(['secondgroup']);
done();
})); }));
it("can share contacts with other roster groups", it("can share contacts with other roster groups",
mock.initConverse( [], {'roster_groups': true}, async function (done, _converse) { mock.initConverse( [], {'roster_groups': true}, async function (_converse) {
await mock.waitForRoster(_converse, 'current', 0); await mock.waitForRoster(_converse, 'current', 0);
const groups = ['Colleagues', 'friends']; const groups = ['Colleagues', 'friends'];
@ -507,11 +495,10 @@ describe("The Contacts Roster", function () {
expect(names).toEqual(_.clone(names).sort()); expect(names).toEqual(_.clone(names).sort());
expect(names.length).toEqual(mock.cur_names.length); expect(names.length).toEqual(mock.cur_names.length);
}); });
done();
})); }));
it("remembers whether it is closed or opened", it("remembers whether it is closed or opened",
mock.initConverse([], {}, async function (done, _converse) { mock.initConverse([], {}, async function (_converse) {
await mock.waitForRoster(_converse, 'current', 0); await mock.waitForRoster(_converse, 'current', 0);
await mock.openControlBox(_converse); await mock.openControlBox(_converse);
@ -544,14 +531,13 @@ describe("The Contacts Roster", function () {
expect(state.get('collapsed_groups')).toEqual(['Colleagues']); expect(state.get('collapsed_groups')).toEqual(['Colleagues']);
toggle.click(); toggle.click();
expect(state.get('collapsed_groups')).toEqual([]); expect(state.get('collapsed_groups')).toEqual([]);
done();
})); }));
}); });
describe("Pending Contacts", function () { describe("Pending Contacts", function () {
it("can be collapsed under their own header", it("can be collapsed under their own header",
mock.initConverse([], {}, async function (done, _converse) { mock.initConverse([], {}, async function (_converse) {
await mock.openControlBox(_converse); await mock.openControlBox(_converse);
await mock.waitForRoster(_converse, 'all'); await mock.waitForRoster(_converse, 'all');
@ -559,13 +545,12 @@ describe("The Contacts Roster", function () {
const rosterview = document.querySelector('converse-roster'); const rosterview = document.querySelector('converse-roster');
await u.waitUntil(() => sizzle('.roster-group', rosterview).filter(u.isVisible).map(e => e.querySelector('li')).length, 1000); await u.waitUntil(() => sizzle('.roster-group', rosterview).filter(u.isVisible).map(e => e.querySelector('li')).length, 1000);
await checkHeaderToggling.apply(_converse, [rosterview.querySelector('[data-group="Pending contacts"]')]); await checkHeaderToggling.apply(_converse, [rosterview.querySelector('[data-group="Pending contacts"]')]);
done();
})); }));
it("can be added to the roster", it("can be added to the roster",
mock.initConverse( mock.initConverse(
[], {}, [], {},
async function (done, _converse) { async function (_converse) {
await mock.waitForRoster(_converse, 'all', 0); await mock.waitForRoster(_converse, 'all', 0);
await mock.openControlBox(_converse); await mock.openControlBox(_converse);
@ -578,13 +563,12 @@ describe("The Contacts Roster", function () {
}); });
expect(u.isVisible(rosterview)).toBe(true); expect(u.isVisible(rosterview)).toBe(true);
await u.waitUntil(() => sizzle('li', rosterview).filter(u.isVisible).length === 1); await u.waitUntil(() => sizzle('li', rosterview).filter(u.isVisible).length === 1);
done();
})); }));
it("are shown in the roster when hide_offline_users", it("are shown in the roster when hide_offline_users",
mock.initConverse( mock.initConverse(
[], {'hide_offline_users': true}, [], {'hide_offline_users': true},
async function (done, _converse) { async function (_converse) {
await mock.openControlBox(_converse); await mock.openControlBox(_converse);
await mock.waitForRoster(_converse, 'pending'); await mock.waitForRoster(_converse, 'pending');
@ -594,11 +578,10 @@ describe("The Contacts Roster", function () {
expect(u.isVisible(rosterview)).toBe(true); expect(u.isVisible(rosterview)).toBe(true);
expect(sizzle('li', rosterview).filter(u.isVisible).length).toBe(3); expect(sizzle('li', rosterview).filter(u.isVisible).length).toBe(3);
expect(sizzle('ul.roster-group-contacts', rosterview).filter(u.isVisible).length).toBe(1); expect(sizzle('ul.roster-group-contacts', rosterview).filter(u.isVisible).length).toBe(1);
done();
})); }));
it("can be removed by the user", it("can be removed by the user",
mock.initConverse([], {}, async function (done, _converse) { mock.initConverse([], {}, async function (_converse) {
await mock.openControlBox(_converse); await mock.openControlBox(_converse);
await mock.waitForRoster(_converse, 'all'); await mock.waitForRoster(_converse, 'all');
@ -626,13 +609,12 @@ describe("The Contacts Roster", function () {
`<item jid="lord.capulet@montague.lit" subscription="remove"/>`+ `<item jid="lord.capulet@montague.lit" subscription="remove"/>`+
`</query>`+ `</query>`+
`</iq>`); `</iq>`);
done();
})); }));
it("do not have a header if there aren't any", it("do not have a header if there aren't any",
mock.initConverse( mock.initConverse(
['VCardsInitialized'], {}, ['VCardsInitialized'], {},
async function (done, _converse) { async function (_converse) {
await mock.openControlBox(_converse); await mock.openControlBox(_converse);
await mock.waitForRoster(_converse, 'current', 0); await mock.waitForRoster(_converse, 'current', 0);
@ -665,11 +647,10 @@ describe("The Contacts Roster", function () {
const stanza = u.toStanza(`<iq id="${iq.getAttribute('id')}" to="romeo@montague.lit/orchard" type="result"/>`); const stanza = u.toStanza(`<iq id="${iq.getAttribute('id')}" to="romeo@montague.lit/orchard" type="result"/>`);
_converse.connection._dataRecv(mock.createRequest(stanza)); _converse.connection._dataRecv(mock.createRequest(stanza));
await u.waitUntil(() => rosterview.querySelector(`ul[data-group="Pending contacts"]`) === null); await u.waitUntil(() => rosterview.querySelector(`ul[data-group="Pending contacts"]`) === null);
done();
})); }));
it("is shown when a new private message is received", it("is shown when a new private message is received",
mock.initConverse([], {}, async function (done, _converse) { mock.initConverse([], {}, async function (_converse) {
await mock.openControlBox(_converse); await mock.openControlBox(_converse);
await mock.waitForRoster(_converse, 'all'); await mock.waitForRoster(_converse, 'all');
@ -683,13 +664,12 @@ describe("The Contacts Roster", function () {
} }
await u.waitUntil(() => rosterview.querySelector(`ul[data-group="Pending contacts"]`) === null); await u.waitUntil(() => rosterview.querySelector(`ul[data-group="Pending contacts"]`) === null);
expect(rosterview.querySelectorAll('ul').length).toBe(5); expect(rosterview.querySelectorAll('ul').length).toBe(5);
done();
})); }));
it("can be added to the roster and they will be sorted alphabetically", it("can be added to the roster and they will be sorted alphabetically",
mock.initConverse( mock.initConverse(
[], {}, [], {},
async function (done, _converse) { async function (_converse) {
await mock.openControlBox(_converse); await mock.openControlBox(_converse);
await mock.waitForRoster(_converse, 'current'); await mock.waitForRoster(_converse, 'current');
@ -710,7 +690,6 @@ describe("The Contacts Roster", function () {
const spans = el.querySelectorAll('.pending-xmpp-contact span'); const spans = el.querySelectorAll('.pending-xmpp-contact span');
const t = Array.from(spans).reduce((result, value) => result + value.textContent?.trim(), ''); const t = Array.from(spans).reduce((result, value) => result + value.textContent?.trim(), '');
expect(t).toEqual(mock.pend_names.slice(0,i+1).sort().join('')); expect(t).toEqual(mock.pend_names.slice(0,i+1).sort().join(''));
done();
})); }));
}); });
@ -724,19 +703,18 @@ describe("The Contacts Roster", function () {
it("can be collapsed under their own header", it("can be collapsed under their own header",
mock.initConverse( mock.initConverse(
[], {}, [], {},
async function (done, _converse) { async function (_converse) {
await _addContacts(_converse); await _addContacts(_converse);
const rosterview = document.querySelector('converse-roster'); const rosterview = document.querySelector('converse-roster');
await u.waitUntil(() => sizzle('li', rosterview).filter(u.isVisible).length, 500); await u.waitUntil(() => sizzle('li', rosterview).filter(u.isVisible).length, 500);
await checkHeaderToggling.apply(_converse, [rosterview.querySelector('.roster-group')]); await checkHeaderToggling.apply(_converse, [rosterview.querySelector('.roster-group')]);
done();
})); }));
it("will be hidden when appearing under a collapsed group", it("will be hidden when appearing under a collapsed group",
mock.initConverse( mock.initConverse(
[], {'roster_groups': false}, [], {'roster_groups': false},
async function (done, _converse) { async function (_converse) {
await _addContacts(_converse); await _addContacts(_converse);
const rosterview = document.querySelector('converse-roster'); const rosterview = document.querySelector('converse-roster');
@ -753,13 +731,12 @@ describe("The Contacts Roster", function () {
}); });
const el = rosterview.querySelector(`ul[data-group="My contacts"]`); const el = rosterview.querySelector(`ul[data-group="My contacts"]`);
expect(u.hasClass('collapsed', el)).toBe(true); expect(u.hasClass('collapsed', el)).toBe(true);
done();
})); }));
it("can be added to the roster and they will be sorted alphabetically", it("can be added to the roster and they will be sorted alphabetically",
mock.initConverse( mock.initConverse(
[], {}, [], {},
async function (done, _converse) { async function (_converse) {
await mock.waitForRoster(_converse, 'current', 0); await mock.waitForRoster(_converse, 'current', 0);
await mock.openControlBox(_converse); await mock.openControlBox(_converse);
@ -778,13 +755,12 @@ describe("The Contacts Roster", function () {
const els = sizzle('.current-xmpp-contact.offline a.open-chat', rosterview) const els = sizzle('.current-xmpp-contact.offline a.open-chat', rosterview)
const t = els.reduce((result, value) => (result + value.textContent.trim()), ''); const t = els.reduce((result, value) => (result + value.textContent.trim()), '');
expect(t).toEqual(mock.cur_names.slice(0,mock.cur_names.length).sort().join('')); expect(t).toEqual(mock.cur_names.slice(0,mock.cur_names.length).sort().join(''));
done();
})); }));
it("can be removed by the user", it("can be removed by the user",
mock.initConverse( mock.initConverse(
[], {}, [], {},
async function (done, _converse) { async function (_converse) {
await _addContacts(_converse); await _addContacts(_converse);
const rosterview = document.querySelector('converse-roster'); const rosterview = document.querySelector('converse-roster');
@ -808,13 +784,12 @@ describe("The Contacts Roster", function () {
`</iq>`); `</iq>`);
expect(contact.removeFromRoster).toHaveBeenCalled(); expect(contact.removeFromRoster).toHaveBeenCalled();
await u.waitUntil(() => sizzle(".open-chat:contains('"+name+"')", rosterview).length === 0); await u.waitUntil(() => sizzle(".open-chat:contains('"+name+"')", rosterview).length === 0);
done();
})); }));
it("do not have a header if there aren't any", it("do not have a header if there aren't any",
mock.initConverse( mock.initConverse(
[], {}, [], {},
async function (done, _converse) { async function (_converse) {
await mock.openControlBox(_converse); await mock.openControlBox(_converse);
await mock.waitForRoster(_converse, 'current', 0); await mock.waitForRoster(_converse, 'current', 0);
@ -838,13 +813,12 @@ describe("The Contacts Roster", function () {
expect(_converse.connection.sendIQ).toHaveBeenCalled(); expect(_converse.connection.sendIQ).toHaveBeenCalled();
expect(contact.removeFromRoster).toHaveBeenCalled(); expect(contact.removeFromRoster).toHaveBeenCalled();
await u.waitUntil(() => rosterview.querySelectorAll('.roster-group').length === 0); await u.waitUntil(() => rosterview.querySelectorAll('.roster-group').length === 0);
done();
})); }));
it("can change their status to online and be sorted alphabetically", it("can change their status to online and be sorted alphabetically",
mock.initConverse( mock.initConverse(
[], {}, [], {},
async function (done, _converse) { async function (_converse) {
await _addContacts(_converse); await _addContacts(_converse);
const rosterview = document.querySelector('converse-roster'); const rosterview = document.querySelector('converse-roster');
@ -865,13 +839,12 @@ describe("The Contacts Roster", function () {
expect(t).toEqual(mock.groups_map[groupname].slice(0, els.length).sort().join('')); expect(t).toEqual(mock.groups_map[groupname].slice(0, els.length).sort().join(''));
} }
} }
done();
})); }));
it("can change their status to busy and be sorted alphabetically", it("can change their status to busy and be sorted alphabetically",
mock.initConverse( mock.initConverse(
[], {}, [], {},
async function (done, _converse) { async function (_converse) {
await _addContacts(_converse); await _addContacts(_converse);
const rosterview = document.querySelector('converse-roster'); const rosterview = document.querySelector('converse-roster');
@ -892,13 +865,12 @@ describe("The Contacts Roster", function () {
expect(t).toEqual(mock.groups_map[groupname].slice(0, els.length).sort().join('')); expect(t).toEqual(mock.groups_map[groupname].slice(0, els.length).sort().join(''));
} }
} }
done();
})); }));
it("can change their status to away and be sorted alphabetically", it("can change their status to away and be sorted alphabetically",
mock.initConverse( mock.initConverse(
[], {}, [], {},
async function (done, _converse) { async function (_converse) {
await _addContacts(_converse); await _addContacts(_converse);
const rosterview = document.querySelector('converse-roster'); const rosterview = document.querySelector('converse-roster');
@ -919,13 +891,12 @@ describe("The Contacts Roster", function () {
expect(t).toEqual(mock.groups_map[groupname].slice(0, els.length).sort().join('')); expect(t).toEqual(mock.groups_map[groupname].slice(0, els.length).sort().join(''));
} }
} }
done();
})); }));
it("can change their status to xa and be sorted alphabetically", it("can change their status to xa and be sorted alphabetically",
mock.initConverse( mock.initConverse(
[], {}, [], {},
async function (done, _converse) { async function (_converse) {
await _addContacts(_converse); await _addContacts(_converse);
const rosterview = document.querySelector('converse-roster'); const rosterview = document.querySelector('converse-roster');
@ -946,13 +917,12 @@ describe("The Contacts Roster", function () {
expect(t).toEqual(mock.groups_map[groupname].slice(0, els.length).sort().join('')); expect(t).toEqual(mock.groups_map[groupname].slice(0, els.length).sort().join(''));
} }
} }
done();
})); }));
it("can change their status to unavailable and be sorted alphabetically", it("can change their status to unavailable and be sorted alphabetically",
mock.initConverse( mock.initConverse(
[], {}, [], {},
async function (done, _converse) { async function (_converse) {
await _addContacts(_converse); await _addContacts(_converse);
const rosterview = document.querySelector('converse-roster'); const rosterview = document.querySelector('converse-roster');
@ -973,13 +943,12 @@ describe("The Contacts Roster", function () {
expect(t).toEqual(mock.groups_map[groupname].slice(0, els.length).sort().join('')); expect(t).toEqual(mock.groups_map[groupname].slice(0, els.length).sort().join(''));
} }
} }
done();
})); }));
it("are ordered according to status: online, busy, away, xa, unavailable, offline", it("are ordered according to status: online, busy, away, xa, unavailable, offline",
mock.initConverse( mock.initConverse(
[], {}, [], {},
async function (done, _converse) { async function (_converse) {
await _addContacts(_converse); await _addContacts(_converse);
const rosterview = document.querySelector('converse-roster'); const rosterview = document.querySelector('converse-roster');
@ -1060,7 +1029,6 @@ describe("The Contacts Roster", function () {
expect(subscription_classes.join(" ")).toBe("both both"); expect(subscription_classes.join(" ")).toBe("both both");
} }
} }
done();
})); }));
}); });
@ -1069,7 +1037,7 @@ describe("The Contacts Roster", function () {
it("can be added to the roster and they will be sorted alphabetically", it("can be added to the roster and they will be sorted alphabetically",
mock.initConverse( mock.initConverse(
[], {}, [], {},
async function (done, _converse) { async function (_converse) {
await mock.waitForRoster(_converse, "current", 0); await mock.waitForRoster(_converse, "current", 0);
await mock.openControlBox(_converse); await mock.openControlBox(_converse);
@ -1096,10 +1064,9 @@ describe("The Contacts Roster", function () {
names = []; names = [];
Array.from(children).forEach(addName); Array.from(children).forEach(addName);
expect(names.join('')).toEqual(mock.req_names.slice(0,mock.req_names.length+1).sort().join('')); expect(names.join('')).toEqual(mock.req_names.slice(0,mock.req_names.length+1).sort().join(''));
done();
})); }));
it("do not have a header if there aren't any", mock.initConverse([], {}, async function (done, _converse) { it("do not have a header if there aren't any", mock.initConverse([], {}, async function (_converse) {
await mock.openControlBox(_converse); await mock.openControlBox(_converse);
await mock.waitForRoster(_converse, "current", 0); await mock.waitForRoster(_converse, "current", 0);
const name = mock.req_names[0]; const name = mock.req_names[0];
@ -1118,10 +1085,9 @@ describe("The Contacts Roster", function () {
sizzle('.roster-group', rosterview).filter(u.isVisible).map(e => e.querySelector('li .decline-xmpp-request'))[0].click(); sizzle('.roster-group', rosterview).filter(u.isVisible).map(e => e.querySelector('li .decline-xmpp-request'))[0].click();
expect(window.confirm).toHaveBeenCalled(); expect(window.confirm).toHaveBeenCalled();
await u.waitUntil(() => rosterview.querySelector(`ul[data-group="Contact requests"]`) === null); await u.waitUntil(() => rosterview.querySelector(`ul[data-group="Contact requests"]`) === null);
done();
})); }));
it("can be collapsed under their own header", mock.initConverse([], {}, async function (done, _converse) { it("can be collapsed under their own header", mock.initConverse([], {}, async function (_converse) {
await mock.waitForRoster(_converse, 'current', 0); await mock.waitForRoster(_converse, 'current', 0);
mock.createContacts(_converse, 'requesting'); mock.createContacts(_converse, 'requesting');
await mock.openControlBox(_converse); await mock.openControlBox(_converse);
@ -1129,13 +1095,12 @@ describe("The Contacts Roster", function () {
await u.waitUntil(() => sizzle('.roster-group', rosterview).filter(u.isVisible).length, 700); await u.waitUntil(() => sizzle('.roster-group', rosterview).filter(u.isVisible).length, 700);
const el = await u.waitUntil(() => rosterview.querySelector(`ul[data-group="Contact requests"]`)); const el = await u.waitUntil(() => rosterview.querySelector(`ul[data-group="Contact requests"]`));
await checkHeaderToggling.apply(_converse, [el.parentElement]); await checkHeaderToggling.apply(_converse, [el.parentElement]);
done();
})); }));
it("can have their requests accepted by the user", it("can have their requests accepted by the user",
mock.initConverse( mock.initConverse(
[], {}, [], {},
async function (done, _converse) { async function (_converse) {
await mock.openControlBox(_converse); await mock.openControlBox(_converse);
await mock.waitForRoster(_converse, 'current', 0); await mock.waitForRoster(_converse, 'current', 0);
@ -1155,13 +1120,12 @@ describe("The Contacts Roster", function () {
expect(_converse.roster.sendContactAddIQ).toHaveBeenCalled(); expect(_converse.roster.sendContactAddIQ).toHaveBeenCalled();
await u.waitUntil(() => contact.authorize.calls.count()); await u.waitUntil(() => contact.authorize.calls.count());
expect(contact.authorize).toHaveBeenCalled(); expect(contact.authorize).toHaveBeenCalled();
done();
})); }));
it("can have their requests denied by the user", it("can have their requests denied by the user",
mock.initConverse( mock.initConverse(
[], {}, [], {},
async function (done, _converse) { async function (_converse) {
await mock.waitForRoster(_converse, 'current', 0); await mock.waitForRoster(_converse, 'current', 0);
await mock.createContacts(_converse, 'requesting'); await mock.createContacts(_converse, 'requesting');
@ -1179,11 +1143,10 @@ describe("The Contacts Roster", function () {
expect(contact.unauthorize).toHaveBeenCalled(); expect(contact.unauthorize).toHaveBeenCalled();
// There should now be one less contact // There should now be one less contact
expect(_converse.roster.length).toEqual(mock.req_names.length-1); expect(_converse.roster.length).toEqual(mock.req_names.length-1);
done();
})); }));
it("are persisted even if other contacts' change their presence ", mock.initConverse( it("are persisted even if other contacts' change their presence ", mock.initConverse(
[], {}, async function (done, _converse) { [], {}, async function (_converse) {
const sent_IQs = _converse.connection.IQ_stanzas; const sent_IQs = _converse.connection.IQ_stanzas;
const stanza = await u.waitUntil(() => sent_IQs.filter(iq => iq.querySelector('iq query[xmlns="jabber:iq:roster"]')).pop()); const stanza = await u.waitUntil(() => sent_IQs.filter(iq => iq.querySelector('iq query[xmlns="jabber:iq:roster"]')).pop());
@ -1227,7 +1190,6 @@ describe("The Contacts Roster", function () {
expect(_converse.roster.data.get('version')).toBe('ver34'); expect(_converse.roster.data.get('version')).toBe('ver34');
expect(_converse.roster.models.length).toBe(4); expect(_converse.roster.models.length).toBe(4);
expect(_converse.roster.pluck('jid').includes('data@enterprise')).toBeTruthy(); expect(_converse.roster.pluck('jid').includes('data@enterprise')).toBeTruthy();
done();
})); }));
}); });
@ -1236,7 +1198,7 @@ describe("The Contacts Roster", function () {
it("are saved to, and can be retrieved from browserStorage", it("are saved to, and can be retrieved from browserStorage",
mock.initConverse( mock.initConverse(
[], {}, [], {},
async function (done, _converse) { async function (_converse) {
await mock.waitForRoster(_converse, 'current', 0); await mock.waitForRoster(_converse, 'current', 0);
await mock.createContacts(_converse, 'requesting'); await mock.createContacts(_converse, 'requesting');
@ -1260,13 +1222,12 @@ describe("The Contacts Roster", function () {
// comparison // comparison
expect(new_attrs.sort()).toEqual(old_attrs.sort()); expect(new_attrs.sort()).toEqual(old_attrs.sort());
} }
done();
})); }));
it("will show fullname and jid properties on tooltip", it("will show fullname and jid properties on tooltip",
mock.initConverse( mock.initConverse(
[], {}, [], {},
async function (done, _converse) { async function (_converse) {
await mock.waitForRoster(_converse, 'current', 'all'); await mock.waitForRoster(_converse, 'current', 'all');
await mock.createContacts(_converse, 'requesting'); await mock.createContacts(_converse, 'requesting');
@ -1288,7 +1249,6 @@ describe("The Contacts Roster", function () {
expect(child.textContent.trim()).toBe(name); expect(child.textContent.trim()).toBe(name);
expect(child.firstElementChild.getAttribute('title')).toContain(jid); expect(child.firstElementChild.getAttribute('title')).toContain(jid);
})); }));
done();
})); }));
}); });
}); });