Make the message view's render
method async
So that we first render dynamic content (e.g. images) before inserting it into the chat. Also, add the `show_images_inline` setting (which is the cause of this whole change). Updated tests to handle this new change and start using async/await instead of promise callbacks.
This commit is contained in:
parent
2426f9b7c8
commit
e181aaf99b
13027
dist/converse.js
vendored
13027
dist/converse.js
vendored
File diff suppressed because one or more lines are too long
4
package-lock.json
generated
4
package-lock.json
generated
|
@ -2252,9 +2252,7 @@
|
|||
}
|
||||
},
|
||||
"backbone.browserStorage": {
|
||||
"version": "0.0.3",
|
||||
"resolved": "https://registry.npmjs.org/backbone.browserStorage/-/backbone.browserStorage-0.0.3.tgz",
|
||||
"integrity": "sha1-ikIi8I2bHQslLR14/1CUuNCKc2s=",
|
||||
"version": "github:jcbrand/Backbone.browserStorage#7079bf7bf9a43474da1d48e31e3cda6c4a716382",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"backbone": "1.3.3",
|
||||
|
|
|
@ -40,7 +40,7 @@
|
|||
"awesomplete-avoid-xss": "^1.1.2",
|
||||
"babel-loader": "^8.0.0-beta.3",
|
||||
"backbone": "1.3.3",
|
||||
"backbone.browserStorage": "0.0.3",
|
||||
"backbone.browserStorage": "jcbrand/Backbone.browserStorage#78e4a58f7cee10cad6af4fd5f3213331a396aa5a",
|
||||
"backbone.nativeview": "^0.3.3",
|
||||
"backbone.overview": "1.0.2",
|
||||
"backbone.vdomview": "1.0.1",
|
||||
|
|
229
spec/chatbox.js
229
spec/chatbox.js
|
@ -58,61 +58,49 @@
|
|||
it("supports the /me command",
|
||||
mock.initConverseWithPromises(
|
||||
null, ['rosterGroupsFetched'], {},
|
||||
function (done, _converse) {
|
||||
async function (done, _converse) {
|
||||
|
||||
var view;
|
||||
test_utils.createContacts(_converse, 'current');
|
||||
test_utils.waitUntilDiscoConfirmed(_converse, 'localhost', [], ['vcard-temp'])
|
||||
.then(() => test_utils.waitUntil(() => _converse.xmppstatus.vcard.get('fullname')), 300)
|
||||
.then(function () {
|
||||
test_utils.openControlBox();
|
||||
expect(_converse.chatboxes.length).toEqual(1);
|
||||
var sender_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@localhost';
|
||||
var message = '/me is tired';
|
||||
var msg = $msg({
|
||||
from: sender_jid,
|
||||
to: _converse.connection.jid,
|
||||
type: 'chat',
|
||||
id: (new Date()).getTime()
|
||||
}).c('body').t(message).up()
|
||||
.c('active', {'xmlns': 'http://jabber.org/protocol/chatstates'}).tree();
|
||||
await test_utils.waitUntilDiscoConfirmed(_converse, 'localhost', [], ['vcard-temp']);
|
||||
await test_utils.waitUntil(() => _converse.xmppstatus.vcard.get('fullname'));
|
||||
await test_utils.openControlBox();
|
||||
expect(_converse.chatboxes.length).toEqual(1);
|
||||
const sender_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@localhost';
|
||||
let message = '/me is tired';
|
||||
const msg = $msg({
|
||||
from: sender_jid,
|
||||
to: _converse.connection.jid,
|
||||
type: 'chat',
|
||||
id: (new Date()).getTime()
|
||||
}).c('body').t(message).up()
|
||||
.c('active', {'xmlns': 'http://jabber.org/protocol/chatstates'}).tree();
|
||||
|
||||
_converse.chatboxes.onMessage(msg);
|
||||
view = _converse.chatboxviews.get(sender_jid);
|
||||
|
||||
test_utils.waitUntil(function () {
|
||||
return u.isVisible(view.el);
|
||||
}).then(function () {
|
||||
expect(view.el.querySelectorAll('.chat-msg--action').length).toBe(1);
|
||||
expect(_.includes(view.el.querySelector('.chat-msg__author').textContent, '**Max Frankfurter')).toBeTruthy();
|
||||
expect($(view.el).find('.chat-msg__text').text()).toBe(' is tired');
|
||||
|
||||
message = '/me is as well';
|
||||
test_utils.sendMessage(view, message);
|
||||
expect(view.el.querySelectorAll('.chat-msg--action').length).toBe(2);
|
||||
|
||||
return test_utils.waitUntil(() => $(view.el).find('.chat-msg__author:last').text().trim() === '**Max Mustermann');
|
||||
}).then(function () {
|
||||
expect($(view.el).find('.chat-msg__text:last').text()).toBe(' is as well');
|
||||
expect($(view.el).find('.chat-msg:last').hasClass('chat-msg--followup')).toBe(false);
|
||||
|
||||
// Check that /me messages after a normal message don't
|
||||
// get the 'chat-msg--followup' class.
|
||||
message = 'This a normal message';
|
||||
test_utils.sendMessage(view, message);
|
||||
let message_el = view.el.querySelector('.message:last-child');
|
||||
expect(u.hasClass('chat-msg--followup', message_el)).toBeFalsy();
|
||||
|
||||
message = '/me wrote a 3rd person message';
|
||||
test_utils.sendMessage(view, message);
|
||||
message_el = view.el.querySelector('.message:last-child');
|
||||
expect(view.el.querySelectorAll('.chat-msg--action').length).toBe(3);
|
||||
expect($(view.el).find('.chat-msg__text:last').text()).toBe(' wrote a 3rd person message');
|
||||
expect($(view.el).find('.chat-msg__author:last').is(':visible')).toBeTruthy();
|
||||
expect(u.hasClass('chat-msg--followup', message_el)).toBeFalsy();
|
||||
done();
|
||||
});
|
||||
});
|
||||
_converse.chatboxes.onMessage(msg);
|
||||
const view = _converse.chatboxviews.get(sender_jid);
|
||||
await new Promise((resolve, reject) => view.once('messageInserted', resolve));
|
||||
expect(view.el.querySelectorAll('.chat-msg--action').length).toBe(1);
|
||||
expect(_.includes(view.el.querySelector('.chat-msg__author').textContent, '**Max Frankfurter')).toBeTruthy();
|
||||
expect(view.el.querySelector('.chat-msg__text').textContent).toBe(' is tired');
|
||||
message = '/me is as well';
|
||||
await test_utils.sendMessage(view, message);
|
||||
expect(view.el.querySelectorAll('.chat-msg--action').length).toBe(2);
|
||||
await test_utils.waitUntil(() => $(view.el).find('.chat-msg__author:last').text().trim() === '**Max Mustermann');
|
||||
expect(sizzle('.chat-msg__text:last', view.el).pop().textContent).toBe(' is as well');
|
||||
expect($(view.el).find('.chat-msg:last').hasClass('chat-msg--followup')).toBe(false);
|
||||
// Check that /me messages after a normal message don't
|
||||
// get the 'chat-msg--followup' class.
|
||||
message = 'This a normal message';
|
||||
await test_utils.sendMessage(view, message);
|
||||
let message_el = view.el.querySelector('.message:last-child');
|
||||
expect(u.hasClass('chat-msg--followup', message_el)).toBeFalsy();
|
||||
message = '/me wrote a 3rd person message';
|
||||
await test_utils.sendMessage(view, message);
|
||||
message_el = view.el.querySelector('.message:last-child');
|
||||
expect(view.el.querySelectorAll('.chat-msg--action').length).toBe(3);
|
||||
expect(sizzle('.chat-msg__text:last', view.el).pop().textContent).toBe(' wrote a 3rd person message');
|
||||
expect(u.isVisible(sizzle('.chat-msg__author:last', view.el).pop())).toBeTruthy();
|
||||
expect(u.hasClass('chat-msg--followup', message_el)).toBeFalsy();
|
||||
done();
|
||||
}));
|
||||
|
||||
it("is created when you click on a roster item", mock.initConverseWithPromises(
|
||||
|
@ -684,7 +672,7 @@
|
|||
it("will be shown if received",
|
||||
mock.initConverseWithPromises(
|
||||
null, ['rosterGroupsFetched'], {},
|
||||
function (done, _converse) {
|
||||
async function (done, _converse) {
|
||||
|
||||
test_utils.createContacts(_converse, 'current');
|
||||
test_utils.openControlBox();
|
||||
|
@ -705,28 +693,27 @@
|
|||
expect(_converse.emit).toHaveBeenCalledWith('message', jasmine.any(Object));
|
||||
var view = _converse.chatboxviews.get(sender_jid);
|
||||
expect(view).toBeDefined();
|
||||
await new Promise((resolve, reject) => view.once('messageInserted', resolve));
|
||||
|
||||
test_utils.waitUntil(() => view.model.vcard.get('fullname') === mock.cur_names[1])
|
||||
.then(function () {
|
||||
var view = _converse.chatboxviews.get(sender_jid);
|
||||
// Check that the notification appears inside the chatbox in the DOM
|
||||
let events = view.el.querySelectorAll('.chat-state-notification');
|
||||
expect(events.length).toBe(1);
|
||||
expect(events[0].textContent).toEqual(mock.cur_names[1] + ' is typing');
|
||||
await test_utils.waitUntil(() => view.model.vcard.get('fullname') === mock.cur_names[1])
|
||||
// Check that the notification appears inside the chatbox in the DOM
|
||||
let events = view.el.querySelectorAll('.chat-state-notification');
|
||||
expect(events.length).toBe(1);
|
||||
expect(events[0].textContent).toEqual(mock.cur_names[1] + ' is typing');
|
||||
|
||||
// Check that it doesn't appear twice
|
||||
msg = $msg({
|
||||
from: sender_jid,
|
||||
to: _converse.connection.jid,
|
||||
type: 'chat',
|
||||
id: (new Date()).getTime()
|
||||
}).c('body').c('composing', {'xmlns': Strophe.NS.CHATSTATES}).tree();
|
||||
_converse.chatboxes.onMessage(msg);
|
||||
events = view.el.querySelectorAll('.chat-state-notification');
|
||||
expect(events.length).toBe(1);
|
||||
expect(events[0].textContent).toEqual(mock.cur_names[1] + ' is typing');
|
||||
done();
|
||||
})
|
||||
// Check that it doesn't appear twice
|
||||
msg = $msg({
|
||||
from: sender_jid,
|
||||
to: _converse.connection.jid,
|
||||
type: 'chat',
|
||||
id: (new Date()).getTime()
|
||||
}).c('body').c('composing', {'xmlns': Strophe.NS.CHATSTATES}).tree();
|
||||
_converse.chatboxes.onMessage(msg);
|
||||
await new Promise((resolve, reject) => view.once('messageInserted', resolve));
|
||||
events = view.el.querySelectorAll('.chat-state-notification');
|
||||
expect(events.length).toBe(1);
|
||||
expect(events[0].textContent).toEqual(mock.cur_names[1] + ' is typing');
|
||||
done();
|
||||
}));
|
||||
|
||||
it("can be a composing carbon message that this user sent from a different client",
|
||||
|
@ -841,38 +828,32 @@
|
|||
}));
|
||||
|
||||
it("will be shown if received",
|
||||
mock.initConverseWithPromises(
|
||||
null, ['rosterGroupsFetched'], {},
|
||||
function (done, _converse) {
|
||||
mock.initConverseWithPromises(
|
||||
null, ['rosterGroupsFetched'], {},
|
||||
async function (done, _converse) {
|
||||
|
||||
test_utils.createContacts(_converse, 'current');
|
||||
test_utils.openControlBox();
|
||||
test_utils.waitUntil(function () {
|
||||
return $(_converse.rosterview.el).find('.roster-group').length;
|
||||
}, 300)
|
||||
.then(function () {
|
||||
// TODO: only show paused state if the previous state was composing
|
||||
// See XEP-0085 http://xmpp.org/extensions/xep-0085.html#definitions
|
||||
spyOn(_converse, 'emit');
|
||||
var sender_jid = mock.cur_names[1].replace(/ /g,'.').toLowerCase() + '@localhost';
|
||||
// <paused> state
|
||||
var msg = $msg({
|
||||
from: sender_jid,
|
||||
to: _converse.connection.jid,
|
||||
type: 'chat',
|
||||
id: (new Date()).getTime()
|
||||
}).c('body').c('paused', {'xmlns': Strophe.NS.CHATSTATES}).tree();
|
||||
_converse.chatboxes.onMessage(msg);
|
||||
expect(_converse.emit).toHaveBeenCalledWith('message', jasmine.any(Object));
|
||||
var view = _converse.chatboxviews.get(sender_jid);
|
||||
test_utils.waitUntil(() => view.model.vcard.get('fullname') === mock.cur_names[1])
|
||||
.then(function () {
|
||||
var view = _converse.chatboxviews.get(sender_jid);
|
||||
var event = view.el.querySelector('.chat-info.chat-state-notification');
|
||||
expect(event.textContent).toEqual(mock.cur_names[1] + ' has stopped typing');
|
||||
done();
|
||||
});
|
||||
});
|
||||
await test_utils.waitUntil(() => _converse.rosterview.el.querySelectorAll('.roster-group').length);
|
||||
// TODO: only show paused state if the previous state was composing
|
||||
// See XEP-0085 http://xmpp.org/extensions/xep-0085.html#definitions
|
||||
spyOn(_converse, 'emit');
|
||||
const sender_jid = mock.cur_names[1].replace(/ /g,'.').toLowerCase() + '@localhost';
|
||||
// <paused> state
|
||||
var msg = $msg({
|
||||
from: sender_jid,
|
||||
to: _converse.connection.jid,
|
||||
type: 'chat',
|
||||
id: (new Date()).getTime()
|
||||
}).c('body').c('paused', {'xmlns': Strophe.NS.CHATSTATES}).tree();
|
||||
_converse.chatboxes.onMessage(msg);
|
||||
expect(_converse.emit).toHaveBeenCalledWith('message', jasmine.any(Object));
|
||||
const view = _converse.chatboxviews.get(sender_jid);
|
||||
await new Promise((resolve, reject) => view.once('messageInserted', resolve));
|
||||
await test_utils.waitUntil(() => view.model.vcard.get('fullname') === mock.cur_names[1])
|
||||
var event = view.el.querySelector('.chat-info.chat-state-notification');
|
||||
expect(event.textContent).toEqual(mock.cur_names[1] + ' has stopped typing');
|
||||
done();
|
||||
}));
|
||||
|
||||
it("can be a paused carbon message that this user sent from a different client",
|
||||
|
@ -1242,14 +1223,11 @@
|
|||
it("is incremented from zero when chatbox was closed after viewing previously received messages and the window is not focused now",
|
||||
mock.initConverseWithPromises(
|
||||
null, ['rosterGroupsFetched'], {},
|
||||
function (done, _converse) {
|
||||
async function (done, _converse) {
|
||||
|
||||
test_utils.createContacts(_converse, 'current');
|
||||
|
||||
// initial state
|
||||
expect(_converse.msg_counter).toBe(0);
|
||||
|
||||
let view;
|
||||
const message = 'This message will always increment the message counter from zero',
|
||||
sender_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@localhost',
|
||||
msgFactory = function () {
|
||||
|
@ -1267,29 +1245,28 @@
|
|||
// leave converse-chat page
|
||||
_converse.windowState = 'hidden';
|
||||
_converse.chatboxes.onMessage(msgFactory());
|
||||
return test_utils.waitUntil(() => _converse.api.chats.get().length)
|
||||
.then(() => {
|
||||
expect(_converse.msg_counter).toBe(1);
|
||||
await test_utils.waitUntil(() => _converse.api.chats.get().length)
|
||||
let view = _converse.chatboxviews.get(sender_jid);
|
||||
await new Promise((resolve, reject) => view.once('messageInserted', resolve));
|
||||
expect(_converse.msg_counter).toBe(1);
|
||||
|
||||
// come back to converse-chat page
|
||||
_converse.saveWindowState(null, 'focus');
|
||||
view = _converse.chatboxviews.get(sender_jid);
|
||||
expect(u.isVisible(view.el)).toBeTruthy();
|
||||
expect(_converse.msg_counter).toBe(0);
|
||||
// come back to converse-chat page
|
||||
_converse.saveWindowState(null, 'focus');
|
||||
expect(u.isVisible(view.el)).toBeTruthy();
|
||||
expect(_converse.msg_counter).toBe(0);
|
||||
|
||||
// close chatbox and leave converse-chat page again
|
||||
view.close();
|
||||
_converse.windowState = 'hidden';
|
||||
// close chatbox and leave converse-chat page again
|
||||
view.close();
|
||||
_converse.windowState = 'hidden';
|
||||
|
||||
// check that msg_counter is incremented from zero again
|
||||
_converse.chatboxes.onMessage(msgFactory());
|
||||
return test_utils.waitUntil(() => _converse.api.chats.get().length)
|
||||
}).then(() => {
|
||||
view = _converse.chatboxviews.get(sender_jid);
|
||||
expect(u.isVisible(view.el)).toBeTruthy();
|
||||
expect(_converse.msg_counter).toBe(1);
|
||||
done();
|
||||
});
|
||||
// check that msg_counter is incremented from zero again
|
||||
_converse.chatboxes.onMessage(msgFactory());
|
||||
await test_utils.waitUntil(() => _converse.api.chats.get().length)
|
||||
view = _converse.chatboxviews.get(sender_jid);
|
||||
await new Promise((resolve, reject) => view.once('messageInserted', resolve));
|
||||
expect(u.isVisible(view.el)).toBeTruthy();
|
||||
expect(_converse.msg_counter).toBe(1);
|
||||
done();
|
||||
}));
|
||||
});
|
||||
|
||||
|
|
2344
spec/chatroom.js
2344
spec/chatroom.js
File diff suppressed because it is too large
Load Diff
|
@ -268,224 +268,210 @@
|
|||
|
||||
describe("when clicked and a file chosen", function () {
|
||||
|
||||
it("is uploaded and sent out", mock.initConverseWithAsync(function (done, _converse) {
|
||||
test_utils.waitUntilDiscoConfirmed(
|
||||
it("is uploaded and sent out", mock.initConverseWithAsync(
|
||||
async function (done, _converse) {
|
||||
|
||||
await test_utils.waitUntilDiscoConfirmed(
|
||||
_converse, _converse.domain,
|
||||
[{'category': 'server', 'type':'IM'}],
|
||||
['http://jabber.org/protocol/disco#items'], [], 'info').then(function () {
|
||||
['http://jabber.org/protocol/disco#items'], [], 'info');
|
||||
|
||||
var send_backup = XMLHttpRequest.prototype.send;
|
||||
var IQ_stanzas = _converse.connection.IQ_stanzas;
|
||||
let contact_jid;
|
||||
const send_backup = XMLHttpRequest.prototype.send;
|
||||
const IQ_stanzas = _converse.connection.IQ_stanzas;
|
||||
|
||||
test_utils.waitUntilDiscoConfirmed(_converse, _converse.domain, [], [], ['upload.montague.tld'], 'items')
|
||||
.then(() => test_utils.waitUntilDiscoConfirmed(_converse, 'upload.montague.tld', [], [Strophe.NS.HTTPUPLOAD], []))
|
||||
await test_utils.waitUntilDiscoConfirmed(_converse, _converse.domain, [], [], ['upload.montague.tld'], 'items');
|
||||
await test_utils.waitUntilDiscoConfirmed(_converse, 'upload.montague.tld', [], [Strophe.NS.HTTPUPLOAD], []);
|
||||
test_utils.createContacts(_converse, 'current');
|
||||
_converse.emit('rosterContactsFetched');
|
||||
const contact_jid = mock.cur_names[2].replace(/ /g,'.').toLowerCase() + '@localhost';
|
||||
await test_utils.openChatBoxFor(_converse, contact_jid);
|
||||
const view = _converse.chatboxviews.get(contact_jid);
|
||||
const file = {
|
||||
'type': 'image/jpeg',
|
||||
'size': '23456' ,
|
||||
'lastModifiedDate': "",
|
||||
'name': "my-juliet.jpg"
|
||||
};
|
||||
view.model.sendFiles([file]);
|
||||
await new Promise((resolve, reject) => view.once('messageInserted', resolve));
|
||||
|
||||
await test_utils.waitUntil(() => _.filter(IQ_stanzas, iq => iq.nodeTree.querySelector('iq[to="upload.montague.tld"] request')).length);
|
||||
var iq = IQ_stanzas.pop();
|
||||
expect(iq.toLocaleString()).toBe(
|
||||
`<iq from="dummy@localhost/resource" `+
|
||||
`id="${iq.nodeTree.getAttribute("id")}" `+
|
||||
`to="upload.montague.tld" `+
|
||||
`type="get" `+
|
||||
`xmlns="jabber:client">`+
|
||||
`<request `+
|
||||
`content-type="image/jpeg" `+
|
||||
`filename="my-juliet.jpg" `+
|
||||
`size="23456" `+
|
||||
`xmlns="urn:xmpp:http:upload:0"/>`+
|
||||
`</iq>`);
|
||||
|
||||
var base_url = document.URL.split(window.location.pathname)[0];
|
||||
var message = base_url+"/logo/conversejs-filled.svg";
|
||||
|
||||
var stanza = Strophe.xmlHtmlNode(
|
||||
"<iq from='upload.montague.tld'"+
|
||||
" id='"+iq.nodeTree.getAttribute('id')+"'"+
|
||||
" to='dummy@localhost/resource'"+
|
||||
" type='result'>"+
|
||||
"<slot xmlns='urn:xmpp:http:upload:0'>"+
|
||||
" <put url='https://upload.montague.tld/4a771ac1-f0b2-4a4a-9700-f2a26fa2bb67/my-juliet.jpg'>"+
|
||||
" <header name='Authorization'>Basic Base64String==</header>"+
|
||||
" <header name='Cookie'>foo=bar; user=romeo</header>"+
|
||||
" </put>"+
|
||||
" <get url='"+message+"' />"+
|
||||
"</slot>"+
|
||||
"</iq>").firstElementChild;
|
||||
|
||||
spyOn(XMLHttpRequest.prototype, 'send').and.callFake(function () {
|
||||
const message = view.model.messages.at(0);
|
||||
expect(view.el.querySelector('.chat-content progress').getAttribute('value')).toBe('0');
|
||||
message.set('progress', 0.5);
|
||||
test_utils.waitUntil(() => view.el.querySelector('.chat-content progress').getAttribute('value') === '0.5')
|
||||
.then(() => {
|
||||
test_utils.createContacts(_converse, 'current');
|
||||
_converse.emit('rosterContactsFetched');
|
||||
contact_jid = mock.cur_names[2].replace(/ /g,'.').toLowerCase() + '@localhost';
|
||||
return test_utils.openChatBoxFor(_converse, contact_jid);
|
||||
message.set('progress', 1);
|
||||
test_utils.waitUntil(() => view.el.querySelector('.chat-content progress').getAttribute('value') === '1')
|
||||
}).then(() => {
|
||||
var view = _converse.chatboxviews.get(contact_jid);
|
||||
var file = {
|
||||
'type': 'image/jpeg',
|
||||
'size': '23456' ,
|
||||
'lastModifiedDate': "",
|
||||
'name': "my-juliet.jpg"
|
||||
};
|
||||
view.model.sendFiles([file]);
|
||||
return test_utils.waitUntil(function () {
|
||||
return _.filter(IQ_stanzas, function (iq) {
|
||||
return iq.nodeTree.querySelector('iq[to="upload.montague.tld"] request');
|
||||
}).length > 0;
|
||||
}).then(function () {
|
||||
var iq = IQ_stanzas.pop();
|
||||
expect(iq.toLocaleString()).toBe(
|
||||
`<iq from="dummy@localhost/resource" `+
|
||||
`id="${iq.nodeTree.getAttribute("id")}" `+
|
||||
`to="upload.montague.tld" `+
|
||||
`type="get" `+
|
||||
`xmlns="jabber:client">`+
|
||||
`<request `+
|
||||
`content-type="image/jpeg" `+
|
||||
`filename="my-juliet.jpg" `+
|
||||
`size="23456" `+
|
||||
`xmlns="urn:xmpp:http:upload:0"/>`+
|
||||
`</iq>`);
|
||||
|
||||
var base_url = document.URL.split(window.location.pathname)[0];
|
||||
var message = base_url+"/logo/conversejs-filled.svg";
|
||||
|
||||
var stanza = Strophe.xmlHtmlNode(
|
||||
"<iq from='upload.montague.tld'"+
|
||||
" id='"+iq.nodeTree.getAttribute('id')+"'"+
|
||||
" to='dummy@localhost/resource'"+
|
||||
" type='result'>"+
|
||||
"<slot xmlns='urn:xmpp:http:upload:0'>"+
|
||||
" <put url='https://upload.montague.tld/4a771ac1-f0b2-4a4a-9700-f2a26fa2bb67/my-juliet.jpg'>"+
|
||||
" <header name='Authorization'>Basic Base64String==</header>"+
|
||||
" <header name='Cookie'>foo=bar; user=romeo</header>"+
|
||||
" </put>"+
|
||||
" <get url='"+message+"' />"+
|
||||
"</slot>"+
|
||||
"</iq>").firstElementChild;
|
||||
|
||||
spyOn(XMLHttpRequest.prototype, 'send').and.callFake(function () {
|
||||
const message = view.model.messages.at(0);
|
||||
expect(view.el.querySelector('.chat-content progress').getAttribute('value')).toBe('0');
|
||||
message.set('progress', 0.5);
|
||||
expect(view.el.querySelector('.chat-content progress').getAttribute('value')).toBe('0.5');
|
||||
message.set('progress', 1);
|
||||
expect(view.el.querySelector('.chat-content progress').getAttribute('value')).toBe('1');
|
||||
message.save({
|
||||
'upload': _converse.SUCCESS,
|
||||
'oob_url': message.get('get'),
|
||||
'message': message.get('get')
|
||||
});
|
||||
});
|
||||
var sent_stanza;
|
||||
spyOn(_converse.connection, 'send').and.callFake(function (stanza) {
|
||||
sent_stanza = stanza;
|
||||
});
|
||||
_converse.connection._dataRecv(test_utils.createRequest(stanza));
|
||||
|
||||
return test_utils.waitUntil(function () {
|
||||
return sent_stanza;
|
||||
}, 1000).then(function () {
|
||||
expect(sent_stanza.toLocaleString()).toBe(
|
||||
`<message from="dummy@localhost/resource" `+
|
||||
`id="${sent_stanza.nodeTree.getAttribute("id")}" `+
|
||||
`to="irini.vlastuin@localhost" `+
|
||||
`type="chat" `+
|
||||
`xmlns="jabber:client">`+
|
||||
`<body>${message}</body>`+
|
||||
`<active xmlns="http://jabber.org/protocol/chatstates"/>`+
|
||||
`<x xmlns="jabber:x:oob">`+
|
||||
`<url>${message}</url>`+
|
||||
`</x>`+
|
||||
`</message>`);
|
||||
return test_utils.waitUntil(() => view.el.querySelector('.chat-image'), 1000);
|
||||
}).then(function () {
|
||||
// Check that the image renders
|
||||
expect(view.el.querySelector('.chat-msg .chat-msg__media').innerHTML.trim()).toEqual(
|
||||
`<!-- src/templates/image.html -->\n`+
|
||||
`<a href="${window.location.origin}/logo/conversejs-filled.svg" target="_blank" rel="noopener">`+
|
||||
`<img class="chat-image img-thumbnail" src="${window.location.origin}/logo/conversejs-filled.svg">`+
|
||||
`</a>`);
|
||||
XMLHttpRequest.prototype.send = send_backup;
|
||||
done();
|
||||
});
|
||||
message.save({
|
||||
'upload': _converse.SUCCESS,
|
||||
'oob_url': message.get('get'),
|
||||
'message': message.get('get')
|
||||
});
|
||||
return new Promise((resolve, reject) => view.model.messages.once('rendered', resolve));
|
||||
});
|
||||
});
|
||||
let sent_stanza;
|
||||
spyOn(_converse.connection, 'send').and.callFake(stanza => (sent_stanza = stanza));
|
||||
_converse.connection._dataRecv(test_utils.createRequest(stanza));
|
||||
|
||||
await test_utils.waitUntil(() => sent_stanza, 1000);
|
||||
expect(sent_stanza.toLocaleString()).toBe(
|
||||
`<message from="dummy@localhost/resource" `+
|
||||
`id="${sent_stanza.nodeTree.getAttribute("id")}" `+
|
||||
`to="irini.vlastuin@localhost" `+
|
||||
`type="chat" `+
|
||||
`xmlns="jabber:client">`+
|
||||
`<body>${message}</body>`+
|
||||
`<active xmlns="http://jabber.org/protocol/chatstates"/>`+
|
||||
`<x xmlns="jabber:x:oob">`+
|
||||
`<url>${message}</url>`+
|
||||
`</x>`+
|
||||
`</message>`);
|
||||
await test_utils.waitUntil(() => view.el.querySelector('.chat-image'), 1000);
|
||||
// Check that the image renders
|
||||
expect(view.el.querySelector('.chat-msg .chat-msg__media').innerHTML.trim()).toEqual(
|
||||
`<!-- src/templates/image.html -->\n`+
|
||||
`<a href="${window.location.origin}/logo/conversejs-filled.svg" target="_blank" rel="noopener">`+
|
||||
`<img class="chat-image img-thumbnail" src="${window.location.origin}/logo/conversejs-filled.svg">`+
|
||||
`</a>`);
|
||||
XMLHttpRequest.prototype.send = send_backup;
|
||||
done();
|
||||
}));
|
||||
|
||||
it("is uploaded and sent out from a groupchat", mock.initConverseWithAsync(function (done, _converse) {
|
||||
test_utils.waitUntilDiscoConfirmed(
|
||||
it("is uploaded and sent out from a groupchat", mock.initConverseWithAsync(
|
||||
async function (done, _converse) {
|
||||
|
||||
await test_utils.waitUntilDiscoConfirmed(
|
||||
_converse, _converse.domain,
|
||||
[{'category': 'server', 'type':'IM'}],
|
||||
['http://jabber.org/protocol/disco#items'], [], 'info').then(function () {
|
||||
['http://jabber.org/protocol/disco#items'], [], 'info');
|
||||
|
||||
var send_backup = XMLHttpRequest.prototype.send;
|
||||
var IQ_stanzas = _converse.connection.IQ_stanzas;
|
||||
const send_backup = XMLHttpRequest.prototype.send;
|
||||
const IQ_stanzas = _converse.connection.IQ_stanzas;
|
||||
|
||||
test_utils.waitUntilDiscoConfirmed(_converse, _converse.domain, [], [], ['upload.montague.tld'], 'items').then(function () {
|
||||
test_utils.waitUntilDiscoConfirmed(_converse, 'upload.montague.tld', [], [Strophe.NS.HTTPUPLOAD], []).then(function () {
|
||||
test_utils.openAndEnterChatRoom(_converse, 'lounge', 'localhost', 'dummy').then(function () {
|
||||
var view = _converse.chatboxviews.get('lounge@localhost');
|
||||
var file = {
|
||||
'type': 'image/jpeg',
|
||||
'size': '23456' ,
|
||||
'lastModifiedDate': "",
|
||||
'name': "my-juliet.jpg"
|
||||
};
|
||||
view.model.sendFiles([file]);
|
||||
await test_utils.waitUntilDiscoConfirmed(_converse, _converse.domain, [], [], ['upload.montague.tld'], 'items');
|
||||
await test_utils.waitUntilDiscoConfirmed(_converse, 'upload.montague.tld', [], [Strophe.NS.HTTPUPLOAD], []);
|
||||
await test_utils.openAndEnterChatRoom(_converse, 'lounge', 'localhost', 'dummy');
|
||||
const view = _converse.chatboxviews.get('lounge@localhost');
|
||||
const file = {
|
||||
'type': 'image/jpeg',
|
||||
'size': '23456' ,
|
||||
'lastModifiedDate': "",
|
||||
'name': "my-juliet.jpg"
|
||||
};
|
||||
view.model.sendFiles([file]);
|
||||
await new Promise((resolve, reject) => view.once('messageInserted', resolve));
|
||||
|
||||
return test_utils.waitUntil(function () {
|
||||
return _.filter(IQ_stanzas, function (iq) {
|
||||
return iq.nodeTree.querySelector('iq[to="upload.montague.tld"] request');
|
||||
}).length > 0;
|
||||
}).then(function () {
|
||||
var iq = IQ_stanzas.pop();
|
||||
expect(iq.toLocaleString()).toBe(
|
||||
`<iq from="dummy@localhost/resource" `+
|
||||
`id="${iq.nodeTree.getAttribute("id")}" `+
|
||||
`to="upload.montague.tld" `+
|
||||
`type="get" `+
|
||||
`xmlns="jabber:client">`+
|
||||
`<request `+
|
||||
`content-type="image/jpeg" `+
|
||||
`filename="my-juliet.jpg" `+
|
||||
`size="23456" `+
|
||||
`xmlns="urn:xmpp:http:upload:0"/>`+
|
||||
`</iq>`);
|
||||
await test_utils.waitUntil(() => _.filter(IQ_stanzas, iq => iq.nodeTree.querySelector('iq[to="upload.montague.tld"] request')).length);
|
||||
var iq = IQ_stanzas.pop();
|
||||
expect(iq.toLocaleString()).toBe(
|
||||
`<iq from="dummy@localhost/resource" `+
|
||||
`id="${iq.nodeTree.getAttribute("id")}" `+
|
||||
`to="upload.montague.tld" `+
|
||||
`type="get" `+
|
||||
`xmlns="jabber:client">`+
|
||||
`<request `+
|
||||
`content-type="image/jpeg" `+
|
||||
`filename="my-juliet.jpg" `+
|
||||
`size="23456" `+
|
||||
`xmlns="urn:xmpp:http:upload:0"/>`+
|
||||
`</iq>`);
|
||||
|
||||
var base_url = document.URL.split(window.location.pathname)[0];
|
||||
var message = base_url+"/logo/conversejs-filled.svg";
|
||||
var base_url = document.URL.split(window.location.pathname)[0];
|
||||
var message = base_url+"/logo/conversejs-filled.svg";
|
||||
|
||||
var stanza = Strophe.xmlHtmlNode(
|
||||
"<iq from='upload.montague.tld'"+
|
||||
" id='"+iq.nodeTree.getAttribute('id')+"'"+
|
||||
" to='dummy@localhost/resource'"+
|
||||
" type='result'>"+
|
||||
"<slot xmlns='urn:xmpp:http:upload:0'>"+
|
||||
" <put url='https://upload.montague.tld/4a771ac1-f0b2-4a4a-9700-f2a26fa2bb67/my-juliet.jpg'>"+
|
||||
" <header name='Authorization'>Basic Base64String==</header>"+
|
||||
" <header name='Cookie'>foo=bar; user=romeo</header>"+
|
||||
" </put>"+
|
||||
" <get url='"+message+"' />"+
|
||||
"</slot>"+
|
||||
"</iq>").firstElementChild;
|
||||
var stanza = Strophe.xmlHtmlNode(
|
||||
"<iq from='upload.montague.tld'"+
|
||||
" id='"+iq.nodeTree.getAttribute('id')+"'"+
|
||||
" to='dummy@localhost/resource'"+
|
||||
" type='result'>"+
|
||||
"<slot xmlns='urn:xmpp:http:upload:0'>"+
|
||||
" <put url='https://upload.montague.tld/4a771ac1-f0b2-4a4a-9700-f2a26fa2bb67/my-juliet.jpg'>"+
|
||||
" <header name='Authorization'>Basic Base64String==</header>"+
|
||||
" <header name='Cookie'>foo=bar; user=romeo</header>"+
|
||||
" </put>"+
|
||||
" <get url='"+message+"' />"+
|
||||
"</slot>"+
|
||||
"</iq>").firstElementChild;
|
||||
|
||||
spyOn(XMLHttpRequest.prototype, 'send').and.callFake(function () {
|
||||
const message = view.model.messages.at(0);
|
||||
expect(view.el.querySelector('.chat-content progress').getAttribute('value')).toBe('0');
|
||||
message.set('progress', 0.5);
|
||||
expect(view.el.querySelector('.chat-content progress').getAttribute('value')).toBe('0.5');
|
||||
message.set('progress', 1);
|
||||
expect(view.el.querySelector('.chat-content progress').getAttribute('value')).toBe('1');
|
||||
message.save({
|
||||
'upload': _converse.SUCCESS,
|
||||
'oob_url': message.get('get'),
|
||||
'message': message.get('get')
|
||||
});
|
||||
});
|
||||
var sent_stanza;
|
||||
spyOn(_converse.connection, 'send').and.callFake(function (stanza) {
|
||||
sent_stanza = stanza;
|
||||
});
|
||||
_converse.connection._dataRecv(test_utils.createRequest(stanza));
|
||||
|
||||
return test_utils.waitUntil(() => sent_stanza, 1000).then(function () {
|
||||
expect(sent_stanza.toLocaleString()).toBe(
|
||||
`<message `+
|
||||
`from="dummy@localhost/resource" `+
|
||||
`id="${sent_stanza.nodeTree.getAttribute("id")}" `+
|
||||
`to="lounge@localhost" `+
|
||||
`type="groupchat" `+
|
||||
`xmlns="jabber:client">`+
|
||||
`<body>${message}</body>`+
|
||||
`<active xmlns="http://jabber.org/protocol/chatstates"/>`+
|
||||
`<x xmlns="jabber:x:oob">`+
|
||||
`<url>${message}</url>`+
|
||||
`</x>`+
|
||||
`</message>`);
|
||||
return test_utils.waitUntil(() => view.el.querySelector('.chat-image'), 1000);
|
||||
}).then(function () {
|
||||
// Check that the image renders
|
||||
expect(view.el.querySelector('.chat-msg .chat-msg__media').innerHTML.trim()).toEqual(
|
||||
`<!-- src/templates/image.html -->\n`+
|
||||
`<a href="${window.location.origin}/logo/conversejs-filled.svg" target="_blank" rel="noopener">`+
|
||||
`<img class="chat-image img-thumbnail" src="${window.location.origin}/logo/conversejs-filled.svg">`+
|
||||
`</a>`);
|
||||
XMLHttpRequest.prototype.send = send_backup;
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
spyOn(XMLHttpRequest.prototype, 'send').and.callFake(function () {
|
||||
const message = view.model.messages.at(0);
|
||||
expect(view.el.querySelector('.chat-content progress').getAttribute('value')).toBe('0');
|
||||
message.set('progress', 0.5);
|
||||
test_utils.waitUntil(() => view.el.querySelector('.chat-content progress').getAttribute('value') === '0.5')
|
||||
.then(() => {
|
||||
message.set('progress', 1);
|
||||
test_utils.waitUntil(() => view.el.querySelector('.chat-content progress').getAttribute('value') === '1')
|
||||
}).then(() => {
|
||||
message.save({
|
||||
'upload': _converse.SUCCESS,
|
||||
'oob_url': message.get('get'),
|
||||
'message': message.get('get')
|
||||
});
|
||||
return new Promise((resolve, reject) => view.model.messages.once('rendered', resolve));
|
||||
});
|
||||
});
|
||||
let sent_stanza;
|
||||
spyOn(_converse.connection, 'send').and.callFake(stanza => (sent_stanza = stanza));
|
||||
_converse.connection._dataRecv(test_utils.createRequest(stanza));
|
||||
|
||||
await test_utils.waitUntil(() => sent_stanza, 1000);
|
||||
expect(sent_stanza.toLocaleString()).toBe(
|
||||
`<message `+
|
||||
`from="dummy@localhost/resource" `+
|
||||
`id="${sent_stanza.nodeTree.getAttribute("id")}" `+
|
||||
`to="lounge@localhost" `+
|
||||
`type="groupchat" `+
|
||||
`xmlns="jabber:client">`+
|
||||
`<body>${message}</body>`+
|
||||
`<active xmlns="http://jabber.org/protocol/chatstates"/>`+
|
||||
`<x xmlns="jabber:x:oob">`+
|
||||
`<url>${message}</url>`+
|
||||
`</x>`+
|
||||
`</message>`);
|
||||
await test_utils.waitUntil(() => view.el.querySelector('.chat-image'), 1000);
|
||||
// Check that the image renders
|
||||
expect(view.el.querySelector('.chat-msg .chat-msg__media').innerHTML.trim()).toEqual(
|
||||
`<!-- src/templates/image.html -->\n`+
|
||||
`<a href="${window.location.origin}/logo/conversejs-filled.svg" target="_blank" rel="noopener">`+
|
||||
`<img class="chat-image img-thumbnail" src="${window.location.origin}/logo/conversejs-filled.svg">`+
|
||||
`</a>`);
|
||||
XMLHttpRequest.prototype.send = send_backup;
|
||||
done();
|
||||
}));
|
||||
|
||||
it("shows an error message if the file is too large", mock.initConverseWithAsync(function (done, _converse) {
|
||||
|
@ -617,82 +603,78 @@
|
|||
describe("While a file is being uploaded", function () {
|
||||
|
||||
it("shows a progress bar", mock.initConverseWithPromises(
|
||||
null, ['rosterGroupsFetched', 'chatBoxesFetched'], {}, function (done, _converse) {
|
||||
null, ['rosterGroupsFetched', 'chatBoxesFetched'], {},
|
||||
async function (done, _converse) {
|
||||
|
||||
test_utils.waitUntilDiscoConfirmed(
|
||||
await test_utils.waitUntilDiscoConfirmed(
|
||||
_converse, _converse.domain,
|
||||
[{'category': 'server', 'type':'IM'}],
|
||||
['http://jabber.org/protocol/disco#items'], [], 'info').then(function () {
|
||||
['http://jabber.org/protocol/disco#items'], [], 'info');
|
||||
|
||||
var send_backup = XMLHttpRequest.prototype.send;
|
||||
var IQ_stanzas = _converse.connection.IQ_stanzas;
|
||||
let view, contact_jid;
|
||||
const send_backup = XMLHttpRequest.prototype.send;
|
||||
const IQ_stanzas = _converse.connection.IQ_stanzas;
|
||||
|
||||
test_utils.waitUntilDiscoConfirmed(_converse, _converse.domain, [], [], ['upload.montague.tld'], 'items')
|
||||
.then(() => test_utils.waitUntilDiscoConfirmed(_converse, 'upload.montague.tld', [], [Strophe.NS.HTTPUPLOAD], []))
|
||||
await test_utils.waitUntilDiscoConfirmed(_converse, _converse.domain, [], [], ['upload.montague.tld'], 'items');
|
||||
await test_utils.waitUntilDiscoConfirmed(_converse, 'upload.montague.tld', [], [Strophe.NS.HTTPUPLOAD], []);
|
||||
test_utils.createContacts(_converse, 'current');
|
||||
_converse.emit('rosterContactsFetched');
|
||||
const contact_jid = mock.cur_names[2].replace(/ /g,'.').toLowerCase() + '@localhost';
|
||||
await test_utils.openChatBoxFor(_converse, contact_jid);
|
||||
const view = _converse.chatboxviews.get(contact_jid);
|
||||
const file = {
|
||||
'type': 'image/jpeg',
|
||||
'size': '23456' ,
|
||||
'lastModifiedDate': "",
|
||||
'name': "my-juliet.jpg"
|
||||
};
|
||||
view.model.sendFiles([file]);
|
||||
await new Promise((resolve, reject) => view.once('messageInserted', resolve));
|
||||
await test_utils.waitUntil(() => _.filter(IQ_stanzas, (iq) => iq.nodeTree.querySelector('iq[to="upload.montague.tld"] request')).length)
|
||||
const iq = IQ_stanzas.pop();
|
||||
expect(iq.toLocaleString()).toBe(
|
||||
`<iq from="dummy@localhost/resource" `+
|
||||
`id="${iq.nodeTree.getAttribute("id")}" `+
|
||||
`to="upload.montague.tld" `+
|
||||
`type="get" `+
|
||||
`xmlns="jabber:client">`+
|
||||
`<request `+
|
||||
`content-type="image/jpeg" `+
|
||||
`filename="my-juliet.jpg" `+
|
||||
`size="23456" `+
|
||||
`xmlns="urn:xmpp:http:upload:0"/>`+
|
||||
`</iq>`);
|
||||
|
||||
const base_url = document.URL.split(window.location.pathname)[0];
|
||||
const message = base_url+"/logo/conversejs-filled.svg";
|
||||
const stanza = Strophe.xmlHtmlNode(
|
||||
"<iq from='upload.montague.tld'"+
|
||||
" id='"+iq.nodeTree.getAttribute('id')+"'"+
|
||||
" to='dummy@localhost/resource'"+
|
||||
" type='result'>"+
|
||||
"<slot xmlns='urn:xmpp:http:upload:0'>"+
|
||||
" <put url='https://upload.montague.tld/4a771ac1-f0b2-4a4a-9700-f2a26fa2bb67/my-juliet.jpg'>"+
|
||||
" <header name='Authorization'>Basic Base64String==</header>"+
|
||||
" <header name='Cookie'>foo=bar; user=romeo</header>"+
|
||||
" </put>"+
|
||||
" <get url='"+message+"' />"+
|
||||
"</slot>"+
|
||||
"</iq>").firstElementChild;
|
||||
spyOn(XMLHttpRequest.prototype, 'send').and.callFake(function () {
|
||||
const message = view.model.messages.at(0);
|
||||
expect(view.el.querySelector('.chat-content progress').getAttribute('value')).toBe('0');
|
||||
message.set('progress', 0.5);
|
||||
test_utils.waitUntil(() => view.el.querySelector('.chat-content progress').getAttribute('value') === '0.5')
|
||||
.then(() => {
|
||||
test_utils.createContacts(_converse, 'current');
|
||||
_converse.emit('rosterContactsFetched');
|
||||
|
||||
contact_jid = mock.cur_names[2].replace(/ /g,'.').toLowerCase() + '@localhost';
|
||||
return test_utils.openChatBoxFor(_converse, contact_jid);
|
||||
message.set('progress', 1);
|
||||
test_utils.waitUntil(() => view.el.querySelector('.chat-content progress').getAttribute('value') === '1')
|
||||
}).then(() => {
|
||||
view = _converse.chatboxviews.get(contact_jid);
|
||||
const file = {
|
||||
'type': 'image/jpeg',
|
||||
'size': '23456' ,
|
||||
'lastModifiedDate': "",
|
||||
'name': "my-juliet.jpg"
|
||||
};
|
||||
view.model.sendFiles([file]);
|
||||
return test_utils.waitUntil(() => _.filter(IQ_stanzas, (iq) => iq.nodeTree.querySelector('iq[to="upload.montague.tld"] request')).length)
|
||||
}).then(function () {
|
||||
const iq = IQ_stanzas.pop();
|
||||
expect(iq.toLocaleString()).toBe(
|
||||
`<iq from="dummy@localhost/resource" `+
|
||||
`id="${iq.nodeTree.getAttribute("id")}" `+
|
||||
`to="upload.montague.tld" `+
|
||||
`type="get" `+
|
||||
`xmlns="jabber:client">`+
|
||||
`<request `+
|
||||
`content-type="image/jpeg" `+
|
||||
`filename="my-juliet.jpg" `+
|
||||
`size="23456" `+
|
||||
`xmlns="urn:xmpp:http:upload:0"/>`+
|
||||
`</iq>`);
|
||||
|
||||
const base_url = document.URL.split(window.location.pathname)[0];
|
||||
const message = base_url+"/logo/conversejs-filled.svg";
|
||||
const stanza = Strophe.xmlHtmlNode(
|
||||
"<iq from='upload.montague.tld'"+
|
||||
" id='"+iq.nodeTree.getAttribute('id')+"'"+
|
||||
" to='dummy@localhost/resource'"+
|
||||
" type='result'>"+
|
||||
"<slot xmlns='urn:xmpp:http:upload:0'>"+
|
||||
" <put url='https://upload.montague.tld/4a771ac1-f0b2-4a4a-9700-f2a26fa2bb67/my-juliet.jpg'>"+
|
||||
" <header name='Authorization'>Basic Base64String==</header>"+
|
||||
" <header name='Cookie'>foo=bar; user=romeo</header>"+
|
||||
" </put>"+
|
||||
" <get url='"+message+"' />"+
|
||||
"</slot>"+
|
||||
"</iq>").firstElementChild;
|
||||
spyOn(XMLHttpRequest.prototype, 'send').and.callFake(function () {
|
||||
const message = view.model.messages.at(0);
|
||||
expect(view.el.querySelector('.chat-content progress').getAttribute('value')).toBe('0');
|
||||
message.set('progress', 0.5);
|
||||
expect(view.el.querySelector('.chat-content progress').getAttribute('value')).toBe('0.5');
|
||||
message.set('progress', 1);
|
||||
expect(view.el.querySelector('.chat-content progress').getAttribute('value')).toBe('1');
|
||||
expect(view.el.querySelector('.chat-content .chat-msg__text').textContent).toBe('Uploading file: my-juliet.jpg, 22.91 KB');
|
||||
done();
|
||||
});
|
||||
var sent_stanza;
|
||||
spyOn(_converse.connection, 'send').and.callFake(function (stanza) {
|
||||
sent_stanza = stanza;
|
||||
});
|
||||
_converse.connection._dataRecv(test_utils.createRequest(stanza));
|
||||
expect(view.el.querySelector('.chat-content .chat-msg__text').textContent).toBe('Uploading file: my-juliet.jpg, 22.91 KB');
|
||||
done();
|
||||
});
|
||||
});
|
||||
let sent_stanza;
|
||||
spyOn(_converse.connection, 'send').and.callFake(stanza => (sent_stanza = stanza));
|
||||
_converse.connection._dataRecv(test_utils.createRequest(stanza));
|
||||
}));
|
||||
});
|
||||
});
|
||||
|
|
3166
spec/messages.js
3166
spec/messages.js
File diff suppressed because it is too large
Load Diff
|
@ -95,113 +95,106 @@
|
|||
{ whitelisted_plugins: ['converse-roomslist'],
|
||||
allow_bookmarks: false // Makes testing easier, otherwise we
|
||||
// have to mock stanza traffic.
|
||||
}, function (done, _converse) {
|
||||
}, async function (done, _converse) {
|
||||
|
||||
let view;
|
||||
const IQ_stanzas = _converse.connection.IQ_stanzas;
|
||||
const room_jid = 'coven@chat.shakespeare.lit';
|
||||
test_utils.openControlBox();
|
||||
_converse.api.rooms.open(room_jid, {'nick': 'some1'})
|
||||
.then(() => {
|
||||
return test_utils.waitUntil(() => _.get(_.filter(
|
||||
IQ_stanzas,
|
||||
iq => iq.nodeTree.querySelector(
|
||||
`iq[to="${room_jid}"] query[xmlns="http://jabber.org/protocol/disco#info"]`
|
||||
)).pop(), 'nodeTree'));
|
||||
}).then(last_stanza => {
|
||||
view = _converse.chatboxviews.get(room_jid);
|
||||
const IQ_id = last_stanza.getAttribute('id');
|
||||
const features_stanza = $iq({
|
||||
'from': 'coven@chat.shakespeare.lit',
|
||||
'id': IQ_id,
|
||||
'to': 'dummy@localhost/desktop',
|
||||
'type': 'result'
|
||||
})
|
||||
.c('query', { 'xmlns': 'http://jabber.org/protocol/disco#info'})
|
||||
.c('identity', {
|
||||
'category': 'conference',
|
||||
'name': 'A Dark Cave',
|
||||
'type': 'text'
|
||||
}).up()
|
||||
.c('feature', {'var': 'http://jabber.org/protocol/muc'}).up()
|
||||
.c('feature', {'var': 'muc_passwordprotected'}).up()
|
||||
.c('feature', {'var': 'muc_hidden'}).up()
|
||||
.c('feature', {'var': 'muc_temporary'}).up()
|
||||
.c('feature', {'var': 'muc_open'}).up()
|
||||
.c('feature', {'var': 'muc_unmoderated'}).up()
|
||||
.c('feature', {'var': 'muc_nonanonymous'}).up()
|
||||
.c('feature', {'var': 'urn:xmpp:mam:0'}).up()
|
||||
.c('x', { 'xmlns':'jabber:x:data', 'type':'result'})
|
||||
.c('field', {'var':'FORM_TYPE', 'type':'hidden'})
|
||||
.c('value').t('http://jabber.org/protocol/muc#roominfo').up().up()
|
||||
.c('field', {'type':'text-single', 'var':'muc#roominfo_description', 'label':'Description'})
|
||||
.c('value').t('This is the description').up().up()
|
||||
.c('field', {'type':'text-single', 'var':'muc#roominfo_occupants', 'label':'Number of occupants'})
|
||||
.c('value').t(0);
|
||||
_converse.connection._dataRecv(test_utils.createRequest(features_stanza));
|
||||
return test_utils.waitUntil(() => view.model.get('connection_status') === converse.ROOMSTATUS.CONNECTING)
|
||||
}).then(function () {
|
||||
var presence = $pres({
|
||||
to: _converse.connection.jid,
|
||||
from: 'coven@chat.shakespeare.lit/some1',
|
||||
id: 'DC352437-C019-40EC-B590-AF29E879AF97'
|
||||
}).c('x').attrs({xmlns:'http://jabber.org/protocol/muc#user'})
|
||||
.c('item').attrs({
|
||||
affiliation: 'member',
|
||||
jid: _converse.bare_jid,
|
||||
role: 'participant'
|
||||
await _converse.api.rooms.open(room_jid, {'nick': 'some1'});
|
||||
const last_stanza = await test_utils.waitUntil(() => _.get(_.filter(
|
||||
IQ_stanzas,
|
||||
iq => iq.nodeTree.querySelector(
|
||||
`iq[to="${room_jid}"] query[xmlns="http://jabber.org/protocol/disco#info"]`
|
||||
)).pop(), 'nodeTree'));
|
||||
const view = _converse.chatboxviews.get(room_jid);
|
||||
const IQ_id = last_stanza.getAttribute('id');
|
||||
const features_stanza = $iq({
|
||||
'from': 'coven@chat.shakespeare.lit',
|
||||
'id': IQ_id,
|
||||
'to': 'dummy@localhost/desktop',
|
||||
'type': 'result'
|
||||
})
|
||||
.c('query', { 'xmlns': 'http://jabber.org/protocol/disco#info'})
|
||||
.c('identity', {
|
||||
'category': 'conference',
|
||||
'name': 'A Dark Cave',
|
||||
'type': 'text'
|
||||
}).up()
|
||||
.c('status').attrs({code:'110'});
|
||||
_converse.connection._dataRecv(test_utils.createRequest(presence));
|
||||
.c('feature', {'var': 'http://jabber.org/protocol/muc'}).up()
|
||||
.c('feature', {'var': 'muc_passwordprotected'}).up()
|
||||
.c('feature', {'var': 'muc_hidden'}).up()
|
||||
.c('feature', {'var': 'muc_temporary'}).up()
|
||||
.c('feature', {'var': 'muc_open'}).up()
|
||||
.c('feature', {'var': 'muc_unmoderated'}).up()
|
||||
.c('feature', {'var': 'muc_nonanonymous'}).up()
|
||||
.c('feature', {'var': 'urn:xmpp:mam:0'}).up()
|
||||
.c('x', { 'xmlns':'jabber:x:data', 'type':'result'})
|
||||
.c('field', {'var':'FORM_TYPE', 'type':'hidden'})
|
||||
.c('value').t('http://jabber.org/protocol/muc#roominfo').up().up()
|
||||
.c('field', {'type':'text-single', 'var':'muc#roominfo_description', 'label':'Description'})
|
||||
.c('value').t('This is the description').up().up()
|
||||
.c('field', {'type':'text-single', 'var':'muc#roominfo_occupants', 'label':'Number of occupants'})
|
||||
.c('value').t(0);
|
||||
_converse.connection._dataRecv(test_utils.createRequest(features_stanza));
|
||||
await test_utils.waitUntil(() => view.model.get('connection_status') === converse.ROOMSTATUS.CONNECTING)
|
||||
let presence = $pres({
|
||||
to: _converse.connection.jid,
|
||||
from: 'coven@chat.shakespeare.lit/some1',
|
||||
id: 'DC352437-C019-40EC-B590-AF29E879AF97'
|
||||
}).c('x').attrs({xmlns:'http://jabber.org/protocol/muc#user'})
|
||||
.c('item').attrs({
|
||||
affiliation: 'member',
|
||||
jid: _converse.bare_jid,
|
||||
role: 'participant'
|
||||
}).up()
|
||||
.c('status').attrs({code:'110'});
|
||||
_converse.connection._dataRecv(test_utils.createRequest(presence));
|
||||
|
||||
const room_els = _converse.rooms_list_view.el.querySelectorAll(".open-room");
|
||||
expect(room_els.length).toBe(1);
|
||||
const info_el = _converse.rooms_list_view.el.querySelector(".room-info");
|
||||
info_el.click();
|
||||
const room_els = _converse.rooms_list_view.el.querySelectorAll(".open-room");
|
||||
expect(room_els.length).toBe(1);
|
||||
const info_el = _converse.rooms_list_view.el.querySelector(".room-info");
|
||||
info_el.click();
|
||||
|
||||
const modal = view.model.room_details_modal;
|
||||
return test_utils.waitUntil(() => u.isVisible(modal.el), 2000);
|
||||
}).then(() => {
|
||||
const modal = view.model.room_details_modal;
|
||||
let els = modal.el.querySelectorAll('p.room-info');
|
||||
expect(els[0].textContent).toBe("Name: A Dark Cave")
|
||||
expect(els[1].textContent).toBe("Groupchat address (JID): coven@chat.shakespeare.lit")
|
||||
expect(els[2].textContent).toBe("Description: This is the description")
|
||||
expect(els[3].textContent).toBe("Online users: 1")
|
||||
const features_list = modal.el.querySelector('.features-list');
|
||||
expect(features_list.textContent.replace(/(\n|\s{2,})/g, '')).toBe(
|
||||
'Password protected - This groupchat requires a password before entry'+
|
||||
'Hidden - This groupchat is not publicly searchable'+
|
||||
'Open - Anyone can join this groupchat'+
|
||||
'Temporary - This groupchat will disappear once the last person leaves'+
|
||||
'Not anonymous - All other groupchat participants can see your XMPP username'+
|
||||
'Not moderated - Participants entering this groupchat can write right away'
|
||||
);
|
||||
const presence = $pres({
|
||||
to: 'dummy@localhost/_converse.js-29092160',
|
||||
from: 'coven@chat.shakespeare.lit/newguy'
|
||||
})
|
||||
.c('x', {xmlns: Strophe.NS.MUC_USER})
|
||||
.c('item', {
|
||||
'affiliation': 'none',
|
||||
'jid': 'newguy@localhost/_converse.js-290929789',
|
||||
'role': 'participant'
|
||||
});
|
||||
_converse.connection._dataRecv(test_utils.createRequest(presence));
|
||||
const modal = view.model.room_details_modal;
|
||||
await test_utils.waitUntil(() => u.isVisible(modal.el), 2000);
|
||||
let els = modal.el.querySelectorAll('p.room-info');
|
||||
expect(els[0].textContent).toBe("Name: A Dark Cave")
|
||||
expect(els[1].textContent).toBe("Groupchat address (JID): coven@chat.shakespeare.lit")
|
||||
expect(els[2].textContent).toBe("Description: This is the description")
|
||||
expect(els[3].textContent).toBe("Online users: 1")
|
||||
const features_list = modal.el.querySelector('.features-list');
|
||||
expect(features_list.textContent.replace(/(\n|\s{2,})/g, '')).toBe(
|
||||
'Password protected - This groupchat requires a password before entry'+
|
||||
'Hidden - This groupchat is not publicly searchable'+
|
||||
'Open - Anyone can join this groupchat'+
|
||||
'Temporary - This groupchat will disappear once the last person leaves'+
|
||||
'Not anonymous - All other groupchat participants can see your XMPP username'+
|
||||
'Not moderated - Participants entering this groupchat can write right away'
|
||||
);
|
||||
presence = $pres({
|
||||
to: 'dummy@localhost/_converse.js-29092160',
|
||||
from: 'coven@chat.shakespeare.lit/newguy'
|
||||
})
|
||||
.c('x', {xmlns: Strophe.NS.MUC_USER})
|
||||
.c('item', {
|
||||
'affiliation': 'none',
|
||||
'jid': 'newguy@localhost/_converse.js-290929789',
|
||||
'role': 'participant'
|
||||
});
|
||||
_converse.connection._dataRecv(test_utils.createRequest(presence));
|
||||
|
||||
els = modal.el.querySelectorAll('p.room-info');
|
||||
expect(els[3].textContent).toBe("Online users: 2")
|
||||
els = modal.el.querySelectorAll('p.room-info');
|
||||
expect(els[3].textContent).toBe("Online users: 2")
|
||||
|
||||
view.model.set({'subject': {'author': 'someone', 'text': 'Hatching dark plots'}});
|
||||
els = modal.el.querySelectorAll('p.room-info');
|
||||
expect(els[0].textContent).toBe("Name: A Dark Cave")
|
||||
expect(els[1].textContent).toBe("Groupchat address (JID): coven@chat.shakespeare.lit")
|
||||
expect(els[2].textContent).toBe("Description: This is the description")
|
||||
expect(els[3].textContent).toBe("Topic: Hatching dark plots")
|
||||
expect(els[4].textContent).toBe("Topic author: someone")
|
||||
expect(els[5].textContent).toBe("Online users: 2")
|
||||
done();
|
||||
}).catch(_.partial(_converse.log, _, Strophe.LogLevel.FATAL));
|
||||
view.model.set({'subject': {'author': 'someone', 'text': 'Hatching dark plots'}});
|
||||
els = modal.el.querySelectorAll('p.room-info');
|
||||
expect(els[0].textContent).toBe("Name: A Dark Cave")
|
||||
expect(els[1].textContent).toBe("Groupchat address (JID): coven@chat.shakespeare.lit")
|
||||
expect(els[2].textContent).toBe("Description: This is the description")
|
||||
expect(els[3].textContent).toBe("Topic: Hatching dark plots")
|
||||
expect(els[4].textContent).toBe("Topic author: someone")
|
||||
expect(els[5].textContent).toBe("Online users: 2")
|
||||
done();
|
||||
}));
|
||||
|
||||
it("can be closed", mock.initConverseWithPromises(
|
||||
|
|
287
spec/spoilers.js
287
spec/spoilers.js
|
@ -1,30 +1,30 @@
|
|||
(function (root, factory) {
|
||||
define(["jasmine", "mock", "test-utils"], factory);
|
||||
} (this, function (jasmine, mock, test_utils) {
|
||||
var _ = converse.env._;
|
||||
var Strophe = converse.env.Strophe;
|
||||
var $msg = converse.env.$msg;
|
||||
var $pres = converse.env.$pres;
|
||||
var u = converse.env.utils;
|
||||
const _ = converse.env._;
|
||||
const Strophe = converse.env.Strophe;
|
||||
const $msg = converse.env.$msg;
|
||||
const $pres = converse.env.$pres;
|
||||
const u = converse.env.utils;
|
||||
|
||||
return describe("A spoiler message", function () {
|
||||
describe("A spoiler message", function () {
|
||||
|
||||
it("can be received with a hint",
|
||||
mock.initConverseWithPromises(
|
||||
null, ['rosterGroupsFetched'], {},
|
||||
function (done, _converse) {
|
||||
async function (done, _converse) {
|
||||
|
||||
test_utils.createContacts(_converse, 'current');
|
||||
var sender_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@localhost';
|
||||
const sender_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@localhost';
|
||||
|
||||
/* <message to='romeo@montague.net/orchard' from='juliet@capulet.net/balcony' id='spoiler2'>
|
||||
* <body>And at the end of the story, both of them die! It is so tragic!</body>
|
||||
* <spoiler xmlns='urn:xmpp:spoiler:0'>Love story end</spoiler>
|
||||
* </message>
|
||||
*/
|
||||
var spoiler_hint = "Love story end"
|
||||
var spoiler = "And at the end of the story, both of them die! It is so tragic!";
|
||||
var msg = $msg({
|
||||
const spoiler_hint = "Love story end"
|
||||
const spoiler = "And at the end of the story, both of them die! It is so tragic!";
|
||||
const msg = $msg({
|
||||
'xmlns': 'jabber:client',
|
||||
'to': _converse.bare_jid,
|
||||
'from': sender_jid,
|
||||
|
@ -36,36 +36,30 @@
|
|||
.tree();
|
||||
_converse.chatboxes.onMessage(msg);
|
||||
|
||||
var view = _converse.chatboxviews.get(sender_jid);
|
||||
|
||||
return test_utils.waitUntil(() => view.model.vcard.get('fullname') === 'Max Frankfurter')
|
||||
.then(function () {
|
||||
expect(view.el.querySelector('.chat-msg__author').textContent.trim()).toBe('Max Frankfurter');
|
||||
|
||||
var message_content = view.el.querySelector('.chat-msg__text');
|
||||
expect(message_content.textContent).toBe(spoiler);
|
||||
|
||||
var spoiler_hint_el = view.el.querySelector('.spoiler-hint');
|
||||
expect(spoiler_hint_el.textContent).toBe(spoiler_hint);
|
||||
done();
|
||||
});
|
||||
const view = _converse.chatboxviews.get(sender_jid);
|
||||
await test_utils.waitUntil(() => view.model.vcard.get('fullname') === 'Max Frankfurter')
|
||||
expect(view.el.querySelector('.chat-msg__author').textContent.trim()).toBe('Max Frankfurter');
|
||||
const message_content = view.el.querySelector('.chat-msg__text');
|
||||
expect(message_content.textContent).toBe(spoiler);
|
||||
const spoiler_hint_el = view.el.querySelector('.spoiler-hint');
|
||||
expect(spoiler_hint_el.textContent).toBe(spoiler_hint);
|
||||
done();
|
||||
}));
|
||||
|
||||
it("can be received without a hint",
|
||||
mock.initConverseWithPromises(
|
||||
null, ['rosterGroupsFetched'], {},
|
||||
function (done, _converse) {
|
||||
async function (done, _converse) {
|
||||
|
||||
test_utils.createContacts(_converse, 'current');
|
||||
var sender_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@localhost';
|
||||
|
||||
const sender_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@localhost';
|
||||
/* <message to='romeo@montague.net/orchard' from='juliet@capulet.net/balcony' id='spoiler2'>
|
||||
* <body>And at the end of the story, both of them die! It is so tragic!</body>
|
||||
* <spoiler xmlns='urn:xmpp:spoiler:0'>Love story end</spoiler>
|
||||
* </message>
|
||||
*/
|
||||
var spoiler = "And at the end of the story, both of them die! It is so tragic!";
|
||||
var msg = $msg({
|
||||
const spoiler = "And at the end of the story, both of them die! It is so tragic!";
|
||||
const msg = $msg({
|
||||
'xmlns': 'jabber:client',
|
||||
'to': _converse.bare_jid,
|
||||
'from': sender_jid,
|
||||
|
@ -75,25 +69,20 @@
|
|||
'xmlns': 'urn:xmpp:spoiler:0',
|
||||
}).tree();
|
||||
_converse.chatboxes.onMessage(msg);
|
||||
|
||||
var view = _converse.chatboxviews.get(sender_jid);
|
||||
return test_utils.waitUntil(() => view.model.vcard.get('fullname') === 'Max Frankfurter')
|
||||
.then(function () {
|
||||
expect(_.includes(view.el.querySelector('.chat-msg__author').textContent, 'Max Frankfurter')).toBeTruthy();
|
||||
|
||||
var message_content = view.el.querySelector('.chat-msg__text');
|
||||
expect(message_content.textContent).toBe(spoiler);
|
||||
|
||||
var spoiler_hint_el = view.el.querySelector('.spoiler-hint');
|
||||
expect(spoiler_hint_el.textContent).toBe('');
|
||||
done();
|
||||
}).catch(_.partial(_converse.log, _, Strophe.LogLevel.FATAL));
|
||||
const view = _converse.chatboxviews.get(sender_jid);
|
||||
await test_utils.waitUntil(() => view.model.vcard.get('fullname') === 'Max Frankfurter')
|
||||
expect(_.includes(view.el.querySelector('.chat-msg__author').textContent, 'Max Frankfurter')).toBeTruthy();
|
||||
const message_content = view.el.querySelector('.chat-msg__text');
|
||||
expect(message_content.textContent).toBe(spoiler);
|
||||
const spoiler_hint_el = view.el.querySelector('.spoiler-hint');
|
||||
expect(spoiler_hint_el.textContent).toBe('');
|
||||
done();
|
||||
}));
|
||||
|
||||
it("can be sent without a hint",
|
||||
mock.initConverseWithPromises(
|
||||
null, ['rosterGroupsFetched', 'chatBoxesFetched'], {},
|
||||
function (done, _converse) {
|
||||
async function (done, _converse) {
|
||||
|
||||
test_utils.createContacts(_converse, 'current', 1);
|
||||
_converse.emit('rosterContactsFetched');
|
||||
|
@ -105,147 +94,145 @@
|
|||
// have a resource, that resource is then queried to see
|
||||
// whether Strophe.NS.SPOILER is supported, in which case
|
||||
// the spoiler button will appear.
|
||||
var presence = $pres({
|
||||
const presence = $pres({
|
||||
'from': contact_jid+'/phone',
|
||||
'to': 'dummy@localhost'
|
||||
});
|
||||
_converse.connection._dataRecv(test_utils.createRequest(presence));
|
||||
test_utils.openChatBoxFor(_converse, contact_jid)
|
||||
.then(() => test_utils.waitUntilDiscoConfirmed(_converse, contact_jid+'/phone', [], [Strophe.NS.SPOILER]))
|
||||
.then(() => {
|
||||
var view = _converse.chatboxviews.get(contact_jid);
|
||||
spyOn(view, 'onMessageSubmitted').and.callThrough();
|
||||
spyOn(_converse.connection, 'send');
|
||||
await test_utils.openChatBoxFor(_converse, contact_jid);
|
||||
await test_utils.waitUntilDiscoConfirmed(_converse, contact_jid+'/phone', [], [Strophe.NS.SPOILER]);
|
||||
const view = _converse.chatboxviews.get(contact_jid);
|
||||
spyOn(view, 'onMessageSubmitted').and.callThrough();
|
||||
spyOn(_converse.connection, 'send');
|
||||
|
||||
var spoiler_toggle = view.el.querySelector('.toggle-compose-spoiler');
|
||||
spoiler_toggle.click();
|
||||
let spoiler_toggle = view.el.querySelector('.toggle-compose-spoiler');
|
||||
spoiler_toggle.click();
|
||||
|
||||
var textarea = view.el.querySelector('.chat-textarea');
|
||||
textarea.value = 'This is the spoiler';
|
||||
view.keyPressed({
|
||||
target: textarea,
|
||||
preventDefault: _.noop,
|
||||
keyCode: 13
|
||||
});
|
||||
expect(view.onMessageSubmitted).toHaveBeenCalled();
|
||||
const textarea = view.el.querySelector('.chat-textarea');
|
||||
textarea.value = 'This is the spoiler';
|
||||
view.keyPressed({
|
||||
target: textarea,
|
||||
preventDefault: _.noop,
|
||||
keyCode: 13
|
||||
});
|
||||
expect(view.onMessageSubmitted).toHaveBeenCalled();
|
||||
await new Promise((resolve, reject) => view.once('messageInserted', resolve));
|
||||
|
||||
/* Test the XML stanza
|
||||
*
|
||||
* <message from="dummy@localhost/resource"
|
||||
* to="max.frankfurter@localhost"
|
||||
* type="chat"
|
||||
* id="4547c38b-d98b-45a5-8f44-b4004dbc335e"
|
||||
* xmlns="jabber:client">
|
||||
* <body>This is the spoiler</body>
|
||||
* <active xmlns="http://jabber.org/protocol/chatstates"/>
|
||||
* <spoiler xmlns="urn:xmpp:spoiler:0"/>
|
||||
* </message>"
|
||||
*/
|
||||
var stanza = _converse.connection.send.calls.argsFor(0)[0].tree();
|
||||
var spoiler_el = stanza.querySelector('spoiler[xmlns="urn:xmpp:spoiler:0"]');
|
||||
expect(_.isNull(spoiler_el)).toBeFalsy();
|
||||
expect(spoiler_el.textContent).toBe('');
|
||||
/* Test the XML stanza
|
||||
*
|
||||
* <message from="dummy@localhost/resource"
|
||||
* to="max.frankfurter@localhost"
|
||||
* type="chat"
|
||||
* id="4547c38b-d98b-45a5-8f44-b4004dbc335e"
|
||||
* xmlns="jabber:client">
|
||||
* <body>This is the spoiler</body>
|
||||
* <active xmlns="http://jabber.org/protocol/chatstates"/>
|
||||
* <spoiler xmlns="urn:xmpp:spoiler:0"/>
|
||||
* </message>"
|
||||
*/
|
||||
const stanza = _converse.connection.send.calls.argsFor(0)[0].tree();
|
||||
const spoiler_el = stanza.querySelector('spoiler[xmlns="urn:xmpp:spoiler:0"]');
|
||||
expect(_.isNull(spoiler_el)).toBeFalsy();
|
||||
expect(spoiler_el.textContent).toBe('');
|
||||
|
||||
var body_el = stanza.querySelector('body');
|
||||
expect(body_el.textContent).toBe('This is the spoiler');
|
||||
const body_el = stanza.querySelector('body');
|
||||
expect(body_el.textContent).toBe('This is the spoiler');
|
||||
|
||||
/* Test the HTML spoiler message */
|
||||
expect(view.el.querySelector('.chat-msg__author').textContent.trim()).toBe('Max Mustermann');
|
||||
/* Test the HTML spoiler message */
|
||||
expect(view.el.querySelector('.chat-msg__author').textContent.trim()).toBe('Max Mustermann');
|
||||
|
||||
var spoiler_msg_el = view.el.querySelector('.chat-msg__text.spoiler');
|
||||
expect(spoiler_msg_el.textContent).toBe('This is the spoiler');
|
||||
expect(_.includes(spoiler_msg_el.classList, 'collapsed')).toBeTruthy();
|
||||
const spoiler_msg_el = view.el.querySelector('.chat-msg__text.spoiler');
|
||||
expect(spoiler_msg_el.textContent).toBe('This is the spoiler');
|
||||
expect(_.includes(spoiler_msg_el.classList, 'collapsed')).toBeTruthy();
|
||||
|
||||
spoiler_toggle = view.el.querySelector('.spoiler-toggle');
|
||||
expect(spoiler_toggle.textContent).toBe('Show more');
|
||||
spoiler_toggle.click();
|
||||
expect(_.includes(spoiler_msg_el.classList, 'collapsed')).toBeFalsy();
|
||||
expect(spoiler_toggle.textContent).toBe('Show less');
|
||||
spoiler_toggle.click();
|
||||
expect(_.includes(spoiler_msg_el.classList, 'collapsed')).toBeTruthy();
|
||||
done();
|
||||
}).catch(_.partial(_converse.log, _, Strophe.LogLevel.FATAL));
|
||||
spoiler_toggle = view.el.querySelector('.spoiler-toggle');
|
||||
expect(spoiler_toggle.textContent).toBe('Show more');
|
||||
spoiler_toggle.click();
|
||||
expect(_.includes(spoiler_msg_el.classList, 'collapsed')).toBeFalsy();
|
||||
expect(spoiler_toggle.textContent).toBe('Show less');
|
||||
spoiler_toggle.click();
|
||||
expect(_.includes(spoiler_msg_el.classList, 'collapsed')).toBeTruthy();
|
||||
done();
|
||||
}));
|
||||
|
||||
it("can be sent with a hint",
|
||||
mock.initConverseWithPromises(
|
||||
null, ['rosterGroupsFetched', 'chatBoxesFetched'], {},
|
||||
function (done, _converse) {
|
||||
async function (done, _converse) {
|
||||
|
||||
test_utils.createContacts(_converse, 'current', 1);
|
||||
_converse.emit('rosterContactsFetched');
|
||||
|
||||
test_utils.openControlBox();
|
||||
var contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@localhost';
|
||||
const contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@localhost';
|
||||
|
||||
// XXX: We need to send a presence from the contact, so that we
|
||||
// have a resource, that resource is then queried to see
|
||||
// whether Strophe.NS.SPOILER is supported, in which case
|
||||
// the spoiler button will appear.
|
||||
var presence = $pres({
|
||||
const presence = $pres({
|
||||
'from': contact_jid+'/phone',
|
||||
'to': 'dummy@localhost'
|
||||
});
|
||||
_converse.connection._dataRecv(test_utils.createRequest(presence));
|
||||
test_utils.openChatBoxFor(_converse, contact_jid)
|
||||
.then(() => test_utils.waitUntilDiscoConfirmed(_converse, contact_jid+'/phone', [], [Strophe.NS.SPOILER]))
|
||||
.then(() => {
|
||||
var view = _converse.chatboxviews.get(contact_jid);
|
||||
var spoiler_toggle = view.el.querySelector('.toggle-compose-spoiler');
|
||||
spoiler_toggle.click();
|
||||
await test_utils.openChatBoxFor(_converse, contact_jid);
|
||||
await test_utils.waitUntilDiscoConfirmed(_converse, contact_jid+'/phone', [], [Strophe.NS.SPOILER]);
|
||||
const view = _converse.chatboxviews.get(contact_jid);
|
||||
let spoiler_toggle = view.el.querySelector('.toggle-compose-spoiler');
|
||||
spoiler_toggle.click();
|
||||
|
||||
spyOn(view, 'onMessageSubmitted').and.callThrough();
|
||||
spyOn(_converse.connection, 'send');
|
||||
spyOn(view, 'onMessageSubmitted').and.callThrough();
|
||||
spyOn(_converse.connection, 'send');
|
||||
|
||||
var textarea = view.el.querySelector('.chat-textarea');
|
||||
textarea.value = 'This is the spoiler';
|
||||
var hint_input = view.el.querySelector('.spoiler-hint');
|
||||
hint_input.value = 'This is the hint';
|
||||
const textarea = view.el.querySelector('.chat-textarea');
|
||||
textarea.value = 'This is the spoiler';
|
||||
const hint_input = view.el.querySelector('.spoiler-hint');
|
||||
hint_input.value = 'This is the hint';
|
||||
|
||||
view.keyPressed({
|
||||
target: textarea,
|
||||
preventDefault: _.noop,
|
||||
keyCode: 13
|
||||
});
|
||||
expect(view.onMessageSubmitted).toHaveBeenCalled();
|
||||
|
||||
/* Test the XML stanza
|
||||
*
|
||||
* <message from="dummy@localhost/resource"
|
||||
* to="max.frankfurter@localhost"
|
||||
* type="chat"
|
||||
* id="4547c38b-d98b-45a5-8f44-b4004dbc335e"
|
||||
* xmlns="jabber:client">
|
||||
* <body>This is the spoiler</body>
|
||||
* <active xmlns="http://jabber.org/protocol/chatstates"/>
|
||||
* <spoiler xmlns="urn:xmpp:spoiler:0">This is the hint</spoiler>
|
||||
* </message>"
|
||||
*/
|
||||
var stanza = _converse.connection.send.calls.argsFor(0)[0].tree();
|
||||
var spoiler_el = stanza.querySelector('spoiler[xmlns="urn:xmpp:spoiler:0"]');
|
||||
|
||||
expect(_.isNull(spoiler_el)).toBeFalsy();
|
||||
expect(spoiler_el.textContent).toBe('This is the hint');
|
||||
|
||||
var body_el = stanza.querySelector('body');
|
||||
expect(body_el.textContent).toBe('This is the spoiler');
|
||||
|
||||
/* Test the HTML spoiler message */
|
||||
expect(view.el.querySelector('.chat-msg__author').textContent.trim()).toBe('Max Mustermann');
|
||||
|
||||
var spoiler_msg_el = view.el.querySelector('.chat-msg__text.spoiler');
|
||||
expect(spoiler_msg_el.textContent).toBe('This is the spoiler');
|
||||
expect(_.includes(spoiler_msg_el.classList, 'collapsed')).toBeTruthy();
|
||||
|
||||
spoiler_toggle = view.el.querySelector('.spoiler-toggle');
|
||||
expect(spoiler_toggle.textContent).toBe('Show more');
|
||||
spoiler_toggle.click();
|
||||
expect(_.includes(spoiler_msg_el.classList, 'collapsed')).toBeFalsy();
|
||||
expect(spoiler_toggle.textContent).toBe('Show less');
|
||||
spoiler_toggle.click();
|
||||
expect(_.includes(spoiler_msg_el.classList, 'collapsed')).toBeTruthy();
|
||||
done();
|
||||
view.keyPressed({
|
||||
target: textarea,
|
||||
preventDefault: _.noop,
|
||||
keyCode: 13
|
||||
});
|
||||
expect(view.onMessageSubmitted).toHaveBeenCalled();
|
||||
await new Promise((resolve, reject) => view.once('messageInserted', resolve));
|
||||
|
||||
/* Test the XML stanza
|
||||
*
|
||||
* <message from="dummy@localhost/resource"
|
||||
* to="max.frankfurter@localhost"
|
||||
* type="chat"
|
||||
* id="4547c38b-d98b-45a5-8f44-b4004dbc335e"
|
||||
* xmlns="jabber:client">
|
||||
* <body>This is the spoiler</body>
|
||||
* <active xmlns="http://jabber.org/protocol/chatstates"/>
|
||||
* <spoiler xmlns="urn:xmpp:spoiler:0">This is the hint</spoiler>
|
||||
* </message>"
|
||||
*/
|
||||
const stanza = _converse.connection.send.calls.argsFor(0)[0].tree();
|
||||
const spoiler_el = stanza.querySelector('spoiler[xmlns="urn:xmpp:spoiler:0"]');
|
||||
|
||||
expect(_.isNull(spoiler_el)).toBeFalsy();
|
||||
expect(spoiler_el.textContent).toBe('This is the hint');
|
||||
|
||||
const body_el = stanza.querySelector('body');
|
||||
expect(body_el.textContent).toBe('This is the spoiler');
|
||||
|
||||
/* Test the HTML spoiler message */
|
||||
expect(view.el.querySelector('.chat-msg__author').textContent.trim()).toBe('Max Mustermann');
|
||||
|
||||
const spoiler_msg_el = view.el.querySelector('.chat-msg__text.spoiler');
|
||||
expect(spoiler_msg_el.textContent).toBe('This is the spoiler');
|
||||
expect(_.includes(spoiler_msg_el.classList, 'collapsed')).toBeTruthy();
|
||||
|
||||
spoiler_toggle = view.el.querySelector('.spoiler-toggle');
|
||||
expect(spoiler_toggle.textContent).toBe('Show more');
|
||||
spoiler_toggle.click();
|
||||
expect(_.includes(spoiler_msg_el.classList, 'collapsed')).toBeFalsy();
|
||||
expect(spoiler_toggle.textContent).toBe('Show less');
|
||||
spoiler_toggle.click();
|
||||
expect(_.includes(spoiler_msg_el.classList, 'collapsed')).toBeTruthy();
|
||||
done();
|
||||
}));
|
||||
});
|
||||
}));
|
||||
|
|
|
@ -297,7 +297,7 @@
|
|||
'message': _converse.chatboxes.getMessageBody(stanza),
|
||||
'references': this.getReferencesFromStanza(stanza),
|
||||
'older_versions': older_versions,
|
||||
'edited': true
|
||||
'edited': moment().format()
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
@ -395,7 +395,7 @@
|
|||
older_versions.push(message.get('message'));
|
||||
message.save({
|
||||
'correcting': false,
|
||||
'edited': true,
|
||||
'edited': moment().format(),
|
||||
'message': attrs.message,
|
||||
'older_versions': older_versions,
|
||||
'references': attrs.references
|
||||
|
|
|
@ -17,8 +17,10 @@
|
|||
const { Backbone, _ } = converse.env;
|
||||
|
||||
const AvatarMixin = {
|
||||
renderAvatar () {
|
||||
const canvas_el = this.el.querySelector('canvas');
|
||||
|
||||
renderAvatar (el) {
|
||||
el = el || this.el;
|
||||
const canvas_el = el.querySelector('canvas');
|
||||
if (_.isNull(canvas_el)) {
|
||||
return;
|
||||
}
|
||||
|
@ -27,19 +29,22 @@
|
|||
img_src = "data:" + image_type + ";base64," + image,
|
||||
img = new Image();
|
||||
|
||||
img.onload = () => {
|
||||
const ctx = canvas_el.getContext('2d'),
|
||||
ratio = img.width / img.height;
|
||||
ctx.clearRect(0, 0, canvas_el.width, canvas_el.height);
|
||||
if (ratio < 1) {
|
||||
const scaled_img_with = canvas_el.width*ratio,
|
||||
x = Math.floor((canvas_el.width-scaled_img_with)/2);
|
||||
ctx.drawImage(img, x, 0, scaled_img_with, canvas_el.height);
|
||||
} else {
|
||||
ctx.drawImage(img, 0, 0, canvas_el.width, canvas_el.height*ratio);
|
||||
}
|
||||
};
|
||||
img.src = img_src;
|
||||
return new Promise((resolve, reject) => {
|
||||
img.onload = () => {
|
||||
const ctx = canvas_el.getContext('2d'),
|
||||
ratio = img.width / img.height;
|
||||
ctx.clearRect(0, 0, canvas_el.width, canvas_el.height);
|
||||
if (ratio < 1) {
|
||||
const scaled_img_with = canvas_el.width*ratio,
|
||||
x = Math.floor((canvas_el.width-scaled_img_with)/2);
|
||||
ctx.drawImage(img, x, 0, scaled_img_with, canvas_el.height);
|
||||
} else {
|
||||
ctx.drawImage(img, 0, 0, canvas_el.width, canvas_el.height*ratio);
|
||||
}
|
||||
resolve();
|
||||
};
|
||||
img.src = img_src;
|
||||
});
|
||||
},
|
||||
};
|
||||
|
||||
|
|
|
@ -312,6 +312,7 @@
|
|||
|
||||
this.model.messages.on('add', this.onMessageAdded, this);
|
||||
this.model.messages.on('rendered', this.scrollDown, this);
|
||||
this.model.messages.on('edited', (view) => this.markFollowups(view.el));
|
||||
|
||||
this.model.on('show', this.show, this);
|
||||
this.model.on('destroy', this.remove, this);
|
||||
|
@ -673,7 +674,8 @@
|
|||
if (view.model.get('type') === 'error') {
|
||||
const previous_msg_el = this.content.querySelector(`[data-msgid="${view.model.get('msgid')}"]`);
|
||||
if (previous_msg_el) {
|
||||
return previous_msg_el.insertAdjacentElement('afterend', view.el);
|
||||
previous_msg_el.insertAdjacentElement('afterend', view.el);
|
||||
return this.trigger('messageInserted', view.el);
|
||||
}
|
||||
}
|
||||
const current_msg_date = moment(view.model.get('time')) || moment,
|
||||
|
@ -692,6 +694,7 @@
|
|||
previous_msg_el.insertAdjacentElement('afterend', view.el);
|
||||
this.markFollowups(view.el);
|
||||
}
|
||||
return this.trigger('messageInserted', view.el);
|
||||
},
|
||||
|
||||
markFollowups (el) {
|
||||
|
@ -731,7 +734,7 @@
|
|||
}
|
||||
},
|
||||
|
||||
showMessage (message) {
|
||||
async showMessage (message) {
|
||||
/* Inserts a chat message into the content area of the chat box.
|
||||
*
|
||||
* Will also insert a new day indicator if the message is on a
|
||||
|
@ -741,6 +744,8 @@
|
|||
* (Backbone.Model) message: The message object
|
||||
*/
|
||||
const view = new _converse.MessageView({'model': message});
|
||||
await view.render();
|
||||
|
||||
this.clearChatStateNotification(message);
|
||||
this.insertMessage(view);
|
||||
this.insertDayIndicator(view.el);
|
||||
|
|
|
@ -41,8 +41,11 @@
|
|||
{ __ } = _converse;
|
||||
|
||||
|
||||
_converse.MessageVersionsModal = _converse.BootstrapModal.extend({
|
||||
_converse.api.settings.update({
|
||||
'show_images_inline': true
|
||||
});
|
||||
|
||||
_converse.MessageVersionsModal = _converse.BootstrapModal.extend({
|
||||
toHTML () {
|
||||
return tpl_message_versions_modal(_.extend(
|
||||
this.model.toJSON(), {
|
||||
|
@ -61,17 +64,11 @@
|
|||
if (this.model.vcard) {
|
||||
this.model.vcard.on('change', this.render, this);
|
||||
}
|
||||
this.model.on('change:correcting', this.onMessageCorrection, this);
|
||||
this.model.on('change:message', this.render, this);
|
||||
this.model.on('change:progress', this.renderFileUploadProgresBar, this);
|
||||
this.model.on('change:type', this.render, this);
|
||||
this.model.on('change:upload', this.render, this);
|
||||
this.model.on('change', this.onChanged, this);
|
||||
this.model.on('destroy', this.remove, this);
|
||||
this.render();
|
||||
},
|
||||
|
||||
render () {
|
||||
const is_followup = u.hasClass('chat-msg--followup', this.el);
|
||||
async render () {
|
||||
let msg;
|
||||
if (this.model.isOnlyChatStateNotification()) {
|
||||
this.renderChatStateNotification()
|
||||
|
@ -80,20 +77,32 @@
|
|||
} else if (this.model.get('type') === 'error') {
|
||||
this.renderErrorMessage();
|
||||
} else {
|
||||
this.renderChatMessage();
|
||||
}
|
||||
if (is_followup) {
|
||||
u.addClass('chat-msg--followup', this.el);
|
||||
await this.renderChatMessage();
|
||||
}
|
||||
return this.el;
|
||||
},
|
||||
|
||||
onMessageCorrection () {
|
||||
this.render();
|
||||
if (!this.model.get('correcting') && this.model.changed.message) {
|
||||
this.el.addEventListener('animationend', () => u.removeClass('onload', this.el));
|
||||
u.addClass('onload', this.el);
|
||||
async onChanged (item) {
|
||||
// Jot down whether it was edited because the `changed`
|
||||
// attr gets removed when this.render() gets called further
|
||||
// down.
|
||||
const edited = item.changed.edited;
|
||||
if (this.model.changed.progress) {
|
||||
return this.renderFileUploadProgresBar();
|
||||
}
|
||||
if (_.filter(['correcting', 'message', 'type', 'upload'],
|
||||
prop => Object.prototype.hasOwnProperty.call(this.model.changed, prop)).length) {
|
||||
await this.render();
|
||||
}
|
||||
if (edited) {
|
||||
this.onMessageEdited();
|
||||
}
|
||||
},
|
||||
|
||||
onMessageEdited () {
|
||||
this.el.addEventListener('animationend', () => u.removeClass('onload', this.el));
|
||||
this.model.collection.trigger('edited', this);
|
||||
u.addClass('onload', this.el);
|
||||
},
|
||||
|
||||
replaceElement (msg) {
|
||||
|
@ -104,7 +113,7 @@
|
|||
return this.el;
|
||||
},
|
||||
|
||||
renderChatMessage () {
|
||||
async renderChatMessage () {
|
||||
const is_me_message = this.isMeCommand(),
|
||||
moment_time = moment(this.model.get('time')),
|
||||
role = this.model.vcard ? this.model.vcard.get('role') : null,
|
||||
|
@ -148,14 +157,14 @@
|
|||
_.partial(u.addEmoji, _converse, _)
|
||||
)(text);
|
||||
}
|
||||
u.renderImageURLs(_converse, msg_content).then(() => {
|
||||
this.model.collection.trigger('rendered');
|
||||
});
|
||||
this.replaceElement(msg);
|
||||
|
||||
if (this.model.get('type') !== 'headline') {
|
||||
this.renderAvatar();
|
||||
if (_converse.show_images_inline) {
|
||||
await u.renderImageURLs(_converse, msg_content);
|
||||
}
|
||||
if (this.model.get('type') !== 'headline') {
|
||||
await this.renderAvatar(msg);
|
||||
}
|
||||
this.replaceElement(msg);
|
||||
this.model.collection.trigger('rendered', this);
|
||||
},
|
||||
|
||||
renderErrorMessage () {
|
||||
|
|
|
@ -478,6 +478,7 @@
|
|||
initialize () {
|
||||
_converse.BootstrapModal.prototype.initialize.apply(this, arguments);
|
||||
this.model.on('change', this.render, this);
|
||||
this.model.occupants.on('add', this.render, this);
|
||||
this.model.occupants.on('change', this.render, this);
|
||||
},
|
||||
|
||||
|
|
|
@ -71,7 +71,7 @@
|
|||
'warn': _.get(console, 'log') ? console.log.bind(console) : _.noop
|
||||
}, console);
|
||||
|
||||
var isImage = function (url) {
|
||||
const isImage = function (url) {
|
||||
return new Promise((resolve, reject) => {
|
||||
var img = new Image();
|
||||
var timer = window.setTimeout(function () {
|
||||
|
|
|
@ -297,13 +297,15 @@
|
|||
.c('active', {'xmlns': Strophe.NS.CHATSTATES}).tree();
|
||||
}
|
||||
|
||||
utils.sendMessage = function (chatboxview, message) {
|
||||
chatboxview.el.querySelector('.chat-textarea').value = message;
|
||||
chatboxview.keyPressed({
|
||||
target: chatboxview.el.querySelector('textarea.chat-textarea'),
|
||||
utils.sendMessage = function (view, message) {
|
||||
const promise = new Promise((resolve, reject) => view.on('messageInserted', resolve));
|
||||
view.el.querySelector('.chat-textarea').value = message;
|
||||
view.keyPressed({
|
||||
target: view.el.querySelector('textarea.chat-textarea'),
|
||||
preventDefault: _.noop,
|
||||
keyCode: 13
|
||||
});
|
||||
return promise;
|
||||
};
|
||||
return utils;
|
||||
}));
|
||||
|
|
Loading…
Reference in New Issue
Block a user