Commit 89ac4a69 authored by JC Brand's avatar JC Brand

Show error message with option to retry when MAM query times out

parent 6307fa69
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
- Add a new GUI for moderator actions. You can trigger it by entering `/modtools` in a MUC. - Add a new GUI for moderator actions. You can trigger it by entering `/modtools` in a MUC.
- Reconnect if the server doesn't respond to a `ping` within 10 seconds. - Reconnect if the server doesn't respond to a `ping` within 10 seconds.
- Don't query for MAM MUC messages before the cached messages have been restored (another cause of duplicate messages). - Don't query for MAM MUC messages before the cached messages have been restored (another cause of duplicate messages).
- Show an error message and option to retry when fetching of the MAM archive times out
## 5.0.0 (2019-08-08) ## 5.0.0 (2019-08-08)
......
...@@ -450,7 +450,7 @@ body.converse-fullscreen { ...@@ -450,7 +450,7 @@ body.converse-fullscreen {
width: 1em; width: 1em;
display: block; display: block;
text-align: center; text-align: center;
margin: 2em; padding: 0.5em 0;
font-size: 24px; font-size: 24px;
} }
.left { .left {
......
...@@ -573,7 +573,7 @@ ...@@ -573,7 +573,7 @@
await u.waitUntil(() => view.el.querySelectorAll('.message').length) await u.waitUntil(() => view.el.querySelectorAll('.message').length)
const messages = view.el.querySelectorAll('.message.chat-error'); const messages = view.el.querySelectorAll('.message.chat-error');
expect(messages.length).toBe(1); expect(messages.length).toBe(1);
expect(messages[0].textContent).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(); done();
})); }));
......
...@@ -772,7 +772,7 @@ ...@@ -772,7 +772,7 @@
* </result> * </result>
* </message> * </message>
*/ */
const msg1 = $msg({'id':'aeb213', 'to':'juliet@capulet.lit/chamber'}) const msg1 = $msg({'id':'aeb212', 'to':'juliet@capulet.lit/chamber'})
.c('result', {'xmlns': 'urn:xmpp:mam:2', 'queryid':queryid, 'id':'28482-98726-73623'}) .c('result', {'xmlns': 'urn:xmpp:mam:2', 'queryid':queryid, 'id':'28482-98726-73623'})
.c('forwarded', {'xmlns':'urn:xmpp:forward:0'}) .c('forwarded', {'xmlns':'urn:xmpp:forward:0'})
.c('delay', {'xmlns':'urn:xmpp:delay', 'stamp':'2010-07-10T23:08:25Z'}).up() .c('delay', {'xmlns':'urn:xmpp:delay', 'stamp':'2010-07-10T23:08:25Z'}).up()
...@@ -943,7 +943,7 @@ ...@@ -943,7 +943,7 @@
`</query>`+ `</query>`+
`</iq>` `</iq>`
); );
const msg1 = $msg({'id':'aeb213', 'to': contact_jid}) const msg1 = $msg({'id':'aeb212', 'to': contact_jid})
.c('result', {'xmlns': 'urn:xmpp:mam:2', 'queryid':queryid, 'id':'28482-98726-73623'}) .c('result', {'xmlns': 'urn:xmpp:mam:2', 'queryid':queryid, 'id':'28482-98726-73623'})
.c('forwarded', {'xmlns':'urn:xmpp:forward:0'}) .c('forwarded', {'xmlns':'urn:xmpp:forward:0'})
.c('delay', {'xmlns':'urn:xmpp:delay', 'stamp':'2010-07-10T23:08:25Z'}).up() .c('delay', {'xmlns':'urn:xmpp:delay', 'stamp':'2010-07-10T23:08:25Z'}).up()
...@@ -974,6 +974,110 @@ ...@@ -974,6 +974,110 @@
_converse.connection._dataRecv(test_utils.createRequest(stanza)); _converse.connection._dataRecv(test_utils.createRequest(stanza));
done(); done();
})); }));
it("will show an error message if the MAM query times out",
mock.initConverse(
null, ['discoInitialized'], {},
async function (done, _converse) {
const sendIQ = _converse.connection.sendIQ;
let timeout_happened = false;
spyOn(_converse.connection, 'sendIQ').and.callFake(function (iq, callback, errback) {
sendIQ.bind(this)(iq, callback, errback);
if (!timeout_happened) {
if (typeof(iq.tree) === "function") {
iq = iq.tree();
}
if (sizzle('query[xmlns="urn:xmpp:mam:2"]', iq).length) {
// We emulate a timeout event
callback(null);
timeout_happened = true;
}
}
});
await test_utils.waitForRoster(_converse, 'current', 1);
const contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit';
await test_utils.openChatBoxFor(_converse, contact_jid);
await test_utils.waitUntilDiscoConfirmed(_converse, _converse.bare_jid, null, [Strophe.NS.MAM]);
const IQ_stanzas = _converse.connection.IQ_stanzas;
let sent_stanza = await u.waitUntil(() => IQ_stanzas.filter(iq => sizzle('query[xmlns="urn:xmpp:mam:2"]', iq).length).pop());
let queryid = sent_stanza.querySelector('query').getAttribute('queryid');
expect(Strophe.serialize(sent_stanza)).toBe(
`<iq id="${sent_stanza.getAttribute('id')}" type="set" xmlns="jabber:client">`+
`<query queryid="${queryid}" xmlns="urn:xmpp:mam:2">`+
`<x type="submit" xmlns="jabber:x:data">`+
`<field type="hidden" var="FORM_TYPE"><value>urn:xmpp:mam:2</value></field>`+
`<field var="with"><value>mercutio@montague.lit</value></field>`+
`</x>`+
`<set xmlns="http://jabber.org/protocol/rsm"><max>50</max><before></before></set>`+
`</query>`+
`</iq>`);
const view = _converse.chatboxviews.get(contact_jid);
expect(view.model.messages.length).toBe(1);
expect(view.model.messages.at(0).get('ephemeral')).toBe(false);
expect(view.model.messages.at(0).get('type')).toBe('error');
expect(view.model.messages.at(0).get('message')).toBe('Timeout while trying to fetch archived messages.');
let err_message = view.el.querySelector('.message.chat-error');
err_message.querySelector('.retry').click();
expect(err_message.querySelector('.spinner')).not.toBe(null);
while (_converse.connection.IQ_stanzas.length) {
_converse.connection.IQ_stanzas.pop();
}
sent_stanza = await u.waitUntil(() => IQ_stanzas.filter(iq => sizzle('query[xmlns="urn:xmpp:mam:2"]', iq).length).pop());
queryid = sent_stanza.querySelector('query').getAttribute('queryid');
expect(Strophe.serialize(sent_stanza)).toBe(
`<iq id="${sent_stanza.getAttribute('id')}" type="set" xmlns="jabber:client">`+
`<query queryid="${queryid}" xmlns="urn:xmpp:mam:2">`+
`<x type="submit" xmlns="jabber:x:data">`+
`<field type="hidden" var="FORM_TYPE"><value>urn:xmpp:mam:2</value></field>`+
`<field var="with"><value>mercutio@montague.lit</value></field>`+
`</x>`+
`<set xmlns="http://jabber.org/protocol/rsm"><max>50</max><before></before></set>`+
`</query>`+
`</iq>`);
const msg1 = $msg({'id':'aeb212', 'to': contact_jid})
.c('result', {'xmlns': 'urn:xmpp:mam:2', 'queryid': queryid, 'id':'28482-98726-73623'})
.c('forwarded', {'xmlns':'urn:xmpp:forward:0'})
.c('delay', {'xmlns':'urn:xmpp:delay', 'stamp':'2010-07-10T23:08:25Z'}).up()
.c('message', {
'xmlns':'jabber:client',
'to': contact_jid,
'from': _converse.bare_jid,
'type':'chat' })
.c('body').t("Call me but love, and I'll be new baptized;");
_converse.connection._dataRecv(test_utils.createRequest(msg1));
const msg2 = $msg({'id':'aeb213', 'to': contact_jid})
.c('result', {'xmlns': 'urn:xmpp:mam:2', 'queryid': queryid, 'id':'28482-98726-73624'})
.c('forwarded', {'xmlns':'urn:xmpp:forward:0'})
.c('delay', {'xmlns':'urn:xmpp:delay', 'stamp':'2010-07-10T23:18:25Z'}).up()
.c('message', {
'xmlns':'jabber:client',
'to': contact_jid,
'from': _converse.bare_jid,
'type':'chat' })
.c('body').t("Henceforth I never will be Romeo.");
_converse.connection._dataRecv(test_utils.createRequest(msg2));
const stanza = $iq({'type': 'result', 'id': sent_stanza.getAttribute('id')})
.c('fin', {'xmlns': 'urn:xmpp:mam:2', 'complete': true})
.c('set', {'xmlns': 'http://jabber.org/protocol/rsm'})
.c('first', {'index': '0'}).t('28482-98726-73623').up()
.c('last').t('28482-98726-73624').up()
.c('count').t('2');
_converse.connection._dataRecv(test_utils.createRequest(stanza));
await u.waitUntil(() => view.model.messages.length === 2, 500);
err_message = view.el.querySelector('.message.chat-error');
expect(err_message).toBe(null);
done();
}));
}); });
}); });
})); }));
...@@ -1761,7 +1761,7 @@ ...@@ -1761,7 +1761,7 @@
.t('Server-to-server connection failed: Connecting failed: connection timeout'); .t('Server-to-server connection failed: Connecting failed: connection timeout');
_converse.connection._dataRecv(test_utils.createRequest(stanza)); _converse.connection._dataRecv(test_utils.createRequest(stanza));
await new Promise((resolve, reject) => view.once('messageInserted', resolve)); await new Promise((resolve, reject) => view.once('messageInserted', resolve));
expect(chat_content.querySelector('.chat-error').textContent).toEqual(error_txt); expect(chat_content.querySelector('.chat-error').textContent.trim()).toEqual(error_txt);
stanza = $msg({ stanza = $msg({
'to': _converse.connection.jid, 'to': _converse.connection.jid,
'type': 'error', 'type': 'error',
......
...@@ -247,15 +247,15 @@ ...@@ -247,15 +247,15 @@
await u.waitUntil(() => chatroomview.model.sendConfiguration.calls.count() === 1); await u.waitUntil(() => chatroomview.model.sendConfiguration.calls.count() === 1);
const sent_stanza = IQ_stanzas.filter(s => s.getAttribute('type') === 'set').pop(); const sent_stanza = IQ_stanzas.filter(s => s.getAttribute('type') === 'set').pop();
expect(sizzle('field[var="muc#roomconfig_roomname"] value', sent_stanza).pop().textContent).toBe('Room'); expect(sizzle('field[var="muc#roomconfig_roomname"] value', sent_stanza).pop().textContent.trim()).toBe('Room');
expect(sizzle('field[var="muc#roomconfig_roomdesc"] value', sent_stanza).pop().textContent).toBe('Welcome to this groupchat'); expect(sizzle('field[var="muc#roomconfig_roomdesc"] value', sent_stanza).pop().textContent.trim()).toBe('Welcome to this groupchat');
expect(sizzle('field[var="muc#roomconfig_persistentroom"] value', sent_stanza).pop().textContent).toBe('1'); expect(sizzle('field[var="muc#roomconfig_persistentroom"] value', sent_stanza).pop().textContent.trim()).toBe('1');
expect(sizzle('field[var="muc#roomconfig_getmemberlist"] value', sent_stanza).map(e => e.textContent).join(' ')).toBe('moderator participant'); expect(sizzle('field[var="muc#roomconfig_getmemberlist"] value', sent_stanza).map(e => e.textContent.trim()).join(' ')).toBe('moderator participant');
expect(sizzle('field[var="muc#roomconfig_publicroom"] value ', sent_stanza).pop().textContent).toBe('1'); expect(sizzle('field[var="muc#roomconfig_publicroom"] value ', sent_stanza).pop().textContent.trim()).toBe('1');
expect(sizzle('field[var="muc#roomconfig_changesubject"] value', sent_stanza).pop().textContent).toBe('0'); expect(sizzle('field[var="muc#roomconfig_changesubject"] value', sent_stanza).pop().textContent.trim()).toBe('0');
expect(sizzle('field[var="muc#roomconfig_whois"] value ', sent_stanza).pop().textContent).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).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).toBe('20'); expect(sizzle('field[var="muc#roomconfig_historylength"] value', sent_stanza).pop().textContent.trim()).toBe('20');
done(); done();
})); }));
}); });
...@@ -378,7 +378,7 @@ ...@@ -378,7 +378,7 @@
await test_utils.returnMemberLists(_converse, muc_jid); await test_utils.returnMemberLists(_converse, muc_jid);
// await u.waitUntil(() => view.el.querySelectorAll('.chat-content .chat-info').length === 2); // await u.waitUntil(() => view.el.querySelectorAll('.chat-content .chat-info').length === 2);
const info_texts = Array.from(view.el.querySelectorAll('.chat-content .chat-info')).map(e => e.textContent); const info_texts = Array.from(view.el.querySelectorAll('.chat-content .chat-info')).map(e => e.textContent.trim());
expect(info_texts[0]).toBe('A new groupchat has been created'); expect(info_texts[0]).toBe('A new groupchat has been created');
expect(info_texts[1]).toBe('nicky has entered the groupchat'); expect(info_texts[1]).toBe('nicky has entered the groupchat');
...@@ -613,9 +613,9 @@ ...@@ -613,9 +613,9 @@
_converse.connection._dataRecv(test_utils.createRequest(presence)); _converse.connection._dataRecv(test_utils.createRequest(presence));
await u.waitUntil(() => chat_content.querySelectorAll('.chat-info').length === 2); await u.waitUntil(() => chat_content.querySelectorAll('.chat-info').length === 2);
expect(sizzle('div.chat-info:first', chat_content).pop().textContent) expect(sizzle('div.chat-info:first', chat_content).pop().textContent.trim())
.toBe("This groupchat is not anonymous"); .toBe("This groupchat is not anonymous");
expect(sizzle('div.chat-info:last', chat_content).pop().textContent) expect(sizzle('div.chat-info:last', chat_content).pop().textContent.trim())
.toBe("some1 has entered the groupchat"); .toBe("some1 has entered the groupchat");
done(); done();
})); }));
...@@ -664,7 +664,7 @@ ...@@ -664,7 +664,7 @@
}).up() }).up()
.c('status', {code: '110'}); .c('status', {code: '110'});
_converse.connection._dataRecv(test_utils.createRequest(presence)); _converse.connection._dataRecv(test_utils.createRequest(presence));
expect(sizzle('div.chat-info:first', chat_content).pop().textContent) expect(sizzle('div.chat-info:first', chat_content).pop().textContent.trim())
.toBe("some1 has entered the groupchat"); .toBe("some1 has entered the groupchat");
presence = $pres({ presence = $pres({
...@@ -679,7 +679,7 @@ ...@@ -679,7 +679,7 @@
}); });
_converse.connection._dataRecv(test_utils.createRequest(presence)); _converse.connection._dataRecv(test_utils.createRequest(presence));
expect(chat_content.querySelectorAll('div.chat-info').length).toBe(2); expect(chat_content.querySelectorAll('div.chat-info').length).toBe(2);
expect(sizzle('div.chat-info:last', chat_content).pop().textContent) expect(sizzle('div.chat-info:last', chat_content).pop().textContent.trim())
.toBe("newguy has entered the groupchat"); .toBe("newguy has entered the groupchat");
const msg = $msg({ const msg = $msg({
...@@ -705,7 +705,7 @@ ...@@ -705,7 +705,7 @@
}); });
_converse.connection._dataRecv(test_utils.createRequest(presence)); _converse.connection._dataRecv(test_utils.createRequest(presence));
expect(chat_content.querySelectorAll('div.chat-info').length).toBe(3); expect(chat_content.querySelectorAll('div.chat-info').length).toBe(3);
expect(sizzle('div.chat-info:last', chat_content).pop().textContent) expect(sizzle('div.chat-info:last', chat_content).pop().textContent.trim())
.toBe("newgirl has entered the groupchat"); .toBe("newgirl has entered the groupchat");
// Don't show duplicate join messages // Don't show duplicate join messages
...@@ -747,7 +747,7 @@ ...@@ -747,7 +747,7 @@
}); });
_converse.connection._dataRecv(test_utils.createRequest(presence)); _converse.connection._dataRecv(test_utils.createRequest(presence));
expect(chat_content.querySelectorAll('div.chat-info').length).toBe(4); expect(chat_content.querySelectorAll('div.chat-info').length).toBe(4);
expect(sizzle('div.chat-info:last', chat_content).pop().textContent).toBe( expect(sizzle('div.chat-info:last', chat_content).pop().textContent.trim()).toBe(
'newguy has left the groupchat. '+ 'newguy has left the groupchat. '+
'"Disconnected: Replaced by new connection"'); '"Disconnected: Replaced by new connection"');
...@@ -765,7 +765,7 @@ ...@@ -765,7 +765,7 @@
_converse.connection._dataRecv(test_utils.createRequest(presence)); _converse.connection._dataRecv(test_utils.createRequest(presence));
expect(chat_content.querySelectorAll('div.chat-info').length).toBe(4); expect(chat_content.querySelectorAll('div.chat-info').length).toBe(4);
let msg_el = sizzle('div.chat-info:last', chat_content).pop(); let msg_el = sizzle('div.chat-info:last', chat_content).pop();
expect(msg_el.textContent).toBe("newguy has left and re-entered the groupchat"); expect(msg_el.textContent.trim()).toBe("newguy has left and re-entered the groupchat");
expect(msg_el.getAttribute('data-leavejoin')).toBe('newguy'); expect(msg_el.getAttribute('data-leavejoin')).toBe('newguy');
presence = $pres({ presence = $pres({
...@@ -782,7 +782,7 @@ ...@@ -782,7 +782,7 @@
_converse.connection._dataRecv(test_utils.createRequest(presence)); _converse.connection._dataRecv(test_utils.createRequest(presence));
expect(chat_content.querySelectorAll('div.chat-info').length).toBe(4); expect(chat_content.querySelectorAll('div.chat-info').length).toBe(4);
msg_el = sizzle('div.chat-info', chat_content).pop(); msg_el = sizzle('div.chat-info', chat_content).pop();
expect(msg_el.textContent).toBe('newguy has left the groupchat'); expect(msg_el.textContent.trim()).toBe('newguy has left the groupchat');
expect(msg_el.getAttribute('data-leave')).toBe('newguy'); expect(msg_el.getAttribute('data-leave')).toBe('newguy');
presence = $pres({ presence = $pres({
...@@ -797,7 +797,7 @@ ...@@ -797,7 +797,7 @@
}); });
_converse.connection._dataRecv(test_utils.createRequest(presence)); _converse.connection._dataRecv(test_utils.createRequest(presence));
expect(chat_content.querySelectorAll('div.chat-info').length).toBe(5); expect(chat_content.querySelectorAll('div.chat-info').length).toBe(5);
expect(sizzle('div.chat-info:last', chat_content).pop().textContent) expect(sizzle('div.chat-info:last', chat_content).pop().textContent.trim())
.toBe("nomorenicks has entered the groupchat"); .toBe("nomorenicks has entered the groupchat");
presence = $pres({ presence = $pres({
...@@ -812,7 +812,7 @@ ...@@ -812,7 +812,7 @@
}); });
_converse.connection._dataRecv(test_utils.createRequest(presence)); _converse.connection._dataRecv(test_utils.createRequest(presence));
expect(chat_content.querySelectorAll('div.chat-info').length).toBe(5); expect(chat_content.querySelectorAll('div.chat-info').length).toBe(5);
expect(sizzle('div.chat-info:last', chat_content).pop().textContent) expect(sizzle('div.chat-info:last', chat_content).pop().textContent.trim())
.toBe("nomorenicks has entered and left the groupchat"); .toBe("nomorenicks has entered and left the groupchat");
presence = $pres({ presence = $pres({
...@@ -827,7 +827,7 @@ ...@@ -827,7 +827,7 @@
}); });
_converse.connection._dataRecv(test_utils.createRequest(presence)); _converse.connection._dataRecv(test_utils.createRequest(presence));
expect(chat_content.querySelectorAll('div.chat-info').length).toBe(5); expect(chat_content.querySelectorAll('div.chat-info').length).toBe(5);
expect(sizzle('div.chat-info:last', chat_content).pop().textContent) expect(sizzle('div.chat-info:last', chat_content).pop().textContent.trim())
.toBe("nomorenicks has entered the groupchat"); .toBe("nomorenicks has entered the groupchat");
// Test a member joining and leaving // Test a member joining and leaving
...@@ -869,7 +869,7 @@ ...@@ -869,7 +869,7 @@
}); });
_converse.connection._dataRecv(test_utils.createRequest(presence)); _converse.connection._dataRecv(test_utils.createRequest(presence));
expect(chat_content.querySelectorAll('div.chat-info').length).toBe(6); expect(chat_content.querySelectorAll('div.chat-info').length).toBe(6);
expect(sizzle('div.chat-info:last', chat_content).pop().textContent).toBe( expect(sizzle('div.chat-info:last', chat_content).pop().textContent.trim()).toBe(
'insider has entered and left the groupchat. '+ 'insider has entered and left the groupchat. '+
'"Disconnected: Replaced by new connection"'); '"Disconnected: Replaced by new connection"');
...@@ -891,7 +891,7 @@ ...@@ -891,7 +891,7 @@
_converse.connection._dataRecv(test_utils.createRequest(presence)); _converse.connection._dataRecv(test_utils.createRequest(presence));
expect(chat_content.querySelectorAll('div.chat-info').length).toBe(6); expect(chat_content.querySelectorAll('div.chat-info').length).toBe(6);
expect(sizzle('div.chat-info:last', chat_content).pop().textContent).toBe("newgirl has entered and left the groupchat"); expect(sizzle('div.chat-info:last', chat_content).pop().textContent.trim()).toBe("newgirl has entered and left the groupchat");
expect(view.model.occupants.length).toBe(4); expect(view.model.occupants.length).toBe(4);
done(); done();
})); }));
...@@ -906,7 +906,7 @@ ...@@ -906,7 +906,7 @@
const chat_content = view.el.querySelector('.chat-content'); const chat_content = view.el.querySelector('.chat-content');
expect(sizzle('div.chat-info', chat_content).length).toBe(1); expect(sizzle('div.chat-info', chat_content).length).toBe(1);
expect(sizzle('div.chat-info:last', chat_content).pop().textContent).toBe("romeo has entered the groupchat"); expect(sizzle('div.chat-info:last', chat_content).pop().textContent.trim()).toBe("romeo has entered the groupchat");
let presence = u.toStanza( let presence = u.toStanza(
`<presence xmlns="jabber:client" to="romeo@montague.lit/orchard" from="coven@chat.shakespeare.lit/fabio"> `<presence xmlns="jabber:client" to="romeo@montague.lit/orchard" from="coven@chat.shakespeare.lit/fabio">
...@@ -917,7 +917,7 @@ ...@@ -917,7 +917,7 @@
</presence>`); </presence>`);
_converse.connection._dataRecv(test_utils.createRequest(presence)); _converse.connection._dataRecv(test_utils.createRequest(presence));
expect(sizzle('div.chat-info', chat_content).length).toBe(2); expect(sizzle('div.chat-info', chat_content).length).toBe(2);
expect(sizzle('div.chat-info:last', chat_content).pop().textContent).toBe("fabio has entered the groupchat"); expect(sizzle('div.chat-info:last', chat_content).pop().textContent.trim()).toBe("fabio has entered the groupchat");
presence = u.toStanza( presence = u.toStanza(
`<presence xmlns="jabber:client" to="romeo@montague.lit/orchard" from="coven@chat.shakespeare.lit/Dele Olajide"> `<presence xmlns="jabber:client" to="romeo@montague.lit/orchard" from="coven@chat.shakespeare.lit/Dele Olajide">
...@@ -927,7 +927,7 @@ ...@@ -927,7 +927,7 @@
</presence>`); </presence>`);
_converse.connection._dataRecv(test_utils.createRequest(presence)); _converse.connection._dataRecv(test_utils.createRequest(presence));
expect(sizzle('div.chat-info', chat_content).length).toBe(3); expect(sizzle('div.chat-info', chat_content).length).toBe(3);
expect(sizzle('div.chat-info:last', chat_content).pop().textContent).toBe("Dele Olajide has entered the groupchat"); expect(sizzle('div.chat-info:last', chat_content).pop().textContent.trim()).toBe("Dele Olajide has entered the groupchat");
presence = u.toStanza( presence = u.toStanza(
`<presence xmlns="jabber:client" to="romeo@montague.lit/orchard" from="coven@chat.shakespeare.lit/jcbrand"> `<presence xmlns="jabber:client" to="romeo@montague.lit/orchard" from="coven@chat.shakespeare.lit/jcbrand">
...@@ -938,7 +938,7 @@ ...@@ -938,7 +938,7 @@
</presence>`); </presence>`);
_converse.connection._dataRecv(test_utils.createRequest(presence)); _converse.connection._dataRecv(test_utils.createRequest(presence));
expect(sizzle('div.chat-info', chat_content).length).toBe(4); expect(sizzle('div.chat-info', chat_content).length).toBe(4);
expect(sizzle('div.chat-info:last', chat_content).pop().textContent).toBe("jcbrand has entered the groupchat"); expect(sizzle('div.chat-info:last', chat_content).pop().textContent.trim()).toBe("jcbrand has entered the groupchat");
presence = u.toStanza( presence = u.toStanza(
`<presence xmlns="jabber:client" to="romeo@montague.lit/orchard" type="unavailable" from="coven@chat.shakespeare.lit/Dele Olajide"> `<presence xmlns="jabber:client" to="romeo@montague.lit/orchard" type="unavailable" from="coven@chat.shakespeare.lit/Dele Olajide">
...@@ -948,7 +948,7 @@ ...@@ -948,7 +948,7 @@
</presence>`); </presence>`);
_converse.connection._dataRecv(test_utils.createRequest(presence)); _converse.connection._dataRecv(test_utils.createRequest(presence));
expect(sizzle('div.chat-info', chat_content).length).toBe(4); expect(sizzle('div.chat-info', chat_content).length).toBe(4);
expect(sizzle('div.chat-info:last', chat_content).pop().textContent).toBe("Dele Olajide has entered and left the groupchat"); expect(sizzle('div.chat-info:last', chat_content).pop().textContent.trim()).toBe("Dele Olajide has entered and left the groupchat");
presence = u.toStanza( presence = u.toStanza(
`<presence xmlns="jabber:client" to="romeo@montague.lit/orchard" from="coven@chat.shakespeare.lit/Dele Olajide"> `<presence xmlns="jabber:client" to="romeo@montague.lit/orchard" from="coven@chat.shakespeare.lit/Dele Olajide">
...@@ -958,7 +958,7 @@ ...@@ -958,7 +958,7 @@
</presence>`); </presence>`);
_converse.connection._dataRecv(test_utils.createRequest(presence)); _converse.connection._dataRecv(test_utils.createRequest(presence));
expect(sizzle('div.chat-info', chat_content).length).toBe(4); expect(sizzle('div.chat-info', chat_content).length).toBe(4);
expect(sizzle('div.chat-info:last', chat_content).pop().textContent).toBe("Dele Olajide has entered the groupchat"); expect(sizzle('div.chat-info:last', chat_content).pop().textContent.trim()).toBe("Dele Olajide has entered the groupchat");
presence = u.toStanza( presence = u.toStanza(
`<presence xmlns="jabber:client" to="romeo@montague.lit/orchard" from="coven@chat.shakespeare.lit/fuvuv" xml:lang="en"> `<presence xmlns="jabber:client" to="romeo@montague.lit/orchard" from="coven@chat.shakespeare.lit/fuvuv" xml:lang="en">
...@@ -970,7 +970,7 @@ ...@@ -970,7 +970,7 @@
</presence>`); </presence>`);
_converse.connection._dataRecv(test_utils.createRequest(presence)); _converse.connection._dataRecv(test_utils.createRequest(presence));
expect(sizzle('div.chat-info', chat_content).length).toBe(5); expect(sizzle('div.chat-info', chat_content).length).toBe(5);
expect(sizzle('div.chat-info:last', chat_content).pop().textContent).toBe("fuvuv has entered the groupchat"); expect(sizzle('div.chat-info:last', chat_content).pop().textContent.trim()).toBe("fuvuv has entered the groupchat");
presence = u.toStanza( presence = u.toStanza(
`<presence xmlns="jabber:client" to="romeo@montague.lit/orchard" type="unavailable" from="coven@chat.shakespeare.lit/fuvuv"> `<presence xmlns="jabber:client" to="romeo@montague.lit/orchard" type="unavailable" from="coven@chat.shakespeare.lit/fuvuv">
...@@ -980,7 +980,7 @@ ...@@ -980,7 +980,7 @@
</presence>`); </presence>`);
_converse.connection._dataRecv(test_utils.createRequest(presence)); _converse.connection._dataRecv(test_utils.createRequest(presence));
expect(sizzle('div.chat-info', chat_content).length).toBe(5); expect(sizzle('div.chat-info', chat_content).length).toBe(5);
expect(sizzle('div.chat-info:last', chat_content).pop().textContent).toBe("fuvuv has entered and left the groupchat"); expect(sizzle('div.chat-info:last', chat_content).pop().textContent.trim()).toBe("fuvuv has entered and left the groupchat");
presence = u.toStanza( presence = u.toStanza(
`<presence xmlns="jabber:client" to="romeo@montague.lit/orchard" type="unavailable" from="coven@chat.shakespeare.lit/fabio"> `<presence xmlns="jabber:client" to="romeo@montague.lit/orchard" type="unavailable" from="coven@chat.shakespeare.lit/fabio">
...@@ -991,7 +991,7 @@ ...@@ -991,7 +991,7 @@
</presence>`); </presence>`);
_converse.connection._dataRecv(test_utils.createRequest(presence)); _converse.connection._dataRecv(test_utils.createRequest(presence));
expect(sizzle('div.chat-info', chat_content).length).toBe(5); expect(sizzle('div.chat-info', chat_content).length).toBe(5);
expect(sizzle('div.chat-info:last', chat_content).pop().textContent).toBe( expect(sizzle('div.chat-info:last', chat_content).pop().textContent.trim()).toBe(
`fabio has entered and left the groupchat. "Disconnected: Replaced by new connection"`); `fabio has entered and left the groupchat. "Disconnected: Replaced by new connection"`);
presence = u.toStanza( presence = u.toStanza(
...@@ -1004,7 +1004,7 @@ ...@@ -1004,7 +1004,7 @@
</presence>`); </presence>`);
_converse.connection._dataRecv(test_utils.createRequest(presence)); _converse.connection._dataRecv(test_utils.createRequest(presence));
expect(sizzle('div.chat-info', chat_content).length).toBe(5); expect(sizzle('div.chat-info', chat_content).length).toBe(5);
expect(sizzle('div.chat-info:last', chat_content).pop().textContent).toBe( expect(sizzle('div.chat-info:last', chat_content).pop().textContent.trim()).toBe(
`fabio has entered the groupchat. "Ready for a new day"`); `fabio has entered the groupchat. "Ready for a new day"`);
// XXX: hack so that we can test leave/enter of occupants // XXX: hack so that we can test leave/enter of occupants
...@@ -1020,7 +1020,7 @@ ...@@ -1020,7 +1020,7 @@
</presence>`); </presence>`);
_converse.connection._dataRecv(test_utils.createRequest(presence)); _converse.connection._dataRecv(test_utils.createRequest(presence));
expect(sizzle('div.chat-info', chat_content).length).toBe(1); expect(sizzle('div.chat-info', chat_content).length).toBe(1);
expect(sizzle('div.chat-info:last', chat_content).pop().textContent).toBe( expect(sizzle('div.chat-info:last', chat_content).pop().textContent.trim()).toBe(
`fabio has left the groupchat. "Disconnected: closed"`); `fabio has left the groupchat. "Disconnected: closed"`);
presence = u.toStanza( presence = u.toStanza(
...@@ -1031,7 +1031,7 @@ ...@@ -1031,7 +1031,7 @@
</presence>`); </presence>`);
_converse.connection._dataRecv(test_utils.createRequest(presence)); _converse.connection._dataRecv(test_utils.createRequest(presence));
expect(sizzle('div.chat-info', chat_content).length).toBe(2); expect(sizzle('div.chat-info', chat_content).length).toBe(2);
expect(sizzle('div.chat-info:last', chat_content).pop().textContent).toBe( expect(sizzle('div.chat-info:last', chat_content).pop().textContent.trim()).toBe(
`Dele Olajide has left the groupchat`); `Dele Olajide has left the groupchat`);
presence = u.toStanza( presence = u.toStanza(
...@@ -1043,7 +1043,7 @@ ...@@ -1043,7 +1043,7 @@
</presence>`); </presence>`);
_converse.connection._dataRecv(test_utils.createRequest(presence)); _converse.connection._dataRecv(test_utils.createRequest(presence));
expect(sizzle('div.chat-info', chat_content).length).toBe(2); expect(sizzle('div.chat-info', chat_content).length).toBe(2);
expect(sizzle('div.chat-info:last', chat_content).pop().textContent).toBe( expect(sizzle('div.chat-info:last', chat_content).pop().textContent.trim()).toBe(
`fabio has left and re-entered the groupchat`); `fabio has left and re-entered the groupchat`);
done(); done();
})); }));
...@@ -1056,7 +1056,7 @@ ...@@ -1056,7 +1056,7 @@
await test_utils.openAndEnterChatRoom(_converse, 'coven@chat.shakespeare.lit', 'some1'); await test_utils.openAndEnterChatRoom(_converse, 'coven@chat.shakespeare.lit', 'some1');
const view = _converse.chatboxviews.get('coven@chat.shakespeare.lit'); const view = _converse.chatboxviews.get('coven@chat.shakespeare.lit');
const chat_content = view.el.querySelector('.chat-content'); const chat_content = view.el.querySelector('.chat-content');
expect(sizzle('div.chat-info', chat_content).pop().textContent).toBe('some1 has entered the groupchat'); expect(sizzle('div.chat-info', chat_content).pop().textContent.trim()).toBe('some1 has entered the groupchat');
let presence = $pres({ let presence = $pres({
to: 'romeo@montague.lit/orchard', to: 'romeo@montague.lit/orchard',
...@@ -1069,7 +1069,7 @@ ...@@ -1069,7 +1069,7 @@
}); });
_converse.connection._dataRecv(test_utils.createRequest(presence)); _converse.connection._dataRecv(test_utils.createRequest(presence));
expect(chat_content.querySelectorAll('div.chat-info').length).toBe(2); expect(chat_content.querySelectorAll('div.chat-info').length).toBe(2);
expect(sizzle('div.chat-info', chat_content).pop().textContent).toBe('newguy has entered the groupchat'); expect(sizzle('div.chat-info', chat_content).pop().textContent.trim()).toBe('newguy has entered the groupchat');
presence = $pres({ presence = $pres({
to: 'romeo@montague.lit/orchard', to: 'romeo@montague.lit/orchard',
...@@ -1085,7 +1085,7 @@ ...@@ -1085,7 +1085,7 @@
}); });
_converse.connection._dataRecv(test_utils.createRequest(presence)); _converse.connection._dataRecv(test_utils.createRequest(presence));
expect(chat_content.querySelectorAll('div.chat-info').length).toBe(2); expect(chat_content.querySelectorAll('div.chat-info').length).toBe(2);
expect(sizzle('div.chat-info', chat_content).pop().textContent).toBe('newguy has entered and left the groupchat'); expect(sizzle('div.chat-info', chat_content).pop().textContent.trim()).toBe('newguy has entered and left the groupchat');
presence = u.toStanza( presence = u.toStanza(
`<presence xmlns="jabber:client" to="romeo@montague.lit/orchard" from="coven@chat.shakespeare.lit/fabio"> `<presence xmlns="jabber:client" to="romeo@montague.lit/orchard" from="coven@chat.shakespeare.lit/fabio">
...@@ -1097,7 +1097,7 @@ ...@@ -1097,7 +1097,7 @@
</presence>`); </presence>`);
_converse.connection._dataRecv(test_utils.createRequest(presence)); _converse.connection._dataRecv(test_utils.createRequest(presence));
expect(sizzle('div.chat-info:last', chat_content).pop().textContent).toBe(`fabio has entered the groupchat`); expect(sizzle('div.chat-info:last', chat_content).pop().textContent.trim()).toBe(`fabio has entered the groupchat`);
presence = u.toStanza( presence = u.toStanza(
`<presence xmlns="jabber:client" to="romeo@montague.lit/orchard" from="coven@chat.shakespeare.lit/Dele Olajide"> `<presence xmlns="jabber:client" to="romeo@montague.lit/orchard" from="coven@chat.shakespeare.lit/Dele Olajide">
...@@ -1107,7 +1107,7 @@ ...@@ -1107,7 +1107,7 @@
</presence>`); </presence>`);
_converse.connection._dataRecv(test_utils.createRequest(presence)); _converse.connection._dataRecv(test_utils.createRequest(presence));
expect(sizzle('div.chat-info', chat_content).length).toBe(4); expect(sizzle('div.chat-info', chat_content).length).toBe(4);
expect(sizzle('div.chat-info:last', chat_content).pop().textContent).toBe("Dele Olajide has entered the groupchat"); expect(sizzle('div.chat-info:last', chat_content).pop().textContent.trim()).toBe("Dele Olajide has entered the groupchat");
await test_utils.sendMessage(view, 'hello world'); await test_utils.sendMessage(view, 'hello world');
presence = u.toStanza( presence = u.toStanza(
...@@ -1119,7 +1119,7 @@ ...@@ -1119,7 +1119,7 @@
</presence>`); </presence>`);
_converse.connection._dataRecv(test_utils.createRequest(presence)); _converse.connection._dataRecv(test_utils.createRequest(presence));
expect(sizzle('div.chat-info', chat_content).length).toBe(5); expect(sizzle('div.chat-info', chat_content).length).toBe(5);
expect(sizzle('div.chat-info:last', chat_content).pop().textContent).toBe(`Dele Olajide has left the groupchat`); expect(sizzle('div.chat-info:last', chat_content).pop().textContent.trim()).toBe(`Dele Olajide has left the groupchat`);
done(); done();
})); }));
...@@ -1178,9 +1178,9 @@ ...@@ -1178,9 +1178,9 @@
const chat_content = view.el.querySelector('.chat-content'); const chat_content = view.el.querySelector('.chat-content');
const messages = chat_content.querySelectorAll('div.chat-info'); const messages = chat_content.querySelectorAll('div.chat-info');
expect(messages.length).toBe(3); expect(messages.length).toBe(3);
expect(messages[0].textContent).toBe('romeo has entered the groupchat'); expect(messages[0].textContent.trim()).toBe('romeo has entered the groupchat');
expect(messages[1].textContent).toBe('Guus has entered the groupchat'); expect(messages[1].textContent.trim()).toBe('Guus has entered the groupchat');
expect(messages[2].textContent).toBe('Guus has left and re-entered the groupchat'); expect(messages[2].textContent.trim()).toBe('Guus has left and re-entered the groupchat');
done(); done();
})); }));
...@@ -1197,9 +1197,9 @@ ...@@ -1197,9 +1197,9 @@
expect(indicator).not.toBe(null); expect(indicator).not.toBe(null);
expect(indicator.getAttribute('class')).toEqual('message date-separator'); expect(indicator.getAttribute('class')).toEqual('message date-separator');
expect(indicator.getAttribute('data-isodate')).toEqual(dayjs().startOf('day').toISOString()); expect(indicator.getAttribute('data-isodate')).toEqual(dayjs().startOf('day').toISOString());
expect(indicator.querySelector('time').textContent).toEqual(dayjs().startOf('day').format("dddd MMM Do YYYY")); expect(indicator.querySelector('time').textContent.trim()).toEqual(dayjs().startOf('day').format("dddd MMM Do YYYY"));
expect(chat_content.querySelectorAll('div.chat-info').length).toBe(1); expect(chat_content.querySelectorAll('div.chat-info').length).toBe(1);
expect(chat_content.querySelector('div.chat-info').textContent).toBe("romeo has entered the groupchat"); expect(chat_content.querySelector('div.chat-info').textContent.trim()).toBe("romeo has entered the groupchat");
const baseTime = new Date(); const baseTime = new Date();
jasmine.clock().install(); jasmine.clock().install();
...@@ -1232,9 +1232,9 @@ ...@@ -1232,9 +1232,9 @@
expect(indicator.getAttribute('class')).toEqual('message date-separator'); expect(indicator.getAttribute('class')).toEqual('message date-separator');
expect(indicator.getAttribute('data-isodate')).toEqual(dayjs().startOf('day').toISOString()); expect(indicator.getAttribute('data-isodate')).toEqual(dayjs().startOf('day').toISOString());
expect(indicator.querySelector('time').getAttribute('class')).toEqual('separator-text'); expect(indicator.querySelector('time').getAttribute('class')).toEqual('separator-text');
expect(indicator.querySelector('time').textContent).toEqual(dayjs().startOf('day').format("dddd MMM Do YYYY")); expect(indicator.querySelector('time').textContent.trim()).toEqual(dayjs().startOf('day').format("dddd MMM Do YYYY"));
expect(chat_content.querySelectorAll('div.chat-info').length).toBe(2); expect(chat_content.querySelectorAll('div.chat-info').length).toBe(2);
expect(chat_content.querySelector('div.chat-info:last-child').textContent).toBe( expect(chat_content.querySelector('div.chat-info:last-child').textContent.trim()).toBe(
"some1 has entered the groupchat" "some1 has entered the groupchat"
); );
...@@ -1261,9 +1261,9 @@ ...@@ -1261,9 +1261,9 @@
expect(indicator.getAttribute('class')).toEqual('message date-separator'); expect(indicator.getAttribute('class')).toEqual('message date-separator');
expect(indicator.getAttribute('data-isodate')).toEqual(dayjs().startOf('day').toISOString()); expect(indicator.getAttribute('data-isodate')).toEqual(dayjs().startOf('day').toISOString());
expect(indicator.querySelector('time').textContent).toEqual(dayjs().startOf('day').format("dddd MMM Do YYYY")); expect(indicator.querySelector('time').textContent.trim()).toEqual(dayjs().startOf('day').format("dddd MMM Do YYYY"));
expect(chat_content.querySelectorAll('div.chat-info').length).toBe(3); expect(chat_content.querySelectorAll('div.chat-info').length).toBe(3);
expect(sizzle('div.chat-info:last', chat_content).pop().textContent).toBe( expect(sizzle('div.chat-info:last', chat_content).pop().textContent.trim()).toBe(
'some1 has left the groupchat. '+ 'some1 has left the groupchat. '+
'"Disconnected: Replaced by new connection"'); '"Disconnected: Replaced by new connection"');
...@@ -1297,9 +1297,9 @@ ...@@ -1297,9 +1297,9 @@
indicator = sizzle('.date-separator:eq(3)', chat_content).pop(); indicator = sizzle('.date-separator:eq(3)', chat_content).pop();
expect(indicator.getAttribute('class')).toEqual('message date-separator'); expect(indicator.getAttribute('class')).toEqual('message date-separator');
expect(indicator.getAttribute('data-isodate')).toEqual(dayjs().startOf('day').toISOString()); expect(indicator.getAttribute('data-isodate')).toEqual(dayjs().startOf('day').toISOString());
expect(indicator.querySelector('time').textContent).toEqual(dayjs().startOf('day').format("dddd MMM Do YYYY")); expect(indicator.querySelector('time').textContent.trim()).toEqual(dayjs().startOf('day').format("dddd MMM Do YYYY"));
expect(chat_content.querySelectorAll('div.chat-info').length).toBe(4); expect(chat_content.querySelectorAll('div.chat-info').length).toBe(4);
expect(sizzle('div.chat-info:last', chat_content).pop().textContent) expect(sizzle('div.chat-info:last', chat_content).pop().textContent.trim())
.toBe("newguy has entered the groupchat"); .toBe("newguy has entered the groupchat");
jasmine.clock().tick(ONE_DAY_LATER); jasmine.clock().tick(ONE_DAY_LATER);
...@@ -1337,9 +1337,9 @@ ...@@ -1337,9 +1337,9 @@
indicator = sizzle('.date-separator:eq(5)', chat_content).pop(); indicator = sizzle('.date-separator:eq(5)', chat_content).pop();
expect(indicator.getAttribute('class')).toEqual('message date-separator'); expect(indicator.getAttribute('class')).toEqual('message date-separator');
expect(indicator.getAttribute('data-isodate')).toEqual(dayjs().startOf('day').toISOString()); expect(indicator.getAttribute('data-isodate')).toEqual(dayjs().startOf('day').toISOString());
expect(indicator.querySelector('time').textContent).toEqual(dayjs().startOf('day').format("dddd MMM Do YYYY")); expect(indicator.querySelector('time').textContent.trim()).toEqual(dayjs().startOf('day').format("dddd MMM Do YYYY"));
expect(chat_content.querySelectorAll('div.chat-info').length).toBe(5); expect(chat_content.querySelectorAll('div.chat-info').length).toBe(5);
expect(sizzle('div.chat-info:last', chat_content).pop().textContent).toBe( expect(sizzle('div.chat-info:last', chat_content).pop().textContent.trim()).toBe(
'newguy has left the groupchat. '+ 'newguy has left the groupchat. '+
'"Disconnected: Replaced by new connection"'); '"Disconnected: Replaced by new connection"');
jasmine.clock().uninstall(); jasmine.clock().uninstall();
...@@ -1371,7 +1371,7 @@ ...@@ -1371,7 +1371,7 @@
await view.model.onMessage(msg); await view.model.onMessage(msg);
await new Promise((resolve, reject) => view.once('messageInserted', resolve)); await new Promise((resolve, reject) => view.once('messageInserted', resolve));
expect(_.includes(view.el.querySelector('.chat-msg__author').textContent, '**Dyon van de Wege')).toBeTruthy(); expect(_.includes(view.el.querySelector('.chat-msg__author').textContent, '**Dyon van de Wege')).toBeTruthy();
expect(view.el.querySelector('.chat-msg__text').textContent).toBe('is tired'); expect(view.el.querySelector('.chat-msg__text').textContent.trim()).toBe('is tired');
message = '/me is as well'; message = '/me is as well';
msg = $msg({ msg = $msg({
...@@ -1383,7 +1383,7 @@ ...@@ -1383,7 +1383,7 @@
await view.model.onMessage(msg); await view.model.onMessage(msg);
await new Promise((resolve, reject) => view.once('messageInserted', resolve)); await new Promise((resolve, reject) => view.once('messageInserted', resolve));
expect(_.includes(sizzle('.chat-msg__author:last', view.el).pop().textContent, '**Romeo Montague')).toBeTruthy(); expect(_.includes(sizzle('.chat-msg__author:last', view.el).pop().textContent, '**Romeo Montague')).toBeTruthy();
expect(sizzle('.chat-msg__text:last', view.el).pop().textContent).toBe('is as well'); expect(sizzle('.chat-msg__text:last', view.el).pop().textContent.trim()).toBe('is as well');
done(); done();
})); }));
...@@ -1600,10 +1600,10 @@ ...@@ -1600,10 +1600,10 @@
view.el.querySelector('input[type="submit"]').click(); view.el.querySelector('input[type="submit"]').click();
const sent_stanza = sent_IQ.nodeTree; const sent_stanza = sent_IQ.nodeTree;
expect(sent_stanza.querySelector('field[var="muc#roomconfig_membersonly"] value').textContent).toBe('1'); expect(sent_stanza.querySelector('field[var="muc#roomconfig_membersonly"] value').textContent.trim()).toBe('1');
expect(sent_stanza.querySelector('field[var="muc#roomconfig_moderatedroom"] value').textContent).toBe('1'); expect(sent_stanza.querySelector('field[var="muc#roomconfig_moderatedroom"] value').textContent.trim()).toBe('1');
expect(sent_stanza.querySelector('field[var="muc#roomconfig_allowpm"] value').textContent).toBe('moderators'); expect(sent_stanza.querySelector('field[var="muc#roomconfig_allowpm"] value').textContent.trim()).toBe('moderators');
expect(sent_stanza.querySelector('field[var="muc#roomconfig_presencebroadcast"] value').textContent).toBe('moderator'); expect(sent_stanza.querySelector('field[var="muc#roomconfig_presencebroadcast"] value').textContent.trim()).toBe('moderator');
done(); done();
})); }));
...@@ -1797,8 +1797,8 @@ ...@@ -1797,8 +1797,8 @@
expect(occupants.length).toBe(1); expect(occupants.length).toBe(1);
expect(occupants[0].querySelector('.occupant-nick').textContent.trim()).toBe("romeo"); expect(occupants[0].querySelector('.occupant-nick').textContent.trim()).toBe("romeo");
expect(occupants[0].querySelectorAll('.badge').length).toBe(2); expect(occupants[0].querySelectorAll('.badge').length).toBe(2);
expect(occupants[0].querySelectorAll('.badge')[0].textContent).toBe('Owner'); expect(occupants[0].querySelectorAll('.badge')[0].textContent.trim()).toBe('Owner');
expect(sizzle('.badge:last', occupants[0]).pop().textContent).toBe('Moderator'); expect(sizzle('.badge:last', occupants[0]).pop().textContent.trim()).toBe('Moderator');
var presence = $pres({ var presence = $pres({
to:'romeo@montague.lit/pda', to:'romeo@montague.lit/pda',
...@@ -1818,8 +1818,8 @@ ...@@ -1818,8 +1818,8 @@
expect(occupants[0].querySelector('.occupant-nick').textContent.trim()).toBe("moderatorman"); expect(occupants[0].querySelector('.occupant-nick').textContent.trim()).toBe("moderatorman");
expect(occupants[1].querySelector('.occupant-nick').textContent.trim()).toBe("romeo"); expect(occupants[1].querySelector('.occupant-nick').textContent.trim()).toBe("romeo");
expect(occupants[0].querySelectorAll('.badge').length).toBe(2); expect(occupants[0].querySelectorAll('.badge').length).toBe(2);
expect(occupants[0].querySelectorAll('.badge')[0].textContent).toBe('Admin'); expect(occupants[0].querySelectorAll('.badge')[0].textContent.trim()).toBe('Admin');
expect(occupants[0].querySelectorAll('.badge')[1].textContent).toBe('Moderator'); expect(occupants[0].querySelectorAll('.badge')[1].textContent.trim()).toBe('Moderator');
expect(occupants[0].getAttribute('title')).toBe( expect(occupants[0].getAttribute('title')).toBe(
contact_jid + ' This user is a moderator. Click to mention moderatorman in your message.' contact_jid + ' This user is a moderator. Click to mention moderatorman in your message.'
...@@ -1842,7 +1842,7 @@ ...@@ -1842,7 +1842,7 @@
expect(occupants.length).toBe(3); expect(occupants.length).toBe(3);
expect(occupants[2].querySelector('.occupant-nick').textContent.trim()).toBe("visitorwoman"); expect(occupants[2].querySelector('.occupant-nick').textContent.trim()).toBe("visitorwoman");
expect(occupants[2].querySelectorAll('.badge').length).toBe(1); expect(occupants[2].querySelectorAll('.badge').length).toBe(1);
expect(sizzle('.badge', occupants[2]).pop().textContent).toBe('Visitor'); expect(sizzle('.badge', occupants[2]).pop().textContent.trim()).toBe('Visitor');
expect(occupants[2].getAttribute('title')).toBe( expect(occupants[2].getAttribute('title')).toBe(
contact_jid + ' This user can NOT send messages in this groupchat. Click to mention visitorwoman in your message.' contact_jid + ' This user can NOT send messages in this groupchat. Click to mention visitorwoman in your message.'
); );
...@@ -1869,9 +1869,9 @@ ...@@ -1869,9 +1869,9 @@
const view = _converse.chatboxviews.get('problematic@muc.montague.lit'); const view = _converse.chatboxviews.get('problematic@muc.montague.lit');
spyOn(view, 'showErrorMessage').and.callThrough(); spyOn(view, 'showErrorMessage').and.callThrough();
_converse.connection._dataRecv(test_utils.createRequest(presence)); _converse.connection._dataRecv(test_utils.createRequest(presence));
expect(view.el.querySelector('.chatroom-body .disconnect-msg').textContent) expect(view.el.querySelector('.chatroom-body .disconnect-msg').textContent.trim())
.toBe('This groupchat no longer exists'); .toBe('This groupchat no longer exists');
expect(view.el.querySelector('.chatroom-body .destroyed-reason').textContent) expect(view.el.querySelector('.chatroom-body .destroyed-reason').textContent.trim())
.toBe(`"We didn't like the name"`); .toBe(`"We didn't like the name"`);
expect(view.el.querySelector('.chatroom-body .moved-label').textContent.trim()) expect(view.el.querySelector('.chatroom-body .moved-label').textContent.trim())
.toBe('The conversation has moved. Click below to enter.'); .toBe('The conversation has moved. Click below to enter.');
...@@ -1971,7 +1971,7 @@ ...@@ -1971,7 +1971,7 @@
_converse.connection._dataRecv(test_utils.createRequest(presence)); _converse.connection._dataRecv(test_utils.createRequest(presence));
await u.waitUntil(() => view.el.querySelectorAll('.chat-content .chat-info').length === 2); await u.waitUntil(() => view.el.querySelectorAll('.chat-content .chat-info').length === 2);
const info_text = sizzle('.chat-content .chat-info:first', view.el).pop().textContent; const info_text = sizzle('.chat-content .chat-info:first', view.el).pop().textContent.trim();
expect(info_text).toBe('Your nickname has been automatically set to thirdwitch'); expect(info_text).toBe('Your nickname has been automatically set to thirdwitch');
done(); done();
})); }));
...@@ -2022,7 +2022,7 @@ ...@@ -2022,7 +2022,7 @@
spyOn(_converse.connection, 'send').and.callFake(stanza => (sent_stanza = stanza)); spyOn(_converse.connection, 'send').and.callFake(stanza => (sent_stanza = stanza));
const hint = await u.waitUntil(() => view.el.querySelector('.suggestion-box__results li')); const hint = await u.waitUntil(() => view.el.querySelector('.suggestion-box__results li'));
expect(input.value).toBe('Balt'); expect(input.value).toBe('Balt');
expect(hint.textContent).toBe('Balthasar'); expect(hint.textContent.trim()).toBe('Balthasar');
evt = new Event('mousedown', {'bubbles': true}); evt = new Event('mousedown', {'bubbles': true});
evt.button = 0; evt.button = 0;
...@@ -2101,7 +2101,7 @@ ...@@ -2101,7 +2101,7 @@
await new Promise((resolve, reject) => view.once('messageInserted', resolve)); await new Promise((resolve, reject) => view.once('messageInserted', resolve));
const chat_content = view.el.querySelector('.chat-content'); const chat_content = view.el.querySelector('.chat-content');
expect(chat_content.querySelectorAll('.chat-msg').length).toBe(1); expect(chat_content.querySelectorAll('.chat-msg').length).toBe(1);
expect(chat_content.querySelector('.chat-msg__text').textContent).toBe(text); expect(chat_content.querySelector('.chat-msg__text').textContent.trim()).toBe(text);
expect(_converse.api.trigger).toHaveBeenCalledWith('message', jasmine.any(Object)); expect(_converse.api.trigger).toHaveBeenCalledWith('message', jasmine.any(Object));
done(); done();
})); }));
...@@ -2146,7 +2146,7 @@ ...@@ -2146,7 +2146,7 @@
</message>`); </message>`);
await view.model.onMessage(stanza); await view.model.onMessage(stanza);
expect(chat_content.querySelectorAll('.chat-msg').length).toBe(1); expect(chat_content.querySelectorAll('.chat-msg').length).toBe(1);
expect(sizzle('.chat-msg__text:last').pop().textContent).toBe(text); expect(sizzle('.chat-msg__text:last').pop().textContent.trim()).toBe(text);
expect(view.model.messages.length).toBe(1); expect(view.model.messages.length).toBe(1);
// We don't emit an event if it's our own message // We don't emit an event if it's our own message
expect(_converse.api.trigger.calls.count(), 1); expect(_converse.api.trigger.calls.count(), 1);
...@@ -2212,9 +2212,9 @@ ...@@ -2212,9 +2212,9 @@
_converse.connection._dataRecv(test_utils.createRequest(stanza)); _converse.connection._dataRecv(test_utils.createRequest(stanza));
const view = _converse.chatboxviews.get('jdev@conference.jabber.org'); const view = _converse.chatboxviews.get('jdev@conference.jabber.org');
await new Promise((resolve, reject) => view.model.once('change:subject', resolve)); await new Promise((resolve, reject) => view.model.once('change:subject', resolve));
expect(sizzle('.chat-event:last').pop().textContent).toBe('Topic set by ralphm'); expect(sizzle('.chat-event:last').pop().textContent.trim()).toBe('Topic set by ralphm');
expect(sizzle('.chat-topic:last').pop().textContent).toBe(text); expect(sizzle('.chat-topic:last').pop().textContent.trim()).toBe(text);
expect(view.el.querySelector('.chatroom-description').textContent).toBe(text); expect(view.el.querySelector('.chatroom-description').textContent.trim()).toBe(text);
stanza = u.toStanza( stanza = u.toStanza(
`<message xmlns="jabber:client" to="jc@opkode.com/_converse.js-60429116" type="groupchat" from="jdev@conference.jabber.org/ralphm"> `<message xmlns="jabber:client" to="jc@opkode.com/_converse.js-60429116" type="groupchat" from="jdev@conference.jabber.org/ralphm">
...@@ -2225,10 +2225,10 @@ ...@@ -2225,10 +2225,10 @@
await new Promise((resolve, reject) => view.once('messageInserted', resolve)); await new Promise((resolve, reject) => view.once('messageInserted', resolve));
expect(sizzle('.chat-topic').length).toBe(1); expect(sizzle('.chat-topic').length).toBe(1);
expect(sizzle('.chat-msg__subject').length).toBe(1); expect(sizzle('.chat-msg__subject').length).toBe(1);
expect(sizzle('.chat-msg__subject').pop().textContent).toBe('This is a message subject'); expect(sizzle('.chat-msg__subject').pop().textContent.trim()).toBe('This is a message subject');
expect(sizzle('.chat-msg__text').length).toBe(1); expect(sizzle('.chat-msg__text').length).toBe(1);
expect(sizzle('.chat-msg__text').pop().textContent).toBe('This is a message'); expect(sizzle('.chat-msg__text').pop().textContent.trim()).toBe('This is a message');
expect(view.el.querySelector('.chatroom-description').textContent).toBe(text); expect(view.el.querySelector('.chatroom-description').textContent.trim()).toBe(text);
done(); done();
})); }));
...@@ -2246,8 +2246,8 @@ ...@@ -2246,8 +2246,8 @@
'author': 'ralphm' 'author': 'ralphm'
}}); }});
const chat_content = view.el.querySelector('.chat-content'); const chat_content = view.el.querySelector('.chat-content');
expect(sizzle('.chat-event:last').pop().textContent).toBe('Topic set by ralphm'); expect(sizzle('.chat-event:last').pop().textContent.trim()).toBe('Topic set by ralphm');
expect(sizzle('.chat-topic:last').pop().textContent).toBe(subject); expect(sizzle('.chat-topic:last').pop().textContent.trim()).toBe(subject);
done(); done();
})); }));
...@@ -2328,8 +2328,8 @@ ...@@ -2328,8 +2328,8 @@
_converse.connection._dataRecv(test_utils.createRequest(stanza)); _converse.connection._dataRecv(test_utils.createRequest(stanza));
await u.waitUntil(() => view.el.querySelectorAll('.chat-content .chat-info').length === 2); await u.waitUntil(() => view.el.querySelectorAll('.chat-content .chat-info').length === 2);
const info_messages = view.el.querySelectorAll('.chat-content .chat-info'); const info_messages = view.el.querySelectorAll('.chat-content .chat-info');
expect(info_messages[0].textContent).toBe('romeo has entered the groupchat'); expect(info_messages[0].textContent.trim()).toBe('romeo has entered the groupchat');
expect(info_messages[1].textContent).toBe('groupchat logging is now enabled'); expect(info_messages[1].textContent.trim()).toBe('groupchat logging is now enabled');
done(); done();
})); }));
...@@ -2386,7 +2386,7 @@ ...@@ -2386,7 +2386,7 @@
expect(occupants.firstElementChild.querySelector('.occupant-nick').textContent.trim()).toBe("oldnick"); expect(occupants.firstElementChild.querySelector('.occupant-nick').textContent.trim()).toBe("oldnick");
expect(chat_content.querySelectorAll('div.chat-info').length).toBe(1); expect(chat_content.querySelectorAll('div.chat-info').length).toBe(1);
expect(sizzle('div.chat-info:first', chat_content).pop().textContent) expect(sizzle('div.chat-info:first', chat_content).pop().textContent.trim())
.toBe("oldnick has entered the groupchat"); .toBe("oldnick has entered the groupchat");
let presence = $pres().attrs({ let presence = $pres().attrs({
...@@ -2408,7 +2408,7 @@ ...@@ -2408,7 +2408,7 @@
_converse.connection._dataRecv(test_utils.createRequest(presence)); _converse.connection._dataRecv(test_utils.createRequest(presence));
await u.waitUntil(() => view.el.querySelectorAll('.chat-info').length === 2); await u.waitUntil(() => view.el.querySelectorAll('.chat-info').length === 2);
expect(sizzle('div.chat-info:last').pop().textContent).toBe( expect(sizzle('div.chat-info:last').pop().textContent.trim()).toBe(
__(_converse.muc.new_nickname_messages["303"], "newnick") __(_converse.muc.new_nickname_messages["303"], "newnick")
); );
expect(view.model.get('connection_status')).toBe(converse.ROOMSTATUS.ENTERED); expect(view.model.get('connection_status')).toBe(converse.ROOMSTATUS.ENTERED);
...@@ -2436,12 +2436,12 @@ ...@@ -2436,12 +2436,12 @@
// that, but that's probably not possible without some // that, but that's probably not possible without some
// significant refactoring. // significant refactoring.
expect(chat_content.querySelectorAll('div.chat-info').length).toBe(3); expect(chat_content.querySelectorAll('div.chat-info').length).toBe(3);
expect(sizzle('div.chat-info', chat_content)[1].textContent).toBe( expect(sizzle('div.chat-info', chat_content)[1].textContent.trim()).toBe(
__(_converse.muc.new_nickname_messages["303"], "newnick") __(_converse.muc.new_nickname_messages["303"], "newnick")
); );
occupants = view.el.querySelector('.occupant-list'); occupants = view.el.querySelector('.occupant-list');
expect(occupants.childNodes.length).toBe(1); expect(occupants.childNodes.length).toBe(1);
expect(sizzle('.occupant-nick:first', occupants).pop().textContent).toBe("newnick"); expect(sizzle('.occupant-nick:first', occupants).pop().textContent.trim()).toBe("newnick");
done(); done();
})); }));
...@@ -2630,7 +2630,7 @@ ...@@ -2630,7 +2630,7 @@
</iq>`); </iq>`);
_converse.connection._dataRecv(test_utils.createRequest(response_el)); _converse.connection._dataRecv(test_utils.createRequest(response_el));
const el = await u.waitUntil(() => document.querySelector('.chatroom-form legend')); const el = await u.waitUntil(() => document.querySelector('.chatroom-form legend'));
expect(el.textContent).toBe("Configuration for room@conference.example.org"); expect(el.textContent.trim()).toBe("Configuration for room@conference.example.org");
sizzle('[name="muc#roomconfig_membersonly"]', chatroomview.el).pop().click(); sizzle('[name="muc#roomconfig_membersonly"]', chatroomview.el).pop().click();
sizzle('[name="muc#roomconfig_roomname"]', chatroomview.el).pop().value = "New room name" sizzle('[name="muc#roomconfig_roomname"]', chatroomview.el).pop().value = "New room name"
chatroomview.el.querySelector('.btn-primary').click(); chatroomview.el.querySelector('.btn-primary').click();
...@@ -2751,7 +2751,7 @@ ...@@ -2751,7 +2751,7 @@
_converse.connection._dataRecv(test_utils.createRequest(message)); _converse.connection._dataRecv(test_utils.createRequest(message));
await u.waitUntil(() => view.el.querySelectorAll('.chat-content .chat-info').length === 3); await u.waitUntil(() => view.el.querySelectorAll('.chat-content .chat-info').length === 3);
const chat_body = view.el.querySelector('.chatroom-body'); const chat_body = view.el.querySelector('.chatroom-body');
expect(sizzle('.message:last', chat_body).pop().textContent) expect(sizzle('.message:last', chat_body).pop().textContent.trim())
.toBe('This groupchat is now no longer anonymous'); .toBe('This groupchat is now no longer anonymous');
done(); done();
})); }));
...@@ -2800,11 +2800,11 @@ ...@@ -2800,11 +2800,11 @@
expect(u.isVisible(view.el.querySelector('.occupants'))).toBeFalsy(); expect(u.isVisible(view.el.querySelector('.occupants'))).toBeFalsy();
const chat_body = view.el.querySelector('.chatroom-body'); const chat_body = view.el.querySelector('.chatroom-body');
expect(chat_body.querySelectorAll('.disconnect-msg').length).toBe(3); expect(chat_body.querySelectorAll('.disconnect-msg').length).toBe(3);
expect(chat_body.querySelector('.disconnect-msg:first-child').textContent).toBe( expect(chat_body.querySelector('.disconnect-msg:first-child').textContent.trim()).toBe(
'You have been kicked from this groupchat'); 'You have been kicked from this groupchat');
expect(chat_body.querySelector('.disconnect-msg:nth-child(2)').textContent).toBe( expect(chat_body.querySelector('.disconnect-msg:nth-child(2)').textContent.trim()).toBe(
'This action was done by Fluellen.'); 'This action was done by Fluellen.');
expect(chat_body.querySelector('.disconnect-msg:nth-child(3)').textContent).toBe( expect(chat_body.querySelector('.disconnect-msg:nth-child(3)').textContent.trim()).toBe(
'The reason given is: "Avaunt, you cullion!".'); 'The reason given is: "Avaunt, you cullion!".');
done(); done();
})); }));
...@@ -2912,7 +2912,7 @@ ...@@ -2912,7 +2912,7 @@
}); });
_converse.connection._dataRecv(test_utils.createRequest(presence)); _converse.connection._dataRecv(test_utils.createRequest(presence));
let info_msgs = Array.prototype.slice.call(view.el.querySelectorAll('.chat-info'), 0); let info_msgs = Array.prototype.slice.call(view.el.querySelectorAll('.chat-info'), 0);
expect(info_msgs.pop().textContent).toBe("annoyingGuy has entered the groupchat"); expect(info_msgs.pop().textContent.trim()).toBe("annoyingGuy has entered the groupchat");
presence = $pres({ presence = $pres({
'from': 'lounge@montague.lit/annoyingGuy', 'from': 'lounge@montague.lit/annoyingGuy',
...@@ -2926,7 +2926,7 @@ ...@@ -2926,7 +2926,7 @@
}); });
_converse.connection._dataRecv(test_utils.createRequest(presence)); _converse.connection._dataRecv(test_utils.createRequest(presence));
info_msgs = Array.prototype.slice.call(view.el.querySelectorAll('.chat-info'), 0); info_msgs = Array.prototype.slice.call(view.el.querySelectorAll('.chat-info'), 0);
expect(info_msgs.pop().textContent).toBe("annoyingGuy has been muted"); expect(info_msgs.pop().textContent.trim()).toBe("annoyingGuy has been muted");
presence = $pres({ presence = $pres({
'from': 'lounge@montague.lit/annoyingGuy', 'from': 'lounge@montague.lit/annoyingGuy',
...@@ -2940,7 +2940,7 @@ ...@@ -2940,7 +2940,7 @@
}); });
_converse.connection._dataRecv(test_utils.createRequest(presence)); _converse.connection._dataRecv(test_utils.createRequest(presence));
info_msgs = Array.prototype.slice.call(view.el.querySelectorAll('.chat-info'), 0); info_msgs = Array.prototype.slice.call(view.el.querySelectorAll('.chat-info'), 0);
expect(info_msgs.pop().textContent).toBe("annoyingGuy has been given a voice"); expect(info_msgs.pop().textContent.trim()).toBe("annoyingGuy has been given a voice");
// Check that we don't see an info message concerning the role, // Check that we don't see an info message concerning the role,
// if the affiliation has changed. // if the affiliation has changed.
...@@ -2956,7 +2956,7 @@ ...@@ -2956,7 +2956,7 @@
}); });
_converse.connection._dataRecv(test_utils.createRequest(presence)); _converse.connection._dataRecv(test_utils.createRequest(presence));
info_msgs = Array.prototype.slice.call(view.el.querySelectorAll('.chat-info'), 0); info_msgs = Array.prototype.slice.call(view.el.querySelectorAll('.chat-info'), 0);
expect(info_msgs.pop().textContent).toBe("annoyingGuy is no longer a member of this groupchat"); expect(info_msgs.pop().textContent.trim()).toBe("annoyingGuy is no longer a member of this groupchat");
done(); done();
})); }));
}); });
...@@ -2982,26 +2982,26 @@ ...@@ -2982,26 +2982,26 @@
let info_messages = Array.prototype.slice.call(view.el.querySelectorAll('.chat-info'), 0); let info_messages = Array.prototype.slice.call(view.el.querySelectorAll('.chat-info'), 0);
expect(info_messages.length).toBe(20); expect(info_messages.length).toBe(20);
expect(info_messages.pop().textContent).toBe('/voice: Allow muted user to post messages'); expect(info_messages.pop().textContent.trim()).toBe('/voice: Allow muted user to post messages');
expect(info_messages.pop().textContent).toBe('/topic: Set groupchat subject (alias for /subject)'); expect(info_messages.pop().textContent.trim()).toBe('/topic: Set groupchat subject (alias for /subject)');
expect(info_messages.pop().textContent).toBe('/subject: Set groupchat subject'); expect(info_messages.pop().textContent.trim()).toBe('/subject: Set groupchat subject');
expect(info_messages.pop().textContent).toBe('/revoke: Revoke the user\'s current affiliation'); expect(info_messages.pop().textContent.trim()).toBe('/revoke: Revoke the user\'s current affiliation');
expect(info_messages.pop().textContent).toBe('/register: Register your nickname'); expect(info_messages.pop().textContent.trim()).toBe('/register: Register your nickname');
expect(info_messages.pop().textContent).toBe('/owner: Grant ownership of this groupchat'); expect(info_messages.pop().textContent.trim()).toBe('/owner: Grant ownership of this groupchat');
expect(info_messages.pop().textContent).toBe('/op: Grant moderator role to user'); expect(info_messages.pop().textContent.trim()).toBe('/op: Grant moderator role to user');
expect(info_messages.pop().textContent).toBe('/nick: Change your nickname'); expect(info_messages.pop().textContent.trim()).toBe('/nick: Change your nickname');
expect(info_messages.pop().textContent).toBe('/mute: Remove user\'s ability to post messages'); expect(info_messages.pop().textContent.trim()).toBe('/mute: Remove user\'s ability to post messages');
expect(info_messages.pop().textContent).toBe('/modtools: Opens up the moderator tools GUI'); expect(info_messages.pop().textContent.trim()).toBe('/modtools: Opens up the moderator tools GUI');
expect(info_messages.pop().textContent).toBe('/member: Grant membership to a user'); expect(info_messages.pop().textContent.trim()).toBe('/member: Grant membership to a user');
expect(info_messages.pop().textContent).toBe('/me: Write in 3rd person'); expect(info_messages.pop().textContent.trim()).toBe('/me: Write in 3rd person');
expect(info_messages.pop().textContent).toBe('/kick: Kick user from groupchat'); expect(info_messages.pop().textContent.trim()).toBe('/kick: Kick user from groupchat');
expect(info_messages.pop().textContent).toBe('/help: Show this menu'); expect(info_messages.pop().textContent.trim()).toBe('/help: Show this menu');
expect(info_messages.pop().textContent).toBe('/destroy: Remove this groupchat'); expect(info_messages.pop().textContent.trim()).toBe('/destroy: Remove this groupchat');
expect(info_messages.pop().textContent).toBe('/deop: Change user role to participant'); expect(info_messages.pop().textContent.trim()).toBe('/deop: Change user role to participant');
expect(info_messages.pop().textContent).toBe('/clear: Clear the chat area'); expect(info_messages.pop().textContent.trim()).toBe('/clear: Clear the chat area');
expect(info_messages.pop().textContent).toBe('/ban: Ban user by changing their affiliation to outcast'); expect(info_messages.pop().textContent.trim()).toBe('/ban: Ban user by changing their affiliation to outcast');
expect(info_messages.pop().textContent).toBe('/admin: Change user\'s affiliation to admin'); expect(info_messages.pop().textContent.trim()).toBe('/admin: Change user\'s affiliation to admin');
expect(info_messages.pop().textContent).toBe('You can run the following commands'); expect(info_messages.pop().textContent.trim()).toBe('You can run the following commands');
const occupant = view.model.occupants.findWhere({'jid': _converse.bare_jid}); const occupant = view.model.occupants.findWhere({'jid': _converse.bare_jid});
occupant.set('affiliation', 'admin'); occupant.set('affiliation', 'admin');
...@@ -3056,24 +3056,24 @@ ...@@ -3056,24 +3056,24 @@
const info_messages = Array.prototype.slice.call(view.el.querySelectorAll('.chat-info'), 0); const info_messages = Array.prototype.slice.call(view.el.querySelectorAll('.chat-info'), 0);
expect(info_messages.length).toBe(18); expect(info_messages.length).toBe(18);
expect(info_messages.pop().textContent).toBe('/topic: Set groupchat subject (alias for /subject)'); expect(info_messages.pop().textContent.trim()).toBe('/topic: Set groupchat subject (alias for /subject)');
expect(info_messages.pop().textContent).toBe('/subject: Set groupchat subject'); expect(info_messages.pop().textContent.trim()).toBe('/subject: Set groupchat subject');
expect(info_messages.pop().textContent).toBe('/revoke: Revoke the user\'s current affiliation'); expect(info_messages.pop().textContent.trim()).toBe('/revoke: Revoke the user\'s current affiliation');
expect(info_messages.pop().textContent).toBe('/register: Register your nickname'); expect(info_messages.pop().textContent.trim()).toBe('/register: Register your nickname');
expect(info_messages.pop().textContent).toBe('/owner: Grant ownership of this groupchat'); expect(info_messages.pop().textContent.trim()).toBe('/owner: Grant ownership of this groupchat');
expect(info_messages.pop().textContent).toBe('/op: Grant moderator role to user'); expect(info_messages.pop().textContent.trim()).toBe('/op: Grant moderator role to user');
expect(info_messages.pop().textContent).toBe('/nick: Change your nickname'); expect(info_messages.pop().textContent.trim()).toBe('/nick: Change your nickname');
expect(info_messages.pop().textContent).toBe('/modtools: Opens up the moderator tools GUI'); expect(info_messages.pop().textContent.trim()).toBe('/modtools: Opens up the moderator tools GUI');
expect(info_messages.pop().textContent).toBe('/member: Grant membership to a user'); expect(info_messages.pop().textContent.trim()).toBe('/member: Grant membership to a user');
expect(info_messages.pop().textContent).toBe('/me: Write in 3rd person'); expect(info_messages.pop().textContent.trim()).toBe('/me: Write in 3rd person');
expect(info_messages.pop().textContent).toBe('/kick: Kick user from groupchat'); expect(info_messages.pop().textContent.trim()).toBe('/kick: Kick user from groupchat');
expect(info_messages.pop().textContent).toBe('/help: Show this menu'); expect(info_messages.pop().textContent.trim()).toBe('/help: Show this menu');
expect(info_messages.pop().textContent).toBe('/destroy: Remove this groupchat'); expect(info_messages.pop().textContent.trim()).toBe('/destroy: Remove this groupchat');
expect(info_messages.pop().textContent).toBe('/deop: Change user role to participant'); expect(info_messages.pop().textContent.trim()).toBe('/deop: Change user role to participant');
expect(info_messages.pop().textContent).toBe('/clear: Clear the chat area'); expect(info_messages.pop().textContent.trim()).toBe('/clear: Clear the chat area');
expect(info_messages.pop().textContent).toBe('/ban: Ban user by changing their affiliation to outcast'); expect(info_messages.pop().textContent.trim()).toBe('/ban: Ban user by changing their affiliation to outcast');
expect(info_messages.pop().textContent).toBe('/admin: Change user\'s affiliation to admin'); expect(info_messages.pop().textContent.trim()).toBe('/admin: Change user\'s affiliation to admin');
expect(info_messages.pop().textContent).toBe('You can run the following commands'); expect(info_messages.pop().textContent.trim()).toBe('You can run the following commands');
done(); done();
})); }));
...@@ -3243,7 +3243,7 @@ ...@@ -3243,7 +3243,7 @@
keyCode: 13 keyCode: 13
}); });
expect(_converse.connection.send).toHaveBeenCalled(); expect(_converse.connection.send).toHaveBeenCalled();
expect(sent_stanza.textContent).toBe('This is the groupchat subject'); expect(sent_stanza.textContent.trim()).toBe('This is the groupchat subject');
// Check /subject // Check /subject
textarea.value = '/subject This is a new subject'; textarea.value = '/subject This is a new subject';
...@@ -3253,7 +3253,7 @@ ...@@ -3253,7 +3253,7 @@
keyCode: 13 keyCode: 13
}); });
expect(sent_stanza.textContent).toBe('This is a new subject'); expect(sent_stanza.textContent.trim()).toBe('This is a new subject');
expect(Strophe.serialize(sent_stanza).toLocaleString()).toBe( expect(Strophe.serialize(sent_stanza).toLocaleString()).toBe(
'<message from="romeo@montague.lit/orchard" to="lounge@montague.lit" type="groupchat" xmlns="jabber:client">'+ '<message from="romeo@montague.lit/orchard" to="lounge@montague.lit" type="groupchat" xmlns="jabber:client">'+
'<subject xmlns="jabber:client">This is a new subject</subject>'+ '<subject xmlns="jabber:client">This is a new subject</subject>'+
...@@ -3266,7 +3266,7 @@ ...@@ -3266,7 +3266,7 @@
preventDefault: function preventDefault () {}, preventDefault: function preventDefault () {},
keyCode: 13 keyCode: 13
}); });
expect(sent_stanza.textContent).toBe('This is yet another subject'); expect(sent_stanza.textContent.trim()).toBe('This is yet another subject');
expect(Strophe.serialize(sent_stanza).toLocaleString()).toBe( expect(Strophe.serialize(sent_stanza).toLocaleString()).toBe(
'<message from="romeo@montague.lit/orchard" to="lounge@montague.lit" type="groupchat" xmlns="jabber:client">'+ '<message from="romeo@montague.lit/orchard" to="lounge@montague.lit" type="groupchat" xmlns="jabber:client">'+
'<subject xmlns="jabber:client">This is yet another subject</subject>'+ '<subject xmlns="jabber:client">This is yet another subject</subject>'+
...@@ -3377,7 +3377,7 @@ ...@@ -3377,7 +3377,7 @@
'role': 'participant' 'role': 'participant'
}); });
_converse.connection._dataRecv(test_utils.createRequest(presence)); _converse.connection._dataRecv(test_utils.createRequest(presence));
expect(view.el.querySelectorAll('.chat-info')[4].textContent).toBe("annoyingGuy is now an owner of this groupchat"); expect(view.el.querySelectorAll('.chat-info')[4].textContent.trim()).toBe("annoyingGuy is now an owner of this groupchat");
done(); done();
})); }));
...@@ -3421,7 +3421,7 @@ ...@@ -3421,7 +3421,7 @@
}); });
expect(view.validateRoleOrAffiliationChangeArgs).toHaveBeenCalled(); expect(view.validateRoleOrAffiliationChangeArgs).toHaveBeenCalled();
expect(view.showErrorMessage).toHaveBeenCalled(); expect(view.showErrorMessage).toHaveBeenCalled();
expect(view.el.querySelector('.message:last-child').textContent).toBe( expect(view.el.querySelector('.message:last-child').textContent.trim()).toBe(
"Error: the \"ban\" command takes two arguments, the user's nickname and optionally a reason."); "Error: the \"ban\" command takes two arguments, the user's nickname and optionally a reason.");
expect(view.model.setAffiliation).not.toHaveBeenCalled(); expect(view.model.setAffiliation).not.toHaveBeenCalled();
...@@ -3457,7 +3457,7 @@ ...@@ -3457,7 +3457,7 @@
'role': 'participant' 'role': 'participant'
}); });
_converse.connection._dataRecv(test_utils.createRequest(presence)); _converse.connection._dataRecv(test_utils.createRequest(presence));
expect(view.el.querySelectorAll('.chat-info')[3].textContent).toBe( expect(view.el.querySelectorAll('.chat-info')[3].textContent.trim()).toBe(
"annoyingGuy has been banned from this groupchat"); "annoyingGuy has been banned from this groupchat");
presence = $pres({ presence = $pres({
...@@ -3475,7 +3475,7 @@ ...@@ -3475,7 +3475,7 @@
textarea.value = '/ban joe22'; textarea.value = '/ban joe22';
view.onFormSubmitted(new Event('submit')); view.onFormSubmitted(new Event('submit'));
expect(view.el.querySelector('.message:last-child').textContent).toBe( expect(view.el.querySelector('.message:last-child').textContent.trim()).toBe(
"Error: couldn't find a groupchat participant based on your arguments"); "Error: couldn't find a groupchat participant based on your arguments");
done(); done();
})); }));
...@@ -3567,7 +3567,7 @@ ...@@ -3567,7 +3567,7 @@
_converse.connection._dataRecv(test_utils.createRequest(presence)); _converse.connection._dataRecv(test_utils.createRequest(presence));
await u.waitUntil(() => view.el.querySelectorAll('.chat-info').length === 4); await u.waitUntil(() => view.el.querySelectorAll('.chat-info').length === 4);
expect(view.el.querySelectorAll('.chat-info')[3].textContent).toBe("annoying guy has been kicked out"); expect(view.el.querySelectorAll('.chat-info')[3].textContent.trim()).toBe("annoying guy has been kicked out");
expect(view.el.querySelectorAll('.chat-info').length).toBe(4); expect(view.el.querySelectorAll('.chat-info').length).toBe(4);
done(); done();
})); }));
...@@ -3615,7 +3615,7 @@ ...@@ -3615,7 +3615,7 @@
}); });
_converse.connection._dataRecv(test_utils.createRequest(presence)); _converse.connection._dataRecv(test_utils.createRequest(presence));
var info_msgs = Array.prototype.slice.call(view.el.querySelectorAll('.chat-info'), 0); var info_msgs = Array.prototype.slice.call(view.el.querySelectorAll('.chat-info'), 0);
expect(info_msgs.pop().textContent).toBe("trustworthyguy has entered the groupchat"); expect(info_msgs.pop().textContent.trim()).toBe("trustworthyguy has entered the groupchat");
var textarea = view.el.querySelector('.chat-textarea') var textarea = view.el.querySelector('.chat-textarea')
textarea.value = '/op'; textarea.value = '/op';
...@@ -3671,7 +3671,7 @@ ...@@ -3671,7 +3671,7 @@
}); });
_converse.connection._dataRecv(test_utils.createRequest(presence)); _converse.connection._dataRecv(test_utils.createRequest(presence));
info_msgs = Array.prototype.slice.call(view.el.querySelectorAll('.chat-info'), 0); info_msgs = Array.prototype.slice.call(view.el.querySelectorAll('.chat-info'), 0);
expect(info_msgs.pop().textContent).toBe("trustworthyguy is now a moderator"); expect(info_msgs.pop().textContent.trim()).toBe("trustworthyguy is now a moderator");
// Call now with the correct amount of arguments. // Call now with the correct amount of arguments.
// XXX: Calling onFormSubmitted directly, trying // XXX: Calling onFormSubmitted directly, trying
// again via triggering Event doesn't work for some weird // again via triggering Event doesn't work for some weird
...@@ -3712,7 +3712,7 @@ ...@@ -3712,7 +3712,7 @@
}); });
_converse.connection._dataRecv(test_utils.createRequest(presence)); _converse.connection._dataRecv(test_utils.createRequest(presence));
info_msgs = Array.prototype.slice.call(view.el.querySelectorAll('.chat-info'), 0); info_msgs = Array.prototype.slice.call(view.el.querySelectorAll('.chat-info'), 0);
expect(info_msgs.pop().textContent).toBe("trustworthyguy is no longer a moderator"); expect(info_msgs.pop().textContent.trim()).toBe("trustworthyguy is no longer a moderator");
done(); done();
})); }));
...@@ -3758,7 +3758,7 @@ ...@@ -3758,7 +3758,7 @@
}); });
_converse.connection._dataRecv(test_utils.createRequest(presence)); _converse.connection._dataRecv(test_utils.createRequest(presence));
var info_msgs = Array.prototype.slice.call(view.el.querySelectorAll('.chat-info'), 0); var info_msgs = Array.prototype.slice.call(view.el.querySelectorAll('.chat-info'), 0);
expect(info_msgs.pop().textContent).toBe("annoyingGuy has entered the groupchat"); expect(info_msgs.pop().textContent.trim()).toBe("annoyingGuy has entered the groupchat");
const textarea = view.el.querySelector('.chat-textarea') const textarea = view.el.querySelector('.chat-textarea')
textarea.value = '/mute'; textarea.value = '/mute';
...@@ -3813,7 +3813,7 @@ ...@@ -3813,7 +3813,7 @@
}); });
_converse.connection._dataRecv(test_utils.createRequest(presence)); _converse.connection._dataRecv(test_utils.createRequest(presence));
info_msgs = Array.prototype.slice.call(view.el.querySelectorAll('.chat-info'), 0); info_msgs = Array.prototype.slice.call(view.el.querySelectorAll('.chat-info'), 0);
expect(info_msgs.pop().textContent).toBe("annoyingGuy has been muted"); expect(info_msgs.pop().textContent.trim()).toBe("annoyingGuy has been muted");
// Call now with the correct of arguments. // Call now with the correct of arguments.
// XXX: Calling onFormSubmitted directly, trying // XXX: Calling onFormSubmitted directly, trying
...@@ -3856,7 +3856,7 @@ ...@@ -3856,7 +3856,7 @@
}); });
_converse.connection._dataRecv(test_utils.createRequest(presence)); _converse.connection._dataRecv(test_utils.createRequest(presence));
info_msgs = Array.prototype.slice.call(view.el.querySelectorAll('.chat-info'), 0); info_msgs = Array.prototype.slice.call(view.el.querySelectorAll('.chat-info'), 0);
expect(info_msgs.pop().textContent).toBe("annoyingGuy has been given a voice"); expect(info_msgs.pop().textContent.trim()).toBe("annoyingGuy has been given a voice");
done(); done();
})); }));
...@@ -3947,7 +3947,7 @@ ...@@ -3947,7 +3947,7 @@
const chat_body = view.el.querySelector('.chatroom-body'); const chat_body = view.el.querySelector('.chatroom-body');
expect(view.renderPasswordForm).toHaveBeenCalled(); expect(view.renderPasswordForm).toHaveBeenCalled();
expect(chat_body.querySelectorAll('form.chatroom-form').length).toBe(1); expect(chat_body.querySelectorAll('form.chatroom-form').length).toBe(1);
expect(chat_body.querySelector('label').textContent) expect(chat_body.querySelector('label').textContent.trim())
.toBe('This groupchat requires a password'); .toBe('This groupchat requires a password');
// Let's submit the form // Let's submit the form
...@@ -4003,7 +4003,7 @@ ...@@ -4003,7 +4003,7 @@
.c('registration-required').attrs({xmlns:'urn:ietf:params:xml:ns:xmpp-stanzas'}).nodeTree; .c('registration-required').attrs({xmlns:'urn:ietf:params:xml:ns:xmpp-stanzas'}).nodeTree;
_converse.connection._dataRecv(test_utils.createRequest(presence)); _converse.connection._dataRecv(test_utils.createRequest(presence));
expect(view.el.querySelector('.chatroom-body .disconnect-container .disconnect-msg:last-child').textContent) expect(view.el.querySelector('.chatroom-body .disconnect-container .disconnect-msg:last-child').textContent.trim())
.toBe('You are not on the member list of this groupchat.'); .toBe('You are not on the member list of this groupchat.');
done(); done();
})); }));
...@@ -4049,7 +4049,7 @@ ...@@ -4049,7 +4049,7 @@
spyOn(view, 'showErrorMessage').and.callThrough(); spyOn(view, 'showErrorMessage').and.callThrough();
_converse.connection._dataRecv(test_utils.createRequest(presence)); _converse.connection._dataRecv(test_utils.createRequest(presence));
expect(view.el.querySelector('.chatroom-body .disconnect-container .disconnect-msg:last-child').textContent) expect(view.el.querySelector('.chatroom-body .disconnect-container .disconnect-msg:last-child').textContent.trim())
.toBe('You have been banned from this groupchat.'); .toBe('You have been banned from this groupchat.');
done(); done();
})); }));
...@@ -4073,7 +4073,7 @@ ...@@ -4073,7 +4073,7 @@
const view = _converse.chatboxviews.get(muc_jid); const view = _converse.chatboxviews.get(muc_jid);
spyOn(view, 'showErrorMessage').and.callThrough(); spyOn(view, 'showErrorMessage').and.callThrough();
_converse.connection._dataRecv(test_utils.createRequest(presence)); _converse.connection._dataRecv(test_utils.createRequest(presence));
expect(sizzle('.chatroom-body form.chatroom-form label:first', view.el).pop().textContent) expect(sizzle('.chatroom-body form.chatroom-form label:first', view.el).pop().textContent.trim())
.toBe('Please choose your nickname'); .toBe('Please choose your nickname');
const input = sizzle('.chatroom-body form.chatroom-form input:first', view.el).pop(); const input = sizzle('.chatroom-body form.chatroom-form input:first', view.el).pop();
...@@ -4180,7 +4180,7 @@ ...@@ -4180,7 +4180,7 @@
.c('not-allowed').attrs({xmlns:'urn:ietf:params:xml:ns:xmpp-stanzas'}).nodeTree; .c('not-allowed').attrs({xmlns:'urn:ietf:params:xml:ns:xmpp-stanzas'}).nodeTree;
spyOn(view, 'showErrorMessage').and.callThrough(); spyOn(view, 'showErrorMessage').and.callThrough();
_converse.connection._dataRecv(test_utils.createRequest(presence)); _converse.connection._dataRecv(test_utils.createRequest(presence));
expect(view.el.querySelector('.chatroom-body .disconnect-container .disconnect-msg:last-child').textContent) expect(view.el.querySelector('.chatroom-body .disconnect-container .disconnect-msg:last-child').textContent.trim())
.toBe('You are not allowed to create new groupchats.'); .toBe('You are not allowed to create new groupchats.');
done(); done();
})); }));
...@@ -4222,7 +4222,7 @@ ...@@ -4222,7 +4222,7 @@
spyOn(view, 'showErrorMessage').and.callThrough(); spyOn(view, 'showErrorMessage').and.callThrough();
_converse.connection._dataRecv(test_utils.createRequest(presence)); _converse.connection._dataRecv(test_utils.createRequest(presence));
expect(view.el.querySelector('.chatroom-body .disconnect-container .disconnect-msg:last-child').textContent) expect(view.el.querySelector('.chatroom-body .disconnect-container .disconnect-msg:last-child').textContent.trim())
.toBe("Your nickname doesn't conform to this groupchat's policies."); .toBe("Your nickname doesn't conform to this groupchat's policies.");
done(); done();
})); }));
...@@ -4264,7 +4264,7 @@ ...@@ -4264,7 +4264,7 @@
spyOn(view, 'showErrorMessage').and.callThrough(); spyOn(view, 'showErrorMessage').and.callThrough();
_converse.connection._dataRecv(test_utils.createRequest(presence)); _converse.connection._dataRecv(test_utils.createRequest(presence));
expect(view.el.querySelector('.chatroom-body .disconnect-container .disconnect-msg:last-child').textContent) expect(view.el.querySelector('.chatroom-body .disconnect-container .disconnect-msg:last-child').textContent.trim())
.toBe("This groupchat does not (yet) exist."); .toBe("This groupchat does not (yet) exist.");
done(); done();
})); }));
...@@ -4306,7 +4306,7 @@ ...@@ -4306,7 +4306,7 @@
spyOn(view, 'showErrorMessage').and.callThrough(); spyOn(view, 'showErrorMessage').and.callThrough();
_converse.connection._dataRecv(test_utils.createRequest(presence)); _converse.connection._dataRecv(test_utils.createRequest(presence));
expect(view.el.querySelector('.chatroom-body .disconnect-container .disconnect-msg:last-child').textContent) expect(view.el.querySelector('.chatroom-body .disconnect-container .disconnect-msg:last-child').textContent.trim())
.toBe("This groupchat has reached its maximum number of participants."); .toBe("This groupchat has reached its maximum number of participants.");
done(); done();
})); }));
...@@ -4543,17 +4543,17 @@ ...@@ -4543,17 +4543,17 @@
await u.waitUntil(() => u.isVisible(modal.el), 1000) await u.waitUntil(() => u.isVisible(modal.el), 1000)
let label_name = modal.el.querySelector('label[for="chatroom"]'); let label_name = modal.el.querySelector('label[for="chatroom"]');
expect(label_name.textContent).toBe('Groupchat address:'); expect(label_name.textContent.trim()).toBe('Groupchat address:');
let name_input = modal.el.querySelector('input[name="chatroom"]'); let name_input = modal.el.querySelector('input[name="chatroom"]');
expect(name_input.placeholder).toBe('name@conference.example.org'); expect(name_input.placeholder).toBe('name@conference.example.org');
const label_nick = modal.el.querySelector('label[for="nickname"]'); const label_nick = modal.el.querySelector('label[for="nickname"]');
expect(label_nick.textContent).toBe('Nickname:'); expect(label_nick.textContent.trim()).toBe('Nickname:');
const nick_input = modal.el.querySelector('input[name="nickname"]'); const nick_input = modal.el.querySelector('input[name="nickname"]');
expect(nick_input.value).toBe(''); expect(nick_input.value).toBe('');
nick_input.value = 'romeo'; nick_input.value = 'romeo';
expect(modal.el.querySelector('.modal-title').textContent).toBe('Enter a new Groupchat'); expect(modal.el.querySelector('.modal-title').textContent.trim()).toBe('Enter a new Groupchat');
spyOn(_converse.ChatRoom.prototype, 'getRoomFeatures').and.callFake(() => Promise.resolve()); spyOn(_converse.ChatRoom.prototype, 'getRoomFeatures').and.callFake(() => Promise.resolve());
roomspanel.delegateEvents(); // We need to rebind all events otherwise our spy won't be called roomspanel.delegateEvents(); // We need to rebind all events otherwise our spy won't be called
modal.el.querySelector('input[name="chatroom"]').value = 'lounce@muc.montague.lit'; modal.el.querySelector('input[name="chatroom"]').value = 'lounce@muc.montague.lit';
...@@ -4564,7 +4564,7 @@ ...@@ -4564,7 +4564,7 @@
roomspanel.model.set('muc_domain', 'muc.example.org'); roomspanel.model.set('muc_domain', 'muc.example.org');
roomspanel.el.querySelector('.show-add-muc-modal').click(); roomspanel.el.querySelector('.show-add-muc-modal').click();
label_name = modal.el.querySelector('label[for="chatroom"]'); label_name = modal.el.querySelector('label[for="chatroom"]');
expect(label_name.textContent).toBe('Groupchat address:'); expect(label_name.textContent.trim()).toBe('Groupchat address:');
name_input = modal.el.querySelector('input[name="chatroom"]'); name_input = modal.el.querySelector('input[name="chatroom"]');
expect(name_input.placeholder).toBe('name@muc.example.org'); expect(name_input.placeholder).toBe('name@muc.example.org');
done(); done();
...@@ -4606,7 +4606,7 @@ ...@@ -4606,7 +4606,7 @@
const modal = roomspanel.add_room_modal; const modal = roomspanel.add_room_modal;
await u.waitUntil(() => u.isVisible(modal.el), 1000) await u.waitUntil(() => u.isVisible(modal.el), 1000)
const label_nick = modal.el.querySelector('label[for="nickname"]'); const label_nick = modal.el.querySelector('label[for="nickname"]');
expect(label_nick.textContent).toBe('Nickname:'); expect(label_nick.textContent.trim()).toBe('Nickname:');
const nick_input = modal.el.querySelector('input[name="nickname"]'); const nick_input = modal.el.querySelector('input[name="nickname"]');
expect(nick_input.value).toBe('romeo'); expect(nick_input.value).toBe('romeo');
done(); done();
...@@ -4625,7 +4625,7 @@ ...@@ -4625,7 +4625,7 @@
const modal = roomspanel.add_room_modal; const modal = roomspanel.add_room_modal;
await u.waitUntil(() => u.isVisible(modal.el), 1000) await u.waitUntil(() => u.isVisible(modal.el), 1000)
const label_nick = modal.el.querySelector('label[for="nickname"]'); const label_nick = modal.el.querySelector('label[for="nickname"]');
expect(label_nick.textContent).toBe('Nickname:'); expect(label_nick.textContent.trim()).toBe('Nickname:');
const nick_input = modal.el.querySelector('input[name="nickname"]'); const nick_input = modal.el.querySelector('input[name="nickname"]');
expect(nick_input.value).toBe('st.nick'); expect(nick_input.value).toBe('st.nick');
done(); done();
...@@ -4641,11 +4641,11 @@ ...@@ -4641,11 +4641,11 @@
roomspanel.el.querySelector('.show-add-muc-modal').click(); roomspanel.el.querySelector('.show-add-muc-modal').click();
const modal = roomspanel.add_room_modal; const modal = roomspanel.add_room_modal;
await u.waitUntil(() => u.isVisible(modal.el), 1000) await u.waitUntil(() => u.isVisible(modal.el), 1000)
expect(modal.el.querySelector('.modal-title').textContent).toBe('Enter a new Groupchat'); expect(modal.el.querySelector('.modal-title').textContent.trim()).toBe('Enter a new Groupchat');
spyOn(_converse.ChatRoom.prototype, 'getRoomFeatures').and.callFake(() => Promise.resolve()); spyOn(_converse.ChatRoom.prototype, 'getRoomFeatures').and.callFake(() => Promise.resolve());
roomspanel.delegateEvents(); // We need to rebind all events otherwise our spy won't be called roomspanel.delegateEvents(); // We need to rebind all events otherwise our spy won't be called
const label_name = modal.el.querySelector('label[for="chatroom"]'); const label_name = modal.el.querySelector('label[for="chatroom"]');
expect(label_name.textContent).toBe('Groupchat name:'); expect(label_name.textContent.trim()).toBe('Groupchat name:');
let name_input = modal.el.querySelector('input[name="chatroom"]'); let name_input = modal.el.querySelector('input[name="chatroom"]');
expect(name_input.placeholder).toBe('name@muc.example.org'); expect(name_input.placeholder).toBe('name@muc.example.org');
name_input.value = 'lounge'; name_input.value = 'lounge';
...@@ -4681,11 +4681,11 @@ ...@@ -4681,11 +4681,11 @@
roomspanel.el.querySelector('.show-add-muc-modal').click(); roomspanel.el.querySelector('.show-add-muc-modal').click();
const modal = roomspanel.add_room_modal; const modal = roomspanel.add_room_modal;
await u.waitUntil(() => u.isVisible(modal.el), 1000) await u.waitUntil(() => u.isVisible(modal.el), 1000)
expect(modal.el.querySelector('.modal-title').textContent).toBe('Enter a new Groupchat'); expect(modal.el.querySelector('.modal-title').textContent.trim()).toBe('Enter a new Groupchat');
spyOn(_converse.ChatRoom.prototype, 'getRoomFeatures').and.callFake(() => Promise.resolve()); spyOn(_converse.ChatRoom.prototype, 'getRoomFeatures').and.callFake(() => Promise.resolve());
roomspanel.delegateEvents(); // We need to rebind all events otherwise our spy won't be called roomspanel.delegateEvents(); // We need to rebind all events otherwise our spy won't be called
const label_name = modal.el.querySelector('label[for="chatroom"]'); const label_name = modal.el.querySelector('label[for="chatroom"]');
expect(label_name.textContent).toBe('Groupchat name:'); expect(label_name.textContent.trim()).toBe('Groupchat name:');
let name_input = modal.el.querySelector('input[name="chatroom"]'); let name_input = modal.el.querySelector('input[name="chatroom"]');
expect(name_input.placeholder).toBe(''); expect(name_input.placeholder).toBe('');
name_input.value = 'lounge'; name_input.value = 'lounge';
...@@ -4887,7 +4887,7 @@ ...@@ -4887,7 +4887,7 @@
await u.waitUntil(() => view.model.messages.length); await u.waitUntil(() => view.model.messages.length);
expect(roomspanel.el.querySelectorAll('.available-room').length).toBe(1); expect(roomspanel.el.querySelectorAll('.available-room').length).toBe(1);
expect(roomspanel.el.querySelectorAll('.msgs-indicator').length).toBe(1); expect(roomspanel.el.querySelectorAll('.msgs-indicator').length).toBe(1);
expect(roomspanel.el.querySelector('.msgs-indicator').textContent).toBe('1'); expect(roomspanel.el.querySelector('.msgs-indicator').textContent.trim()).toBe('1');
await view.model.onMessage($msg({ await view.model.onMessage($msg({
'from': muc_jid+'/'+nick, 'from': muc_jid+'/'+nick,
...@@ -4898,7 +4898,7 @@ ...@@ -4898,7 +4898,7 @@
await u.waitUntil(() => view.model.messages.length > 1); await u.waitUntil(() => view.model.messages.length > 1);
expect(roomspanel.el.querySelectorAll('.available-room').length).toBe(1); expect(roomspanel.el.querySelectorAll('.available-room').length).toBe(1);
expect(roomspanel.el.querySelectorAll('.msgs-indicator').length).toBe(1); expect(roomspanel.el.querySelectorAll('.msgs-indicator').length).toBe(1);
expect(roomspanel.el.querySelector('.msgs-indicator').textContent).toBe('2'); expect(roomspanel.el.querySelector('.msgs-indicator').textContent.trim()).toBe('2');
view.model.set({'minimized': false}); view.model.set({'minimized': false});
expect(roomspanel.el.querySelectorAll('.available-room').length).toBe(1); expect(roomspanel.el.querySelectorAll('.available-room').length).toBe(1);
expect(roomspanel.el.querySelectorAll('.msgs-indicator').length).toBe(0); expect(roomspanel.el.querySelectorAll('.msgs-indicator').length).toBe(0);
...@@ -4972,7 +4972,7 @@ ...@@ -4972,7 +4972,7 @@
const view = _converse.api.chatviews.get(muc_jid); const view = _converse.api.chatviews.get(muc_jid);
const chat_content = view.el.querySelector('.chat-content'); const chat_content = view.el.querySelector('.chat-content');
expect(sizzle('div.chat-info:first', chat_content).pop().textContent) expect(sizzle('div.chat-info:first', chat_content).pop().textContent.trim())
.toBe("some1 has entered the groupchat"); .toBe("some1 has entered the groupchat");
let presence = $pres({ let presence = $pres({
...@@ -4987,7 +4987,7 @@ ...@@ -4987,7 +4987,7 @@
}); });
_converse.connection._dataRecv(test_utils.createRequest(presence)); _converse.connection._dataRecv(test_utils.createRequest(presence));
expect(chat_content.querySelectorAll('div.chat-info').length).toBe(2); expect(chat_content.querySelectorAll('div.chat-info').length).toBe(2);
expect(sizzle('div.chat-info:last', chat_content).pop().textContent) expect(sizzle('div.chat-info:last', chat_content).pop().textContent.trim())
.toBe("newguy has entered the groupchat"); .toBe("newguy has entered the groupchat");
presence = $pres({ presence = $pres({
...@@ -5002,7 +5002,7 @@ ...@@ -5002,7 +5002,7 @@
}); });
_converse.connection._dataRecv(test_utils.createRequest(presence)); _converse.connection._dataRecv(test_utils.createRequest(presence));
expect(chat_content.querySelectorAll('div.chat-info').length).toBe(3); expect(chat_content.querySelectorAll('div.chat-info').length).toBe(3);
expect(sizzle('div.chat-info:last', chat_content).pop().textContent) expect(sizzle('div.chat-info:last', chat_content).pop().textContent.trim())
.toBe("nomorenicks has entered the groupchat"); .toBe("nomorenicks has entered the groupchat");
// See XEP-0085 https://xmpp.org/extensions/xep-0085.html#definitions // See XEP-0085 https://xmpp.org/extensions/xep-0085.html#definitions
...@@ -5021,13 +5021,13 @@ ...@@ -5021,13 +5021,13 @@
// Check that the notification appears inside the chatbox in the DOM // Check that the notification appears inside the chatbox in the DOM
let events = view.el.querySelectorAll('.chat-event'); let events = view.el.querySelectorAll('.chat-event');
expect(events.length).toBe(3); expect(events.length).toBe(3);
expect(events[0].textContent).toEqual('some1 has entered the groupchat'); expect(events[0].textContent.trim()).toEqual('some1 has entered the groupchat');
expect(events[1].textContent).toEqual('newguy has entered the groupchat'); expect(events[1].textContent.trim()).toEqual('newguy has entered the groupchat');
expect(events[2].textContent).toEqual('nomorenicks has entered the groupchat'); expect(events[2].textContent.trim()).toEqual('nomorenicks has entered the groupchat');
let notifications = view.el.querySelectorAll('.chat-state-notification'); let notifications = view.el.querySelectorAll('.chat-state-notification');
expect(notifications.length).toBe(1); expect(notifications.length).toBe(1);
expect(notifications[0].textContent).toEqual('newguy is typing'); expect(notifications[0].textContent.trim()).toEqual('newguy is typing');
const timeout_functions = []; const timeout_functions = [];
spyOn(window, 'setTimeout').and.callFake(f => timeout_functions.push(f)); spyOn(window, 'setTimeout').and.callFake(f => timeout_functions.push(f));
...@@ -5043,13 +5043,13 @@ ...@@ -5043,13 +5043,13 @@
events = view.el.querySelectorAll('.chat-event'); events = view.el.querySelectorAll('.chat-event');
expect(events.length).toBe(3); expect(events.length).toBe(3);
expect(events[0].textContent).toEqual('some1 has entered the groupchat'); expect(events[0].textContent.trim()).toEqual('some1 has entered the groupchat');
expect(events[1].textContent).toEqual('newguy has entered the groupchat'); expect(events[1].textContent.trim()).toEqual('newguy has entered the groupchat');
expect(events[2].textContent).toEqual('nomorenicks has entered the groupchat'); expect(events[2].textContent.trim()).toEqual('nomorenicks has entered the groupchat');
notifications = view.el.querySelectorAll('.chat-state-notification'); notifications = view.el.querySelectorAll('.chat-state-notification');
expect(notifications.length).toBe(1); expect(notifications.length).toBe(1);
expect(notifications[0].textContent).toEqual('newguy is typing'); expect(notifications[0].textContent.trim()).toEqual('newguy is typing');
expect(timeout_functions.length).toBe(1); expect(timeout_functions.length).toBe(1);
// <composing> state for a different occupant // <composing> state for a different occupant
...@@ -5062,15 +5062,15 @@ ...@@ -5062,15 +5062,15 @@
await view.model.onMessage(msg); await view.model.onMessage(msg);
events = view.el.querySelectorAll('.chat-event'); events = view.el.querySelectorAll('.chat-event');
expect(events.length).toBe(3); expect(events.length).toBe(3);
expect(events[0].textContent).toEqual('some1 has entered the groupchat'); expect(events[0].textContent.trim()).toEqual('some1 has entered the groupchat');
expect(events[1].textContent).toEqual('newguy has entered the groupchat'); expect(events[1].textContent.trim()).toEqual('newguy has entered the groupchat');
expect(events[2].textContent).toEqual('nomorenicks has entered the groupchat'); expect(events[2].textContent.trim()).toEqual('nomorenicks has entered the groupchat');
await u.waitUntil(() => (view.el.querySelectorAll('.chat-state-notification').length === 2)); await u.waitUntil(() => (view.el.querySelectorAll('.chat-state-notification').length === 2));
notifications = view.el.querySelectorAll('.chat-state-notification'); notifications = view.el.querySelectorAll('.chat-state-notification');
expect(notifications.length).toBe(2); expect(notifications.length).toBe(2);
expect(notifications[0].textContent).toEqual('nomorenicks is typing'); expect(notifications[0].textContent.trim()).toEqual('nomorenicks is typing');
expect(notifications[1].textContent).toEqual('newguy is typing'); expect(notifications[1].textContent.trim()).toEqual('newguy is typing');
// Check that new messages appear under the chat state notifications // Check that new messages appear under the chat state notifications
msg = $msg({ msg = $msg({
...@@ -5085,26 +5085,26 @@ ...@@ -5085,26 +5085,26 @@
const messages = view.el.querySelectorAll('.message'); const messages = view.el.querySelectorAll('.message');
expect(messages.length).toBe(7); expect(messages.length).toBe(7);
expect(view.el.querySelectorAll('.chat-msg').length).toBe(1); expect(view.el.querySelectorAll('.chat-msg').length).toBe(1);
expect(view.el.querySelector('.chat-msg .chat-msg__text').textContent).toBe('hello world'); expect(view.el.querySelector('.chat-msg .chat-msg__text').textContent.trim()).toBe('hello world');
// Test that the composing notifications get removed via timeout. // Test that the composing notifications get removed via timeout.
timeout_functions[0](); timeout_functions[0]();
events = view.el.querySelectorAll('.chat-event'); events = view.el.querySelectorAll('.chat-event');
expect(events.length).toBe(3); expect(events.length).toBe(3);
expect(events[0].textContent).toEqual('some1 has entered the groupchat'); expect(events[0].textContent.trim()).toEqual('some1 has entered the groupchat');
expect(events[1].textContent).toEqual('newguy has entered the groupchat'); expect(events[1].textContent.trim()).toEqual('newguy has entered the groupchat');
expect(events[2].textContent).toEqual('nomorenicks has entered the groupchat'); expect(events[2].textContent.trim()).toEqual('nomorenicks has entered the groupchat');
notifications = view.el.querySelectorAll('.chat-state-notification'); notifications = view.el.querySelectorAll('.chat-state-notification');
expect(notifications.length).toBe(1); expect(notifications.length).toBe(1);
expect(notifications[0].textContent).toEqual('nomorenicks is typing'); expect(notifications[0].textContent.trim()).toEqual('nomorenicks is typing');
timeout_functions[1](); timeout_functions[1]();
events = view.el.querySelectorAll('.chat-event'); events = view.el.querySelectorAll('.chat-event');
expect(events.length).toBe(3); expect(events.length).toBe(3);
expect(events[0].textContent).toEqual('some1 has entered the groupchat'); expect(events[0].textContent.trim()).toEqual('some1 has entered the groupchat');
expect(events[1].textContent).toEqual('newguy has entered the groupchat'); expect(events[1].textContent.trim()).toEqual('newguy has entered the groupchat');
expect(events[2].textContent).toEqual('nomorenicks has entered the groupchat'); expect(events[2].textContent.trim()).toEqual('nomorenicks has entered the groupchat');
notifications = view.el.querySelectorAll('.chat-state-notification'); notifications = view.el.querySelectorAll('.chat-state-notification');
expect(notifications.length).toBe(0); expect(notifications.length).toBe(0);
...@@ -5142,7 +5142,7 @@ ...@@ -5142,7 +5142,7 @@
}).up() }).up()
.c('status', {code: '110'}); .c('status', {code: '110'});
_converse.connection._dataRecv(test_utils.createRequest(presence)); _converse.connection._dataRecv(test_utils.createRequest(presence));
expect(sizzle('div.chat-info:first', chat_content).pop().textContent) expect(sizzle('div.chat-info:first', chat_content).pop().textContent.trim())
.toBe("some1 has entered the groupchat"); .toBe("some1 has entered the groupchat");
presence = $pres({ presence = $pres({
...@@ -5157,7 +5157,7 @@ ...@@ -5157,7 +5157,7 @@
}); });
_converse.connection._dataRecv(test_utils.createRequest(presence)); _converse.connection._dataRecv(test_utils.createRequest(presence));
expect(chat_content.querySelectorAll('div.chat-info').length).toBe(2); expect(chat_content.querySelectorAll('div.chat-info').length).toBe(2);
expect(sizzle('div.chat-info:last', chat_content).pop().textContent) expect(sizzle('div.chat-info:last', chat_content).pop().textContent.trim())
.toBe("newguy has entered the groupchat"); .toBe("newguy has entered the groupchat");
presence = $pres({ presence = $pres({
...@@ -5172,7 +5172,7 @@ ...@@ -5172,7 +5172,7 @@
}); });
_converse.connection._dataRecv(test_utils.createRequest(presence)); _converse.connection._dataRecv(test_utils.createRequest(presence));
expect(chat_content.querySelectorAll('div.chat-info').length).toBe(3); expect(chat_content.querySelectorAll('div.chat-info').length).toBe(3);
expect(sizzle('div.chat-info:last', chat_content).pop().textContent) expect(sizzle('div.chat-info:last', chat_content).pop().textContent.trim())
.toBe("nomorenicks has entered the groupchat"); .toBe("nomorenicks has entered the groupchat");
// See XEP-0085 https://xmpp.org/extensions/xep-0085.html#definitions // See XEP-0085 https://xmpp.org/extensions/xep-0085.html#definitions
...@@ -5189,14 +5189,14 @@ ...@@ -5189,14 +5189,14 @@
// Check that the notification appears inside the chatbox in the DOM // Check that the notification appears inside the chatbox in the DOM
var events = view.el.querySelectorAll('.chat-event'); var events = view.el.querySelectorAll('.chat-event');
expect(events.length).toBe(3); expect(events.length).toBe(3);
expect(events[0].textContent).toEqual('some1 has entered the groupchat'); expect(events[0].textContent.trim()).toEqual('some1 has entered the groupchat');
expect(events[1].textContent).toEqual('newguy has entered the groupchat'); expect(events[1].textContent.trim()).toEqual('newguy has entered the groupchat');
expect(events[2].textContent).toEqual('nomorenicks has entered the groupchat'); expect(events[2].textContent.trim()).toEqual('nomorenicks has entered the groupchat');
await u.waitUntil(() => view.el.querySelectorAll('.chat-state-notification').length); await u.waitUntil(() => view.el.querySelectorAll('.chat-state-notification').length);
let notifications = view.el.querySelectorAll('.chat-state-notification'); let notifications = view.el.querySelectorAll('.chat-state-notification');
expect(notifications.length).toBe(1); expect(notifications.length).toBe(1);
expect(notifications[0].textContent).toEqual('newguy is typing'); expect(notifications[0].textContent.trim()).toEqual('newguy is typing');
// Check that it doesn't appear twice // Check that it doesn't appear twice
msg = $msg({ msg = $msg({
...@@ -5209,13 +5209,13 @@ ...@@ -5209,13 +5209,13 @@
events = view.el.querySelectorAll('.chat-event'); events = view.el.querySelectorAll('.chat-event');
expect(events.length).toBe(3); expect(events.length).toBe(3);
expect(events[0].textContent).toEqual('some1 has entered the groupchat'); expect(events[0].textContent.trim()).toEqual('some1 has entered the groupchat');
expect(events[1].textContent).toEqual('newguy has entered the groupchat'); expect(events[1].textContent.trim()).toEqual('newguy has entered the groupchat');
expect(events[2].textContent).toEqual('nomorenicks has entered the groupchat'); expect(events[2].textContent.trim()).toEqual('nomorenicks has entered the groupchat');
notifications = view.el.querySelectorAll('.chat-state-notification'); notifications = view.el.querySelectorAll('.chat-state-notification');
expect(notifications.length).toBe(1); expect(notifications.length).toBe(1);
expect(notifications[0].textContent).toEqual('newguy is typing'); expect(notifications[0].textContent.trim()).toEqual('newguy is typing');
// <composing> state for a different occupant // <composing> state for a different occupant
msg = $msg({ msg = $msg({
...@@ -5227,9 +5227,9 @@ ...@@ -5227,9 +5227,9 @@
await view.model.onMessage(msg); await view.model.onMessage(msg);
events = view.el.querySelectorAll('.chat-event'); events = view.el.querySelectorAll('.chat-event');
expect(events.length).toBe(3); expect(events.length).toBe(3);
expect(events[0].textContent).toEqual('some1 has entered the groupchat'); expect(events[0].textContent.trim()).toEqual('some1 has entered the groupchat');
expect(events[1].textContent).toEqual('newguy has entered the groupchat'); expect(events[1].textContent.trim()).toEqual('newguy has entered the groupchat');
expect(events[2].textContent).toEqual('nomorenicks has entered the groupchat'); expect(events[2].textContent.trim()).toEqual('nomorenicks has entered the groupchat');
await u.waitUntil(() => view.el.querySelectorAll('.chat-state-notification').length === 2); await u.waitUntil(() => view.el.querySelectorAll('.chat-state-notification').length === 2);
notifications = view.el.querySelectorAll('.chat-state-notification'); notifications = view.el.querySelectorAll('.chat-state-notification');
...@@ -5250,9 +5250,9 @@ ...@@ -5250,9 +5250,9 @@
await view.model.onMessage(msg); await view.model.onMessage(msg);
events = view.el.querySelectorAll('.chat-event'); events = view.el.querySelectorAll('.chat-event');
expect(events.length).toBe(3); expect(events.length).toBe(3);
expect(events[0].textContent).toEqual('some1 has entered the groupchat'); expect(events[0].textContent.trim()).toEqual('some1 has entered the groupchat');
expect(events[1].textContent).toEqual('newguy has entered the groupchat'); expect(events[1].textContent.trim()).toEqual('newguy has entered the groupchat');
expect(events[2].textContent).toEqual('nomorenicks has entered the groupchat'); expect(events[2].textContent.trim()).toEqual('nomorenicks has entered the groupchat');
await u.waitUntil(() => { await u.waitUntil(() => {
return _.map( return _.map(
...@@ -5290,7 +5290,7 @@ ...@@ -5290,7 +5290,7 @@
_converse.connection._dataRecv(test_utils.createRequest(stanza)); _converse.connection._dataRecv(test_utils.createRequest(stanza));
await new Promise((resolve, reject) => view.once('messageInserted', resolve)); await new Promise((resolve, reject) => view.once('messageInserted', resolve));
expect(view.el.querySelector('.chat-error').textContent).toBe( expect(view.el.querySelector('.chat-error').textContent.trim()).toBe(
"Your message was not delivered because you're not allowed to send messages in this groupchat."); "Your message was not delivered because you're not allowed to send messages in this groupchat.");
done(); done();
})); }));
...@@ -5344,8 +5344,8 @@ ...@@ -5344,8 +5344,8 @@
// Check now that things get restored when the user is given a voice // Check now that things get restored when the user is given a voice
let info_msgs = sizzle('.chat-info', view.el); let info_msgs = sizzle('.chat-info', view.el);
expect(info_msgs.length).toBe(2); expect(info_msgs.length).toBe(2);
expect(info_msgs[0].textContent).toBe("troll has entered the groupchat"); expect(info_msgs[0].textContent.trim()).toBe("troll has entered the groupchat");
expect(info_msgs[1].textContent).toBe("troll is no longer an owner of this groupchat"); expect(info_msgs[1].textContent.trim()).toBe("troll is no longer an owner of this groupchat");
stanza = u.toStanza(` stanza = u.toStanza(`
<presence <presence
...@@ -5368,7 +5368,7 @@ ...@@ -5368,7 +5368,7 @@
expect(textarea === null).toBe(false); expect(textarea === null).toBe(false);
expect(info_msgs.length).toBe(3); expect(info_msgs.length).toBe(3);
expect(info_msgs[2].textContent).toBe("troll has been given a voice"); expect(info_msgs[2].textContent.trim()).toBe("troll has been given a voice");
done(); done();
})); }));
}); });
......
...@@ -1430,7 +1430,7 @@ ...@@ -1430,7 +1430,7 @@
await u.waitUntil(() => !view.model.get('omemo_supported')); await u.waitUntil(() => !view.model.get('omemo_supported'));
expect(view.el.querySelector('.chat-error').textContent).toBe( expect(view.el.querySelector('.chat-error').textContent.trim()).toBe(
"oldguy doesn't appear to have a client that supports OMEMO. "+ "oldguy doesn't appear to have a client that supports OMEMO. "+
"Encrypted chat will no longer be possible in this grouchat." "Encrypted chat will no longer be possible in this grouchat."
); );
......
...@@ -15,6 +15,7 @@ import tpl_file_progress from "templates/file_progress.html"; ...@@ -15,6 +15,7 @@ import tpl_file_progress from "templates/file_progress.html";
import tpl_info from "templates/info.html"; import tpl_info from "templates/info.html";
import tpl_message from "templates/message.html"; import tpl_message from "templates/message.html";
import tpl_message_versions_modal from "templates/message_versions_modal.html"; import tpl_message_versions_modal from "templates/message_versions_modal.html";
import tpl_spinner from "templates/spinner.html";
import u from "@converse/headless/utils/emoji"; import u from "@converse/headless/utils/emoji";
import xss from "xss/dist/xss"; import xss from "xss/dist/xss";
...@@ -80,7 +81,8 @@ converse.plugins.add('converse-message-view', { ...@@ -80,7 +81,8 @@ converse.plugins.add('converse-message-view', {
_converse.MessageView = _converse.ViewWithAvatar.extend({ _converse.MessageView = _converse.ViewWithAvatar.extend({
events: { events: {
'click .chat-msg__edit-modal': 'showMessageVersionsModal' 'click .chat-msg__edit-modal': 'showMessageVersionsModal',
'click .retry': 'onRetryClicked'
}, },
initialize () { initialize () {
...@@ -164,6 +166,16 @@ converse.plugins.add('converse-message-view', { ...@@ -164,6 +166,16 @@ converse.plugins.add('converse-message-view', {
} }
}, },
async onRetryClicked () {
this.showSpinner();
await this.model.error.retry();
this.model.destroy();
},
showSpinner () {
this.el.innerHTML = tpl_spinner();
},
onMessageEdited () { onMessageEdited () {
if (this.model.get('is_archived')) { if (this.model.get('is_archived')) {
return; return;
......
...@@ -2,7 +2,6 @@ ...@@ -2,7 +2,6 @@
* -------------------- * --------------------
* Any of the following components may be removed if they're not needed. * Any of the following components may be removed if they're not needed.
*/ */
import "@converse/headless/headless"; import "@converse/headless/headless";
import "converse-autocomplete"; import "converse-autocomplete";
import "converse-bookmark-views"; // Views for XEP-0048 Bookmarks import "converse-bookmark-views"; // Views for XEP-0048 Bookmarks
......
...@@ -90,7 +90,8 @@ converse.plugins.add('converse-chatboxes', { ...@@ -90,7 +90,8 @@ converse.plugins.add('converse-chatboxes', {
defaults () { defaults () {
return { return {
'msgid': _converse.connection.getUniqueId(), 'msgid': _converse.connection.getUniqueId(),
'time': (new Date()).toISOString() 'time': (new Date()).toISOString(),
'ephemeral': false
}; };
}, },
...@@ -134,7 +135,7 @@ converse.plugins.add('converse-chatboxes', { ...@@ -134,7 +135,7 @@ converse.plugins.add('converse-chatboxes', {
}, },
isEphemeral () { isEphemeral () {
return this.isOnlyChatStateNotification() || this.get('type') === 'error'; return this.isOnlyChatStateNotification() || this.get('ephemeral');
}, },
getDisplayName () { getDisplayName () {
...@@ -178,7 +179,8 @@ converse.plugins.add('converse-chatboxes', { ...@@ -178,7 +179,8 @@ converse.plugins.add('converse-chatboxes', {
_converse.log(e, Strophe.LogLevel.ERROR); _converse.log(e, Strophe.LogLevel.ERROR);
return this.save({ return this.save({
'type': 'error', 'type': 'error',
'message': __("Sorry, could not determine upload URL.") 'message': __("Sorry, could not determine upload URL."),
'ephemeral': true
}); });
} }
const slot = stanza.querySelector('slot'); const slot = stanza.querySelector('slot');
...@@ -190,7 +192,8 @@ converse.plugins.add('converse-chatboxes', { ...@@ -190,7 +192,8 @@ converse.plugins.add('converse-chatboxes', {
} else { } else {
return this.save({ return this.save({
'type': 'error', 'type': 'error',
'message': __("Sorry, could not determine file upload URL.") 'message': __("Sorry, could not determine file upload URL."),
'ephemeral': true
}); });
} }
}, },
...@@ -228,7 +231,8 @@ converse.plugins.add('converse-chatboxes', { ...@@ -228,7 +231,8 @@ converse.plugins.add('converse-chatboxes', {
this.save({ this.save({
'type': 'error', 'type': 'error',
'upload': _converse.FAILURE, 'upload': _converse.FAILURE,
'message': message 'message': message,
'ephemeral': true
}); });
}; };
xhr.open('PUT', this.get('put'), true); xhr.open('PUT', this.get('put'), true);
...@@ -401,6 +405,13 @@ converse.plugins.add('converse-chatboxes', { ...@@ -401,6 +405,13 @@ converse.plugins.add('converse-chatboxes', {
} }
}, },
createMessageFromError (error) {
if (error instanceof _converse.TimeoutError) {
const msg = this.messages.create({'type': 'error', 'message': error.message, 'retry': true});
msg.error = error;
}
},
getOldestMessage () { getOldestMessage () {
for (let i=0; i<this.messages.length; i++) { for (let i=0; i<this.messages.length; i++) {
const message = this.messages.at(i); const message = this.messages.at(i);
...@@ -798,7 +809,8 @@ converse.plugins.add('converse-chatboxes', { ...@@ -798,7 +809,8 @@ converse.plugins.add('converse-chatboxes', {
if (!item) { if (!item) {
this.messages.create({ this.messages.create({
'message': __("Sorry, looks like file upload is not supported by your server."), 'message': __("Sorry, looks like file upload is not supported by your server."),
'type': 'error' 'type': 'error',
'ephemeral': true
}); });
return; return;
} }
...@@ -809,7 +821,8 @@ converse.plugins.add('converse-chatboxes', { ...@@ -809,7 +821,8 @@ converse.plugins.add('converse-chatboxes', {
if (!slot_request_url) { if (!slot_request_url) {
this.messages.create({ this.messages.create({
'message': __("Sorry, looks like file upload is not supported by your server."), 'message': __("Sorry, looks like file upload is not supported by your server."),
'type': 'error' 'type': 'error',
'ephemeral': true
}); });
return; return;
} }
...@@ -818,7 +831,8 @@ converse.plugins.add('converse-chatboxes', { ...@@ -818,7 +831,8 @@ converse.plugins.add('converse-chatboxes', {
return this.messages.create({ return this.messages.create({
'message': __('The size of your file, %1$s, exceeds the maximum allowed by your server, which is %2$s.', 'message': __('The size of your file, %1$s, exceeds the maximum allowed by your server, which is %2$s.',
file.name, filesize(max_file_size)), file.name, filesize(max_file_size)),
'type': 'error' 'type': 'error',
'ephemeral': true
}); });
} else { } else {
const message = this.messages.create( const message = this.messages.create(
...@@ -887,9 +901,12 @@ converse.plugins.add('converse-chatboxes', { ...@@ -887,9 +901,12 @@ converse.plugins.add('converse-chatboxes', {
__('Sorry, an error occurred:') + ' ' + error.innerHTML; __('Sorry, an error occurred:') + ' ' + error.innerHTML;
}, },
/**
* Given a message stanza, return the text contained in its body.
* @private
* @param { XMLElement } stanza
*/
getMessageBody (stanza) { getMessageBody (stanza) {
/* Given a message stanza, return the text contained in its body.
*/
const type = stanza.getAttribute('type'); const type = stanza.getAttribute('type');
if (type === 'error') { if (type === 'error') {
return this.getErrorMessage(stanza); return this.getErrorMessage(stanza);
......
...@@ -117,6 +117,14 @@ _converse.Collection = Backbone.Collection.extend({ ...@@ -117,6 +117,14 @@ _converse.Collection = Backbone.Collection.extend({
}); });
/**
* Custom error for indicating timeouts
* @namespace _converse
*/
class TimeoutError extends Error {}
_converse.TimeoutError = TimeoutError;
// Make converse pluggable // Make converse pluggable
pluggable.enable(_converse, '_converse', 'pluggable'); pluggable.enable(_converse, '_converse', 'pluggable');
......
...@@ -128,6 +128,11 @@ converse.plugins.add('converse-mam', { ...@@ -128,6 +128,11 @@ converse.plugins.add('converse-mam', {
const result = await _converse.api.archive.query(query); const result = await _converse.api.archive.query(query);
result.messages.forEach(message_handler); result.messages.forEach(message_handler);
if (result.error) {
result.error.retry = () => this.fetchArchivedMessages(options, page);
this.createMessageFromError(result.error);
}
if (page && result.rsm) { if (page && result.rsm) {
if (page === 'forwards') { if (page === 'forwards') {
options = result.rsm.next(_converse.archived_messages_page_size, options.before); options = result.rsm.next(_converse.archived_messages_page_size, options.before);
...@@ -298,9 +303,9 @@ converse.plugins.add('converse-mam', { ...@@ -298,9 +303,9 @@ converse.plugins.add('converse-mam', {
* * `index` * * `index`
* * `count` * * `count`
* @throws {Error} An error is thrown if the XMPP server responds with an error. * @throws {Error} An error is thrown if the XMPP server responds with an error.
* @returns {Promise<Object>} A promise which resolves to an object which * @returns { (Promise<Object> | _converse.TimeoutError) } A promise which resolves
* will have keys `messages` and `rsm` which contains a _converse.RSM object * to an object which will have keys `messages` and `rsm` which contains a _converse.RSM
* on which "next" or "previous" can be called before passing it in again * object on which "next" or "previous" can be called before passing it in again
* to this method, to get the next or previous page in the result set. * to this method, to get the next or previous page in the result set.
* *
* @example * @example
...@@ -506,17 +511,22 @@ converse.plugins.add('converse-mam', { ...@@ -506,17 +511,22 @@ converse.plugins.add('converse-mam', {
return true; return true;
}, Strophe.NS.MAM); }, Strophe.NS.MAM);
let iq_result, rsm; let error;
try { const iq_result = await _converse.api.sendIQ(stanza, _converse.message_archiving_timeout, false)
iq_result = await _converse.api.sendIQ(stanza, _converse.message_archiving_timeout) if (iq_result === null) {
} catch (e) { const err_msg = "Timeout while trying to fetch archived messages.";
_converse.log( _converse.log(err_msg, Strophe.LogLevel.ERROR);
"Error or timeout while trying to fetch "+ error = new _converse.TimeoutError(err_msg);
"archived messages", Strophe.LogLevel.ERROR); return { messages, error };
_converse.log(e, Strophe.LogLevel.ERROR);
} else if (u.isErrorStanza(iq_result)) {
_converse.log("Error stanza received while trying to fetch archived messages", Strophe.LogLevel.ERROR);
_converse.log(iq_result, Strophe.LogLevel.ERROR);
return { messages };
} }
_converse.connection.deleteHandler(message_handler); _converse.connection.deleteHandler(message_handler);
let rsm;
const fin = iq_result && sizzle(`fin[xmlns="${Strophe.NS.MAM}"]`, iq_result).pop(); const fin = iq_result && sizzle(`fin[xmlns="${Strophe.NS.MAM}"]`, iq_result).pop();
if (fin && [null, 'false'].includes(fin.getAttribute('complete'))) { if (fin && [null, 'false'].includes(fin.getAttribute('complete'))) {
const set = sizzle(`set[xmlns="${Strophe.NS.RSM}"]`, fin).pop(); const set = sizzle(`set[xmlns="${Strophe.NS.RSM}"]`, fin).pop();
...@@ -525,7 +535,7 @@ converse.plugins.add('converse-mam', { ...@@ -525,7 +535,7 @@ converse.plugins.add('converse-mam', {
Object.assign(rsm, Object.assign(pick(options, [...MAM_ATTRIBUTES, ..._converse.RSM_ATTRIBUTES]), rsm)); Object.assign(rsm, Object.assign(pick(options, [...MAM_ATTRIBUTES, ..._converse.RSM_ATTRIBUTES]), rsm));
} }
} }
return { messages, rsm } return { messages, rsm, error };
} }
} }
}); });
......
...@@ -1550,7 +1550,8 @@ converse.plugins.add('converse-muc', { ...@@ -1550,7 +1550,8 @@ converse.plugins.add('converse-muc', {
} else { } else {
const attrs = { const attrs = {
'type': 'error', 'type': 'error',
'message': text 'message': text,
'ephemeral': true
} }
this.messages.create(attrs); this.messages.create(attrs);
} }
......
{[ if (o.render_message) { ]} <div class="message chat-info {{{o.extra_classes}}}" data-isodate="{{{o.isodate}}}" {[ if (o.data_name) { ]} data-{{{o.data_name}}}="{{{o.data_value}}}"{[ } ]}>
<!-- XXX: Should only ever be rendered if the message text has been sanitized already --> {[ if (o.render_message) {
<div class="message chat-info {{{o.extra_classes}}}" // XXX: Should only ever be rendered if the message text has been sanitized already
data-isodate="{{{o.isodate}}}" {[ if (o.data_name) { ]} data-{{{o.data_name}}}="{{{o.data_value}}}"{[ } ]}>{{o.message}}</div> ]}
{{o.message}}
{[ } else { ]} {[ } else { ]}
<div class="message chat-info {{{o.extra_classes}}}" {{{o.message}}}
data-isodate="{{{o.isodate}}}" {[ if (o.data_name) { ]} data-{{{o.data_name}}}="{{{o.data_value}}}"{[ } ]}>{{{o.message}}}</div>
{[ } ]} {[ } ]}
{[ if (o.retry) { ]}
<a class="retry">Retry</a>
{[ } ]}
</div>
...@@ -6,7 +6,6 @@ ...@@ -6,7 +6,6 @@
<meta name="description" content="Converse XMPP Chat" /> <meta name="description" content="Converse XMPP Chat" />
<link rel="shortcut icon" type="image/png" href="../node_modules/jasmine-core/images/jasmine_favicon.png"> <link rel="shortcut icon" type="image/png" href="../node_modules/jasmine-core/images/jasmine_favicon.png">
<link rel="stylesheet" type="text/css" media="screen" href="../node_modules/jasmine-core/lib/jasmine-core/jasmine.css"> <link rel="stylesheet" type="text/css" media="screen" href="../node_modules/jasmine-core/lib/jasmine-core/jasmine.css">
<link type="text/css" rel="stylesheet" media="screen" href="../dist/website.css" />
<link type="text/css" rel="stylesheet" media="screen" href="../dist/converse.css" /> <link type="text/css" rel="stylesheet" media="screen" href="../dist/converse.css" />
<script src="../dist/converse.js"></script> <script src="../dist/converse.js"></script>
<script data-main="runner" src="../node_modules/requirejs/require.js"></script> <script data-main="runner" src="../node_modules/requirejs/require.js"></script>
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment