3b29e5754d
If we've fetched the roster before within this session, then we don't have to do so again, regardless of whether versioning is supported or not, otherwise, even if we have a cached roster, we still need to get the latest one again.
368 lines
18 KiB
JavaScript
368 lines
18 KiB
JavaScript
(function (root, factory) {
|
|
define([
|
|
"jasmine",
|
|
"mock",
|
|
"test-utils"], factory);
|
|
} (this, function (jasmine, mock, test_utils) {
|
|
const b64_sha1 = converse.env.b64_sha1,
|
|
_ = converse.env._,
|
|
u = converse.env.utils;
|
|
|
|
describe("Converse", function() {
|
|
|
|
describe("Authentication", function () {
|
|
|
|
it("needs either a bosh_service_url a websocket_url or both", mock.initConverse(async (done, _converse) => {
|
|
const url = _converse.bosh_service_url;
|
|
const connection = _converse.connection;
|
|
delete _converse.bosh_service_url;
|
|
delete _converse.connection;
|
|
try {
|
|
await _converse.initConnection();
|
|
} catch (e) {
|
|
_converse.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();
|
|
}
|
|
}));
|
|
});
|
|
|
|
describe("A chat state indication", function () {
|
|
|
|
it("are sent out when the client becomes or stops being idle",
|
|
mock.initConverse(null, ['discoInitialized'], {}, (done, _converse) => {
|
|
|
|
spyOn(_converse, 'sendCSI').and.callThrough();
|
|
let sent_stanza;
|
|
spyOn(_converse.connection, 'send').and.callFake(function (stanza) {
|
|
sent_stanza = stanza;
|
|
});
|
|
let i = 0;
|
|
_converse.idle_seconds = 0; // Usually initialized by registerIntervalHandler
|
|
_converse.disco_entities.get(_converse.domain).features['urn:xmpp:csi:0'] = true; // Mock that the server supports CSI
|
|
|
|
_converse.csi_waiting_time = 3; // The relevant config option
|
|
while (i <= _converse.csi_waiting_time) {
|
|
expect(_converse.sendCSI).not.toHaveBeenCalled();
|
|
_converse.onEverySecond();
|
|
i++;
|
|
}
|
|
expect(_converse.sendCSI).toHaveBeenCalledWith('inactive');
|
|
expect(sent_stanza.toLocaleString()).toBe('<inactive xmlns="urn:xmpp:csi:0"/>');
|
|
_converse.onUserActivity();
|
|
expect(_converse.sendCSI).toHaveBeenCalledWith('active');
|
|
expect(sent_stanza.toLocaleString()).toBe('<active xmlns="urn:xmpp:csi:0"/>');
|
|
// Reset values
|
|
_converse.csi_waiting_time = 0;
|
|
_converse.disco_entities.get(_converse.domain).features['urn:xmpp:csi:0'] = false;
|
|
done();
|
|
}));
|
|
});
|
|
|
|
describe("Automatic status change", function () {
|
|
|
|
it("happens when the client is idle for long enough", mock.initConverse((done, _converse) => {
|
|
let i = 0;
|
|
// Usually initialized by registerIntervalHandler
|
|
_converse.idle_seconds = 0;
|
|
_converse.auto_changed_status = false;
|
|
|
|
// The relevant config options
|
|
_converse.auto_away = 3;
|
|
_converse.auto_xa = 6;
|
|
|
|
expect(_converse.api.user.status.get()).toBe('online');
|
|
while (i <= _converse.auto_away) {
|
|
_converse.onEverySecond(); i++;
|
|
}
|
|
expect(_converse.auto_changed_status).toBe(true);
|
|
|
|
while (i <= _converse.auto_xa) {
|
|
expect(_converse.api.user.status.get()).toBe('away');
|
|
_converse.onEverySecond();
|
|
i++;
|
|
}
|
|
expect(_converse.api.user.status.get()).toBe('xa');
|
|
expect(_converse.auto_changed_status).toBe(true);
|
|
|
|
_converse.onUserActivity();
|
|
expect(_converse.api.user.status.get()).toBe('online');
|
|
expect(_converse.auto_changed_status).toBe(false);
|
|
|
|
// Check that it also works for the chat feature
|
|
_converse.api.user.status.set('chat')
|
|
i = 0;
|
|
while (i <= _converse.auto_away) {
|
|
_converse.onEverySecond();
|
|
i++;
|
|
}
|
|
expect(_converse.auto_changed_status).toBe(true);
|
|
while (i <= _converse.auto_xa) {
|
|
expect(_converse.api.user.status.get()).toBe('away');
|
|
_converse.onEverySecond();
|
|
i++;
|
|
}
|
|
expect(_converse.api.user.status.get()).toBe('xa');
|
|
expect(_converse.auto_changed_status).toBe(true);
|
|
|
|
_converse.onUserActivity();
|
|
expect(_converse.api.user.status.get()).toBe('online');
|
|
expect(_converse.auto_changed_status).toBe(false);
|
|
|
|
// Check that it doesn't work for 'dnd'
|
|
_converse.api.user.status.set('dnd');
|
|
i = 0;
|
|
while (i <= _converse.auto_away) {
|
|
_converse.onEverySecond();
|
|
i++;
|
|
}
|
|
expect(_converse.api.user.status.get()).toBe('dnd');
|
|
expect(_converse.auto_changed_status).toBe(false);
|
|
while (i <= _converse.auto_xa) {
|
|
expect(_converse.api.user.status.get()).toBe('dnd');
|
|
_converse.onEverySecond();
|
|
i++;
|
|
}
|
|
expect(_converse.api.user.status.get()).toBe('dnd');
|
|
expect(_converse.auto_changed_status).toBe(false);
|
|
|
|
_converse.onUserActivity();
|
|
expect(_converse.api.user.status.get()).toBe('dnd');
|
|
expect(_converse.auto_changed_status).toBe(false);
|
|
done();
|
|
}));
|
|
});
|
|
|
|
describe("The \"user\" grouping", function () {
|
|
|
|
describe("The \"status\" API", function () {
|
|
|
|
it("has a method for getting the user's availability", mock.initConverse((done, _converse) => {
|
|
_converse.xmppstatus.set('status', 'online');
|
|
expect(_converse.api.user.status.get()).toBe('online');
|
|
_converse.xmppstatus.set('status', 'dnd');
|
|
expect(_converse.api.user.status.get()).toBe('dnd');
|
|
done();
|
|
}));
|
|
|
|
it("has a method for setting the user's availability", mock.initConverse((done, _converse) => {
|
|
_converse.api.user.status.set('away');
|
|
expect(_converse.xmppstatus.get('status')).toBe('away');
|
|
_converse.api.user.status.set('dnd');
|
|
expect(_converse.xmppstatus.get('status')).toBe('dnd');
|
|
_converse.api.user.status.set('xa');
|
|
expect(_converse.xmppstatus.get('status')).toBe('xa');
|
|
_converse.api.user.status.set('chat');
|
|
expect(_converse.xmppstatus.get('status')).toBe('chat');
|
|
expect(_.partial(_converse.api.user.status.set, 'invalid')).toThrow(
|
|
new Error('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((done, _converse) => {
|
|
_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((done, _converse) => {
|
|
_converse.xmppstatus.set('status_message', undefined);
|
|
expect(_converse.api.user.status.message.get()).toBe(undefined);
|
|
_converse.xmppstatus.set('status_message', "I'm in a meeting");
|
|
expect(_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((done, _converse) => {
|
|
_converse.xmppstatus.set('status_message', undefined);
|
|
_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) => {
|
|
test_utils.createContacts(_converse, 'current');
|
|
const old_connection = _converse.connection;
|
|
_converse.connection._proto.rid = '1234';
|
|
expect(_converse.api.tokens.get('rid')).toBe('1234');
|
|
_converse.connection = undefined;
|
|
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) => {
|
|
test_utils.createContacts(_converse, 'current');
|
|
const old_connection = _converse.connection;
|
|
_converse.connection._proto.sid = '1234';
|
|
expect(_converse.api.tokens.get('sid')).toBe('1234');
|
|
_converse.connection = undefined;
|
|
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 (done, _converse) => {
|
|
// Check that it returns nothing if a non-existing JID is given
|
|
test_utils.createContacts(_converse, 'current');
|
|
// Hack to avoid having to fetch the roster again.
|
|
_converse.session.set('roster_fetched', true);
|
|
|
|
let contact = await _converse.api.contacts.get('non-existing@jabber.org');
|
|
expect(contact).toBeFalsy();
|
|
// Check when a single jid is given
|
|
const jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit';
|
|
contact = await _converse.api.contacts.get(jid);
|
|
expect(contact.getDisplayName()).toBe(mock.cur_names[0]);
|
|
expect(contact.get('jid')).toBe(jid);
|
|
// You can retrieve multiple contacts by passing in an array
|
|
const jid2 = mock.cur_names[1].replace(/ /g,'.').toLowerCase() + '@montague.lit';
|
|
let list = await _converse.api.contacts.get([jid, jid2]);
|
|
expect(Array.isArray(list)).toBeTruthy();
|
|
expect(list[0].getDisplayName()).toBe(mock.cur_names[0]);
|
|
expect(list[1].getDisplayName()).toBe(mock.cur_names[1]);
|
|
// 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((done, _converse) => {
|
|
test_utils.createContacts(_converse, 'current');
|
|
const error = new TypeError('contacts.add: invalid jid');
|
|
expect(_converse.api.contacts.add).toThrow(error);
|
|
expect(_converse.api.contacts.add.bind(_converse.api, "invalid jid")).toThrow(error);
|
|
spyOn(_converse.roster, 'addAndSubscribe');
|
|
_converse.api.contacts.add("newcontact@example.org");
|
|
expect(_converse.roster.addAndSubscribe).toHaveBeenCalled();
|
|
done();
|
|
}));
|
|
});
|
|
|
|
describe("The \"chats\" API", function() {
|
|
|
|
it("has a method 'get' which returns the promise that resolves to a chat model", mock.initConverse(
|
|
null, ['rosterInitialized', 'chatBoxesInitialized'], {},
|
|
async (done, _converse) => {
|
|
|
|
test_utils.openControlBox();
|
|
test_utils.createContacts(_converse, 'current', 2);
|
|
_converse.api.trigger('rosterContactsFetched');
|
|
|
|
// Test on chat that doesn't exist.
|
|
expect(_converse.api.chats.get('non-existing@jabber.org')).toBeFalsy();
|
|
const jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit';
|
|
const jid2 = mock.cur_names[1].replace(/ /g,'.').toLowerCase() + '@montague.lit';
|
|
|
|
// Test on chat that's not open
|
|
let box = _converse.api.chats.get(jid);
|
|
expect(typeof box === 'undefined').toBeTruthy();
|
|
expect(_converse.chatboxes.length).toBe(1);
|
|
|
|
// Test for one JID
|
|
box = await _converse.api.chats.open(jid);
|
|
expect(box instanceof Object).toBeTruthy();
|
|
expect(box.get('box_id')).toBe(`box-${btoa(jid)}`);
|
|
|
|
const view = _converse.chatboxviews.get(jid);
|
|
await u.waitUntil(() => u.isVisible(view.el));
|
|
// Test for multiple JIDs
|
|
test_utils.openChatBoxFor(_converse, jid2);
|
|
await u.waitUntil(() => _converse.chatboxes.length == 2);
|
|
const list = _converse.api.chats.get([jid, jid2]);
|
|
expect(Array.isArray(list)).toBeTruthy();
|
|
expect(list[0].get('box_id')).toBe(`box-${btoa(jid)}`);
|
|
expect(list[1].get('box_id')).toBe(`box-${btoa(jid2)}`);
|
|
done();
|
|
}));
|
|
|
|
it("has a method 'open' which opens and returns a promise that resolves to a chat model", mock.initConverse(
|
|
null, ['rosterGroupsFetched', 'chatBoxesInitialized'], {},
|
|
async (done, _converse) => {
|
|
|
|
test_utils.openControlBox();
|
|
test_utils.createContacts(_converse, 'current', 2);
|
|
_converse.api.trigger('rosterContactsFetched');
|
|
|
|
const jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit';
|
|
const jid2 = mock.cur_names[1].replace(/ /g,'.').toLowerCase() + '@montague.lit';
|
|
// Test on chat that doesn't exist.
|
|
expect(_converse.api.chats.get('non-existing@jabber.org')).toBeFalsy();
|
|
|
|
const box = await _converse.api.chats.open(jid);
|
|
expect(box instanceof Object).toBeTruthy();
|
|
expect(box.get('box_id')).toBe(`box-${btoa(jid)}`);
|
|
expect(
|
|
_.keys(box),
|
|
['close', 'endOTR', 'focus', 'get', 'initiateOTR', 'is_chatroom', 'maximize', 'minimize', 'open', 'set']
|
|
);
|
|
const view = _converse.chatboxviews.get(jid);
|
|
await u.waitUntil(() => u.isVisible(view.el));
|
|
// Test for multiple JIDs
|
|
const list = await _converse.api.chats.open([jid, jid2]);
|
|
expect(Array.isArray(list)).toBeTruthy();
|
|
expect(list[0].get('box_id')).toBe(`box-${btoa(jid)}`);
|
|
expect(list[1].get('box_id')).toBe(`box-${btoa(jid2)}`);
|
|
done();
|
|
}));
|
|
});
|
|
|
|
describe("The \"settings\" API", function() {
|
|
it("has methods 'get' and 'set' to set configuration settings", mock.initConverse(
|
|
null, null, {'play_sounds': true},
|
|
(done, _converse) => {
|
|
|
|
expect(_.keys(_converse.api.settings)).toEqual(["update", "get", "set"]);
|
|
expect(_converse.api.settings.get("play_sounds")).toBe(true);
|
|
_converse.api.settings.set("play_sounds", false);
|
|
expect(_converse.api.settings.get("play_sounds")).toBe(false);
|
|
_converse.api.settings.set({"play_sounds": true});
|
|
expect(_converse.api.settings.get("play_sounds")).toBe(true);
|
|
// Only whitelisted settings allowed.
|
|
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();
|
|
}));
|
|
});
|
|
|
|
describe("The \"plugins\" API", function() {
|
|
it("only has a method 'add' for registering plugins", mock.initConverse((done, _converse) => {
|
|
expect(_.keys(converse.plugins)).toEqual(["add"]);
|
|
// Cheating a little bit. We clear the plugins to test more easily.
|
|
const _old_plugins = _converse.pluggable.plugins;
|
|
_converse.pluggable.plugins = [];
|
|
converse.plugins.add('plugin1', {});
|
|
expect(_.keys(_converse.pluggable.plugins)).toEqual(['plugin1']);
|
|
converse.plugins.add('plugin2', {});
|
|
expect(_.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) => {
|
|
|
|
converse.plugins.add('myplugin', {});
|
|
const error = new TypeError('Error: plugin with name "myplugin" has already been registered!');
|
|
expect(_.partial(converse.plugins.add, 'myplugin', {})).toThrow(error);
|
|
done();
|
|
}));
|
|
});
|
|
});
|
|
});
|
|
}));
|