Stop using the Jasmine "done" callback

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

File diff suppressed because it is too large Load Diff

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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