Commit 53b3f2d0 authored by JC Brand's avatar JC Brand

Fix failing tests and rewrite to use async/await

parent 65190834
...@@ -9,12 +9,13 @@ ...@@ -9,12 +9,13 @@
], factory); ], factory);
} (this, function (jasmine, $, mock, test_utils) { } (this, function (jasmine, $, mock, test_utils) {
"use strict"; "use strict";
var $iq = converse.env.$iq, const $iq = converse.env.$iq,
$msg = converse.env.$msg, $msg = converse.env.$msg,
Backbone = converse.env.Backbone, Backbone = converse.env.Backbone,
Strophe = converse.env.Strophe, Strophe = converse.env.Strophe,
_ = converse.env._, sizzle = converse.env.sizzle,
u = converse.env.utils; _ = converse.env._,
u = converse.env.utils;
describe("A chat room", function () { describe("A chat room", function () {
...@@ -369,242 +370,246 @@ ...@@ -369,242 +370,246 @@
}); });
})); }));
it("can be retrieved from the XMPP server", mock.initConverseWithPromises( it("can be retrieved from the XMPP server", mock.initConverseWithPromises(
['send'], ['chatBoxesFetched', 'roomsPanelRendered', 'rosterGroupsFetched'], {}, ['send'], ['chatBoxesFetched', 'roomsPanelRendered', 'rosterGroupsFetched'], {},
function (done, _converse) { async function (done, _converse) {
test_utils.waitUntilDiscoConfirmed( await test_utils.waitUntilDiscoConfirmed(
_converse, _converse.bare_jid, _converse, _converse.bare_jid,
[{'category': 'pubsub', 'type': 'pep'}], [{'category': 'pubsub', 'type': 'pep'}],
['http://jabber.org/protocol/pubsub#publish-options'] ['http://jabber.org/protocol/pubsub#publish-options']
).then(function () { );
/* Client requests all items /* Client requests all items
* ------------------------- * -------------------------
* *
* <iq from='juliet@capulet.lit/randomID' type='get' id='retrieve1'> * <iq from='juliet@capulet.lit/randomID' type='get' id='retrieve1'>
* <pubsub xmlns='http://jabber.org/protocol/pubsub'> * <pubsub xmlns='http://jabber.org/protocol/pubsub'>
* <items node='storage:bookmarks'/> * <items node='storage:bookmarks'/>
* </pubsub> * </pubsub>
* </iq> * </iq>
*/ */
var IQ_id; let IQ_id;
expect(_.filter(_converse.connection.send.calls.all(), function (call) { const call = await test_utils.waitUntil(() =>
var stanza = call.args[0]; _.filter(
if (!(stanza instanceof Element) || stanza.nodeName !== 'iq') { _converse.connection.send.calls.all(),
return; call => {
} const stanza = call.args[0];
// XXX: Wrapping in a div is a workaround for PhantomJS if (!(stanza instanceof Element) || stanza.nodeName !== 'iq') {
var div = document.createElement('div'); return;
div.appendChild(stanza); }
if (div.innerHTML === if (sizzle('items[node="storage:bookmarks"]', stanza).length) {
'<iq from="dummy@localhost/resource" type="get" '+ IQ_id = stanza.getAttribute('id');
'xmlns="jabber:client" id="'+stanza.getAttribute('id')+'">'+ return true;
'<pubsub xmlns="http://jabber.org/protocol/pubsub">'+ }
'<items node="storage:bookmarks"></items>'+
'</pubsub>'+
'</iq>') {
IQ_id = stanza.getAttribute('id');
return true;
} }
}).length).toBe(1); ).pop()
);
/*
* Server returns all items expect(Strophe.serialize(call.args[0])).toBe(
* ------------------------ `<iq from="dummy@localhost/resource" id="${IQ_id}" type="get" xmlns="jabber:client">`+
* <iq type='result' '<pubsub xmlns="http://jabber.org/protocol/pubsub">'+
* to='juliet@capulet.lit/randomID' '<items node="storage:bookmarks"/>'+
* id='retrieve1'> '</pubsub>'+
* <pubsub xmlns='http://jabber.org/protocol/pubsub'> '</iq>');
* <items node='storage:bookmarks'>
* <item id='current'> /*
* <storage xmlns='storage:bookmarks'> * Server returns all items
* <conference name='The Play&apos;s the Thing' * ------------------------
* autojoin='true' * <iq type='result'
* jid='theplay@conference.shakespeare.lit'> * to='juliet@capulet.lit/randomID'
* <nick>JC</nick> * id='retrieve1'>
* </conference> * <pubsub xmlns='http://jabber.org/protocol/pubsub'>
* </storage> * <items node='storage:bookmarks'>
* </item> * <item id='current'>
* </items> * <storage xmlns='storage:bookmarks'>
* </pubsub> * <conference name='The Play&apos;s the Thing'
* </iq> * autojoin='true'
*/ * jid='theplay@conference.shakespeare.lit'>
expect(_converse.bookmarks.models.length).toBe(0); * <nick>JC</nick>
* </conference>
spyOn(_converse.bookmarks, 'onBookmarksReceived').and.callThrough(); * </storage>
var stanza = $iq({'to': _converse.connection.jid, 'type':'result', 'id':IQ_id}) * </item>
* </items>
* </pubsub>
* </iq>
*/
expect(_converse.bookmarks.models.length).toBe(0);
spyOn(_converse.bookmarks, 'onBookmarksReceived').and.callThrough();
var stanza = $iq({'to': _converse.connection.jid, 'type':'result', 'id':IQ_id})
.c('pubsub', {'xmlns': Strophe.NS.PUBSUB})
.c('items', {'node': 'storage:bookmarks'})
.c('item', {'id': 'current'})
.c('storage', {'xmlns': 'storage:bookmarks'})
.c('conference', {
'name': 'The Play&apos;s the Thing',
'autojoin': 'true',
'jid': 'theplay@conference.shakespeare.lit'
}).c('nick').t('JC').up().up()
.c('conference', {
'name': 'Another room',
'autojoin': 'false',
'jid': 'another@conference.shakespeare.lit'
}); // Purposefully exclude the <nick> element to test #1043
_converse.connection._dataRecv(test_utils.createRequest(stanza));
await test_utils.waitUntil(() => _converse.bookmarks.onBookmarksReceived.calls.count());
expect(_converse.bookmarks.models.length).toBe(2);
expect(_converse.bookmarks.findWhere({'jid': 'theplay@conference.shakespeare.lit'}).get('autojoin')).toBe(true);
expect(_converse.bookmarks.findWhere({'jid': 'another@conference.shakespeare.lit'}).get('autojoin')).toBe(false);
done();
}));
describe("The rooms panel", function () {
it("shows a list of bookmarks", mock.initConverseWithPromises(
['send'], ['rosterGroupsFetched'], {},
async function (done, _converse) {
await test_utils.waitUntilDiscoConfirmed(
_converse, _converse.bare_jid,
[{'category': 'pubsub', 'type': 'pep'}],
['http://jabber.org/protocol/pubsub#publish-options']
);
test_utils.openControlBox();
let IQ_id;
const call = await test_utils.waitUntil(() =>
_.filter(
_converse.connection.send.calls.all(),
call => {
const stanza = call.args[0];
if (!(stanza instanceof Element) || stanza.nodeName !== 'iq') {
return;
}
if (sizzle('items[node="storage:bookmarks"]', stanza).length) {
IQ_id = stanza.getAttribute('id');
return true;
}
}
).pop()
);
expect(Strophe.serialize(call.args[0])).toBe(
`<iq from="dummy@localhost/resource" id="${IQ_id}" type="get" xmlns="jabber:client">`+
'<pubsub xmlns="http://jabber.org/protocol/pubsub">'+
'<items node="storage:bookmarks"/>'+
'</pubsub>'+
'</iq>'
);
const stanza = $iq({'to': _converse.connection.jid, 'type':'result', 'id':IQ_id})
.c('pubsub', {'xmlns': Strophe.NS.PUBSUB}) .c('pubsub', {'xmlns': Strophe.NS.PUBSUB})
.c('items', {'node': 'storage:bookmarks'}) .c('items', {'node': 'storage:bookmarks'})
.c('item', {'id': 'current'}) .c('item', {'id': 'current'})
.c('storage', {'xmlns': 'storage:bookmarks'}) .c('storage', {'xmlns': 'storage:bookmarks'})
.c('conference', { .c('conference', {
'name': 'The Play&apos;s the Thing', 'name': 'The Play&apos;s the Thing',
'autojoin': 'true', 'autojoin': 'false',
'jid': 'theplay@conference.shakespeare.lit' 'jid': 'theplay@conference.shakespeare.lit'
}).c('nick').t('JC').up().up() }).c('nick').t('JC').up().up()
.c('conference', {
'name': '1st Bookmark',
'autojoin': 'false',
'jid': 'first@conference.shakespeare.lit'
}).c('nick').t('JC').up().up()
.c('conference', {
'autojoin': 'false',
'jid': 'noname@conference.shakespeare.lit'
}).c('nick').t('JC').up().up()
.c('conference', {
'name': 'Bookmark with a very very long name that will be shortened',
'autojoin': 'false',
'jid': 'longname@conference.shakespeare.lit'
}).c('nick').t('JC').up().up()
.c('conference', { .c('conference', {
'name': 'Another room', 'name': 'Another room',
'autojoin': 'false', 'autojoin': 'false',
'jid': 'another@conference.shakespeare.lit' 'jid': 'another@conference.shakespeare.lit'
}); // Purposefully exclude the <nick> element to test #1043 }).c('nick').t('JC').up().up();
_converse.connection._dataRecv(test_utils.createRequest(stanza)); _converse.connection._dataRecv(test_utils.createRequest(stanza));
return test_utils.waitUntil(() => _converse.bookmarks.onBookmarksReceived.calls.count(), 300)
}).then(() => {
expect(_converse.bookmarks.models.length).toBe(2);
expect(_converse.bookmarks.findWhere({'jid': 'theplay@conference.shakespeare.lit'}).get('autojoin')).toBe(true);
expect(_converse.bookmarks.findWhere({'jid': 'another@conference.shakespeare.lit'}).get('autojoin')).toBe(false);
done();
}).catch(_.partial(console.error, _));
}));
describe("The rooms panel", function () {
it("shows a list of bookmarks", mock.initConverseWithPromises(
['send'], ['rosterGroupsFetched'], {}, function (done, _converse) {
test_utils.waitUntilDiscoConfirmed( await test_utils.waitUntil(() => document.querySelectorAll('#chatrooms div.bookmarks.rooms-list .room-item').length);
_converse, _converse.bare_jid, expect(document.querySelectorAll('#chatrooms div.bookmarks.rooms-list .room-item').length).toBe(5);
[{'category': 'pubsub', 'type': 'pep'}], let els = document.querySelectorAll('#chatrooms div.bookmarks.rooms-list .room-item a.list-item-link');
['http://jabber.org/protocol/pubsub#publish-options'] expect(els[0].textContent).toBe("1st Bookmark");
).then(function () { expect(els[1].textContent).toBe("Another room");
test_utils.openControlBox(); expect(els[2].textContent).toBe("Bookmark with a very very long name that will be shortened");
expect(els[3].textContent).toBe("noname@conference.shakespeare.lit");
var IQ_id; expect(els[4].textContent).toBe("The Play's the Thing");
expect(_.filter(_converse.connection.send.calls.all(), function (call) {
var stanza = call.args[0]; spyOn(window, 'confirm').and.returnValue(true);
if (!(stanza instanceof Element) || stanza.nodeName !== 'iq') { document.querySelector('#chatrooms .bookmarks.rooms-list .room-item:nth-child(2) a:nth-child(2)').click();
return; expect(window.confirm).toHaveBeenCalled();
} await test_utils.waitUntil(() => document.querySelectorAll('#chatrooms div.bookmarks.rooms-list .room-item').length === 4)
// XXX: Wrapping in a div is a workaround for PhantomJS els = document.querySelectorAll('#chatrooms div.bookmarks.rooms-list .room-item a.list-item-link');
var div = document.createElement('div'); expect(els[0].textContent).toBe("1st Bookmark");
div.appendChild(stanza); expect(els[1].textContent).toBe("Bookmark with a very very long name that will be shortened");
if (div.innerHTML === expect(els[2].textContent).toBe("noname@conference.shakespeare.lit");
'<iq from="dummy@localhost/resource" type="get" '+ expect(els[3].textContent).toBe("The Play's the Thing");
'xmlns="jabber:client" id="'+stanza.getAttribute('id')+'">'+ done();
'<pubsub xmlns="http://jabber.org/protocol/pubsub">'+
'<items node="storage:bookmarks"></items>'+
'</pubsub>'+
'</iq>') {
IQ_id = stanza.getAttribute('id');
return true;
}
}).length).toBe(1);
var stanza = $iq({'to': _converse.connection.jid, 'type':'result', 'id':IQ_id})
.c('pubsub', {'xmlns': Strophe.NS.PUBSUB})
.c('items', {'node': 'storage:bookmarks'})
.c('item', {'id': 'current'})
.c('storage', {'xmlns': 'storage:bookmarks'})
.c('conference', {
'name': 'The Play&apos;s the Thing',
'autojoin': 'false',
'jid': 'theplay@conference.shakespeare.lit'
}).c('nick').t('JC').up().up()
.c('conference', {
'name': '1st Bookmark',
'autojoin': 'false',
'jid': 'first@conference.shakespeare.lit'
}).c('nick').t('JC').up().up()
.c('conference', {
'autojoin': 'false',
'jid': 'noname@conference.shakespeare.lit'
}).c('nick').t('JC').up().up()
.c('conference', {
'name': 'Bookmark with a very very long name that will be shortened',
'autojoin': 'false',
'jid': 'longname@conference.shakespeare.lit'
}).c('nick').t('JC').up().up()
.c('conference', {
'name': 'Another room',
'autojoin': 'false',
'jid': 'another@conference.shakespeare.lit'
}).c('nick').t('JC').up().up();
_converse.connection._dataRecv(test_utils.createRequest(stanza));
test_utils.waitUntil(() => document.querySelectorAll('#chatrooms div.bookmarks.rooms-list .room-item').length, 300)
.then(() => {
expect(document.querySelectorAll('#chatrooms div.bookmarks.rooms-list .room-item').length).toBe(5);
const els = document.querySelectorAll('#chatrooms div.bookmarks.rooms-list .room-item a.list-item-link');
expect(els[0].textContent).toBe("1st Bookmark");
expect(els[1].textContent).toBe("Another room");
expect(els[2].textContent).toBe("Bookmark with a very very long name that will be shortened");
expect(els[3].textContent).toBe("noname@conference.shakespeare.lit");
expect(els[4].textContent).toBe("The Play's the Thing");
spyOn(window, 'confirm').and.returnValue(true);
document.querySelector('#chatrooms .bookmarks.rooms-list .room-item:nth-child(2) a:nth-child(2)').click();
expect(window.confirm).toHaveBeenCalled();
return test_utils.waitUntil(() => document.querySelectorAll('#chatrooms div.bookmarks.rooms-list .room-item').length === 4, 300)
}).then(() => {
const els = document.querySelectorAll('#chatrooms div.bookmarks.rooms-list .room-item a.list-item-link');
expect(els[0].textContent).toBe("1st Bookmark");
expect(els[1].textContent).toBe("Bookmark with a very very long name that will be shortened");
expect(els[2].textContent).toBe("noname@conference.shakespeare.lit");
expect(els[3].textContent).toBe("The Play's the Thing");
done();
}).catch(_.partial(console.error, _));
});
})); }));
it("remembers the toggle state of the bookmarks list", mock.initConverseWithPromises( it("remembers the toggle state of the bookmarks list", mock.initConverseWithPromises(
['send'], ['rosterGroupsFetched'], {}, function (done, _converse) { ['send'], ['rosterGroupsFetched'], {},
async function (done, _converse) {
test_utils.openControlBox(); test_utils.openControlBox();
await test_utils.waitUntilDiscoConfirmed(
test_utils.waitUntilDiscoConfirmed(
_converse, _converse.bare_jid, _converse, _converse.bare_jid,
[{'category': 'pubsub', 'type': 'pep'}], [{'category': 'pubsub', 'type': 'pep'}],
['http://jabber.org/protocol/pubsub#publish-options'] ['http://jabber.org/protocol/pubsub#publish-options']
).then(function () { );
var IQ_id;
expect(_.filter(_converse.connection.send.calls.all(), function (call) { let IQ_id;
var stanza = call.args[0]; const call = await test_utils.waitUntil(() =>
if (!(stanza instanceof Element) || stanza.nodeName !== 'iq') { _.filter(
return; _converse.connection.send.calls.all(),
} call => {
// XXX: Wrapping in a div is a workaround for PhantomJS const stanza = call.args[0];
var div = document.createElement('div'); if (!(stanza instanceof Element) || stanza.nodeName !== 'iq') {
div.appendChild(stanza); return;
if (div.innerHTML === }
'<iq from="dummy@localhost/resource" type="get" '+ if (sizzle('items[node="storage:bookmarks"]', stanza).length) {
'xmlns="jabber:client" id="'+stanza.getAttribute('id')+'">'+ IQ_id = stanza.getAttribute('id');
'<pubsub xmlns="http://jabber.org/protocol/pubsub">'+ return true;
'<items node="storage:bookmarks"></items>'+ }
'</pubsub>'+
'</iq>') {
IQ_id = stanza.getAttribute('id');
return true;
} }
}).length).toBe(1); ).pop()
);
expect(Strophe.serialize(call.args[0])).toBe(
`<iq from="dummy@localhost/resource" id="${IQ_id}" type="get" xmlns="jabber:client">`+
'<pubsub xmlns="http://jabber.org/protocol/pubsub">'+
'<items node="storage:bookmarks"/>'+
'</pubsub>'+
'</iq>'
);
var stanza = $iq({'to': _converse.connection.jid, 'type':'result', 'id':IQ_id}) const stanza = $iq({'to': _converse.connection.jid, 'type':'result', 'id':IQ_id})
.c('pubsub', {'xmlns': Strophe.NS.PUBSUB}) .c('pubsub', {'xmlns': Strophe.NS.PUBSUB})
.c('items', {'node': 'storage:bookmarks'}) .c('items', {'node': 'storage:bookmarks'})
.c('item', {'id': 'current'}) .c('item', {'id': 'current'})
.c('storage', {'xmlns': 'storage:bookmarks'}); .c('storage', {'xmlns': 'storage:bookmarks'});
_converse.connection._dataRecv(test_utils.createRequest(stanza)); _converse.connection._dataRecv(test_utils.createRequest(stanza));
_converse.bookmarks.create({ _converse.bookmarks.create({
'jid': 'theplay@conference.shakespeare.lit', 'jid': 'theplay@conference.shakespeare.lit',
'autojoin': false, 'autojoin': false,
'name': 'The Play', 'name': 'The Play',
'nick': '' 'nick': ''
});
test_utils.waitUntil(() => $('#chatrooms .bookmarks.rooms-list .room-item:visible').length
).then(function () {
expect($('#chatrooms .bookmarks.rooms-list').hasClass('collapsed')).toBeFalsy();
expect($('#chatrooms .bookmarks.rooms-list .room-item:visible').length).toBe(1);
expect(_converse.bookmarksview.list_model.get('toggle-state')).toBe(_converse.OPENED);
$('#chatrooms .bookmarks-toggle')[0].click();
expect($('#chatrooms .bookmarks.rooms-list').hasClass('collapsed')).toBeTruthy();
expect(_converse.bookmarksview.list_model.get('toggle-state')).toBe(_converse.CLOSED);
$('#chatrooms .bookmarks-toggle')[0].click();
expect($('#chatrooms .bookmarks.rooms-list').hasClass('collapsed')).toBeFalsy();
expect($('#chatrooms .bookmarks.rooms-list .room-item:visible').length).toBe(1);
expect(_converse.bookmarksview.list_model.get('toggle-state')).toBe(_converse.OPENED);
done();
});
}); });
await test_utils.waitUntil(() => $('#chatrooms .bookmarks.rooms-list .room-item:visible').length);
expect($('#chatrooms .bookmarks.rooms-list').hasClass('collapsed')).toBeFalsy();
expect($('#chatrooms .bookmarks.rooms-list .room-item:visible').length).toBe(1);
expect(_converse.bookmarksview.list_model.get('toggle-state')).toBe(_converse.OPENED);
$('#chatrooms .bookmarks-toggle')[0].click();
expect($('#chatrooms .bookmarks.rooms-list').hasClass('collapsed')).toBeTruthy();
expect(_converse.bookmarksview.list_model.get('toggle-state')).toBe(_converse.CLOSED);
$('#chatrooms .bookmarks-toggle')[0].click();
expect($('#chatrooms .bookmarks.rooms-list').hasClass('collapsed')).toBeFalsy();
expect($('#chatrooms .bookmarks.rooms-list .room-item:visible').length).toBe(1);
expect(_converse.bookmarksview.list_model.get('toggle-state')).toBe(_converse.OPENED);
done();
})); }));
}); });
}); });
......
...@@ -150,7 +150,8 @@ ...@@ -150,7 +150,8 @@
})); }));
it("can be trimmed to conserve space", it("can be trimmed to conserve space",
mock.initConverseWithPromises(null, ['rosterGroupsFetched'], {}, function (done, _converse) { mock.initConverseWithPromises(null, ['rosterGroupsFetched'], {},
async function (done, _converse) {
spyOn(_converse.chatboxviews, 'trimChats'); spyOn(_converse.chatboxviews, 'trimChats');
...@@ -163,51 +164,47 @@ ...@@ -163,51 +164,47 @@
test_utils.openControlBox(); test_utils.openControlBox();
let online_contacts; let jid, chatboxview;
var i, jid, chatbox, chatboxview, trimmedview;
// openControlBox was called earlier, so the controlbox is // openControlBox was called earlier, so the controlbox is
// visible, but no other chat boxes have been created. // visible, but no other chat boxes have been created.
expect(_converse.chatboxes.length).toEqual(1); expect(_converse.chatboxes.length).toEqual(1);
expect(document.querySelectorAll("#conversejs .chatbox").length).toBe(1); // Controlbox is open expect(document.querySelectorAll("#conversejs .chatbox").length).toBe(1); // Controlbox is open
_converse.rosterview.update(); // XXX: Hack to make sure $roster element is attached. _converse.rosterview.update(); // XXX: Hack to make sure $roster element is attached.
test_utils.waitUntil(() => _converse.rosterview.el.querySelectorAll('.roster-group li').length) await test_utils.waitUntil(() => _converse.rosterview.el.querySelectorAll('.roster-group li').length);
.then(() => { // Test that they can be maximized again
// Test that they can be maximized again const online_contacts = _converse.rosterview.el.querySelectorAll('.roster-group .current-xmpp-contact a.open-chat');
online_contacts = _converse.rosterview.el.querySelectorAll('.roster-group .current-xmpp-contact a.open-chat'); expect(online_contacts.length).toBe(15);
expect(online_contacts.length).toBe(15); let i;
for (i=0; i<online_contacts.length; i++) { for (i=0; i<online_contacts.length; i++) {
const el = online_contacts[i]; const el = online_contacts[i];
el.click(); el.click();
} }
return test_utils.waitUntil(() => _converse.chatboxes.length == 16) await test_utils.waitUntil(() => _converse.chatboxes.length == 16);
}).then(() => { expect(_converse.chatboxviews.trimChats.calls.count()).toBe(16);
expect(_converse.chatboxviews.trimChats.calls.count()).toBe(16);
for (i=0; i<online_contacts.length; i++) {
for (i=0; i<online_contacts.length; i++) { const el = online_contacts[i];
const el = online_contacts[i]; jid = _.trim(el.textContent.trim()).replace(/ /g,'.').toLowerCase() + '@localhost';
jid = _.trim(el.textContent.trim()).replace(/ /g,'.').toLowerCase() + '@localhost'; chatboxview = _converse.chatboxviews.get(jid);
chatboxview = _converse.chatboxviews.get(jid); spyOn(chatboxview, 'minimize').and.callThrough();
spyOn(chatboxview, 'minimize').and.callThrough(); chatboxview.model.set({'minimized': true});
chatboxview.model.set({'minimized': true}); expect(trimmed_chatboxes.addChat).toHaveBeenCalled();
expect(trimmed_chatboxes.addChat).toHaveBeenCalled(); expect(chatboxview.minimize).toHaveBeenCalled();
expect(chatboxview.minimize).toHaveBeenCalled(); }
} await test_utils.waitUntil(() => _converse.chatboxviews.keys().length);
return test_utils.waitUntil(() => _converse.chatboxviews.keys().length); var key = _converse.chatboxviews.keys()[1];
}).then(function () { const trimmedview = trimmed_chatboxes.get(key);
var key = _converse.chatboxviews.keys()[1]; const chatbox = trimmedview.model;
trimmedview = trimmed_chatboxes.get(key); spyOn(chatbox, 'maximize').and.callThrough();
chatbox = trimmedview.model; spyOn(trimmedview, 'restore').and.callThrough();
spyOn(chatbox, 'maximize').and.callThrough(); trimmedview.delegateEvents();
spyOn(trimmedview, 'restore').and.callThrough(); trimmedview.el.querySelector("a.restore-chat").click();
trimmedview.delegateEvents();
trimmedview.el.querySelector("a.restore-chat").click(); expect(trimmedview.restore).toHaveBeenCalled();
expect(chatbox.maximize).toHaveBeenCalled();
expect(trimmedview.restore).toHaveBeenCalled(); expect(_converse.chatboxviews.trimChats.calls.count()).toBe(17);
expect(chatbox.maximize).toHaveBeenCalled(); done();
expect(_converse.chatboxviews.trimChats.calls.count()).toBe(17);
done();
});
})); }));
it("can be opened in minimized mode initially", it("can be opened in minimized mode initially",
...@@ -453,105 +450,82 @@ ...@@ -453,105 +450,82 @@
it("contains a button for inserting emojis", it("contains a button for inserting emojis",
mock.initConverseWithPromises( mock.initConverseWithPromises(
null, ['rosterGroupsFetched', 'chatBoxesFetched'], {}, null, ['rosterGroupsFetched', 'chatBoxesFetched'], {},
function (done, _converse) { async function (done, _converse) {
test_utils.createContacts(_converse, 'current'); test_utils.createContacts(_converse, 'current');
_converse.emit('rosterContactsFetched'); _converse.emit('rosterContactsFetched');
test_utils.openControlBox(); test_utils.openControlBox();
let timeout = false, view, toolbar;
const contact_jid = mock.cur_names[2].replace(/ /g,'.').toLowerCase() + '@localhost'; const contact_jid = mock.cur_names[2].replace(/ /g,'.').toLowerCase() + '@localhost';
test_utils.openChatBoxFor(_converse, contact_jid) await test_utils.openChatBoxFor(_converse, contact_jid);
.then(() => { const view = _converse.chatboxviews.get(contact_jid);
view = _converse.chatboxviews.get(contact_jid); const toolbar = view.el.querySelector('ul.chat-toolbar');
toolbar = view.el.querySelector('ul.chat-toolbar'); expect(toolbar.querySelectorAll('li.toggle-smiley').length).toBe(1);
expect(toolbar.querySelectorAll('li.toggle-smiley').length).toBe(1); // Register spies
// Register spies spyOn(view, 'toggleEmojiMenu').and.callThrough();
spyOn(view, 'toggleEmojiMenu').and.callThrough(); spyOn(view, 'insertEmoji').and.callThrough();
spyOn(view, 'insertEmoji').and.callThrough();
view.delegateEvents(); // We need to rebind all events otherwise our spy won't be called
view.delegateEvents(); // We need to rebind all events otherwise our spy won't be called toolbar.querySelector('li.toggle-smiley').click();
toolbar.querySelector('li.toggle-smiley').click();
await test_utils.waitUntil(() => u.isVisible(view.el.querySelector('.toggle-smiley .emoji-picker-container')));
return test_utils.waitUntil(() => u.isVisible(view.el.querySelector('.toggle-smiley .emoji-picker-container'), 500)); var picker = view.el.querySelector('.toggle-smiley .emoji-picker-container');
}).then(() => { var items = picker.querySelectorAll('.emoji-picker li');
var picker = view.el.querySelector('.toggle-smiley .emoji-picker-container'); items[0].click()
var items = picker.querySelectorAll('.emoji-picker li'); expect(view.insertEmoji).toHaveBeenCalled();
items[0].click() expect(view.el.querySelector('textarea.chat-textarea').value).toBe(':grinning: ');
expect(view.insertEmoji).toHaveBeenCalled(); toolbar.querySelector('li.toggle-smiley').click(); // Close the panel again
setTimeout(function () { timeout = true; }, 100); done();
return test_utils.waitUntil(() => timeout, 500);
}).then(() => {
timeout = false;
toolbar.querySelector('li.toggle-smiley').click(); // Close the panel again
return test_utils.waitUntil(() => !view.el.querySelector('.toggle-smiley .toolbar-menu').offsetHeight, 500);
}).then(() => {
setTimeout(function () { timeout = true; }, 100);
return test_utils.waitUntil(() => timeout, 500);
}).then(() => {
toolbar.querySelector('li.toggle-smiley').click();
expect(view.toggleEmojiMenu).toHaveBeenCalled();
return test_utils.waitUntil(() => u.isVisible(view.el.querySelector('.toggle-smiley .emoji-picker-container')), 500);
}).then(() => {
var nodes = view.el.querySelectorAll('.toggle-smiley ul li');
nodes[nodes.length-1].click();
expect(view.el.querySelector('textarea.chat-textarea').value).toBe(':grinning: ');
expect(view.insertEmoji).toHaveBeenCalled();
done();
}).catch(_.partial(_converse.log, _, Strophe.LogLevel.FATAL));
})); }));
it("can contain a button for starting a call", it("can contain a button for starting a call",
mock.initConverseWithPromises( mock.initConverseWithPromises(
null, ['rosterGroupsFetched', 'chatBoxesFetched'], {}, null, ['rosterGroupsFetched', 'chatBoxesFetched'], {},
function (done, _converse) { async function (done, _converse) {
test_utils.createContacts(_converse, 'current'); test_utils.createContacts(_converse, 'current');
_converse.emit('rosterContactsFetched'); _converse.emit('rosterContactsFetched');
test_utils.openControlBox(); test_utils.openControlBox();
let view, toolbar, call_button; let toolbar, call_button;
const contact_jid = mock.cur_names[2].replace(/ /g,'.').toLowerCase() + '@localhost'; const contact_jid = mock.cur_names[2].replace(/ /g,'.').toLowerCase() + '@localhost';
spyOn(_converse, 'emit'); spyOn(_converse, 'emit');
// First check that the button doesn't show if it's not enabled // First check that the button doesn't show if it's not enabled
// via "visible_toolbar_buttons" // via "visible_toolbar_buttons"
_converse.visible_toolbar_buttons.call = false; _converse.visible_toolbar_buttons.call = false;
test_utils.openChatBoxFor(_converse, contact_jid) await test_utils.openChatBoxFor(_converse, contact_jid);
.then(() => { let view = _converse.chatboxviews.get(contact_jid);
view = _converse.chatboxviews.get(contact_jid); toolbar = view.el.querySelector('ul.chat-toolbar');
toolbar = view.el.querySelector('ul.chat-toolbar'); call_button = toolbar.querySelector('.toggle-call');
call_button = toolbar.querySelector('.toggle-call'); expect(_.isNull(call_button)).toBeTruthy();
expect(_.isNull(call_button)).toBeTruthy(); view.close();
view.close(); // Now check that it's shown if enabled and that it emits
// Now check that it's shown if enabled and that it emits // callButtonClicked
// callButtonClicked _converse.visible_toolbar_buttons.call = true; // enable the button
_converse.visible_toolbar_buttons.call = true; // enable the button await test_utils.openChatBoxFor(_converse, contact_jid);
return test_utils.openChatBoxFor(_converse, contact_jid); view = _converse.chatboxviews.get(contact_jid);
}).then(() => { toolbar = view.el.querySelector('ul.chat-toolbar');
view = _converse.chatboxviews.get(contact_jid); call_button = toolbar.querySelector('.toggle-call');
toolbar = view.el.querySelector('ul.chat-toolbar'); call_button.click();
call_button = toolbar.querySelector('.toggle-call'); expect(_converse.emit).toHaveBeenCalledWith('callButtonClicked', jasmine.any(Object));
call_button.click(); done();
expect(_converse.emit).toHaveBeenCalledWith('callButtonClicked', jasmine.any(Object));
done();
});
})); }));
}); });
describe("A Chat Status Notification", function () { describe("A Chat Status Notification", function () {
it("does not open a new chatbox", it("does not open a new chatbox",
mock.initConverseWithPromises( mock.initConverseWithPromises(
null, ['rosterGroupsFetched'], {}, null, ['rosterGroupsFetched'], {},
function (done, _converse) { function (done, _converse) {
test_utils.createContacts(_converse, 'current'); test_utils.createContacts(_converse, 'current');
test_utils.openControlBox(); test_utils.openControlBox();
spyOn(_converse, 'emit'); spyOn(_converse, 'emit');
var sender_jid = mock.cur_names[1].replace(/ /g,'.').toLowerCase() + '@localhost'; const sender_jid = mock.cur_names[1].replace(/ /g,'.').toLowerCase() + '@localhost';
// <composing> state // <composing> state
var msg = $msg({ const msg = $msg({
'from': sender_jid, 'from': sender_jid,
'to': _converse.connection.jid, 'to': _converse.connection.jid,
'type': 'chat', 'type': 'chat',
......
...@@ -2329,35 +2329,34 @@ ...@@ -2329,35 +2329,34 @@
})); }));
it("can be minimized by clicking a DOM element with class 'toggle-chatbox-button'", it("can be minimized by clicking a DOM element with class 'toggle-chatbox-button'",
mock.initConverseWithPromises( mock.initConverseWithPromises(
null, ['rosterGroupsFetched', 'chatBoxesFetched'], {}, null, ['rosterGroupsFetched', 'chatBoxesFetched'], {},
function (done, _converse) { async function (done, _converse) {
test_utils.openChatRoom(_converse, 'lounge', 'localhost', 'dummy') await test_utils.openChatRoom(_converse, 'lounge', 'localhost', 'dummy');
.then(() => { const view = _converse.chatboxviews.get('lounge@localhost'),
const view = _converse.chatboxviews.get('lounge@localhost'), trimmed_chatboxes = _converse.minimized_chats;
trimmed_chatboxes = _converse.minimized_chats;
spyOn(view, 'minimize').and.callThrough(); spyOn(view, 'minimize').and.callThrough();
spyOn(view, 'maximize').and.callThrough(); spyOn(view, 'maximize').and.callThrough();
spyOn(_converse, 'emit'); spyOn(_converse, 'emit');
view.delegateEvents(); // We need to rebind all events otherwise our spy won't be called view.delegateEvents(); // We need to rebind all events otherwise our spy won't be called
view.el.querySelector('.toggle-chatbox-button').click(); view.el.querySelector('.toggle-chatbox-button').click();
expect(view.minimize).toHaveBeenCalled(); expect(view.minimize).toHaveBeenCalled();
expect(_converse.emit).toHaveBeenCalledWith('chatBoxMinimized', jasmine.any(Object)); expect(_converse.emit).toHaveBeenCalledWith('chatBoxMinimized', jasmine.any(Object));
expect(u.isVisible(view.el)).toBeFalsy(); expect(u.isVisible(view.el)).toBeFalsy();
expect(view.model.get('minimized')).toBeTruthy(); expect(view.model.get('minimized')).toBeTruthy();
expect(view.minimize).toHaveBeenCalled(); expect(view.minimize).toHaveBeenCalled();
var trimmedview = trimmed_chatboxes.get(view.model.get('id')); await test_utils.waitUntil(() => trimmed_chatboxes.get(view.model.get('id')));
trimmedview.el.querySelector("a.restore-chat").click(); const trimmedview = trimmed_chatboxes.get(view.model.get('id'));
expect(view.maximize).toHaveBeenCalled(); trimmedview.el.querySelector("a.restore-chat").click();
expect(_converse.emit).toHaveBeenCalledWith('chatBoxMaximized', jasmine.any(Object)); expect(view.maximize).toHaveBeenCalled();
expect(view.model.get('minimized')).toBeFalsy(); expect(_converse.emit).toHaveBeenCalledWith('chatBoxMaximized', jasmine.any(Object));
expect(_converse.emit.calls.count(), 3); expect(view.model.get('minimized')).toBeFalsy();
done(); expect(_converse.emit.calls.count(), 3);
done();
});
})); }));
it("can be closed again by clicking a DOM element with class 'close-chatbox-button'", it("can be closed again by clicking a DOM element with class 'close-chatbox-button'",
......
...@@ -14,159 +14,159 @@ ...@@ -14,159 +14,159 @@
describe("Discovering support", function () { describe("Discovering support", function () {
it("is done automatically", mock.initConverseWithAsync(function (done, _converse) { it("is done automatically", mock.initConverseWithAsync(async function (done, _converse) {
var IQ_stanzas = _converse.connection.IQ_stanzas; var IQ_stanzas = _converse.connection.IQ_stanzas;
var IQ_ids = _converse.connection.IQ_ids; var IQ_ids = _converse.connection.IQ_ids;
test_utils.waitUntilDiscoConfirmed(_converse, _converse.bare_jid, [], []).then(function () { await test_utils.waitUntilDiscoConfirmed(_converse, _converse.bare_jid, [], []);
test_utils.waitUntil(function () { await test_utils.waitUntil(() => _.filter(
IQ_stanzas,
iq => iq.nodeTree.querySelector('iq[to="localhost"] query[xmlns="http://jabber.org/protocol/disco#info"]')).length
);
/* <iq type='result'
* from='plays.shakespeare.lit'
* to='romeo@montague.net/orchard'
* id='info1'>
* <query xmlns='http://jabber.org/protocol/disco#info'>
* <identity
* category='server'
* type='im'/>
* <feature var='http://jabber.org/protocol/disco#info'/>
* <feature var='http://jabber.org/protocol/disco#items'/>
* </query>
* </iq>
*/
let stanza = _.find(IQ_stanzas, function (iq) {
return iq.nodeTree.querySelector(
'iq[to="localhost"] query[xmlns="http://jabber.org/protocol/disco#info"]');
});
var info_IQ_id = IQ_ids[IQ_stanzas.indexOf(stanza)];
stanza = $iq({
'type': 'result',
'from': 'localhost',
'to': 'dummy@localhost/resource',
'id': info_IQ_id
}).c('query', {'xmlns': 'http://jabber.org/protocol/disco#info'})
.c('identity', {
'category': 'server',
'type': 'im'}).up()
.c('feature', {
'var': 'http://jabber.org/protocol/disco#info'}).up()
.c('feature', {
'var': 'http://jabber.org/protocol/disco#items'});
_converse.connection._dataRecv(test_utils.createRequest(stanza));
const entities = await _converse.api.disco.entities.get();
expect(entities.length).toBe(2);
expect(_.includes(entities.pluck('jid'), 'localhost')).toBe(true);
expect(_.includes(entities.pluck('jid'), 'dummy@localhost')).toBe(true);
expect(entities.get(_converse.domain).features.length).toBe(2);
expect(entities.get(_converse.domain).identities.length).toBe(1);
// Converse.js sees that the entity has a disco#items feature,
// so it will make a query for it.
await test_utils.waitUntil(() => _.filter(
IQ_stanzas,
iq => iq.nodeTree.querySelector('iq[to="localhost"] query[xmlns="http://jabber.org/protocol/disco#items"]')
).length
);
/* <iq from='montague.tld'
* id='step_01'
* to='romeo@montague.tld/garden'
* type='result'>
* <query xmlns='http://jabber.org/protocol/disco#items'>
* <item jid='upload.montague.tld' name='HTTP File Upload' />
* <item jid='conference.montague.tld' name='Chatroom Service' />
* </query>
* </iq>
*/
stanza = _.find(IQ_stanzas, function (iq) {
return iq.nodeTree.querySelector('iq[to="localhost"] query[xmlns="http://jabber.org/protocol/disco#items"]');
});
var items_IQ_id = IQ_ids[IQ_stanzas.indexOf(stanza)];
stanza = $iq({
'type': 'result',
'from': 'localhost',
'to': 'dummy@localhost/resource',
'id': items_IQ_id
}).c('query', {'xmlns': 'http://jabber.org/protocol/disco#items'})
.c('item', {
'jid': 'upload.localhost',
'name': 'HTTP File Upload'});
_converse.connection._dataRecv(test_utils.createRequest(stanza));
_converse.api.disco.entities.get().then(function (entities) {
expect(entities.length).toBe(2);
expect(entities.get('localhost').items.length).toBe(1);
return test_utils.waitUntil(function () {
// Converse.js sees that the entity has a disco#info feature,
// so it will make a query for it.
return _.filter(IQ_stanzas, function (iq) { return _.filter(IQ_stanzas, function (iq) {
return iq.nodeTree.querySelector(
'iq[to="localhost"] query[xmlns="http://jabber.org/protocol/disco#info"]');
}).length > 0;
}, 300).then(function () {
/* <iq type='result'
* from='plays.shakespeare.lit'
* to='romeo@montague.net/orchard'
* id='info1'>
* <query xmlns='http://jabber.org/protocol/disco#info'>
* <identity
* category='server'
* type='im'/>
* <feature var='http://jabber.org/protocol/disco#info'/>
* <feature var='http://jabber.org/protocol/disco#items'/>
* </query>
* </iq>
*/
var stanza = _.find(IQ_stanzas, function (iq) {
return iq.nodeTree.querySelector(
'iq[to="localhost"] query[xmlns="http://jabber.org/protocol/disco#info"]');
});
var info_IQ_id = IQ_ids[IQ_stanzas.indexOf(stanza)];
stanza = $iq({
'type': 'result',
'from': 'localhost',
'to': 'dummy@localhost/resource',
'id': info_IQ_id
}).c('query', {'xmlns': 'http://jabber.org/protocol/disco#info'})
.c('identity', {
'category': 'server',
'type': 'im'}).up()
.c('feature', {
'var': 'http://jabber.org/protocol/disco#info'}).up()
.c('feature', {
'var': 'http://jabber.org/protocol/disco#items'});
_converse.connection._dataRecv(test_utils.createRequest(stanza));
_converse.api.disco.entities.get().then(function(entities) {
expect(entities.length).toBe(2);
expect(_.includes(entities.pluck('jid'), 'localhost')).toBe(true);
expect(_.includes(entities.pluck('jid'), 'dummy@localhost')).toBe(true);
expect(entities.get(_converse.domain).features.length).toBe(2);
expect(entities.get(_converse.domain).identities.length).toBe(1);
return test_utils.waitUntil(function () {
// Converse.js sees that the entity has a disco#items feature,
// so it will make a query for it.
return _.filter(IQ_stanzas, function (iq) {
return iq.nodeTree.querySelector('iq[to="localhost"] query[xmlns="http://jabber.org/protocol/disco#items"]');
}).length > 0;
}, 300);
});
}).then(function () {
/* <iq from='montague.tld'
* id='step_01'
* to='romeo@montague.tld/garden'
* type='result'>
* <query xmlns='http://jabber.org/protocol/disco#items'>
* <item jid='upload.montague.tld' name='HTTP File Upload' />
* <item jid='conference.montague.tld' name='Chatroom Service' />
* </query>
* </iq>
*/
var stanza = _.find(IQ_stanzas, function (iq) {
return iq.nodeTree.querySelector('iq[to="localhost"] query[xmlns="http://jabber.org/protocol/disco#items"]');
});
var items_IQ_id = IQ_ids[IQ_stanzas.indexOf(stanza)];
stanza = $iq({
'type': 'result',
'from': 'localhost',
'to': 'dummy@localhost/resource',
'id': items_IQ_id
}).c('query', {'xmlns': 'http://jabber.org/protocol/disco#items'})
.c('item', {
'jid': 'upload.localhost',
'name': 'HTTP File Upload'});
_converse.connection._dataRecv(test_utils.createRequest(stanza));
_converse.api.disco.entities.get().then(function (entities) {
expect(entities.length).toBe(2);
expect(entities.get('localhost').items.length).toBe(1);
return test_utils.waitUntil(function () {
// Converse.js sees that the entity has a disco#info feature,
// so it will make a query for it.
return _.filter(IQ_stanzas, function (iq) {
return iq.nodeTree.querySelector('iq[to="upload.localhost"] query[xmlns="http://jabber.org/protocol/disco#info"]');
}).length > 0;
}, 300);
});
}).then(function () {
var stanza = _.find(IQ_stanzas, function (iq) {
return iq.nodeTree.querySelector('iq[to="upload.localhost"] query[xmlns="http://jabber.org/protocol/disco#info"]'); return iq.nodeTree.querySelector('iq[to="upload.localhost"] query[xmlns="http://jabber.org/protocol/disco#info"]');
}); }).length > 0;
var IQ_id = IQ_ids[IQ_stanzas.indexOf(stanza)]; }, 300);
expect(stanza.toLocaleString()).toBe( });
`<iq from="dummy@localhost/resource" id="`+IQ_id+`" to="upload.localhost" type="get" xmlns="jabber:client">`+
`<query xmlns="http://jabber.org/protocol/disco#info"/>`+
`</iq>`);
// Upload service responds and reports a maximum file size of 5MiB
/* <iq from='upload.montague.tld'
* id='step_02'
* to='romeo@montague.tld/garden'
* type='result'>
* <query xmlns='http://jabber.org/protocol/disco#info'>
* <identity category='store'
* type='file'
* name='HTTP File Upload' />
* <feature var='urn:xmpp:http:upload:0' />
* <x type='result' xmlns='jabber:x:data'>
* <field var='FORM_TYPE' type='hidden'>
* <value>urn:xmpp:http:upload:0</value>
* </field>
* <field var='max-file-size'>
* <value>5242880</value>
* </field>
* </x>
* </query>
* </iq>
*/
stanza = $iq({'type': 'result', 'to': 'dummy@localhost/resource', 'id': IQ_id, 'from': 'upload.localhost'})
.c('query', {'xmlns': 'http://jabber.org/protocol/disco#info'})
.c('identity', {'category':'store', 'type':'file', 'name':'HTTP File Upload'}).up()
.c('feature', {'var':'urn:xmpp:http:upload:0'}).up()
.c('x', {'type':'result', 'xmlns':'jabber:x:data'})
.c('field', {'var':'FORM_TYPE', 'type':'hidden'})
.c('value').t('urn:xmpp:http:upload:0').up().up()
.c('field', {'var':'max-file-size'})
.c('value').t('5242880');
_converse.connection._dataRecv(test_utils.createRequest(stanza));
_converse.api.disco.entities.get().then(function (entities) { stanza = await test_utils.waitUntil(() =>
expect(entities.get('localhost').items.get('upload.localhost').identities.where({'category': 'store'}).length).toBe(1); _.filter(
_converse.api.disco.supports(Strophe.NS.HTTPUPLOAD, _converse.domain).then( IQ_stanzas,
function (result) { iq => iq.nodeTree.querySelector('iq[to="upload.localhost"] query[xmlns="http://jabber.org/protocol/disco#info"]')
expect(result.length).toBe(1); ).pop()
expect(result[0].get('jid')).toBe('upload.localhost'); );
expect(result[0].dataforms.where({'FORM_TYPE': {value: "urn:xmpp:http:upload:0", type: "hidden"}}).length).toBe(1); const IQ_id = IQ_ids[IQ_stanzas.indexOf(stanza)];
done();
} expect(stanza.toLocaleString()).toBe(
); `<iq from="dummy@localhost/resource" id="`+IQ_id+`" to="upload.localhost" type="get" xmlns="jabber:client">`+
}).catch(_.partial(_converse.log, _, Strophe.LogLevel.FATAL)); `<query xmlns="http://jabber.org/protocol/disco#info"/>`+
}) `</iq>`);
})
// Upload service responds and reports a maximum file size of 5MiB
/* <iq from='upload.montague.tld'
* id='step_02'
* to='romeo@montague.tld/garden'
* type='result'>
* <query xmlns='http://jabber.org/protocol/disco#info'>
* <identity category='store'
* type='file'
* name='HTTP File Upload' />
* <feature var='urn:xmpp:http:upload:0' />
* <x type='result' xmlns='jabber:x:data'>
* <field var='FORM_TYPE' type='hidden'>
* <value>urn:xmpp:http:upload:0</value>
* </field>
* <field var='max-file-size'>
* <value>5242880</value>
* </field>
* </x>
* </query>
* </iq>
*/
stanza = $iq({'type': 'result', 'to': 'dummy@localhost/resource', 'id': IQ_id, 'from': 'upload.localhost'})
.c('query', {'xmlns': 'http://jabber.org/protocol/disco#info'})
.c('identity', {'category':'store', 'type':'file', 'name':'HTTP File Upload'}).up()
.c('feature', {'var':'urn:xmpp:http:upload:0'}).up()
.c('x', {'type':'result', 'xmlns':'jabber:x:data'})
.c('field', {'var':'FORM_TYPE', 'type':'hidden'})
.c('value').t('urn:xmpp:http:upload:0').up().up()
.c('field', {'var':'max-file-size'})
.c('value').t('5242880');
_converse.connection._dataRecv(test_utils.createRequest(stanza));
_converse.api.disco.entities.get().then(function (entities) {
expect(entities.get('localhost').items.get('upload.localhost').identities.where({'category': 'store'}).length).toBe(1);
_converse.api.disco.supports(Strophe.NS.HTTPUPLOAD, _converse.domain).then(
function (result) {
expect(result.length).toBe(1);
expect(result[0].get('jid')).toBe('upload.localhost');
expect(result[0].dataforms.where({'FORM_TYPE': {value: "urn:xmpp:http:upload:0", type: "hidden"}}).length).toBe(1);
done();
}
);
}).catch(_.partial(_converse.log, _, Strophe.LogLevel.FATAL));
})); }));
}); });
...@@ -474,128 +474,124 @@ ...@@ -474,128 +474,124 @@
done(); done();
})); }));
it("shows an error message if the file is too large", mock.initConverseWithAsync(function (done, _converse) { it("shows an error message if the file is too large", mock.initConverseWithAsync(async function (done, _converse) {
const IQ_stanzas = _converse.connection.IQ_stanzas; const IQ_stanzas = _converse.connection.IQ_stanzas;
const IQ_ids = _converse.connection.IQ_ids; const IQ_ids = _converse.connection.IQ_ids;
const send_backup = XMLHttpRequest.prototype.send; const send_backup = XMLHttpRequest.prototype.send;
let view, contact_jid;
await test_utils.waitUntilDiscoConfirmed(_converse, _converse.bare_jid, [], []);
test_utils.waitUntilDiscoConfirmed(_converse, _converse.bare_jid, [], []) await test_utils.waitUntil(() => _.filter(
.then(() => test_utils.waitUntil(() => _.filter( IQ_stanzas,
IQ_stanzas, (iq) => iq.nodeTree.querySelector('iq[to="localhost"] query[xmlns="http://jabber.org/protocol/disco#info"]')).length iq => iq.nodeTree.querySelector('iq[to="localhost"] query[xmlns="http://jabber.org/protocol/disco#info"]')).length
)).then(() => { );
var stanza = _.find(IQ_stanzas, function (iq) {
return iq.nodeTree.querySelector( var stanza = _.find(IQ_stanzas, function (iq) {
'iq[to="localhost"] query[xmlns="http://jabber.org/protocol/disco#info"]'); return iq.nodeTree.querySelector(
}); 'iq[to="localhost"] query[xmlns="http://jabber.org/protocol/disco#info"]');
var info_IQ_id = IQ_ids[IQ_stanzas.indexOf(stanza)]; });
var info_IQ_id = IQ_ids[IQ_stanzas.indexOf(stanza)];
stanza = $iq({
'type': 'result', stanza = $iq({
'from': 'localhost', 'type': 'result',
'to': 'dummy@localhost/resource', 'from': 'localhost',
'id': info_IQ_id 'to': 'dummy@localhost/resource',
}).c('query', {'xmlns': 'http://jabber.org/protocol/disco#info'}) 'id': info_IQ_id
.c('identity', { }).c('query', {'xmlns': 'http://jabber.org/protocol/disco#info'})
'category': 'server', .c('identity', {
'type': 'im'}).up() 'category': 'server',
.c('feature', { 'type': 'im'}).up()
'var': 'http://jabber.org/protocol/disco#info'}).up() .c('feature', {
.c('feature', { 'var': 'http://jabber.org/protocol/disco#info'}).up()
'var': 'http://jabber.org/protocol/disco#items'}); .c('feature', {
_converse.connection._dataRecv(test_utils.createRequest(stanza)); 'var': 'http://jabber.org/protocol/disco#items'});
return _converse.api.disco.entities.get(); _converse.connection._dataRecv(test_utils.createRequest(stanza));
}).then(function (entities) { let entities = await _converse.api.disco.entities.get();
expect(entities.length).toBe(2);
expect(_.includes(entities.pluck('jid'), 'localhost')).toBe(true); expect(entities.length).toBe(2);
expect(_.includes(entities.pluck('jid'), 'dummy@localhost')).toBe(true); expect(_.includes(entities.pluck('jid'), 'localhost')).toBe(true);
expect(_.includes(entities.pluck('jid'), 'dummy@localhost')).toBe(true);
expect(entities.get(_converse.domain).features.length).toBe(2);
expect(entities.get(_converse.domain).identities.length).toBe(1); expect(entities.get(_converse.domain).features.length).toBe(2);
expect(entities.get(_converse.domain).identities.length).toBe(1);
return test_utils.waitUntil(function () {
// Converse.js sees that the entity has a disco#items feature, await test_utils.waitUntil(function () {
// so it will make a query for it. // Converse.js sees that the entity has a disco#items feature,
return _.filter(IQ_stanzas, function (iq) { // so it will make a query for it.
return iq.nodeTree.querySelector('iq[to="localhost"] query[xmlns="http://jabber.org/protocol/disco#items"]'); return _.filter(IQ_stanzas, function (iq) {
}).length > 0;
}, 300);
}).then(function () {
var stanza = _.find(IQ_stanzas, function (iq) {
return iq.nodeTree.querySelector('iq[to="localhost"] query[xmlns="http://jabber.org/protocol/disco#items"]'); return iq.nodeTree.querySelector('iq[to="localhost"] query[xmlns="http://jabber.org/protocol/disco#items"]');
}); }).length > 0;
var items_IQ_id = IQ_ids[IQ_stanzas.indexOf(stanza)]; }, 300);
stanza = $iq({
'type': 'result', stanza = _.find(IQ_stanzas, function (iq) {
'from': 'localhost', return iq.nodeTree.querySelector('iq[to="localhost"] query[xmlns="http://jabber.org/protocol/disco#items"]');
'to': 'dummy@localhost/resource', });
'id': items_IQ_id var items_IQ_id = IQ_ids[IQ_stanzas.indexOf(stanza)];
}).c('query', {'xmlns': 'http://jabber.org/protocol/disco#items'}) stanza = $iq({
.c('item', { 'type': 'result',
'jid': 'upload.localhost', 'from': 'localhost',
'name': 'HTTP File Upload'}); 'to': 'dummy@localhost/resource',
'id': items_IQ_id
_converse.connection._dataRecv(test_utils.createRequest(stanza)); }).c('query', {'xmlns': 'http://jabber.org/protocol/disco#items'})
.c('item', {
_converse.api.disco.entities.get().then(function (entities) { 'jid': 'upload.localhost',
expect(entities.length).toBe(2); 'name': 'HTTP File Upload'});
expect(entities.get('localhost').items.length).toBe(1);
return test_utils.waitUntil(function () { _converse.connection._dataRecv(test_utils.createRequest(stanza));
// Converse.js sees that the entity has a disco#info feature,
// so it will make a query for it. entities = await _converse.api.disco.entities.get()
return _.filter(IQ_stanzas, function (iq) {
return iq.nodeTree.querySelector('iq[to="upload.localhost"] query[xmlns="http://jabber.org/protocol/disco#info"]'); expect(entities.length).toBe(2);
}).length > 0; expect(entities.get('localhost').items.length).toBe(1);
}, 300); await test_utils.waitUntil(function () {
}); // Converse.js sees that the entity has a disco#info feature,
}).then(function () { // so it will make a query for it.
var stanza = _.find(IQ_stanzas, function (iq) { return _.filter(IQ_stanzas, function (iq) {
return iq.nodeTree.querySelector('iq[to="upload.localhost"] query[xmlns="http://jabber.org/protocol/disco#info"]'); return iq.nodeTree.querySelector('iq[to="upload.localhost"] query[xmlns="http://jabber.org/protocol/disco#info"]');
}); }).length > 0;
var IQ_id = IQ_ids[IQ_stanzas.indexOf(stanza)]; }, 300);
expect(stanza.toLocaleString()).toBe(
`<iq from="dummy@localhost/resource" id="${IQ_id}" to="upload.localhost" type="get" xmlns="jabber:client">`+
`<query xmlns="http://jabber.org/protocol/disco#info"/>`+
`</iq>`);
// Upload service responds and reports a maximum file size of 5MiB
stanza = $iq({'type': 'result', 'to': 'dummy@localhost/resource', 'id': IQ_id, 'from': 'upload.localhost'})
.c('query', {'xmlns': 'http://jabber.org/protocol/disco#info'})
.c('identity', {'category':'store', 'type':'file', 'name':'HTTP File Upload'}).up()
.c('feature', {'var':'urn:xmpp:http:upload:0'}).up()
.c('x', {'type':'result', 'xmlns':'jabber:x:data'})
.c('field', {'var':'FORM_TYPE', 'type':'hidden'})
.c('value').t('urn:xmpp:http:upload:0').up().up()
.c('field', {'var':'max-file-size'})
.c('value').t('5242880');
_converse.connection._dataRecv(test_utils.createRequest(stanza));
return _converse.api.disco.entities.get();
}).then(function (entities) {
expect(entities.get('localhost').items.get('upload.localhost').identities.where({'category': 'store'}).length).toBe(1);
return _converse.api.disco.supports(Strophe.NS.HTTPUPLOAD, _converse.domain);
}).then(function (result) {
test_utils.createContacts(_converse, 'current');
_converse.emit('rosterContactsFetched');
contact_jid = mock.cur_names[2].replace(/ /g,'.').toLowerCase() + '@localhost'; stanza = _.find(IQ_stanzas, function (iq) {
return test_utils.openChatBoxFor(_converse, contact_jid); return iq.nodeTree.querySelector('iq[to="upload.localhost"] query[xmlns="http://jabber.org/protocol/disco#info"]');
}).then(() => { });
view = _converse.chatboxviews.get(contact_jid); var IQ_id = IQ_ids[IQ_stanzas.indexOf(stanza)];
var file = { expect(stanza.toLocaleString()).toBe(
'type': 'image/jpeg', `<iq from="dummy@localhost/resource" id="${IQ_id}" to="upload.localhost" type="get" xmlns="jabber:client">`+
'size': '5242881', `<query xmlns="http://jabber.org/protocol/disco#info"/>`+
'lastModifiedDate': "", `</iq>`);
'name': "my-juliet.jpg"
}; // Upload service responds and reports a maximum file size of 5MiB
view.model.sendFiles([file]); stanza = $iq({'type': 'result', 'to': 'dummy@localhost/resource', 'id': IQ_id, 'from': 'upload.localhost'})
return test_utils.waitUntil(() => view.el.querySelectorAll('.message').length) .c('query', {'xmlns': 'http://jabber.org/protocol/disco#info'})
}).then(function () { .c('identity', {'category':'store', 'type':'file', 'name':'HTTP File Upload'}).up()
const messages = view.el.querySelectorAll('.message.chat-error'); .c('feature', {'var':'urn:xmpp:http:upload:0'}).up()
expect(messages.length).toBe(1); .c('x', {'type':'result', 'xmlns':'jabber:x:data'})
expect(messages[0].textContent).toBe( .c('field', {'var':'FORM_TYPE', 'type':'hidden'})
'The size of your file, my-juliet.jpg, exceeds the maximum allowed by your server, which is 5 MB.'); .c('value').t('urn:xmpp:http:upload:0').up().up()
done(); .c('field', {'var':'max-file-size'})
}).catch(_.partial(_converse.log, _, Strophe.LogLevel.FATAL)) .c('value').t('5242880');
_converse.connection._dataRecv(test_utils.createRequest(stanza));
entities = await _converse.api.disco.entities.get();
expect(entities.get('localhost').items.get('upload.localhost').identities.where({'category': 'store'}).length).toBe(1);
const result = await _converse.api.disco.supports(Strophe.NS.HTTPUPLOAD, _converse.domain);
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);
var file = {
'type': 'image/jpeg',
'size': '5242881',
'lastModifiedDate': "",
'name': "my-juliet.jpg"
};
view.model.sendFiles([file]);
await test_utils.waitUntil(() => view.el.querySelectorAll('.message').length)
const messages = view.el.querySelectorAll('.message.chat-error');
expect(messages.length).toBe(1);
expect(messages[0].textContent).toBe(
'The size of your file, my-juliet.jpg, exceeds the maximum allowed by your server, which is 5 MB.');
done();
})); }));
}); });
}); });
......
...@@ -159,47 +159,50 @@ ...@@ -159,47 +159,50 @@
it("is played when the current user is mentioned in a chat room", it("is played when the current user is mentioned in a chat room",
mock.initConverseWithPromises( mock.initConverseWithPromises(
null, ['rosterGroupsFetched'], {}, null, ['rosterGroupsFetched'], {},
function (done, _converse) { async function (done, _converse) {
test_utils.createContacts(_converse, 'current'); test_utils.createContacts(_converse, 'current');
test_utils.openAndEnterChatRoom(_converse, 'lounge', 'localhost', 'dummy').then(function () { await test_utils.openAndEnterChatRoom(_converse, 'lounge', 'localhost', 'dummy');
_converse.play_sounds = true; _converse.play_sounds = true;
spyOn(_converse, 'playSoundNotification'); spyOn(_converse, 'playSoundNotification');
var view = _converse.chatboxviews.get('lounge@localhost'); const view = _converse.chatboxviews.get('lounge@localhost');
if (!$(view.el).find('.chat-area').length) { view.renderChatArea(); } if (!view.el.querySelectorAll('.chat-area').length) {
var text = 'This message will play a sound because it mentions dummy'; view.renderChatArea();
var message = $msg({ }
from: 'lounge@localhost/otheruser', let text = 'This message will play a sound because it mentions dummy';
id: '1', let message = $msg({
to: 'dummy@localhost', from: 'lounge@localhost/otheruser',
type: 'groupchat' id: '1',
}).c('body').t(text); to: 'dummy@localhost',
view.model.onMessage(message.nodeTree); type: 'groupchat'
expect(_converse.playSoundNotification).toHaveBeenCalled(); }).c('body').t(text);
view.model.onMessage(message.nodeTree);
text = "This message won't play a sound";
message = $msg({ await test_utils.waitUntil(() => _converse.playSoundNotification.calls.count());
from: 'lounge@localhost/otheruser', expect(_converse.playSoundNotification).toHaveBeenCalled();
id: '2',
to: 'dummy@localhost', text = "This message won't play a sound";
type: 'groupchat' message = $msg({
}).c('body').t(text); from: 'lounge@localhost/otheruser',
view.model.onMessage(message.nodeTree); id: '2',
expect(_converse.playSoundNotification, 1); to: 'dummy@localhost',
_converse.play_sounds = false; type: 'groupchat'
}).c('body').t(text);
text = "This message won't play a sound because it is sent by dummy"; view.model.onMessage(message.nodeTree);
message = $msg({ expect(_converse.playSoundNotification, 1);
from: 'lounge@localhost/dummy', _converse.play_sounds = false;
id: '3',
to: 'dummy@localhost', text = "This message won't play a sound because it is sent by dummy";
type: 'groupchat' message = $msg({
}).c('body').t(text); from: 'lounge@localhost/dummy',
view.model.onMessage(message.nodeTree); id: '3',
expect(_converse.playSoundNotification, 1); to: 'dummy@localhost',
_converse.play_sounds = false; type: 'groupchat'
done(); }).c('body').t(text);
}); view.model.onMessage(message.nodeTree);
expect(_converse.playSoundNotification, 1);
_converse.play_sounds = false;
done();
})); }));
}); });
}); });
......
...@@ -10,28 +10,21 @@ ...@@ -10,28 +10,21 @@
const u = converse.env.utils; const u = converse.env.utils;
const checkHeaderToggling = function (group) { const checkHeaderToggling = async function (group) {
var $group = $(group);
var toggle = group.querySelector('a.group-toggle'); var toggle = group.querySelector('a.group-toggle');
expect(u.isVisible($group[0])).toBeTruthy(); expect(u.isVisible(group)).toBeTruthy();
expect($group.find('ul.collapsed').length).toBe(0); expect(group.querySelectorAll('ul.collapsed').length).toBe(0);
expect(u.hasClass('fa-caret-right', toggle.firstElementChild)).toBeFalsy(); expect(u.hasClass('fa-caret-right', toggle.firstElementChild)).toBeFalsy();
expect(u.hasClass('fa-caret-down', toggle.firstElementChild)).toBeTruthy(); expect(u.hasClass('fa-caret-down', toggle.firstElementChild)).toBeTruthy();
toggle.click(); toggle.click();
return test_utils.waitUntil(function () { await test_utils.waitUntil(() => group.querySelectorAll('ul.collapsed').length === 1);
return $group.find('ul.collapsed').length === 1; expect(u.hasClass('fa-caret-right', toggle.firstElementChild)).toBeTruthy();
}, 500).then(function () { expect(u.hasClass('fa-caret-down', toggle.firstElementChild)).toBeFalsy();
expect(u.hasClass('fa-caret-right', toggle.firstElementChild)).toBeTruthy(); toggle.click();
expect(u.hasClass('fa-caret-down', toggle.firstElementChild)).toBeFalsy(); await test_utils.waitUntil(() => group.querySelectorAll('li').length === $(group).find('li:visible').length);
toggle.click(); expect(u.hasClass('fa-caret-right', toggle.firstElementChild)).toBeFalsy();
return test_utils.waitUntil(function () { expect(u.hasClass('fa-caret-down', toggle.firstElementChild)).toBeTruthy();
return $group.find('li').length === $group.find('li:visible').length
}, 500);
}).then(function () {
expect(u.hasClass('fa-caret-right', toggle.firstElementChild)).toBeFalsy();
expect(u.hasClass('fa-caret-down', toggle.firstElementChild)).toBeTruthy();
});
}; };
...@@ -501,7 +494,7 @@ ...@@ -501,7 +494,7 @@
it("remembers whether it is closed or opened", it("remembers whether it is closed or opened",
mock.initConverseWithPromises( mock.initConverseWithPromises(
null, ['rosterGroupsFetched'], {}, null, ['rosterGroupsFetched'], {},
function (done, _converse) { async function (done, _converse) {
_converse.roster_groups = true; _converse.roster_groups = true;
test_utils.openControlBox(); test_utils.openControlBox();
...@@ -524,20 +517,14 @@ ...@@ -524,20 +517,14 @@
}); });
} }
}); });
var view = _converse.rosterview.get('colleagues'); const view = _converse.rosterview.get('colleagues');
var $toggle = $(view.el).find('a.group-toggle'); const toggle = view.el.querySelector('a.group-toggle');
expect(view.model.get('state')).toBe('opened'); expect(view.model.get('state')).toBe('opened');
$toggle[0].click(); toggle.click();
return test_utils.waitUntil(function () { await test_utils.waitUntil(() => view.model.get('state') === 'closed');
return view.model.get('state') === 'closed'; toggle.click();
}, 500).then(function () { await test_utils.waitUntil(() => view.model.get('state') === 'opened');
$toggle[0].click(); done();
return test_utils.waitUntil(function () {
return view.model.get('state') === 'opened';
}, 500)
}).then(function () {
done();
});
})); }));
}); });
......
...@@ -105,6 +105,7 @@ ...@@ -105,6 +105,7 @@
spyOn(view, 'onMessageSubmitted').and.callThrough(); spyOn(view, 'onMessageSubmitted').and.callThrough();
spyOn(_converse.connection, 'send'); spyOn(_converse.connection, 'send');
await test_utils.waitUntil(() => view.el.querySelector('.toggle-compose-spoiler'));
let spoiler_toggle = view.el.querySelector('.toggle-compose-spoiler'); let spoiler_toggle = view.el.querySelector('.toggle-compose-spoiler');
spoiler_toggle.click(); spoiler_toggle.click();
...@@ -178,6 +179,8 @@ ...@@ -178,6 +179,8 @@
await test_utils.openChatBoxFor(_converse, contact_jid); await test_utils.openChatBoxFor(_converse, contact_jid);
await test_utils.waitUntilDiscoConfirmed(_converse, contact_jid+'/phone', [], [Strophe.NS.SPOILER]); await test_utils.waitUntilDiscoConfirmed(_converse, contact_jid+'/phone', [], [Strophe.NS.SPOILER]);
const view = _converse.chatboxviews.get(contact_jid); const view = _converse.chatboxviews.get(contact_jid);
await test_utils.waitUntil(() => view.el.querySelector('.toggle-compose-spoiler'));
let spoiler_toggle = view.el.querySelector('.toggle-compose-spoiler'); let spoiler_toggle = view.el.querySelector('.toggle-compose-spoiler');
spoiler_toggle.click(); spoiler_toggle.click();
......
...@@ -179,7 +179,6 @@ require.config(config); ...@@ -179,7 +179,6 @@ require.config(config);
var specs = [ var specs = [
"jasmine", "jasmine",
//"spec/transcripts", //"spec/transcripts",
//"spec/otr",
"spec/spoilers", "spec/spoilers",
"spec/profiling", "spec/profiling",
"spec/utils", "spec/utils",
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment