/*global mock, converse */
const { u, $msg } = converse.env;
describe("An incoming chat Message", function () {
it("can have styling disabled via an \"unstyled\" element",
mock.initConverse(['chatBoxesFetched'], {},
async function (done, _converse) {
const include_nick = false;
await mock.waitForRoster(_converse, 'current', 2, include_nick);
await mock.openControlBox(_converse);
const msg_text = '> _ >';
const sender_jid = mock.cur_names[1].replace(/ /g,'.').toLowerCase() + '@montague.lit';
const msg = $msg({
'from': sender_jid,
'id': u.getUniqueId(),
'to': _converse.connection.jid,
'type': 'chat',
'xmlns': 'jabber:client'
}).c('body').t(msg_text).up()
.c('unstyled', {'xmlns': 'urn:xmpp:styling:0'}).tree();
await _converse.handleMessageStanza(msg);
const view = _converse.api.chatviews.get(sender_jid);
await u.waitUntil(() => view.model.messages.length);
expect(view.model.messages.models[0].get('is_unstyled')).toBe(true);
setTimeout(() => {
const msg_el = view.querySelector('converse-chat-message-body');
expect(msg_el.innerText).toBe(msg_text);
done();
}, 500);
}));
it("can have styling disabled via the allow_message_styling setting",
mock.initConverse(['chatBoxesFetched'], {'allow_message_styling': false},
async function (done, _converse) {
const include_nick = false;
await mock.waitForRoster(_converse, 'current', 2, include_nick);
await mock.openControlBox(_converse);
const msg_text = '> _ >';
const sender_jid = mock.cur_names[1].replace(/ /g,'.').toLowerCase() + '@montague.lit';
const msg = $msg({
'from': sender_jid,
'id': u.getUniqueId(),
'to': _converse.connection.jid,
'type': 'chat',
'xmlns': 'jabber:client'
}).c('body').t(msg_text).tree();
await _converse.handleMessageStanza(msg);
const view = _converse.api.chatviews.get(sender_jid);
await u.waitUntil(() => view.model.messages.length);
expect(view.model.messages.models[0].get('is_unstyled')).toBe(false);
setTimeout(() => {
const msg_el = view.querySelector('converse-chat-message-body');
expect(msg_el.innerText).toBe(msg_text);
done();
}, 500);
}));
it("can be styled with span XEP-0393 message styling hints",
mock.initConverse(['chatBoxesFetched'], {},
async function (done, _converse) {
let msg_text, msg, msg_el;
await mock.waitForRoster(_converse, 'current', 1);
const contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit';
await mock.openChatBoxFor(_converse, contact_jid);
const view = _converse.api.chatviews.get(contact_jid);
msg_text = "This *message _contains_* styling hints! \`Here's *some* code\`";
msg = mock.createChatMessage(_converse, contact_jid, msg_text)
await _converse.handleMessageStanza(msg);
await u.waitUntil(() => view.querySelectorAll('.chat-msg__text').length);
msg_el = view.querySelector('converse-chat-message-body');
expect(msg_el.innerText).toBe(msg_text);
await u.waitUntil(() => msg_el.innerHTML.replace(//g, '') ===
'This *'+
'message _contains_'+
'*'+
' styling hints! '+
'`Here\'s *some* code
`'
);
msg_text = "Here's a ~strikethrough section~";
msg = mock.createChatMessage(_converse, contact_jid, msg_text)
await _converse.handleMessageStanza(msg);
await u.waitUntil(() => view.querySelectorAll('.chat-msg__text').length === 2);
msg_el = Array.from(view.querySelectorAll('converse-chat-message-body')).pop();
expect(msg_el.innerText).toBe(msg_text);
await u.waitUntil(() => msg_el.innerHTML.replace(//g, '') ===
'Here\'s a ~strikethrough section~');
// Span directives containing hyperlinks
msg_text = "~Check out this site: https://conversejs.org~"
msg = mock.createChatMessage(_converse, contact_jid, msg_text)
await _converse.handleMessageStanza(msg);
await u.waitUntil(() => view.querySelectorAll('.chat-msg__text').length === 3);
msg_el = Array.from(view.querySelectorAll('converse-chat-message-body')).pop();
expect(msg_el.innerText).toBe(msg_text);
await u.waitUntil(() => msg_el.innerHTML.replace(//g, '') ===
'~'+
'Check out this site: https://conversejs.org'+
'~');
// Images inside directives aren't shown inline
const base_url = 'https://conversejs.org';
msg_text = `*${base_url}/logo/conversejs-filled.svg*`;
msg = mock.createChatMessage(_converse, contact_jid, msg_text)
await _converse.handleMessageStanza(msg);
await u.waitUntil(() => view.querySelectorAll('.chat-msg__text').length === 4);
msg_el = Array.from(view.querySelectorAll('converse-chat-message-body')).pop();
expect(msg_el.innerText).toBe(msg_text);
await u.waitUntil(() => msg_el.innerHTML.replace(//g, '') ===
'*'+
'https://conversejs.org/logo/conversejs-filled.svg'+
'*');
// Emojis inside directives
msg_text = `~ Hello! :poop: ~`;
msg = mock.createChatMessage(_converse, contact_jid, msg_text)
await _converse.handleMessageStanza(msg);
await u.waitUntil(() => view.querySelectorAll('.chat-msg__text').length === 5);
msg_el = Array.from(view.querySelectorAll('converse-chat-message-body')).pop();
expect(msg_el.innerText).toBe(msg_text);
await u.waitUntil(() => msg_el.innerHTML.replace(//g, '') ===
'~ Hello! 💩 ~');
// Span directives don't cross lines
msg_text = "This *is not a styling hint \n * _But this is_!";
msg = mock.createChatMessage(_converse, contact_jid, msg_text)
await _converse.handleMessageStanza(msg);
await u.waitUntil(() => view.querySelectorAll('.chat-msg__text').length === 6);
msg_el = Array.from(view.querySelectorAll('converse-chat-message-body')).pop();
expect(msg_el.innerText).toBe(msg_text);
await u.waitUntil(() => msg_el.innerHTML.replace(//g, '') ===
'This *is not a styling hint \n'+
' * _But this is_!');
msg_text = `(There are three blocks in this body marked by parens,)\n (but there is no *formatting)\n (as spans* may not escape blocks.)\n ~strikethrough~`;
msg = mock.createChatMessage(_converse, contact_jid, msg_text)
await _converse.handleMessageStanza(msg);
await u.waitUntil(() => view.querySelectorAll('.chat-msg__text').length === 7);
msg_el = Array.from(view.querySelectorAll('converse-chat-message-body')).pop();
expect(msg_el.innerText).toBe(msg_text);
await u.waitUntil(() => msg_el.innerHTML.replace(//g, '') ===
'(There are three blocks in this body marked by parens,)\n'+
' (but there is no *formatting)\n'+
' (as spans* may not escape blocks.)\n'+
' ~strikethrough~');
// Some edge-case (unspecified) spans
msg_text = `__ hello world _`;
msg = mock.createChatMessage(_converse, contact_jid, msg_text)
await _converse.handleMessageStanza(msg);
await u.waitUntil(() => view.querySelectorAll('.chat-msg__text').length === 8);
msg_el = Array.from(view.querySelectorAll('converse-chat-message-body')).pop();
expect(msg_el.innerText).toBe(msg_text);
await u.waitUntil(() => msg_el.innerHTML.replace(//g, '') ===
'__ hello world _');
// Directives which are parts of words aren't matched
msg_text = `Go to ~https://conversejs.org~now _please_`;
msg = mock.createChatMessage(_converse, contact_jid, msg_text)
await _converse.handleMessageStanza(msg);
await u.waitUntil(() => view.querySelectorAll('.chat-msg__text').length === 9);
msg_el = Array.from(view.querySelectorAll('converse-chat-message-body')).pop();
expect(msg_el.innerText).toBe(msg_text);
await u.waitUntil(() => msg_el.innerHTML.replace(//g, '') ===
'Go to ~https://conversejs.org~now _please_');
msg_text = `Go to _https://converse_js.org_ _please_`;
msg = mock.createChatMessage(_converse, contact_jid, msg_text)
await _converse.handleMessageStanza(msg);
await u.waitUntil(() => view.querySelectorAll('.chat-msg__text').length === 10);
msg_el = Array.from(view.querySelectorAll('converse-chat-message-body')).pop();
expect(msg_el.innerText).toBe(msg_text);
await u.waitUntil(() => msg_el.innerHTML.replace(//g, '') ===
'Go to _'+
'https://converse_js.org'+
'_ _please_');
done();
}));
it("can be styled with block XEP-0393 message styling hints",
mock.initConverse(['chatBoxesFetched'], {},
async function (done, _converse) {
let msg_text, msg, msg_el;
await mock.waitForRoster(_converse, 'current', 1);
const contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit';
await mock.openChatBoxFor(_converse, contact_jid);
const view = _converse.api.chatviews.get(contact_jid);
msg_text = `Here's a code block: \n\`\`\`\nInside the code-block, hello
we don't enable *styling hints* like ~these~\n\`\`\``;
msg = mock.createChatMessage(_converse, contact_jid, msg_text)
await _converse.handleMessageStanza(msg);
await u.waitUntil(() => view.querySelectorAll('.chat-msg__text').length);
msg_el = Array.from(view.querySelectorAll('converse-chat-message-body')).pop();
expect(msg_el.innerText).toBe(msg_text);
await u.waitUntil(() => msg_el.innerHTML.replace(//g, '') ===
'Here\'s a code block: \n'+
'
Inside the code-block, <code>hello</code> we don\'t enable *styling hints* like ~these~\n'+
'
ignored\n(println "Hello, world!")\n
'+
'This is quoted text\nThis is also quoted\nThis is not quoted'); msg_text = `> This is *quoted* text\n>This is \`also _quoted_\`\nThis is not quoted`; msg = mock.createChatMessage(_converse, contact_jid, msg_text) await _converse.handleMessageStanza(msg); await u.waitUntil(() => view.querySelectorAll('.chat-msg__text').length === 2); msg_el = Array.from(view.querySelectorAll('converse-chat-message-body')).pop(); expect(msg_el.innerText).toBe(msg_text); await u.waitUntil(() => msg_el.innerHTML.replace(//g, '') === '
This is *quoted* text\n'+
'This is `also _quoted_
`
\n'+
'This is not quoted');
msg_text = `> > This is doubly quoted text`;
msg = mock.createChatMessage(_converse, contact_jid, msg_text)
await _converse.handleMessageStanza(msg);
await u.waitUntil(() => view.querySelectorAll('.chat-msg__text').length === 3);
msg_el = Array.from(view.querySelectorAll('converse-chat-message-body')).pop();
expect(msg_el.innerText).toBe(msg_text);
await u.waitUntil(() => msg_el.innerHTML.replace(//g, '') === ""); msg_text = `>> This is doubly quoted text`; msg = mock.createChatMessage(_converse, contact_jid, msg_text) await _converse.handleMessageStanza(msg); await u.waitUntil(() => view.querySelectorAll('.chat-msg__text').length === 4); msg_el = Array.from(view.querySelectorAll('converse-chat-message-body')).pop(); expect(msg_el.innerText).toBe(msg_text); await u.waitUntil(() => msg_el.innerHTML.replace(//g, '') === "This is doubly quoted text
"); msg_text = ">```\n>ignored\n> (println \"Hello, world!\")\n>```\n> This should show up as monospace, preformatted text ^"; msg = mock.createChatMessage(_converse, contact_jid, msg_text) await _converse.handleMessageStanza(msg); await u.waitUntil(() => view.querySelectorAll('.chat-msg__text').length === 5); msg_el = Array.from(view.querySelectorAll('converse-chat-message-body')).pop(); expect(msg_el.innerText).toBe(msg_text); await u.waitUntil(() => msg_el.innerHTML.replace(//g, '') === 'This is doubly quoted text
'+ ''); msg_text = '> ```\n> (println "Hello, world!")\n\nThe entire blockquote is a preformatted text block, but this line is plaintext!'; msg = mock.createChatMessage(_converse, contact_jid, msg_text) await _converse.handleMessageStanza(msg); await u.waitUntil(() => view.querySelectorAll('.chat-msg__text').length === 6); msg_el = Array.from(view.querySelectorAll('converse-chat-message-body')).pop(); expect(msg_el.innerText).toBe(msg_text); await u.waitUntil(() => msg_el.innerHTML.replace(//g, '') === '```'+ 'ignored\n <span></span> (println "Hello, world!")\n'+ '
```\n'+ ' This should show up as monospace, preformatted text ^'+ '
```\n (println "Hello, world!")\n\n'+ 'The entire blockquote is a preformatted text block, but this line is plaintext!'); msg_text = '> Also, icons.js is loaded from /dist, instead of dist.\nhttps://conversejs.org/docs/html/configuration.html#assets-path' msg = mock.createChatMessage(_converse, contact_jid, msg_text) await _converse.handleMessageStanza(msg); await u.waitUntil(() => view.querySelectorAll('.chat-msg__text').length === 7); msg_el = Array.from(view.querySelectorAll('converse-chat-message-body')).pop(); expect(msg_el.innerText).toBe(msg_text); await u.waitUntil(() => msg_el.innerHTML.replace(//g, '') === '
Also, icons.js is loaded from /dist, instead of dist.\n'+ 'https://conversejs.org/docs/html/configuration.html#assets-path'); msg_text = '> Where is it located?\ngeo:37.786971,-122.399677'; msg = mock.createChatMessage(_converse, contact_jid, msg_text) await _converse.handleMessageStanza(msg); await u.waitUntil(() => view.querySelectorAll('.chat-msg__text').length === 8); msg_el = Array.from(view.querySelectorAll('converse-chat-message-body')).pop(); expect(msg_el.innerText).toBe(msg_text); await u.waitUntil(() => msg_el.innerHTML.replace(//g, '') === '
Where is it located?\n'+ 'https://www.openstreetmap.org/?mlat=37.786971&mlon=-122.399677#map=18/37.786971/-122.399677'); msg_text = '> What do you think of it?\n :poop:'; msg = mock.createChatMessage(_converse, contact_jid, msg_text) await _converse.handleMessageStanza(msg); await u.waitUntil(() => view.querySelectorAll('.chat-msg__text').length === 9); msg_el = Array.from(view.querySelectorAll('converse-chat-message-body')).pop(); expect(msg_el.innerText).toBe(msg_text); await u.waitUntil(() => msg_el.innerHTML.replace(//g, '') === '
What do you think of it?\n 💩'); msg_text = '> What do you think of it?\n~hello~'; msg = mock.createChatMessage(_converse, contact_jid, msg_text) await _converse.handleMessageStanza(msg); await u.waitUntil(() => view.querySelectorAll('.chat-msg__text').length === 10); msg_el = Array.from(view.querySelectorAll('converse-chat-message-body')).pop(); expect(msg_el.innerText).toBe(msg_text); await u.waitUntil(() => msg_el.innerHTML.replace(//g, '') === '
What do you think of it?\n~
What do you think of it romeo?\n Did you see this romeo?`); done(); })); it("won't style invalid block quotes", mock.initConverse(['chatBoxesFetched'], {}, async function (done, _converse) { await mock.waitForRoster(_converse, 'current', 1); const contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit'; await mock.openChatBoxFor(_converse, contact_jid); const view = _converse.api.chatviews.get(contact_jid); const msg_text = '```\ncode```'; const msg = $msg({ from: contact_jid, to: _converse.connection.jid, type: 'chat', id: (new Date()).getTime() }).c('body').t(msg_text).up() .c('reference', { 'xmlns':'urn:xmpp:reference:0', 'begin':'26', 'end':'31', 'type':'mention', 'uri': _converse.bare_jid }) .c('reference', { 'xmlns':'urn:xmpp:reference:0', 'begin':'51', 'end':'56', 'type':'mention', 'uri': _converse.bare_jid }).nodeTree; await _converse.handleMessageStanza(msg); await u.waitUntil(() => view.querySelectorAll('.chat-msg__text').length); const msg_el = Array.from(view.querySelectorAll('converse-chat-message-body')).pop(); expect(msg_el.innerText).toBe(msg_text); await u.waitUntil(() => msg_el.innerHTML.replace(//g, '') === '```\ncode```'); done(); })); });