Use Karma as test runner

This commit is contained in:
JC Brand 2020-04-22 13:11:48 +02:00
parent 7e23adf26f
commit 4b270359f6
47 changed files with 21654 additions and 21267 deletions

View File

@ -1,4 +1,4 @@
dist: xenial
dist: bionic
language: node_js
cache:
directories:
@ -6,7 +6,11 @@ cache:
addons:
chrome: stable
node_js:
- "10"
- "14"
install: make node_modules
before_script: make serve_bg
script: make check
services:
- xvfb
before_script:
- make serve_bg
- export DISPLAY=:99.0
script: make check ARGS=--single-run

View File

@ -2,6 +2,7 @@
BABEL ?= node_modules/.bin/babel
BOOTSTRAP = ./node_modules/
BUILDDIR = ./docs
KARMA ?= ./node_modules/.bin/karma
CHROMIUM ?= ./node_modules/.bin/run-headless-chromium
CLEANCSS ?= ./node_modules/clean-css-cli/bin/cleancss --skip-rebase
ESLINT ?= ./node_modules/.bin/eslint
@ -197,7 +198,11 @@ eslint: node_modules
.PHONY: check
check: eslint dev
LOG_CR_VERBOSITY=INFO $(CHROMIUM) --disable-gpu --no-sandbox http://localhost:$(HTTPSERVE_PORT)/tests/index.html
$(KARMA) start karma.conf.js $(ARGS)
.PHONY: test
test:
$(KARMA) start karma.conf.js $(ARGS)
########################################################################
## Documentation

107
karma.conf.js Normal file
View File

@ -0,0 +1,107 @@
/* global module */
const path = require('path');
module.exports = function(config) {
config.set({
// base path that will be used to resolve all patterns (eg. files, exclude)
basePath: '',
frameworks: ['jasmine'],
files: [
{ pattern: 'dist/*.js.map', included: false },
{ pattern: 'dist/*.css.map', included: false },
{ pattern: "dist/emojis.js", served: true },
"dist/converse.js",
"dist/converse.css",
{ pattern: "dist/webfonts/**/*.*", included: false },
{ pattern: "node_modules/sinon/pkg/sinon.js", type: 'module' },
{ pattern: "tests/console-reporter.js", type: 'module' },
{ pattern: "tests/mock.js", type: 'module' },
{ pattern: "spec/spoilers.js", type: 'module' },
{ pattern: "spec/roomslist.js", type: 'module' },
{ pattern: "spec/utils.js", type: 'module' },
{ pattern: "spec/converse.js", type: 'module' },
{ pattern: "spec/bookmarks.js", type: 'module' },
{ pattern: "spec/headline.js", type: 'module' },
{ pattern: "spec/disco.js", type: 'module' },
{ pattern: "spec/protocol.js", type: 'module' },
{ pattern: "spec/presence.js", type: 'module' },
{ pattern: "spec/eventemitter.js", type: 'module' },
{ pattern: "spec/smacks.js", type: 'module' },
{ pattern: "spec/ping.js", type: 'module' },
{ pattern: "spec/push.js", type: 'module' },
{ pattern: "spec/xmppstatus.js", type: 'module' },
{ pattern: "spec/mam.js", type: 'module' },
{ pattern: "spec/omemo.js", type: 'module' },
{ pattern: "spec/controlbox.js", type: 'module' },
{ pattern: "spec/roster.js", type: 'module' },
{ pattern: "spec/chatbox.js", type: 'module' },
{ pattern: "spec/user-details-modal.js", type: 'module' },
{ pattern: "spec/messages.js", type: 'module' },
{ pattern: "spec/muc_messages.js", type: 'module' },
{ pattern: "spec/retractions.js", type: 'module' },
{ pattern: "spec/muc.js", type: 'module' },
{ pattern: "spec/modtools.js", type: 'module' },
{ pattern: "spec/room_registration.js", type: 'module' },
{ pattern: "spec/autocomplete.js", type: 'module' },
{ pattern: "spec/minchats.js", type: 'module' },
{ pattern: "spec/notification.js", type: 'module' },
{ pattern: "spec/login.js", type: 'module' },
{ pattern: "spec/register.js", type: 'module' },
{ pattern: "spec/hats.js", type: 'module' },
{ pattern: "spec/http-file-upload.js", type: 'module' },
{ pattern: "spec/emojis.js", type: 'module' },
{ pattern: "spec/xss.js", type: 'module' },
],
exclude: ['**/*.sw?'],
// preprocess matching files before serving them to the browser
// available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor
preprocessors: {},
// test results reporter to use
// possible values: 'dots', 'progress'
// available reporters: https://npmjs.org/browse/keyword/karma-reporter
reporters: ['progress', 'kjhtml'],
webpack: {
mode: 'development',
devtool: 'inline-source-map',
module: {
rules: [{
test: /\.js$/,
exclude: /(node_modules|test)/
}]
},
output: {
path: path.resolve('test'),
filename: '[name].out.js',
chunkFilename: '[id].[chunkHash].js'
}
},
port: 9876,
colors: true,
// level of logging
// possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG
logLevel: config.LOG_INFO,
// enable / disable watching file and executing tests whenever any file changes
autoWatch: true,
// start these browsers
// available browser launchers: https://npmjs.org/browse/keyword/karma-launcher
browsers: ['Chrome'],
// Continuous Integration mode
// if true, Karma captures browsers, runs the tests and exits
singleRun: false,
// Concurrency level
// how many browser should be started simultaneous
concurrency: Infinity
})
}

901
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -84,8 +84,14 @@
"http-server": "^0.12.1",
"imports-loader": "^0.8.0",
"install": "^0.13.0",
"jasmine-core": "2.99.1",
"jasmine": "^3.5.0",
"jsdoc": "^3.6.4",
"karma": "^5.0.2",
"karma-chrome-launcher": "^3.1.0",
"karma-cli": "^2.0.0",
"karma-jasmine": "^3.1.1",
"karma-jasmine-html-reporter": "^1.5.3",
"karma-webpack": "^4.0.2",
"lerna": "^3.20.2",
"lit-html": "^1.2.1",
"lodash-template-webpack-loader": "jcbrand/lodash-template-webpack-loader",

View File

@ -1,24 +1,23 @@
window.addEventListener('converse-loaded', () => {
const mock = window.mock;
const test_utils = window.test_utils;
const $pres = converse.env.$pres;
const $msg = converse.env.$msg;
const Strophe = converse.env.Strophe;
const u = converse.env.utils;
/*global mock */
describe("The nickname autocomplete feature", function () {
const $pres = converse.env.$pres;
const $msg = converse.env.$msg;
const Strophe = converse.env.Strophe;
const u = converse.env.utils;
describe("The nickname autocomplete feature", function () {
it("shows all autocompletion options when the user presses @",
mock.initConverse(
['rosterGroupsFetched', 'chatBoxesFetched'], {},
async function (done, _converse) {
await test_utils.openAndEnterChatRoom(_converse, 'lounge@montague.lit', 'tom');
await mock.openAndEnterChatRoom(_converse, 'lounge@montague.lit', 'tom');
const view = _converse.chatboxviews.get('lounge@montague.lit');
// Nicknames from presences
['dick', 'harry'].forEach((nick) => {
_converse.connection._dataRecv(test_utils.createRequest(
_converse.connection._dataRecv(mock.createRequest(
$pres({
'to': 'tom@montague.lit/resource',
'from': `lounge@montague.lit/${nick}`
@ -66,7 +65,7 @@ window.addEventListener('converse-loaded', () => {
['rosterGroupsFetched', 'chatBoxesFetched'], {},
async function (done, _converse) {
await test_utils.openAndEnterChatRoom(_converse, 'lounge@montague.lit', 'romeo');
await mock.openAndEnterChatRoom(_converse, 'lounge@montague.lit', 'romeo');
const view = _converse.chatboxviews.get('lounge@montague.lit');
expect(view.model.occupants.length).toBe(1);
let presence = $pres({
@ -79,7 +78,7 @@ window.addEventListener('converse-loaded', () => {
'jid': 'some1@montague.lit/resource',
'role': 'participant'
});
_converse.connection._dataRecv(test_utils.createRequest(presence));
_converse.connection._dataRecv(mock.createRequest(presence));
expect(view.model.occupants.length).toBe(2);
const textarea = view.el.querySelector('textarea.chat-textarea');
@ -122,7 +121,7 @@ window.addEventListener('converse-loaded', () => {
'jid': 'some2@montague.lit/resource',
'role': 'participant'
});
_converse.connection._dataRecv(test_utils.createRequest(presence));
_converse.connection._dataRecv(mock.createRequest(presence));
textarea.value = "hello s s";
view.onKeyDown(tab_event);
@ -161,7 +160,7 @@ window.addEventListener('converse-loaded', () => {
'jid': 'z3r0@montague.lit/resource',
'role': 'participant'
});
_converse.connection._dataRecv(test_utils.createRequest(presence));
_converse.connection._dataRecv(mock.createRequest(presence));
textarea.value = "hello z";
view.onKeyDown(tab_event);
view.onKeyUp(tab_event);
@ -178,7 +177,7 @@ window.addEventListener('converse-loaded', () => {
['rosterGroupsFetched'], {},
async function (done, _converse) {
await test_utils.openAndEnterChatRoom(_converse, 'lounge@montague.lit', 'romeo');
await mock.openAndEnterChatRoom(_converse, 'lounge@montague.lit', 'romeo');
const view = _converse.chatboxviews.get('lounge@montague.lit');
expect(view.model.occupants.length).toBe(1);
const presence = $pres({
@ -191,7 +190,7 @@ window.addEventListener('converse-loaded', () => {
'jid': 'some1@montague.lit/resource',
'role': 'participant'
});
_converse.connection._dataRecv(test_utils.createRequest(presence));
_converse.connection._dataRecv(mock.createRequest(presence));
expect(view.model.occupants.length).toBe(2);
const textarea = view.el.querySelector('textarea.chat-textarea');
@ -213,5 +212,4 @@ window.addEventListener('converse-loaded', () => {
expect(view.el.querySelector('.suggestion-box__results li').textContent).toBe('some1');
done();
}));
});
});

View File

@ -1,23 +1,15 @@
window.addEventListener('converse-loaded', () => {
const mock = window.mock;
const test_utils = window.test_utils;
const $iq = converse.env.$iq,
$msg = converse.env.$msg,
Strophe = converse.env.Strophe,
sizzle = converse.env.sizzle,
_ = converse.env._,
u = converse.env.utils;
/* global mock */
describe("A chat room", function () {
describe("A chat room", function () {
it("can be bookmarked", mock.initConverse(['rosterGroupsFetched'], {}, async function (done, _converse) {
await test_utils.waitUntilDiscoConfirmed(
await mock.waitUntilDiscoConfirmed(
_converse, _converse.bare_jid,
[{'category': 'pubsub', 'type': 'pep'}],
['http://jabber.org/protocol/pubsub#publish-options']
);
const { u, $iq } = converse.env;
let sent_stanza, IQ_id;
const sendIQ = _converse.connection.sendIQ;
spyOn(_converse.connection, 'sendIQ').and.callFake(function (iq, callback, errback) {
@ -26,7 +18,7 @@ window.addEventListener('converse-loaded', () => {
});
spyOn(_converse.connection, 'getUniqueId').and.callThrough();
await test_utils.openChatRoom(_converse, 'theplay', 'conference.shakespeare.lit', 'JC');
await mock.openChatRoom(_converse, 'theplay', 'conference.shakespeare.lit', 'JC');
var jid = 'theplay@conference.shakespeare.lit';
const view = _converse.chatboxviews.get(jid);
spyOn(view, 'renderBookmarkForm').and.callThrough();
@ -123,7 +115,7 @@ window.addEventListener('converse-loaded', () => {
'type':'result',
'id':IQ_id
});
_converse.connection._dataRecv(test_utils.createRequest(stanza));
_converse.connection._dataRecv(mock.createRequest(stanza));
await u.waitUntil(() => view.model.get('bookmarked'));
expect(view.model.get('bookmarked')).toBeTruthy();
await u.waitUntil(() => view.el.querySelector('.toggle-bookmark')?.title === 'Unbookmark this groupchat');
@ -138,7 +130,8 @@ window.addEventListener('converse-loaded', () => {
['rosterGroupsFetched'], {},
async function (done, _converse) {
await test_utils.waitUntilDiscoConfirmed(
const { u, _ } = converse.env;
await mock.waitUntilDiscoConfirmed(
_converse, _converse.bare_jid,
[{'category': 'pubsub', 'type': 'pep'}],
['http://jabber.org/protocol/pubsub#publish-options']
@ -182,7 +175,8 @@ window.addEventListener('converse-loaded', () => {
it("will use the nickname from the bookmark", mock.initConverse(
['rosterGroupsFetched'], {}, async function (done, _converse) {
await test_utils.waitUntilBookmarksReturned(_converse);
const { u } = converse.env;
await mock.waitUntilBookmarksReturned(_converse);
const muc_jid = 'coven@chat.shakespeare.lit';
_converse.bookmarks.create({
'jid': muc_jid,
@ -192,7 +186,7 @@ window.addEventListener('converse-loaded', () => {
});
spyOn(_converse.ChatRoom.prototype, 'getAndPersistNickname').and.callThrough();
const room_creation_promise = _converse.api.rooms.open(muc_jid);
await test_utils.getRoomFeatures(_converse, muc_jid);
await mock.getRoomFeatures(_converse, muc_jid);
const room = await room_creation_promise;
await u.waitUntil(() => room.getAndPersistNickname.calls.count());
expect(room.get('nick')).toBe('Othello');
@ -203,7 +197,8 @@ window.addEventListener('converse-loaded', () => {
['rosterGroupsFetched'], {},
async function (done, _converse) {
test_utils.waitUntilDiscoConfirmed(
const { u } = converse.env;
mock.waitUntilDiscoConfirmed(
_converse, _converse.bare_jid,
[{'category': 'pubsub', 'type': 'pep'}],
['http://jabber.org/protocol/pubsub#publish-options']
@ -227,7 +222,8 @@ window.addEventListener('converse-loaded', () => {
it("can be unbookmarked", mock.initConverse(
['rosterGroupsFetched'], {}, async function (done, _converse) {
await test_utils.waitUntilBookmarksReturned(_converse);
const { u, Strophe } = converse.env;
await mock.waitUntilBookmarksReturned(_converse);
const muc_jid = 'theplay@conference.shakespeare.lit';
await _converse.api.rooms.open(muc_jid);
const view = _converse.chatboxviews.get(muc_jid);
@ -293,7 +289,7 @@ window.addEventListener('converse-loaded', () => {
['rosterGroupsFetched'], {},
async function (done, _converse) {
await test_utils.waitUntilBookmarksReturned(_converse);
await mock.waitUntilBookmarksReturned(_converse);
spyOn(_converse.api.rooms, 'create').and.callThrough();
const jid = 'theplay@conference.shakespeare.lit';
const model = _converse.bookmarks.create({
@ -314,14 +310,15 @@ window.addEventListener('converse-loaded', () => {
done();
}));
});
});
});
describe("Bookmarks", function () {
describe("Bookmarks", function () {
it("can be pushed from the XMPP server", mock.initConverse(
['rosterGroupsFetched', 'connected'], {}, async function (done, _converse) {
await test_utils.waitUntilBookmarksReturned(_converse);
const { $msg, u } = converse.env;
await mock.waitUntilBookmarksReturned(_converse);
/* The stored data is automatically pushed to all of the user's
* connected resources.
@ -360,7 +357,7 @@ window.addEventListener('converse-loaded', () => {
'autojoin': 'true',
'jid':'theplay@conference.shakespeare.lit'})
.c('nick').t('JC');
_converse.connection._dataRecv(test_utils.createRequest(stanza));
_converse.connection._dataRecv(mock.createRequest(stanza));
await u.waitUntil(() => _converse.bookmarks.length);
expect(_converse.bookmarks.length).toBe(1);
expect(_converse.chatboxviews.get('theplay@conference.shakespeare.lit')).not.toBeUndefined();
@ -372,7 +369,8 @@ window.addEventListener('converse-loaded', () => {
['chatBoxesFetched', 'roomsPanelRendered', 'rosterGroupsFetched'], {},
async function (done, _converse) {
await test_utils.waitUntilDiscoConfirmed(
const { Strophe, sizzle, u, $iq } = converse.env;
await mock.waitUntilDiscoConfirmed(
_converse, _converse.bare_jid,
[{'category': 'pubsub', 'type': 'pep'}],
['http://jabber.org/protocol/pubsub#publish-options']
@ -436,7 +434,7 @@ window.addEventListener('converse-loaded', () => {
'autojoin': 'false',
'jid': 'another@conference.shakespeare.lit'
}); // Purposefully exclude the <nick> element to test #1043
_converse.connection._dataRecv(test_utils.createRequest(stanza));
_converse.connection._dataRecv(mock.createRequest(stanza));
await u.waitUntil(() => _converse.bookmarks.onBookmarksReceived.calls.count());
await _converse.api.waitUntil('bookmarksInitialized');
expect(_converse.bookmarks.models.length).toBe(2);
@ -451,13 +449,14 @@ window.addEventListener('converse-loaded', () => {
['rosterGroupsFetched'], {},
async function (done, _converse) {
await test_utils.waitUntilDiscoConfirmed(
await mock.waitUntilDiscoConfirmed(
_converse, _converse.bare_jid,
[{'category': 'pubsub', 'type': 'pep'}],
['http://jabber.org/protocol/pubsub#publish-options']
);
test_utils.openControlBox(_converse);
mock.openControlBox(_converse);
const { Strophe, u, sizzle, $iq } = converse.env;
const IQ_stanzas = _converse.connection.IQ_stanzas;
const sent_stanza = await u.waitUntil(
() => IQ_stanzas.filter(s => sizzle('items[node="storage:bookmarks"]', s).length).pop());
@ -499,7 +498,7 @@ window.addEventListener('converse-loaded', () => {
'autojoin': 'false',
'jid': 'another@conference.shakespeare.lit'
}).c('nick').t('JC').up().up();
_converse.connection._dataRecv(test_utils.createRequest(stanza));
_converse.connection._dataRecv(mock.createRequest(stanza));
await u.waitUntil(() => document.querySelectorAll('#chatrooms div.bookmarks.rooms-list .room-item').length);
expect(document.querySelectorAll('#chatrooms div.bookmarks.rooms-list .room-item').length).toBe(5);
@ -526,13 +525,14 @@ window.addEventListener('converse-loaded', () => {
it("remembers the toggle state of the bookmarks list", mock.initConverse(
['rosterGroupsFetched'], {}, async function (done, _converse) {
await test_utils.openControlBox(_converse);
await test_utils.waitUntilDiscoConfirmed(
await mock.openControlBox(_converse);
await mock.waitUntilDiscoConfirmed(
_converse, _converse.bare_jid,
[{'category': 'pubsub', 'type': 'pep'}],
['http://jabber.org/protocol/pubsub#publish-options']
);
const { Strophe, u, sizzle, $iq } = converse.env;
const IQ_stanzas = _converse.connection.IQ_stanzas;
const sent_stanza = await u.waitUntil(
() => IQ_stanzas.filter(s => sizzle('iq items[node="storage:bookmarks"]', s).length).pop());
@ -549,7 +549,7 @@ window.addEventListener('converse-loaded', () => {
.c('items', {'node': 'storage:bookmarks'})
.c('item', {'id': 'current'})
.c('storage', {'xmlns': 'storage:bookmarks'});
_converse.connection._dataRecv(test_utils.createRequest(stanza));
_converse.connection._dataRecv(mock.createRequest(stanza));
await _converse.api.waitUntil('bookmarksInitialized');
_converse.bookmarks.create({
@ -574,17 +574,17 @@ window.addEventListener('converse-loaded', () => {
done();
}));
});
});
});
describe("When hide_open_bookmarks is true and a bookmarked room is opened", function () {
describe("When hide_open_bookmarks is true and a bookmarked room is opened", function () {
it("can be closed", mock.initConverse(
['rosterGroupsFetched'],
{ hide_open_bookmarks: true },
async function (done, _converse) {
await test_utils.openControlBox(_converse);
await test_utils.waitUntilBookmarksReturned(_converse);
await mock.openControlBox(_converse);
await mock.waitUntilBookmarksReturned(_converse);
// Check that it's there
const jid = 'room@conference.example.org';
@ -596,6 +596,7 @@ window.addEventListener('converse-loaded', () => {
});
expect(_converse.bookmarks.length).toBe(1);
const u = converse.env.utils;
const bmarks_view = _converse.bookmarksview;
await u.waitUntil(() => bmarks_view.el.querySelectorAll(".open-room").length, 500);
const room_els = bmarks_view.el.querySelectorAll(".open-room");
@ -612,5 +613,4 @@ window.addEventListener('converse-loaded', () => {
await u.waitUntil(() => !u.hasClass('hidden', _converse.bookmarksview.el.querySelector(".available-chatroom")));
done();
}));
});
});

View File

@ -1,25 +1,24 @@
window.addEventListener('converse-loaded', () => {
const mock = window.mock;
const test_utils = window.test_utils;
const _ = converse.env._;
const $msg = converse.env.$msg;
const Strophe = converse.env.Strophe;
const u = converse.env.utils;
const sizzle = converse.env.sizzle;
/*global mock */
return describe("Chatboxes", function () {
const _ = converse.env._;
const $msg = converse.env.$msg;
const Strophe = converse.env.Strophe;
const u = converse.env.utils;
const sizzle = converse.env.sizzle;
describe("Chatboxes", function () {
describe("A Chatbox", function () {
it("has a /help command to show the available commands", mock.initConverse(['rosterGroupsFetched', 'chatBoxesFetched'], {}, async function (done, _converse) {
await test_utils.waitForRoster(_converse, 'current', 1);
await test_utils.openControlBox(_converse);
await mock.waitForRoster(_converse, 'current', 1);
await mock.openControlBox(_converse);
const contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit';
await test_utils.openChatBoxFor(_converse, contact_jid);
await mock.openChatBoxFor(_converse, contact_jid);
const view = _converse.chatboxviews.get(contact_jid);
test_utils.sendMessage(view, '/help');
mock.sendMessage(view, '/help');
const info_messages = Array.prototype.slice.call(view.el.querySelectorAll('.chat-info:not(.chat-date)'), 0);
expect(info_messages.length).toBe(4);
@ -42,10 +41,10 @@ window.addEventListener('converse-loaded', () => {
it("supports the /me command", mock.initConverse(['rosterGroupsFetched'], {}, async function (done, _converse) {
await test_utils.waitForRoster(_converse, 'current');
await test_utils.waitUntilDiscoConfirmed(_converse, 'montague.lit', [], ['vcard-temp']);
await mock.waitForRoster(_converse, 'current');
await mock.waitUntilDiscoConfirmed(_converse, 'montague.lit', [], ['vcard-temp']);
await u.waitUntil(() => _converse.xmppstatus.vcard.get('fullname'));
await test_utils.openControlBox(_converse);
await mock.openControlBox(_converse);
expect(_converse.chatboxes.length).toEqual(1);
const sender_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit';
let message = '/me is tired';
@ -64,7 +63,7 @@ window.addEventListener('converse-loaded', () => {
expect(_.includes(view.el.querySelector('.chat-msg__author').textContent, '**Mercutio')).toBeTruthy();
expect(view.el.querySelector('.chat-msg__text').textContent).toBe('is tired');
message = '/me is as well';
await test_utils.sendMessage(view, message);
await mock.sendMessage(view, message);
expect(view.el.querySelectorAll('.chat-msg--action').length).toBe(2);
await u.waitUntil(() => sizzle('.chat-msg__author:last', view.el).pop().textContent.trim() === '**Romeo Montague');
const last_el = sizzle('.chat-msg__text:last', view.el).pop();
@ -73,11 +72,11 @@ window.addEventListener('converse-loaded', () => {
// Check that /me messages after a normal message don't
// get the 'chat-msg--followup' class.
message = 'This a normal message';
await test_utils.sendMessage(view, message);
await mock.sendMessage(view, message);
let message_el = view.el.querySelector('.message:last-child');
expect(u.hasClass('chat-msg--followup', message_el)).toBeFalsy();
message = '/me wrote a 3rd person message';
await test_utils.sendMessage(view, message);
await mock.sendMessage(view, message);
message_el = view.el.querySelector('.message:last-child');
expect(view.el.querySelectorAll('.chat-msg--action').length).toBe(3);
expect(sizzle('.chat-msg__text:last', view.el).pop().textContent).toBe('wrote a 3rd person message');
@ -90,8 +89,8 @@ window.addEventListener('converse-loaded', () => {
['rosterGroupsFetched', 'chatBoxesFetched'], {},
async function (done, _converse) {
await test_utils.waitForRoster(_converse, 'current');
await test_utils.openControlBox(_converse);
await mock.waitForRoster(_converse, 'current');
await mock.openControlBox(_converse);
// openControlBox was called earlier, so the controlbox is
// visible, but no other chat boxes have been created.
@ -120,7 +119,7 @@ window.addEventListener('converse-loaded', () => {
['rosterGroupsFetched'], {'allow_non_roster_messaging': true},
async function (done, _converse) {
await test_utils.waitForRoster(_converse, 'current', 0);
await mock.waitForRoster(_converse, 'current', 0);
const sender_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit';
const stanza = u.toStanza(`
<message from="${sender_jid}"
@ -130,7 +129,7 @@ window.addEventListener('converse-loaded', () => {
</message>`);
const message_promise = new Promise(resolve => _converse.api.listen.on('message', resolve));
_converse.connection._dataRecv(test_utils.createRequest(stanza));
_converse.connection._dataRecv(mock.createRequest(stanza));
await new Promise(resolve => _converse.api.listen.once('chatBoxViewInitialized', resolve));
await u.waitUntil(() => message_promise);
expect(_converse.chatboxviews.keys().length).toBe(2);
@ -141,7 +140,7 @@ window.addEventListener('converse-loaded', () => {
['rosterGroupsFetched'], {},
async function (done, _converse) {
await test_utils.waitForRoster(_converse, 'current', 1);
await mock.waitForRoster(_converse, 'current', 1);
const sender_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit';
const stanza = u.toStanza(`
<message from="${sender_jid}"
@ -150,7 +149,7 @@ window.addEventListener('converse-loaded', () => {
<composing xmlns="http://jabber.org/protocol/chatstates"/>
</message>`);
const message_promise = new Promise(resolve => _converse.api.listen.on('message', resolve))
_converse.connection._dataRecv(test_utils.createRequest(stanza));
_converse.connection._dataRecv(mock.createRequest(stanza));
await u.waitUntil(() => message_promise);
expect(_converse.chatboxviews.keys().length).toBe(1);
done();
@ -166,8 +165,8 @@ window.addEventListener('converse-loaded', () => {
spyOn(trimmed_chatboxes, 'addChat').and.callThrough();
spyOn(trimmed_chatboxes, 'removeChat').and.callThrough();
await test_utils.waitForRoster(_converse, 'current');
await test_utils.openControlBox(_converse);
await mock.waitForRoster(_converse, 'current');
await mock.openControlBox(_converse);
expect(_converse.chatboxviews.trimChats.calls.count()).toBe(1);
let jid, chatboxview;
@ -218,7 +217,7 @@ window.addEventListener('converse-loaded', () => {
['rosterGroupsFetched'], {},
async function (done, _converse) {
await test_utils.waitForRoster(_converse, 'current');
await mock.waitForRoster(_converse, 'current');
const sender_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit';
await _converse.api.chats.create(sender_jid, {'minimized': true});
await u.waitUntil(() => _converse.chatboxes.length > 1);
@ -236,12 +235,12 @@ window.addEventListener('converse-loaded', () => {
mock.initConverse(['rosterGroupsFetched', 'chatBoxesFetched'], {},
async function (done, _converse) {
await test_utils.waitForRoster(_converse, 'current');
await test_utils.openControlBox(_converse);
await mock.waitForRoster(_converse, 'current');
await mock.openControlBox(_converse);
expect(_converse.chatboxes.length).toEqual(1);
const contact_jid = mock.cur_names[2].replace(/ /g,'.').toLowerCase() + '@montague.lit';
const view = await test_utils.openChatBoxFor(_converse, contact_jid);
const view = await mock.openChatBoxFor(_converse, contact_jid);
const el = sizzle('a.open-chat:contains("'+view.model.getDisplayName()+'")', _converse.rosterview.el).pop();
await u.waitUntil(() => u.isVisible(el));
const textarea = view.el.querySelector('.chat-textarea');
@ -263,12 +262,12 @@ window.addEventListener('converse-loaded', () => {
async function (done, _converse) {
spyOn(_converse.ChatBoxViews.prototype, 'trimChats');
await test_utils.waitForRoster(_converse, 'current');
await test_utils.openControlBox(_converse);
await mock.waitForRoster(_converse, 'current');
await mock.openControlBox(_converse);
spyOn(_converse.api, "trigger").and.callThrough();
test_utils.openChatBoxes(_converse, 6);
mock.openChatBoxes(_converse, 6);
await u.waitUntil(() => _converse.chatboxes.length == 7);
expect(_converse.chatboxviews.trimChats).toHaveBeenCalled();
// We instantiate a new ChatBoxes collection, which by default
@ -298,12 +297,12 @@ window.addEventListener('converse-loaded', () => {
['rosterGroupsFetched', 'chatBoxesFetched'], {},
async function (done, _converse) {
await test_utils.waitForRoster(_converse, 'current');
await test_utils.openControlBox(_converse);
await mock.waitForRoster(_converse, 'current');
await mock.openControlBox(_converse);
const contact_jid = mock.cur_names[7].replace(/ /g,'.').toLowerCase() + '@montague.lit';
await u.waitUntil(() => _converse.rosterview.el.querySelectorAll('.roster-group').length);
await test_utils.openChatBoxFor(_converse, contact_jid);
await mock.openChatBoxFor(_converse, contact_jid);
const controlview = _converse.chatboxviews.get('controlbox'), // The controlbox is currently open
chatview = _converse.chatboxviews.get(contact_jid);
@ -332,12 +331,12 @@ window.addEventListener('converse-loaded', () => {
['rosterGroupsFetched', 'chatBoxesFetched'], {},
async function (done, _converse) {
await test_utils.waitForRoster(_converse, 'current');
await test_utils.openControlBox(_converse);
await mock.waitForRoster(_converse, 'current');
await mock.openControlBox(_converse);
const contact_jid = mock.cur_names[7].replace(/ /g,'.').toLowerCase() + '@montague.lit';
await u.waitUntil(() => _converse.rosterview.el.querySelectorAll('.roster-group').length);
await test_utils.openChatBoxFor(_converse, contact_jid);
await mock.openChatBoxFor(_converse, contact_jid);
const trimmed_chatboxes = _converse.minimized_chats;
const chatview = _converse.chatboxviews.get(contact_jid);
spyOn(chatview, 'minimize').and.callThrough();
@ -369,22 +368,22 @@ window.addEventListener('converse-loaded', () => {
async function (done, _converse) {
spyOn(_converse.ChatBoxViews.prototype, 'trimChats');
await test_utils.waitForRoster(_converse, 'current');
await test_utils.openControlBox(_converse);
await mock.waitForRoster(_converse, 'current');
await mock.openControlBox(_converse);
await u.waitUntil(() => _converse.rosterview.el.querySelectorAll('.roster-group').length);
spyOn(_converse.api, "trigger").and.callThrough();
test_utils.closeControlBox();
mock.closeControlBox();
await new Promise(resolve => _converse.api.listen.once('chatBoxClosed', resolve));
expect(_converse.api.trigger).toHaveBeenCalledWith('chatBoxClosed', jasmine.any(Object));
expect(_converse.chatboxes.length).toEqual(1);
expect(_converse.chatboxes.pluck('id')).toEqual(['controlbox']);
test_utils.openChatBoxes(_converse, 6);
mock.openChatBoxes(_converse, 6);
await u.waitUntil(() => _converse.chatboxes.length == 7)
expect(_converse.chatboxviews.trimChats).toHaveBeenCalled();
expect(_converse.chatboxes.length).toEqual(7);
expect(_converse.api.trigger).toHaveBeenCalledWith('chatBoxViewInitialized', jasmine.any(Object));
await test_utils.closeAllChatBoxes(_converse);
await mock.closeAllChatBoxes(_converse);
expect(_converse.chatboxes.length).toEqual(1);
expect(_converse.chatboxes.pluck('id')).toEqual(['controlbox']);
@ -409,10 +408,10 @@ window.addEventListener('converse-loaded', () => {
['rosterGroupsFetched', 'chatBoxesFetched'], {},
async function (done, _converse) {
await test_utils.waitForRoster(_converse, 'current', 3);
await test_utils.openControlBox(_converse);
await mock.waitForRoster(_converse, 'current', 3);
await mock.openControlBox(_converse);
const contact_jid = mock.cur_names[2].replace(/ /g,'.').toLowerCase() + '@montague.lit';
await test_utils.openChatBoxFor(_converse, contact_jid);
await mock.openChatBoxFor(_converse, contact_jid);
const chatbox = _converse.chatboxes.get(contact_jid);
const view = _converse.chatboxviews.get(contact_jid);
expect(chatbox).toBeDefined();
@ -428,10 +427,10 @@ window.addEventListener('converse-loaded', () => {
['rosterGroupsFetched', 'chatBoxesFetched'], {'message_limit': 200},
async function (done, _converse) {
await test_utils.waitForRoster(_converse, 'current', 3);
await test_utils.openControlBox(_converse);
await mock.waitForRoster(_converse, 'current', 3);
await mock.openControlBox(_converse);
const contact_jid = mock.cur_names[2].replace(/ /g,'.').toLowerCase() + '@montague.lit';
await test_utils.openChatBoxFor(_converse, contact_jid);
await mock.openChatBoxFor(_converse, contact_jid);
const view = _converse.chatboxviews.get(contact_jid);
const toolbar = view.el.querySelector('.chat-toolbar');
const counter = toolbar.querySelector('.message-limit');
@ -468,10 +467,10 @@ window.addEventListener('converse-loaded', () => {
['rosterGroupsFetched', 'chatBoxesFetched'], {'message_limit': 0},
async function (done, _converse) {
await test_utils.waitForRoster(_converse, 'current', 3);
await test_utils.openControlBox(_converse);
await mock.waitForRoster(_converse, 'current', 3);
await mock.openControlBox(_converse);
const contact_jid = mock.cur_names[2].replace(/ /g,'.').toLowerCase() + '@montague.lit';
await test_utils.openChatBoxFor(_converse, contact_jid);
await mock.openChatBoxFor(_converse, contact_jid);
const view = _converse.chatboxviews.get(contact_jid);
const counter = view.el.querySelector('.chat-toolbar .message-limit');
expect(counter).toBe(null);
@ -484,8 +483,8 @@ window.addEventListener('converse-loaded', () => {
['rosterGroupsFetched', 'chatBoxesFetched'], {},
async function (done, _converse) {
await test_utils.waitForRoster(_converse, 'current');
await test_utils.openControlBox(_converse);
await mock.waitForRoster(_converse, 'current');
await mock.openControlBox(_converse);
let toolbar, call_button;
const contact_jid = mock.cur_names[2].replace(/ /g,'.').toLowerCase() + '@montague.lit';
@ -493,7 +492,7 @@ window.addEventListener('converse-loaded', () => {
// First check that the button doesn't show if it's not enabled
// via "visible_toolbar_buttons"
_converse.visible_toolbar_buttons.call = false;
await test_utils.openChatBoxFor(_converse, contact_jid);
await mock.openChatBoxFor(_converse, contact_jid);
let view = _converse.chatboxviews.get(contact_jid);
toolbar = view.el.querySelector('ul.chat-toolbar');
call_button = toolbar.querySelector('.toggle-call');
@ -502,7 +501,7 @@ window.addEventListener('converse-loaded', () => {
// Now check that it's shown if enabled and that it emits
// callButtonClicked
_converse.visible_toolbar_buttons.call = true; // enable the button
await test_utils.openChatBoxFor(_converse, contact_jid);
await mock.openChatBoxFor(_converse, contact_jid);
view = _converse.chatboxviews.get(contact_jid);
toolbar = view.el.querySelector('ul.chat-toolbar');
call_button = toolbar.querySelector('.toggle-call');
@ -519,8 +518,8 @@ window.addEventListener('converse-loaded', () => {
['rosterGroupsFetched'], {},
async function (done, _converse) {
await test_utils.waitForRoster(_converse, 'current');
await test_utils.openControlBox(_converse);
await mock.waitForRoster(_converse, 'current');
await mock.openControlBox(_converse);
const sender_jid = mock.cur_names[1].replace(/ /g,'.').toLowerCase() + '@montague.lit';
// <composing> state
@ -532,7 +531,7 @@ window.addEventListener('converse-loaded', () => {
}).c('composing', {'xmlns': Strophe.NS.CHATSTATES}).tree();
spyOn(_converse.api, "trigger").and.callThrough();
_converse.connection._dataRecv(test_utils.createRequest(stanza));
_converse.connection._dataRecv(mock.createRequest(stanza));
await u.waitUntil(() => _converse.api.trigger.calls.count());
expect(_converse.api.trigger).toHaveBeenCalledWith('message', jasmine.any(Object));
expect(_converse.chatboxviews.keys().length).toBe(1);
@ -546,12 +545,12 @@ window.addEventListener('converse-loaded', () => {
['rosterGroupsFetched', 'chatBoxesFetched'], {},
async function (done, _converse) {
await test_utils.waitForRoster(_converse, 'current');
await mock.waitForRoster(_converse, 'current');
const contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit';
await test_utils.openControlBox(_converse);
await mock.openControlBox(_converse);
u.waitUntil(() => _converse.rosterview.el.querySelectorAll('.roster-group').length);
spyOn(_converse.connection, 'send');
await test_utils.openChatBoxFor(_converse, contact_jid);
await mock.openChatBoxFor(_converse, contact_jid);
const view = _converse.chatboxviews.get(contact_jid);
expect(view.model.get('chat_state')).toBe('active');
expect(_converse.connection.send).toHaveBeenCalled();
@ -568,12 +567,12 @@ window.addEventListener('converse-loaded', () => {
['rosterGroupsFetched', 'chatBoxesFetched'], {},
async function (done, _converse) {
await test_utils.waitForRoster(_converse, 'current', 1);
await test_utils.openControlBox(_converse);
await mock.waitForRoster(_converse, 'current', 1);
await mock.openControlBox(_converse);
const contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit';
await u.waitUntil(() => _converse.rosterview.el.querySelectorAll('.roster-group').length);
await test_utils.openChatBoxFor(_converse, contact_jid);
await mock.openChatBoxFor(_converse, contact_jid);
const view = _converse.chatboxviews.get(contact_jid);
view.model.minimize();
expect(view.model.get('chat_state')).toBe('inactive');
@ -602,12 +601,12 @@ window.addEventListener('converse-loaded', () => {
['rosterGroupsFetched', 'chatBoxesFetched'], {},
async function (done, _converse) {
await test_utils.waitForRoster(_converse, 'current');
await test_utils.openControlBox(_converse);
await mock.waitForRoster(_converse, 'current');
await mock.openControlBox(_converse);
const contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit';
await u.waitUntil(() => _converse.rosterview.el.querySelectorAll('.roster-group').length);
await test_utils.openChatBoxFor(_converse, contact_jid);
await mock.openChatBoxFor(_converse, contact_jid);
var view = _converse.chatboxviews.get(contact_jid);
expect(view.model.get('chat_state')).toBe('active');
spyOn(_converse.connection, 'send');
@ -641,12 +640,12 @@ window.addEventListener('converse-loaded', () => {
['rosterGroupsFetched', 'chatBoxesFetched'], {'send_chat_state_notifications': []},
async function (done, _converse) {
await test_utils.waitForRoster(_converse, 'current');
await test_utils.openControlBox(_converse);
await mock.waitForRoster(_converse, 'current');
await mock.openControlBox(_converse);
const contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit';
await u.waitUntil(() => _converse.rosterview.el.querySelectorAll('.roster-group').length);
await test_utils.openChatBoxFor(_converse, contact_jid);
await mock.openChatBoxFor(_converse, contact_jid);
var view = _converse.chatboxviews.get(contact_jid);
expect(view.model.get('chat_state')).toBe('active');
spyOn(_converse.connection, 'send');
@ -665,13 +664,13 @@ window.addEventListener('converse-loaded', () => {
['rosterGroupsFetched'], {},
async function (done, _converse) {
await test_utils.waitForRoster(_converse, 'current');
await test_utils.openControlBox(_converse);
await mock.waitForRoster(_converse, 'current');
await mock.openControlBox(_converse);
// See XEP-0085 https://xmpp.org/extensions/xep-0085.html#definitions
const sender_jid = mock.cur_names[1].replace(/ /g,'.').toLowerCase() + '@montague.lit';
await u.waitUntil(() => _converse.rosterview.el.querySelectorAll('.roster-group').length);
await test_utils.openChatBoxFor(_converse, sender_jid);
await mock.openChatBoxFor(_converse, sender_jid);
// <composing> state
let msg = $msg({
@ -681,7 +680,7 @@ window.addEventListener('converse-loaded', () => {
id: u.getUniqueId()
}).c('composing', {'xmlns': Strophe.NS.CHATSTATES}).tree();
_converse.connection._dataRecv(test_utils.createRequest(msg));
_converse.connection._dataRecv(mock.createRequest(msg));
const view = _converse.chatboxviews.get(sender_jid);
let csn = mock.cur_names[1] + ' is typing';
await u.waitUntil( () => view.el.querySelector('.chat-content__notifications').innerText === csn);
@ -694,7 +693,7 @@ window.addEventListener('converse-loaded', () => {
type: 'chat',
id: u.getUniqueId()
}).c('paused', {'xmlns': Strophe.NS.CHATSTATES}).tree();
_converse.connection._dataRecv(test_utils.createRequest(msg));
_converse.connection._dataRecv(mock.createRequest(msg));
csn = mock.cur_names[1] + ' has stopped typing';
await u.waitUntil( () => view.el.querySelector('.chat-content__notifications').innerText === csn);
@ -716,12 +715,12 @@ window.addEventListener('converse-loaded', () => {
['rosterGroupsFetched', 'chatBoxesFetched'], {},
async function (done, _converse) {
await test_utils.waitUntilDiscoConfirmed(_converse, 'montague.lit', [], ['vcard-temp']);
await mock.waitUntilDiscoConfirmed(_converse, 'montague.lit', [], ['vcard-temp']);
await u.waitUntil(() => _converse.xmppstatus.vcard.get('fullname'));
await test_utils.waitForRoster(_converse, 'current');
await mock.waitForRoster(_converse, 'current');
// Send a message from a different resource
const recipient_jid = mock.cur_names[5].replace(/ /g,'.').toLowerCase() + '@montague.lit';
const view = await test_utils.openChatBoxFor(_converse, recipient_jid);
const view = await mock.openChatBoxFor(_converse, recipient_jid);
spyOn(u, 'shouldCreateMessage').and.callThrough();
@ -739,7 +738,7 @@ window.addEventListener('converse-loaded', () => {
'to': recipient_jid,
'type': 'chat'
}).c('composing', {'xmlns': Strophe.NS.CHATSTATES}).tree();
_converse.connection._dataRecv(test_utils.createRequest(msg));
_converse.connection._dataRecv(mock.createRequest(msg));
await u.waitUntil(() => u.shouldCreateMessage.calls.count());
expect(view.model.messages.length).toEqual(0);
@ -756,12 +755,12 @@ window.addEventListener('converse-loaded', () => {
['rosterGroupsFetched', 'chatBoxesFetched'], {},
async function (done, _converse) {
await test_utils.waitForRoster(_converse, 'current');
await mock.waitForRoster(_converse, 'current');
const contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit';
await test_utils.openControlBox(_converse);
await mock.openControlBox(_converse);
await u.waitUntil(() => _converse.rosterview.el.querySelectorAll('.roster-group li').length, 700);
_converse.TIMEOUTS.PAUSED = 200; // Make the timeout shorter so that we can test
await test_utils.openChatBoxFor(_converse, contact_jid);
await mock.openChatBoxFor(_converse, contact_jid);
const view = _converse.chatboxviews.get(contact_jid);
spyOn(_converse.connection, 'send');
spyOn(view.model, 'setChatState').and.callThrough();
@ -810,14 +809,14 @@ window.addEventListener('converse-loaded', () => {
['rosterGroupsFetched'], {},
async function (done, _converse) {
await test_utils.waitForRoster(_converse, 'current');
await test_utils.openControlBox(_converse);
await mock.waitForRoster(_converse, 'current');
await mock.openControlBox(_converse);
await u.waitUntil(() => _converse.rosterview.el.querySelectorAll('.roster-group').length);
// TODO: only show paused state if the previous state was composing
// See XEP-0085 https://xmpp.org/extensions/xep-0085.html#definitions
spyOn(_converse.api, "trigger").and.callThrough();
const sender_jid = mock.cur_names[1].replace(/ /g,'.').toLowerCase() + '@montague.lit';
const view = await test_utils.openChatBoxFor(_converse, sender_jid);
const view = await mock.openChatBoxFor(_converse, sender_jid);
// <paused> state
const msg = $msg({
from: sender_jid,
@ -826,7 +825,7 @@ window.addEventListener('converse-loaded', () => {
id: u.getUniqueId()
}).c('paused', {'xmlns': Strophe.NS.CHATSTATES}).tree();
_converse.connection._dataRecv(test_utils.createRequest(msg));
_converse.connection._dataRecv(mock.createRequest(msg));
const csn = mock.cur_names[1] + ' has stopped typing';
await u.waitUntil( () => view.el.querySelector('.chat-content__notifications').innerText === csn);
expect(view.model.messages.length).toEqual(0);
@ -838,13 +837,13 @@ window.addEventListener('converse-loaded', () => {
['rosterGroupsFetched', 'chatBoxesFetched'], {},
async function (done, _converse) {
await test_utils.waitUntilDiscoConfirmed(_converse, 'montague.lit', [], ['vcard-temp']);
await mock.waitUntilDiscoConfirmed(_converse, 'montague.lit', [], ['vcard-temp']);
await u.waitUntil(() => _converse.xmppstatus.vcard.get('fullname'));
await test_utils.waitForRoster(_converse, 'current');
await mock.waitForRoster(_converse, 'current');
// Send a message from a different resource
const recipient_jid = mock.cur_names[5].replace(/ /g,'.').toLowerCase() + '@montague.lit';
spyOn(u, 'shouldCreateMessage').and.callThrough();
const view = await test_utils.openChatBoxFor(_converse, recipient_jid);
const view = await mock.openChatBoxFor(_converse, recipient_jid);
const msg = $msg({
'from': _converse.bare_jid,
'id': u.getUniqueId(),
@ -859,7 +858,7 @@ window.addEventListener('converse-loaded', () => {
'to': recipient_jid,
'type': 'chat'
}).c('paused', {'xmlns': Strophe.NS.CHATSTATES}).tree();
_converse.connection._dataRecv(test_utils.createRequest(msg));
_converse.connection._dataRecv(mock.createRequest(msg));
await u.waitUntil(() => u.shouldCreateMessage.calls.count());
expect(view.model.messages.length).toEqual(0);
const el = view.el.querySelector('.chat-content__notifications');
@ -881,11 +880,11 @@ window.addEventListener('converse-loaded', () => {
_converse.TIMEOUTS.PAUSED = 100;
_converse.TIMEOUTS.INACTIVE = 100;
await test_utils.waitForRoster(_converse, 'current');
await mock.waitForRoster(_converse, 'current');
const contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit';
await test_utils.openControlBox(_converse);
await mock.openControlBox(_converse);
await u.waitUntil(() => _converse.rosterview.el.querySelectorAll('.roster-group').length, 1000);
await test_utils.openChatBoxFor(_converse, contact_jid);
await mock.openChatBoxFor(_converse, contact_jid);
const view = _converse.chatboxviews.get(contact_jid);
await u.waitUntil(() => view.model.get('chat_state') === 'active');
let messages = await u.waitUntil(() => sent_stanzas.filter(s => s.matches('message')));
@ -939,11 +938,11 @@ window.addEventListener('converse-loaded', () => {
['rosterGroupsFetched', 'chatBoxesFetched'], {},
async function (done, _converse) {
await test_utils.waitForRoster(_converse, 'current');
await test_utils.openControlBox(_converse);
await mock.waitForRoster(_converse, 'current');
await mock.openControlBox(_converse);
const contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit';
await test_utils.openChatBoxFor(_converse, contact_jid);
await mock.openChatBoxFor(_converse, contact_jid);
const view = _converse.chatboxviews.get(contact_jid);
spyOn(_converse.connection, 'send');
view.minimize();
@ -960,11 +959,11 @@ window.addEventListener('converse-loaded', () => {
['rosterGroupsFetched', 'chatBoxesFetched'], {},
async function (done, _converse) {
await test_utils.waitForRoster(_converse, 'current');
await mock.waitForRoster(_converse, 'current');
const contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit';
await test_utils.openControlBox(_converse);
await mock.openControlBox(_converse);
await u.waitUntil(() => _converse.rosterview.el.querySelectorAll('.roster-group').length);
const view = await test_utils.openChatBoxFor(_converse, contact_jid);
const view = await mock.openChatBoxFor(_converse, contact_jid);
expect(view.model.get('chat_state')).toBe('active');
spyOn(_converse.connection, 'send');
view.close();
@ -984,11 +983,11 @@ window.addEventListener('converse-loaded', () => {
['rosterGroupsFetched', 'chatBoxesFetched'], {},
async function (done, _converse) {
await test_utils.waitForRoster(_converse, 'current');
await test_utils.openControlBox(_converse);
await mock.waitForRoster(_converse, 'current');
await mock.openControlBox(_converse);
const sender_jid = mock.cur_names[1].replace(/ /g,'.').toLowerCase() + '@montague.lit';
// See XEP-0085 https://xmpp.org/extensions/xep-0085.html#definitions
await test_utils.openChatBoxFor(_converse, sender_jid);
await mock.openChatBoxFor(_converse, sender_jid);
const view = _converse.chatboxviews.get(sender_jid);
expect(view.el.querySelectorAll('.chat-event').length).toBe(0);
// Insert <composing> message, to also check that
@ -1001,7 +1000,7 @@ window.addEventListener('converse-loaded', () => {
'type': 'chat'})
.c('composing', {'xmlns': Strophe.NS.CHATSTATES}).up()
.tree();
_converse.connection._dataRecv(test_utils.createRequest(msg));
_converse.connection._dataRecv(mock.createRequest(msg));
const csntext = await u.waitUntil(() => view.el.querySelector('.chat-content__notifications').textContent);
expect(csntext).toEqual(mock.cur_names[1] + ' is typing');
expect(view.model.messages.length).toBe(0);
@ -1012,7 +1011,7 @@ window.addEventListener('converse-loaded', () => {
type: 'chat',
id: u.getUniqueId()
}).c('inactive', {'xmlns': Strophe.NS.CHATSTATES}).tree();
_converse.connection._dataRecv(test_utils.createRequest(msg));
_converse.connection._dataRecv(mock.createRequest(msg));
await u.waitUntil(() => !view.el.querySelector('.chat-content__notifications').textContent);
done();
@ -1026,10 +1025,10 @@ window.addEventListener('converse-loaded', () => {
['rosterGroupsFetched'], {},
async function (done, _converse) {
await test_utils.waitForRoster(_converse, 'current', 3);
await test_utils.openControlBox(_converse);
await mock.waitForRoster(_converse, 'current', 3);
await mock.openControlBox(_converse);
const sender_jid = mock.cur_names[1].replace(/ /g,'.').toLowerCase() + '@montague.lit';
await test_utils.openChatBoxFor(_converse, sender_jid);
await mock.openChatBoxFor(_converse, sender_jid);
const msg = $msg({
from: sender_jid,
@ -1037,7 +1036,7 @@ window.addEventListener('converse-loaded', () => {
type: 'chat',
id: u.getUniqueId()
}).c('body').c('gone', {'xmlns': Strophe.NS.CHATSTATES}).tree();
_converse.connection._dataRecv(test_utils.createRequest(msg));
_converse.connection._dataRecv(mock.createRequest(msg));
const view = _converse.chatboxviews.get(sender_jid);
const csntext = await u.waitUntil(() => view.el.querySelector('.chat-content__notifications').textContent);
@ -1053,13 +1052,13 @@ window.addEventListener('converse-loaded', () => {
['rosterGroupsFetched'], {},
async function (done, _converse) {
await test_utils.waitForRoster(_converse, 'current');
await test_utils.openControlBox(_converse);
await mock.waitForRoster(_converse, 'current');
await mock.openControlBox(_converse);
// See XEP-0085 https://xmpp.org/extensions/xep-0085.html#definitions
const sender_jid = mock.cur_names[1].replace(/ /g,'.').toLowerCase() + '@montague.lit';
await u.waitUntil(() => _converse.rosterview.el.querySelectorAll('.roster-group').length);
await test_utils.openChatBoxFor(_converse, sender_jid);
await mock.openChatBoxFor(_converse, sender_jid);
// Original message
const original_id = u.getUniqueId();
@ -1072,7 +1071,7 @@ window.addEventListener('converse-loaded', () => {
}).c('active', {'xmlns': Strophe.NS.CHATSTATES}).tree();
spyOn(_converse.api, "trigger").and.callThrough();
_converse.connection._dataRecv(test_utils.createRequest(original));
_converse.connection._dataRecv(mock.createRequest(original));
await u.waitUntil(() => _converse.api.trigger.calls.count());
expect(_converse.api.trigger).toHaveBeenCalledWith('message', jasmine.any(Object));
const view = _converse.chatboxviews.get(sender_jid);
@ -1085,7 +1084,7 @@ window.addEventListener('converse-loaded', () => {
type: 'chat',
id: u.getUniqueId()
}).c('composing', {'xmlns': Strophe.NS.CHATSTATES}).tree();
_converse.connection._dataRecv(test_utils.createRequest(msg));
_converse.connection._dataRecv(mock.createRequest(msg));
const csntext = await u.waitUntil(() => view.el.querySelector('.chat-content__notifications').textContent);
expect(csntext).toEqual(mock.cur_names[1] + ' is typing');
@ -1116,15 +1115,15 @@ window.addEventListener('converse-loaded', () => {
['rosterGroupsFetched', 'chatBoxesFetched'], {},
async function (done, _converse) {
await test_utils.waitForRoster(_converse, 'current');
await test_utils.openControlBox(_converse);
await mock.waitForRoster(_converse, 'current');
await mock.openControlBox(_converse);
const contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit';
spyOn(_converse.api, "trigger").and.callThrough();
await test_utils.openChatBoxFor(_converse, contact_jid);
await mock.openChatBoxFor(_converse, contact_jid);
const view = _converse.chatboxviews.get(contact_jid);
let message = 'This message is another sent from this chatbox';
await test_utils.sendMessage(view, message);
await mock.sendMessage(view, message);
expect(view.model.messages.length === 1).toBeTruthy();
let stored_messages = await view.model.messages.browserStorage.findAll();
@ -1161,13 +1160,13 @@ window.addEventListener('converse-loaded', () => {
['rosterGroupsFetched'], {},
async function (done, _converse) {
await test_utils.waitForRoster(_converse, 'current');
await test_utils.openControlBox(_converse);
await mock.waitForRoster(_converse, 'current');
await mock.openControlBox(_converse);
expect(document.title).toBe('Converse Tests');
const sender_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit';
const view = await test_utils.openChatBoxFor(_converse, sender_jid)
const view = await mock.openChatBoxFor(_converse, sender_jid)
const previous_state = _converse.windowState;
const message = 'This message will increment the message counter';
@ -1199,8 +1198,8 @@ window.addEventListener('converse-loaded', () => {
['rosterGroupsFetched'], {},
async function (done, _converse) {
await test_utils.waitForRoster(_converse, 'current');
await test_utils.openControlBox(_converse);
await mock.waitForRoster(_converse, 'current');
await mock.openControlBox(_converse);
_converse.windowState = 'hidden';
spyOn(_converse, 'clearMsgCounter').and.callThrough();
_converse.saveWindowState(null, 'focus');
@ -1214,8 +1213,8 @@ window.addEventListener('converse-loaded', () => {
['rosterGroupsFetched'], {},
async function (done, _converse) {
await test_utils.waitForRoster(_converse, 'current');
await test_utils.openControlBox(_converse);
await mock.waitForRoster(_converse, 'current');
await mock.openControlBox(_converse);
expect(document.title).toBe('Converse Tests');
spyOn(_converse, 'incrementMsgCounter').and.callThrough();
@ -1240,7 +1239,7 @@ window.addEventListener('converse-loaded', () => {
['rosterGroupsFetched'], {},
async function (done, _converse) {
await test_utils.waitForRoster(_converse, 'current');
await mock.waitForRoster(_converse, 'current');
// initial state
expect(document.title).toBe('Converse Tests');
const message = 'This message will always increment the message counter from zero',
@ -1288,11 +1287,11 @@ window.addEventListener('converse-loaded', () => {
['rosterGroupsFetched', 'chatBoxesFetched'], {},
async function (done, _converse) {
await test_utils.waitForRoster(_converse, 'current');
await mock.waitForRoster(_converse, 'current');
const sender_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit',
msg = test_utils.createChatMessage(_converse, sender_jid, 'This message will be unread');
msg = mock.createChatMessage(_converse, sender_jid, 'This message will be unread');
const view = await test_utils.openChatBoxFor(_converse, sender_jid)
const view = await mock.openChatBoxFor(_converse, sender_jid)
view.model.save('scrolled', true);
await _converse.handleMessageStanza(msg);
await u.waitUntil(() => view.model.messages.length);
@ -1305,12 +1304,12 @@ window.addEventListener('converse-loaded', () => {
['rosterGroupsFetched', 'chatBoxesFetched'], {},
async function (done, _converse) {
await test_utils.waitForRoster(_converse, 'current');
await mock.waitForRoster(_converse, 'current');
const sender_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit',
msg = test_utils.createChatMessage(_converse, sender_jid, 'This message will be read');
msg = mock.createChatMessage(_converse, sender_jid, 'This message will be read');
await test_utils.openChatBoxFor(_converse, sender_jid);
await mock.openChatBoxFor(_converse, sender_jid);
const chatbox = _converse.chatboxes.get(sender_jid);
await _converse.handleMessageStanza(msg);
expect(chatbox.get('num_unread')).toBe(0);
@ -1321,13 +1320,13 @@ window.addEventListener('converse-loaded', () => {
mock.initConverse(['rosterGroupsFetched', 'chatBoxesFetched'], {},
async function (done, _converse) {
await test_utils.waitForRoster(_converse, 'current');
await mock.waitForRoster(_converse, 'current');
const sender_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit';
const msgFactory = function () {
return test_utils.createChatMessage(_converse, sender_jid, 'This message will be unread');
return mock.createChatMessage(_converse, sender_jid, 'This message will be unread');
};
await test_utils.openChatBoxFor(_converse, sender_jid);
await mock.openChatBoxFor(_converse, sender_jid);
const chatbox = _converse.chatboxes.get(sender_jid);
_converse.windowState = 'hidden';
_converse.handleMessageStanza(msgFactory());
@ -1341,10 +1340,10 @@ window.addEventListener('converse-loaded', () => {
['rosterGroupsFetched', 'chatBoxesFetched'], {},
async function (done, _converse) {
await test_utils.waitForRoster(_converse, 'current', 1);
await mock.waitForRoster(_converse, 'current', 1);
const sender_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit';
const msgFactory = () => test_utils.createChatMessage(_converse, sender_jid, 'This message will be unread');
await test_utils.openChatBoxFor(_converse, sender_jid);
const msgFactory = () => mock.createChatMessage(_converse, sender_jid, 'This message will be unread');
await mock.openChatBoxFor(_converse, sender_jid);
const chatbox = _converse.chatboxes.get(sender_jid);
chatbox.save('scrolled', true);
_converse.windowState = 'hidden';
@ -1359,10 +1358,10 @@ window.addEventListener('converse-loaded', () => {
['rosterGroupsFetched', 'chatBoxesFetched'], {},
async function (done, _converse) {
await test_utils.waitForRoster(_converse, 'current', 1);
await mock.waitForRoster(_converse, 'current', 1);
const sender_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit';
const msgFactory = () => test_utils.createChatMessage(_converse, sender_jid, 'This message will be unread');
await test_utils.openChatBoxFor(_converse, sender_jid);
const msgFactory = () => mock.createChatMessage(_converse, sender_jid, 'This message will be unread');
await mock.openChatBoxFor(_converse, sender_jid);
const chatbox = _converse.chatboxes.get(sender_jid);
_converse.windowState = 'hidden';
_converse.handleMessageStanza(msgFactory());
@ -1378,10 +1377,10 @@ window.addEventListener('converse-loaded', () => {
['rosterGroupsFetched', 'chatBoxesFetched'], {},
async function (done, _converse) {
await test_utils.waitForRoster(_converse, 'current', 1);
await mock.waitForRoster(_converse, 'current', 1);
const sender_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit';
const msgFactory = () => test_utils.createChatMessage(_converse, sender_jid, 'This message will be unread');
await test_utils.openChatBoxFor(_converse, sender_jid);
const msgFactory = () => mock.createChatMessage(_converse, sender_jid, 'This message will be unread');
await mock.openChatBoxFor(_converse, sender_jid);
const chatbox = _converse.chatboxes.get(sender_jid);
chatbox.save('scrolled', true);
_converse.windowState = 'hidden';
@ -1401,20 +1400,20 @@ window.addEventListener('converse-loaded', () => {
['rosterGroupsFetched', 'chatBoxesFetched'], {},
async function (done, _converse) {
await test_utils.waitForRoster(_converse, 'current', 1);
await mock.waitForRoster(_converse, 'current', 1);
let msg, indicator_el;
const sender_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit';
await u.waitUntil(() => _converse.rosterview.el.querySelectorAll('.roster-group').length, 500);
await test_utils.openChatBoxFor(_converse, sender_jid);
await mock.openChatBoxFor(_converse, sender_jid);
const chatbox = _converse.chatboxes.get(sender_jid);
chatbox.save('scrolled', true);
msg = test_utils.createChatMessage(_converse, sender_jid, 'This message will be unread');
msg = mock.createChatMessage(_converse, sender_jid, 'This message will be unread');
await _converse.handleMessageStanza(msg);
await u.waitUntil(() => chatbox.messages.length);
const selector = 'a.open-chat:contains("' + chatbox.get('nickname') + '") .msgs-indicator';
indicator_el = sizzle(selector, _converse.rosterview.el).pop();
expect(indicator_el.textContent).toBe('1');
msg = test_utils.createChatMessage(_converse, sender_jid, 'This message will be unread too');
msg = mock.createChatMessage(_converse, sender_jid, 'This message will be unread too');
await _converse.handleMessageStanza(msg);
await u.waitUntil(() => chatbox.messages.length > 1);
indicator_el = sizzle(selector, _converse.rosterview.el).pop();
@ -1427,24 +1426,24 @@ window.addEventListener('converse-loaded', () => {
['rosterGroupsFetched', 'chatBoxesFetched'], {},
async function (done, _converse) {
await test_utils.waitForRoster(_converse, 'current', 1);
await mock.waitForRoster(_converse, 'current', 1);
const sender_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit';
let indicator_el, msg;
await u.waitUntil(() => _converse.rosterview.el.querySelectorAll('.roster-group').length, 500);
await test_utils.openChatBoxFor(_converse, sender_jid);
await mock.openChatBoxFor(_converse, sender_jid);
const chatbox = _converse.chatboxes.get(sender_jid);
var chatboxview = _converse.chatboxviews.get(sender_jid);
chatboxview.minimize();
msg = test_utils.createChatMessage(_converse, sender_jid, 'This message will be unread');
msg = mock.createChatMessage(_converse, sender_jid, 'This message will be unread');
await _converse.handleMessageStanza(msg);
await u.waitUntil(() => chatbox.messages.length);
const selector = 'a.open-chat:contains("' + chatbox.get('nickname') + '") .msgs-indicator';
indicator_el = sizzle(selector, _converse.rosterview.el).pop();
expect(indicator_el.textContent).toBe('1');
msg = test_utils.createChatMessage(_converse, sender_jid, 'This message will be unread too');
msg = mock.createChatMessage(_converse, sender_jid, 'This message will be unread too');
await _converse.handleMessageStanza(msg);
await u.waitUntil(() => chatbox.messages.length === 2);
indicator_el = sizzle(selector, _converse.rosterview.el).pop();
@ -1457,11 +1456,11 @@ window.addEventListener('converse-loaded', () => {
['rosterGroupsFetched', 'chatBoxesFetched'], {},
async function (done, _converse) {
await test_utils.waitForRoster(_converse, 'current', 1);
await mock.waitForRoster(_converse, 'current', 1);
const sender_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit';
const msgFactory = () => test_utils.createChatMessage(_converse, sender_jid, 'This message will be received as unread, but eventually will be read');
const msgFactory = () => mock.createChatMessage(_converse, sender_jid, 'This message will be received as unread, but eventually will be read');
await u.waitUntil(() => _converse.rosterview.el.querySelectorAll('.roster-group').length, 500);
await test_utils.openChatBoxFor(_converse, sender_jid);
await mock.openChatBoxFor(_converse, sender_jid);
const chatbox = _converse.chatboxes.get(sender_jid);
const view = _converse.chatboxviews.get(sender_jid);
const selector = 'a.open-chat:contains("' + chatbox.get('nickname') + '") .msgs-indicator';
@ -1483,13 +1482,13 @@ window.addEventListener('converse-loaded', () => {
['rosterGroupsFetched', 'chatBoxesFetched'], {},
async function (done, _converse) {
await test_utils.openControlBox(_converse);
await test_utils.waitForRoster(_converse, 'current', 1);
await mock.openControlBox(_converse);
await mock.waitForRoster(_converse, 'current', 1);
const sender_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit';
await u.waitUntil(() => _converse.rosterview.el.querySelectorAll('.roster-group').length, 500);
await test_utils.openChatBoxFor(_converse, sender_jid);
await mock.openChatBoxFor(_converse, sender_jid);
const chatbox = _converse.chatboxes.get(sender_jid);
const msgFactory = () => test_utils.createChatMessage(_converse, sender_jid, 'This message will be received as unread, but eventually will be read');
const msgFactory = () => mock.createChatMessage(_converse, sender_jid, 'This message will be received as unread, but eventually will be read');
const selector = `a.open-chat:contains("${chatbox.get('nickname')}") .msgs-indicator`;
const select_msgs_indicator = () => sizzle(selector, _converse.rosterview.el).pop();
chatbox.save('scrolled', true);
@ -1508,21 +1507,21 @@ window.addEventListener('converse-loaded', () => {
['rosterGroupsFetched', 'chatBoxesFetched'], {},
async function (done, _converse) {
await test_utils.waitForRoster(_converse, 'current', 1);
await mock.waitForRoster(_converse, 'current', 1);
const sender_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit';
await u.waitUntil(() => _converse.rosterview.el.querySelectorAll('.roster-group').length, 500);
await test_utils.openChatBoxFor(_converse, sender_jid);
await mock.openChatBoxFor(_converse, sender_jid);
const chatbox = _converse.chatboxes.get(sender_jid);
const view = _converse.chatboxviews.get(sender_jid);
const msg = 'This message will be received as unread, but eventually will be read';
const msgFactory = () => test_utils.createChatMessage(_converse, sender_jid, msg);
const msgFactory = () => mock.createChatMessage(_converse, sender_jid, msg);
const selector = 'a.open-chat:contains("' + chatbox.get('nickname') + '") .msgs-indicator';
const select_msgs_indicator = () => sizzle(selector, _converse.rosterview.el).pop();
chatbox.save('scrolled', true);
_converse.handleMessageStanza(msgFactory());
await u.waitUntil(() => view.model.messages.length);
expect(select_msgs_indicator().textContent).toBe('1');
await test_utils.openChatBoxFor(_converse, sender_jid);
await mock.openChatBoxFor(_converse, sender_jid);
expect(select_msgs_indicator().textContent).toBe('1');
done();
}));
@ -1535,11 +1534,11 @@ window.addEventListener('converse-loaded', () => {
['rosterGroupsFetched', 'chatBoxesFetched'], {},
async function (done, _converse) {
await test_utils.waitForRoster(_converse, 'current', 1);
await mock.waitForRoster(_converse, 'current', 1);
const sender_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit';
await test_utils.openChatBoxFor(_converse, sender_jid);
await mock.openChatBoxFor(_converse, sender_jid);
const msgFactory = function () {
return test_utils.createChatMessage(_converse, sender_jid, 'This message will be received as unread, but eventually will be read');
return mock.createChatMessage(_converse, sender_jid, 'This message will be received as unread, but eventually will be read');
};
const selectUnreadMsgCount = function () {
const minimizedChatBoxView = _converse.minimized_chats.get(sender_jid);
@ -1563,11 +1562,11 @@ window.addEventListener('converse-loaded', () => {
['rosterGroupsFetched', 'chatBoxesFetched'], {},
async function (done, _converse) {
await test_utils.waitForRoster(_converse, 'current', 1);
await mock.waitForRoster(_converse, 'current', 1);
const sender_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit';
const view = await test_utils.openChatBoxFor(_converse, sender_jid)
const view = await mock.openChatBoxFor(_converse, sender_jid)
const msgFactory = function () {
return test_utils.createChatMessage(_converse, sender_jid,
return mock.createChatMessage(_converse, sender_jid,
'This message will be received as unread, but eventually will be read');
};
const selectUnreadMsgCount = function () {
@ -1588,15 +1587,15 @@ window.addEventListener('converse-loaded', () => {
['rosterGroupsFetched', 'chatBoxesFetched'], {},
async function (done, _converse) {
await test_utils.waitForRoster(_converse, 'current', 1);
await mock.waitForRoster(_converse, 'current', 1);
const message = "geo:37.786971,-122.399677",
contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit';
await test_utils.openChatBoxFor(_converse, contact_jid);
await mock.openChatBoxFor(_converse, contact_jid);
const view = _converse.chatboxviews.get(contact_jid);
spyOn(view.model, 'sendMessage').and.callThrough();
test_utils.sendMessage(view, message);
mock.sendMessage(view, message);
await u.waitUntil(() => view.el.querySelectorAll('.chat-content .chat-msg').length, 1000);
expect(view.model.sendMessage).toHaveBeenCalled();
const msg = sizzle('.chat-content .chat-msg:last .chat-msg__text', view.el).pop();
@ -1607,5 +1606,4 @@ window.addEventListener('converse-loaded', () => {
done();
}));
});
});
});

View File

@ -1,14 +1,13 @@
window.addEventListener('converse-loaded', () => {
const mock = window.mock;
const test_utils = window.test_utils;
const _ = converse.env._,
/*global mock */
const _ = converse.env._,
$msg = converse.env.$msg,
u = converse.env.utils,
Strophe = converse.env.Strophe,
sizzle = converse.env.sizzle;
describe("The Controlbox", function () {
describe("The Controlbox", function () {
it("can be opened by clicking a DOM element with class 'toggle-controlbox'",
mock.initConverse(
@ -43,7 +42,7 @@ window.addEventListener('converse-loaded', () => {
spyOn(_converse.api, "trigger").and.callThrough();
spyOn(_converse.rosterview, 'update').and.callThrough();
await test_utils.openControlBox(_converse);
await mock.openControlBox(_converse);
// Adding two contacts one with Capital initials and one with small initials of same JID (Case sensitive check)
_converse.roster.create({
jid: mock.pend_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit',
@ -69,11 +68,11 @@ window.addEventListener('converse-loaded', () => {
['rosterGroupsFetched', 'chatBoxesFetched'], {},
async function (done, _converse) {
await test_utils.waitForRoster(_converse, 'all');
await test_utils.openControlBox(_converse);
await mock.waitForRoster(_converse, 'all');
await mock.openControlBox(_converse);
const sender_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit';
await test_utils.openChatBoxFor(_converse, sender_jid);
await mock.openChatBoxFor(_converse, sender_jid);
await u.waitUntil(() => _converse.chatboxes.length);
const chatview = _converse.chatboxviews.get(sender_jid);
chatview.model.set({'minimized': true});
@ -119,7 +118,7 @@ window.addEventListener('converse-loaded', () => {
['rosterGroupsFetched'], {},
function (done, _converse) {
test_utils.openControlBox(_converse);
mock.openControlBox(_converse);
var view = _converse.xmppstatusview;
expect(u.hasClass('online', view.el.querySelector('.xmpp-status span:first-child'))).toBe(true);
expect(view.el.querySelector('.xmpp-status span.online').textContent.trim()).toBe('I am online');
@ -131,7 +130,7 @@ window.addEventListener('converse-loaded', () => {
['rosterGroupsFetched'], {},
async function (done, _converse) {
await test_utils.openControlBox(_converse);
await mock.openControlBox(_converse);
var cbview = _converse.chatboxviews.get('controlbox');
cbview.el.querySelector('.change-status').click()
var modal = _converse.xmppstatusview.status_modal;
@ -160,7 +159,7 @@ window.addEventListener('converse-loaded', () => {
['rosterGroupsFetched'], {},
async function (done, _converse) {
await test_utils.openControlBox(_converse);
await mock.openControlBox(_converse);
const cbview = _converse.chatboxviews.get('controlbox');
cbview.el.querySelector('.change-status').click()
const modal = _converse.xmppstatusview.status_modal;
@ -185,17 +184,17 @@ window.addEventListener('converse-loaded', () => {
done();
}));
});
});
});
describe("The 'Add Contact' widget", function () {
describe("The 'Add Contact' widget", function () {
it("opens up an add modal when you click on it",
mock.initConverse(
['rosterGroupsFetched'], {},
async function (done, _converse) {
await test_utils.waitForRoster(_converse, 'all');
await test_utils.openControlBox(_converse);
await mock.waitForRoster(_converse, 'all');
await mock.openControlBox(_converse);
const cbview = _converse.chatboxviews.get('controlbox');
cbview.el.querySelector('.add-contact').click()
@ -228,8 +227,8 @@ window.addEventListener('converse-loaded', () => {
['rosterGroupsFetched'], {'autocomplete_add_contact': false},
async function (done, _converse) {
await test_utils.waitForRoster(_converse, 'all', 0);
test_utils.openControlBox(_converse);
await mock.waitForRoster(_converse, 'all', 0);
mock.openControlBox(_converse);
const cbview = _converse.chatboxviews.get('controlbox');
cbview.el.querySelector('.add-contact').click()
const modal = _converse.rosterview.add_contact_modal;
@ -261,7 +260,7 @@ window.addEventListener('converse-loaded', () => {
{ 'xhr_user_search_url': 'http://example.org/?' },
async function (done, _converse) {
await test_utils.waitForRoster(_converse, 'all', 0);
await mock.waitForRoster(_converse, 'all', 0);
const xhr = {
'open': function open () {},
@ -318,8 +317,8 @@ window.addEventListener('converse-loaded', () => {
'xhr_user_search_url': 'http://example.org/?' },
async function (done, _converse) {
await test_utils.waitForRoster(_converse, 'all');
await test_utils.openControlBox(_converse);
await mock.waitForRoster(_converse, 'all');
await mock.openControlBox(_converse);
var modal;
const xhr = {
'open': function open () {},
@ -385,5 +384,4 @@ window.addEventListener('converse-loaded', () => {
window.XMLHttpRequest = XMLHttpRequestBackup;
done();
}));
});
});

View File

@ -1,10 +1,6 @@
window.addEventListener('converse-loaded', () => {
const mock = window.mock;
const test_utils = window.test_utils;
const _ = converse.env._,
u = converse.env.utils;
/* global mock */
describe("Converse", function() {
describe("Converse", function() {
describe("Authentication", function () {
@ -146,7 +142,7 @@ window.addEventListener('converse-loaded', () => {
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(
expect(() => _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();
@ -179,7 +175,7 @@ window.addEventListener('converse-loaded', () => {
describe("The \"tokens\" API", function () {
it("has a method for retrieving the next RID", mock.initConverse((done, _converse) => {
test_utils.createContacts(_converse, 'current');
mock.createContacts(_converse, 'current');
const old_connection = _converse.connection;
_converse.connection._proto.rid = '1234';
expect(_converse.api.tokens.get('rid')).toBe('1234');
@ -191,7 +187,7 @@ window.addEventListener('converse-loaded', () => {
}));
it("has a method for retrieving the SID", mock.initConverse((done, _converse) => {
test_utils.createContacts(_converse, 'current');
mock.createContacts(_converse, 'current');
const old_connection = _converse.connection;
_converse.connection._proto.sid = '1234';
expect(_converse.api.tokens.get('sid')).toBe('1234');
@ -208,7 +204,7 @@ window.addEventListener('converse-loaded', () => {
it("has a method 'get' which returns wrapped contacts",
mock.initConverse([], {}, async function (done, _converse) {
await test_utils.waitForRoster(_converse, 'current');
await mock.waitForRoster(_converse, 'current');
let contact = await _converse.api.contacts.get('non-existing@jabber.org');
expect(contact).toBeFalsy();
// Check when a single jid is given
@ -231,7 +227,7 @@ window.addEventListener('converse-loaded', () => {
it("has a method 'add' with which contacts can be added",
mock.initConverse(['rosterInitialized'], {}, async (done, _converse) => {
await test_utils.waitForRoster(_converse, 'current', 0);
await mock.waitForRoster(_converse, 'current', 0);
try {
await _converse.api.contacts.add();
throw new Error('Call should have failed');
@ -258,8 +254,10 @@ window.addEventListener('converse-loaded', () => {
['rosterInitialized', 'chatBoxesInitialized'], {},
async (done, _converse) => {
await test_utils.openControlBox(_converse);
await test_utils.waitForRoster(_converse, 'current', 2);
const u = converse.env.utils;
await mock.openControlBox(_converse);
await mock.waitForRoster(_converse, 'current', 2);
// Test on chat that doesn't exist.
let chat = await _converse.api.chats.get('non-existing@jabber.org');
@ -280,7 +278,7 @@ window.addEventListener('converse-loaded', () => {
const view = _converse.chatboxviews.get(jid);
await u.waitUntil(() => u.isVisible(view.el));
// Test for multiple JIDs
test_utils.openChatBoxFor(_converse, jid2);
mock.openChatBoxFor(_converse, jid2);
await u.waitUntil(() => _converse.chatboxes.length == 3);
const list = await _converse.api.chats.get([jid, jid2]);
expect(Array.isArray(list)).toBeTruthy();
@ -293,8 +291,9 @@ window.addEventListener('converse-loaded', () => {
['rosterGroupsFetched', 'chatBoxesInitialized'], {},
async (done, _converse) => {
await test_utils.openControlBox(_converse);
await test_utils.waitForRoster(_converse, 'current', 2);
const u = converse.env.utils;
await mock.openControlBox(_converse);
await mock.waitForRoster(_converse, 'current', 2);
const jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit';
const jid2 = mock.cur_names[1].replace(/ /g,'.').toLowerCase() + '@montague.lit';
@ -324,7 +323,7 @@ window.addEventListener('converse-loaded', () => {
it("has methods 'get' and 'set' to set configuration settings",
mock.initConverse(null, {'play_sounds': true}, (done, _converse) => {
expect(_.keys(_converse.api.settings)).toEqual(["update", "get", "set"]);
expect(Object.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);
@ -340,14 +339,14 @@ window.addEventListener('converse-loaded', () => {
describe("The \"plugins\" API", function() {
it("only has a method 'add' for registering plugins", mock.initConverse((done, _converse) => {
expect(_.keys(converse.plugins)).toEqual(["add"]);
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;
_converse.pluggable.plugins = [];
converse.plugins.add('plugin1', {});
expect(_.keys(_converse.pluggable.plugins)).toEqual(['plugin1']);
expect(Object.keys(_converse.pluggable.plugins)).toEqual(['plugin1']);
converse.plugins.add('plugin2', {});
expect(_.keys(_converse.pluggable.plugins)).toEqual(['plugin1', 'plugin2']);
expect(Object.keys(_converse.pluggable.plugins)).toEqual(['plugin1', 'plugin2']);
_converse.pluggable.plugins = _old_plugins;
done();
}));
@ -358,10 +357,9 @@ window.addEventListener('converse-loaded', () => {
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);
expect(() => converse.plugins.add('myplugin', {})).toThrow(error);
done();
}));
});
});
});
});

View File

@ -1,12 +1,6 @@
window.addEventListener('converse-loaded', () => {
const mock = window.mock;
const test_utils = window.test_utils;
const Strophe = converse.env.Strophe;
const $iq = converse.env.$iq;
const _ = converse.env._;
const u = converse.env.utils;
/*global mock */
describe("Service Discovery", function () {
describe("Service Discovery", function () {
describe("Whenever converse.js queries a server for its features", function () {
@ -15,10 +9,11 @@ window.addEventListener('converse-loaded', () => {
['discoInitialized'], {},
async function (done, _converse) {
const { u, $iq } = converse.env;
const IQ_stanzas = _converse.connection.IQ_stanzas;
const IQ_ids = _converse.connection.IQ_ids;
await u.waitUntil(function () {
return _.filter(IQ_stanzas, function (iq) {
return IQ_stanzas.filter(function (iq) {
return iq.querySelector('iq[to="montague.lit"] query[xmlns="http://jabber.org/protocol/disco#info"]');
}).length > 0;
});
@ -48,7 +43,7 @@ window.addEventListener('converse-loaded', () => {
* </query>
* </iq>
*/
let stanza = _.find(IQ_stanzas, function (iq) {
let stanza = IQ_stanzas.find(function (iq) {
return iq.querySelector('iq[to="montague.lit"] query[xmlns="http://jabber.org/protocol/disco#info"]');
});
const info_IQ_id = IQ_ids[IQ_stanzas.indexOf(stanza)];
@ -79,7 +74,7 @@ window.addEventListener('converse-loaded', () => {
'var': 'jabber:iq:time'}).up()
.c('feature', {
'var': 'jabber:iq:version'});
_converse.connection._dataRecv(test_utils.createRequest(stanza));
_converse.connection._dataRecv(mock.createRequest(stanza));
let entities = await _converse.api.disco.entities.get()
expect(entities.length).toBe(2); // We have an extra entity, which is the user's JID
@ -96,9 +91,7 @@ window.addEventListener('converse-loaded', () => {
await u.waitUntil(function () {
// Converse.js sees that the entity has a disco#items feature,
// so it will make a query for it.
return _.filter(IQ_stanzas, function (iq) {
return iq.querySelector('query[xmlns="http://jabber.org/protocol/disco#items"]');
}).length > 0;
return IQ_stanzas.filter(iq => iq.querySelector('query[xmlns="http://jabber.org/protocol/disco#items"]')).length > 0;
});
/* <iq type='result'
* from='catalog.shakespeare.lit'
@ -126,10 +119,10 @@ window.addEventListener('converse-loaded', () => {
* </query>
* </iq>
*/
stanza = _.find(IQ_stanzas, function (iq) {
stanza = IQ_stanzas.find(function (iq) {
return iq.querySelector('iq[to="montague.lit"] query[xmlns="http://jabber.org/protocol/disco#items"]');
});
var items_IQ_id = IQ_ids[IQ_stanzas.indexOf(stanza)];
const items_IQ_id = IQ_ids[IQ_stanzas.indexOf(stanza)];
stanza = $iq({
'type': 'result',
'from': 'montague.lit',
@ -158,14 +151,14 @@ window.addEventListener('converse-loaded', () => {
'node': 'music',
'name': 'Music from the time of Shakespeare'
});
_converse.connection._dataRecv(test_utils.createRequest(stanza));
_converse.connection._dataRecv(mock.createRequest(stanza));
await u.waitUntil(() => _converse.disco_entities);
entities = _converse.disco_entities;
expect(entities.length).toBe(2); // We have an extra entity, which is the user's JID
expect(entities.get(_converse.domain).items.length).toBe(3);
expect(_.includes(entities.get(_converse.domain).items.pluck('jid'), 'people.shakespeare.lit')).toBeTruthy();
expect(_.includes(entities.get(_converse.domain).items.pluck('jid'), 'plays.shakespeare.lit')).toBeTruthy();
expect(_.includes(entities.get(_converse.domain).items.pluck('jid'), 'words.shakespeare.lit')).toBeTruthy();
expect(entities.get(_converse.domain).items.pluck('jid').includes('people.shakespeare.lit')).toBeTruthy();
expect(entities.get(_converse.domain).items.pluck('jid').includes('plays.shakespeare.lit')).toBeTruthy();
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();
@ -178,6 +171,7 @@ window.addEventListener('converse-loaded', () => {
['discoInitialized'], {},
function (done, _converse) {
const { Strophe } = converse.env;
sinon.spy(_converse.api, "trigger");
_converse.disco_entities.get(_converse.domain).features.create({'var': Strophe.NS.MAM});
expect(_converse.api.trigger.called).toBe(true);
@ -186,5 +180,4 @@ window.addEventListener('converse-loaded', () => {
done();
}));
});
});
});

View File

@ -1,10 +1,9 @@
window.addEventListener('converse-loaded', () => {
const mock = window.mock;
const test_utils = window.test_utils;
const { Promise, $msg, $pres, sizzle } = converse.env;
const u = converse.env.utils;
/*global mock */
describe("Emojis", function () {
const { Promise, $msg, $pres, sizzle } = converse.env;
const u = converse.env.utils;
describe("Emojis", function () {
describe("The emoji picker", function () {
it("can be opened by clicking a button in the chat toolbar",
@ -13,9 +12,9 @@ window.addEventListener('converse-loaded', () => {
async function (done, _converse) {
const contact_jid = mock.cur_names[2].replace(/ /g,'.').toLowerCase() + '@montague.lit';
await test_utils.waitForRoster(_converse, 'current');
await test_utils.openControlBox(_converse);
await test_utils.openChatBoxFor(_converse, contact_jid);
await mock.waitForRoster(_converse, 'current');
await mock.openControlBox(_converse);
await mock.openChatBoxFor(_converse, contact_jid);
const view = _converse.chatboxviews.get(contact_jid);
const toolbar = await u.waitUntil(() => view.el.querySelector('ul.chat-toolbar'));
expect(toolbar.querySelectorAll('li.toggle-smiley__container').length).toBe(1);
@ -35,7 +34,7 @@ window.addEventListener('converse-loaded', () => {
async function (done, _converse) {
const muc_jid = 'lounge@montague.lit';
await test_utils.openAndEnterChatRoom(_converse, muc_jid, 'romeo');
await mock.openAndEnterChatRoom(_converse, muc_jid, 'romeo');
const view = _converse.chatboxviews.get(muc_jid);
const textarea = view.el.querySelector('textarea.chat-textarea');
@ -85,7 +84,7 @@ window.addEventListener('converse-loaded', () => {
'affiliation': 'member',
'role': 'participant'
});
_converse.connection._dataRecv(test_utils.createRequest(presence));
_converse.connection._dataRecv(mock.createRequest(presence));
textarea.value = ':use';
view.onKeyDown(tab_event);
@ -104,7 +103,7 @@ window.addEventListener('converse-loaded', () => {
async function (done, _converse) {
const muc_jid = 'lounge@montague.lit';
await test_utils.openAndEnterChatRoom(_converse, muc_jid, 'romeo');
await mock.openAndEnterChatRoom(_converse, muc_jid, 'romeo');
const view = _converse.chatboxviews.get(muc_jid);
const toolbar = view.el.querySelector('ul.chat-toolbar');
@ -156,7 +155,7 @@ window.addEventListener('converse-loaded', () => {
['rosterGroupsFetched', 'chatBoxesFetched'], {'use_system_emojis': true},
async function (done, _converse) {
await test_utils.waitForRoster(_converse, 'current');
await mock.waitForRoster(_converse, 'current');
const sender_jid = mock.cur_names[1].replace(/ /g,'.').toLowerCase() + '@montague.lit';
_converse.handleMessageStanza($msg({
'from': sender_jid,
@ -234,5 +233,4 @@ window.addEventListener('converse-loaded', () => {
done()
}));
});
});
});

View File

@ -1,7 +1,6 @@
window.addEventListener('converse-loaded', () => {
const mock = window.mock;
/*global mock */
return describe("The _converse Event Emitter", function() {
describe("The _converse Event Emitter", function() {
it("allows you to subscribe to emitted events", mock.initConverse((done, _converse) => {
this.callback = function () {};
@ -59,5 +58,4 @@ window.addEventListener('converse-loaded', () => {
expect(this.neverCalled).not.toHaveBeenCalled();
done();
}));
});
});

View File

@ -1,9 +1,8 @@
window.addEventListener('converse-loaded', () => {
const mock = window.mock;
const test_utils = window.test_utils;
const u = converse.env.utils;
/*global mock */
describe("A XEP-0317 MUC Hat", function () {
const u = converse.env.utils;
describe("A XEP-0317 MUC Hat", function () {
it("can be included in a presence stanza",
mock.initConverse(
@ -11,11 +10,11 @@ window.addEventListener('converse-loaded', () => {
async function (done, _converse) {
const muc_jid = 'lounge@montague.lit';
await test_utils.openAndEnterChatRoom(_converse, muc_jid, 'romeo');
await mock.openAndEnterChatRoom(_converse, muc_jid, 'romeo');
const view = _converse.chatboxviews.get(muc_jid);
const hat1_id = u.getUniqueId();
const hat2_id = u.getUniqueId();
_converse.connection._dataRecv(test_utils.createRequest(u.toStanza(`
_converse.connection._dataRecv(mock.createRequest(u.toStanza(`
<presence from="${muc_jid}/Terry" id="${u.getUniqueId()}" to="${_converse.jid}">
<x xmlns="http://jabber.org/protocol/muc#user">
<item affiliation="member" role="participant"/>
@ -33,7 +32,7 @@ window.addEventListener('converse-loaded', () => {
expect(hats.length).toBe(2);
expect(hats.map(h => h.title).join(' ')).toBe("Teacher's Assistant Dark Mage");
_converse.connection._dataRecv(test_utils.createRequest(u.toStanza(`
_converse.connection._dataRecv(mock.createRequest(u.toStanza(`
<message type="groupchat" from="${muc_jid}/Terry" id="${u.getUniqueId()}" to="${_converse.jid}">
<body>Hello world</body>
</message>
@ -45,7 +44,7 @@ window.addEventListener('converse-loaded', () => {
expect(badges.map(b => b.textContent.trim()).join(' ' )).toBe("Teacher's Assistant Dark Mage");
const hat3_id = u.getUniqueId();
_converse.connection._dataRecv(test_utils.createRequest(u.toStanza(`
_converse.connection._dataRecv(mock.createRequest(u.toStanza(`
<presence from="${muc_jid}/Terry" id="${u.getUniqueId()}" to="${_converse.jid}">
<x xmlns="http://jabber.org/protocol/muc#user">
<item affiliation="member" role="participant"/>
@ -65,7 +64,7 @@ window.addEventListener('converse-loaded', () => {
badges = Array.from(view.el.querySelectorAll('.chat-msg .badge'));
expect(badges.map(b => b.textContent.trim()).join(' ' )).toBe("Teacher's Assistant Dark Mage Mad hatter");
_converse.connection._dataRecv(test_utils.createRequest(u.toStanza(`
_converse.connection._dataRecv(mock.createRequest(u.toStanza(`
<presence from="${muc_jid}/Terry" id="${u.getUniqueId()}" to="${_converse.jid}">
<x xmlns="http://jabber.org/protocol/muc#user">
<item affiliation="member" role="participant"/>
@ -76,5 +75,4 @@ window.addEventListener('converse-loaded', () => {
await u.waitUntil(() => view.el.querySelectorAll('.chat-msg .badge').length === 0);
done();
}));
})
});
})

View File

@ -1,16 +1,12 @@
window.addEventListener('converse-loaded', () => {
const mock = window.mock;
const test_utils = window.test_utils;
const $msg = converse.env.$msg,
_ = converse.env._,
u = converse.env.utils;
/*global mock */
describe("A headlines box", function () {
describe("A headlines box", function () {
it("will not open nor display non-headline messages",
mock.initConverse(
['rosterGroupsFetched', 'chatBoxesFetched'], {}, function (done, _converse) {
const { u, $msg} = converse.env;
/* XMPP spam message:
*
* <message xmlns="jabber:client"
@ -30,7 +26,7 @@ window.addEventListener('converse-loaded', () => {
})
.c('nick', {'xmlns': "http://jabber.org/protocol/nick"}).t("-wwdmz").up()
.c('body').t('SORRY FOR THIS ADVERT');
_converse.connection._dataRecv(test_utils.createRequest(stanza));
_converse.connection._dataRecv(mock.createRequest(stanza));
expect(u.isHeadlineMessage.called).toBeTruthy();
expect(u.isHeadlineMessage.returned(false)).toBeTruthy();
expect(_converse.api.headlines.get().length === 0);
@ -41,6 +37,7 @@ window.addEventListener('converse-loaded', () => {
it("will open and display headline messages", mock.initConverse(
['rosterGroupsFetched'], {}, async function (done, _converse) {
const { u, $msg} = converse.env;
/* <message from='notify.example.com'
* to='romeo@im.example.com'
* type='headline'
@ -66,7 +63,7 @@ window.addEventListener('converse-loaded', () => {
.c('x', {'xmlns': 'jabber:x:oob'})
.c('url').t('imap://romeo@example.com/INBOX;UIDVALIDITY=385759043/;UID=18');
_converse.connection._dataRecv(test_utils.createRequest(stanza));
_converse.connection._dataRecv(mock.createRequest(stanza));
await u.waitUntil(() => _converse.chatboxviews.keys().includes('notify.example.com'));
expect(u.isHeadlineMessage.called).toBeTruthy();
expect(u.isHeadlineMessage.returned(true)).toBeTruthy();
@ -80,6 +77,7 @@ window.addEventListener('converse-loaded', () => {
it("will show headline messages in the controlbox", mock.initConverse(
['rosterGroupsFetched'], {}, async function (done, _converse) {
const { u, $msg} = converse.env;
/* <message from='notify.example.com'
* to='romeo@im.example.com'
* type='headline'
@ -104,7 +102,7 @@ window.addEventListener('converse-loaded', () => {
.c('x', {'xmlns': 'jabber:x:oob'})
.c('url').t('imap://romeo@example.com/INBOX;UIDVALIDITY=385759043/;UID=18');
_converse.connection._dataRecv(test_utils.createRequest(stanza));
_converse.connection._dataRecv(mock.createRequest(stanza));
const view = _converse.chatboxviews.get('controlbox');
await u.waitUntil(() => view.el.querySelectorAll(".open-headline").length);
expect(view.el.querySelectorAll('.open-headline').length).toBe(1);
@ -115,7 +113,8 @@ window.addEventListener('converse-loaded', () => {
it("will remove headline messages from the controlbox if closed", mock.initConverse(
['rosterGroupsFetched'], {}, async function (done, _converse) {
await test_utils.openControlBox(_converse);
const { u, $msg} = converse.env;
await mock.openControlBox(_converse);
/* <message from='notify.example.com'
* to='romeo@im.example.com'
* type='headline'
@ -140,7 +139,7 @@ window.addEventListener('converse-loaded', () => {
.c('x', {'xmlns': 'jabber:x:oob'})
.c('url').t('imap://romeo@example.com/INBOX;UIDVALIDITY=385759043/;UID=18');
_converse.connection._dataRecv(test_utils.createRequest(stanza));
_converse.connection._dataRecv(mock.createRequest(stanza));
const cbview = _converse.chatboxviews.get('controlbox');
await u.waitUntil(() => cbview.el.querySelectorAll(".open-headline").length);
const hlview = _converse.chatboxviews.get('notify.example.com');
@ -156,6 +155,7 @@ window.addEventListener('converse-loaded', () => {
mock.initConverse(
['rosterGroupsFetched', 'chatBoxesFetched'], {}, function (done, _converse) {
const { u, $msg, _ } = converse.env;
_converse.allow_non_roster_messaging = false;
sinon.spy(u, 'isHeadlineMessage');
const stanza = $msg({
@ -166,12 +166,11 @@ window.addEventListener('converse-loaded', () => {
})
.c('nick').t('gpocy').up()
.c('body').t('Здравствуйте друзья');
_converse.connection._dataRecv(test_utils.createRequest(stanza));
_converse.connection._dataRecv(mock.createRequest(stanza));
expect(_.without('controlbox', _converse.chatboxviews.keys()).length).toBe(0);
expect(u.isHeadlineMessage.called).toBeTruthy();
expect(u.isHeadlineMessage.returned(true)).toBeTruthy();
u.isHeadlineMessage.restore(); // unwraps
done();
}));
});
});

View File

@ -1,13 +1,12 @@
window.addEventListener('converse-loaded', () => {
const mock = window.mock;
const test_utils = window.test_utils;
const Strophe = converse.env.Strophe;
const $iq = converse.env.$iq;
const _ = converse.env._;
const sizzle = converse.env.sizzle;
const u = converse.env.utils;
/*global mock */
describe("XEP-0363: HTTP File Upload", function () {
const Strophe = converse.env.Strophe;
const $iq = converse.env.$iq;
const _ = converse.env._;
const sizzle = converse.env.sizzle;
const u = converse.env.utils;
describe("XEP-0363: HTTP File Upload", function () {
describe("Discovering support", function () {
@ -16,7 +15,7 @@ window.addEventListener('converse-loaded', () => {
['rosterGroupsFetched', 'chatBoxesFetched'], {},
async function (done, _converse) {
const IQ_stanzas = _converse.connection.IQ_stanzas;
await test_utils.waitUntilDiscoConfirmed(_converse, _converse.bare_jid, [], []);
await mock.waitUntilDiscoConfirmed(_converse, _converse.bare_jid, [], []);
let selector = 'iq[to="montague.lit"] query[xmlns="http://jabber.org/protocol/disco#info"]';
let stanza = await u.waitUntil(() => IQ_stanzas.find(iq => iq.querySelector(selector)), 1000);
@ -46,7 +45,7 @@ window.addEventListener('converse-loaded', () => {
'var': 'http://jabber.org/protocol/disco#info'}).up()
.c('feature', {
'var': 'http://jabber.org/protocol/disco#items'});
_converse.connection._dataRecv(test_utils.createRequest(stanza));
_converse.connection._dataRecv(mock.createRequest(stanza));
let entities = await _converse.api.disco.entities.get();
expect(entities.length).toBe(2);
@ -82,7 +81,7 @@ window.addEventListener('converse-loaded', () => {
'jid': 'upload.montague.lit',
'name': 'HTTP File Upload'});
_converse.connection._dataRecv(test_utils.createRequest(stanza));
_converse.connection._dataRecv(mock.createRequest(stanza));
_converse.api.disco.entities.get().then(entities => {
expect(entities.length).toBe(2);
@ -129,7 +128,7 @@ window.addEventListener('converse-loaded', () => {
.c('value').t('urn:xmpp:http:upload:0').up().up()
.c('field', {'var':'max-file-size'})
.c('value').t('5242880');
_converse.connection._dataRecv(test_utils.createRequest(stanza));
_converse.connection._dataRecv(mock.createRequest(stanza));
entities = await _converse.api.disco.entities.get();
expect(entities.get('montague.lit').items.get('upload.montague.lit').identities.where({'category': 'store'}).length).toBe(1);
@ -149,16 +148,16 @@ window.addEventListener('converse-loaded', () => {
it("does not appear in private chats",
mock.initConverse([], {}, async function (done, _converse) {
await test_utils.waitForRoster(_converse, 'current', 3);
test_utils.openControlBox(_converse);
await mock.waitForRoster(_converse, 'current', 3);
mock.openControlBox(_converse);
const contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit';
await test_utils.openChatBoxFor(_converse, contact_jid);
await test_utils.waitUntilDiscoConfirmed(
await mock.openChatBoxFor(_converse, contact_jid);
await mock.waitUntilDiscoConfirmed(
_converse, _converse.domain,
[{'category': 'server', 'type':'IM'}],
['http://jabber.org/protocol/disco#items'], [], 'info');
await test_utils.waitUntilDiscoConfirmed(_converse, _converse.domain, [], [], [], 'items');
await mock.waitUntilDiscoConfirmed(_converse, _converse.domain, [], [], [], 'items');
const view = _converse.chatboxviews.get(contact_jid);
expect(view.el.querySelector('.chat-toolbar .upload-file')).toBe(null);
done();
@ -168,14 +167,14 @@ window.addEventListener('converse-loaded', () => {
['rosterGroupsFetched'], {},
async (done, _converse) => {
await test_utils.openAndEnterChatRoom(_converse, 'lounge@montague.lit', 'romeo');
test_utils.waitUntilDiscoConfirmed(
await mock.openAndEnterChatRoom(_converse, 'lounge@montague.lit', 'romeo');
mock.waitUntilDiscoConfirmed(
_converse, _converse.domain,
[{'category': 'server', 'type':'IM'}],
['http://jabber.org/protocol/disco#items'], [], 'info');
await test_utils.waitUntilDiscoConfirmed(_converse, _converse.domain, [], [], ['upload.montague.lit'], 'items');
await test_utils.waitUntilDiscoConfirmed(_converse, 'upload.montague.lit', [], [Strophe.NS.HTTPUPLOAD], []);
await mock.waitUntilDiscoConfirmed(_converse, _converse.domain, [], [], ['upload.montague.lit'], 'items');
await mock.waitUntilDiscoConfirmed(_converse, 'upload.montague.lit', [], [Strophe.NS.HTTPUPLOAD], []);
const view = _converse.chatboxviews.get('lounge@montague.lit');
expect(view.el.querySelector('.chat-toolbar .upload-file')).toBe(null);
done();
@ -189,16 +188,16 @@ window.addEventListener('converse-loaded', () => {
describe("A file upload toolbar button", function () {
it("appears in private chats", mock.initConverse(async (done, _converse) => {
await test_utils.waitUntilDiscoConfirmed(
await mock.waitUntilDiscoConfirmed(
_converse, _converse.domain,
[{'category': 'server', 'type':'IM'}],
['http://jabber.org/protocol/disco#items'], [], 'info');
await test_utils.waitUntilDiscoConfirmed(_converse, _converse.domain, [], [], ['upload.montague.lit'], 'items')
await test_utils.waitUntilDiscoConfirmed(_converse, 'upload.montague.lit', [], [Strophe.NS.HTTPUPLOAD], []);
await test_utils.waitForRoster(_converse, 'current', 3);
await mock.waitUntilDiscoConfirmed(_converse, _converse.domain, [], [], ['upload.montague.lit'], 'items')
await mock.waitUntilDiscoConfirmed(_converse, 'upload.montague.lit', [], [Strophe.NS.HTTPUPLOAD], []);
await mock.waitForRoster(_converse, 'current', 3);
const contact_jid = mock.cur_names[2].replace(/ /g,'.').toLowerCase() + '@montague.lit';
await test_utils.openChatBoxFor(_converse, contact_jid);
await mock.openChatBoxFor(_converse, contact_jid);
const view = _converse.chatboxviews.get(contact_jid);
u.waitUntil(() => view.el.querySelector('.upload-file'));
expect(view.el.querySelector('.chat-toolbar .upload-file')).not.toBe(null);
@ -209,14 +208,14 @@ window.addEventListener('converse-loaded', () => {
['rosterGroupsFetched', 'chatBoxesFetched'], {},
async (done, _converse) => {
await test_utils.waitUntilDiscoConfirmed(
await mock.waitUntilDiscoConfirmed(
_converse, _converse.domain,
[{'category': 'server', 'type':'IM'}],
['http://jabber.org/protocol/disco#items'], [], 'info');
await test_utils.waitUntilDiscoConfirmed(_converse, _converse.domain, [], [], ['upload.montague.lit'], 'items');
await test_utils.waitUntilDiscoConfirmed(_converse, 'upload.montague.lit', [], [Strophe.NS.HTTPUPLOAD], []);
await test_utils.openAndEnterChatRoom(_converse, 'lounge@montague.lit', 'romeo');
await mock.waitUntilDiscoConfirmed(_converse, _converse.domain, [], [], ['upload.montague.lit'], 'items');
await mock.waitUntilDiscoConfirmed(_converse, 'upload.montague.lit', [], [Strophe.NS.HTTPUPLOAD], []);
await mock.openAndEnterChatRoom(_converse, 'lounge@montague.lit', 'romeo');
await u.waitUntil(() => _converse.chatboxviews.get('lounge@montague.lit').el.querySelector('.upload-file'));
const view = _converse.chatboxviews.get('lounge@montague.lit');
expect(view.el.querySelector('.chat-toolbar .upload-file')).not.toBe(null);
@ -227,7 +226,7 @@ window.addEventListener('converse-loaded', () => {
it("is uploaded and sent out", mock.initConverse(async (done, _converse) => {
const base_url = 'https://conversejs.org';
await test_utils.waitUntilDiscoConfirmed(
await mock.waitUntilDiscoConfirmed(
_converse, _converse.domain,
[{'category': 'server', 'type':'IM'}],
['http://jabber.org/protocol/disco#items'], [], 'info');
@ -235,11 +234,11 @@ window.addEventListener('converse-loaded', () => {
const send_backup = XMLHttpRequest.prototype.send;
const IQ_stanzas = _converse.connection.IQ_stanzas;
await test_utils.waitUntilDiscoConfirmed(_converse, _converse.domain, [], [], ['upload.montague.tld'], 'items');
await test_utils.waitUntilDiscoConfirmed(_converse, 'upload.montague.tld', [], [Strophe.NS.HTTPUPLOAD], []);
await test_utils.waitForRoster(_converse, 'current');
await mock.waitUntilDiscoConfirmed(_converse, _converse.domain, [], [], ['upload.montague.tld'], 'items');
await mock.waitUntilDiscoConfirmed(_converse, 'upload.montague.tld', [], [Strophe.NS.HTTPUPLOAD], []);
await mock.waitForRoster(_converse, 'current');
const contact_jid = mock.cur_names[2].replace(/ /g,'.').toLowerCase() + '@montague.lit';
await test_utils.openChatBoxFor(_converse, contact_jid);
await mock.openChatBoxFor(_converse, contact_jid);
const view = _converse.chatboxviews.get(contact_jid);
const file = {
'type': 'image/jpeg',
@ -300,7 +299,7 @@ window.addEventListener('converse-loaded', () => {
});
let sent_stanza;
spyOn(_converse.connection, 'send').and.callFake(stanza => (sent_stanza = stanza));
_converse.connection._dataRecv(test_utils.createRequest(stanza));
_converse.connection._dataRecv(mock.createRequest(stanza));
await u.waitUntil(() => sent_stanza, 1000);
expect(sent_stanza.toLocaleString()).toBe(
@ -329,7 +328,7 @@ window.addEventListener('converse-loaded', () => {
it("is uploaded and sent out from a groupchat", mock.initConverse(async (done, _converse) => {
const base_url = 'https://conversejs.org';
await test_utils.waitUntilDiscoConfirmed(
await mock.waitUntilDiscoConfirmed(
_converse, _converse.domain,
[{'category': 'server', 'type':'IM'}],
['http://jabber.org/protocol/disco#items'], [], 'info');
@ -337,9 +336,9 @@ window.addEventListener('converse-loaded', () => {
const send_backup = XMLHttpRequest.prototype.send;
const IQ_stanzas = _converse.connection.IQ_stanzas;
await test_utils.waitUntilDiscoConfirmed(_converse, _converse.domain, [], [], ['upload.montague.tld'], 'items');
await test_utils.waitUntilDiscoConfirmed(_converse, 'upload.montague.tld', [], [Strophe.NS.HTTPUPLOAD], []);
await test_utils.openAndEnterChatRoom(_converse, 'lounge@montague.lit', 'romeo');
await mock.waitUntilDiscoConfirmed(_converse, _converse.domain, [], [], ['upload.montague.tld'], 'items');
await mock.waitUntilDiscoConfirmed(_converse, 'upload.montague.tld', [], [Strophe.NS.HTTPUPLOAD], []);
await mock.openAndEnterChatRoom(_converse, 'lounge@montague.lit', 'romeo');
// Wait until MAM query has been sent out
const sent_stanzas = _converse.connection.sent_stanzas;
@ -404,7 +403,7 @@ window.addEventListener('converse-loaded', () => {
});
let sent_stanza;
spyOn(_converse.connection, 'send').and.callFake(stanza => (sent_stanza = stanza));
_converse.connection._dataRecv(test_utils.createRequest(stanza));
_converse.connection._dataRecv(mock.createRequest(stanza));
await u.waitUntil(() => sent_stanza, 1000);
expect(sent_stanza.toLocaleString()).toBe(
@ -437,7 +436,7 @@ window.addEventListener('converse-loaded', () => {
const IQ_stanzas = _converse.connection.IQ_stanzas;
const IQ_ids = _converse.connection.IQ_ids;
await test_utils.waitUntilDiscoConfirmed(_converse, _converse.bare_jid, [], []);
await mock.waitUntilDiscoConfirmed(_converse, _converse.bare_jid, [], []);
await u.waitUntil(() => _.filter(
IQ_stanzas,
iq => iq.querySelector('iq[to="montague.lit"] query[xmlns="http://jabber.org/protocol/disco#info"]')).length
@ -461,7 +460,7 @@ window.addEventListener('converse-loaded', () => {
'var': 'http://jabber.org/protocol/disco#info'}).up()
.c('feature', {
'var': 'http://jabber.org/protocol/disco#items'});
_converse.connection._dataRecv(test_utils.createRequest(stanza));
_converse.connection._dataRecv(mock.createRequest(stanza));
let entities = await _converse.api.disco.entities.get();
expect(entities.length).toBe(2);
@ -493,7 +492,7 @@ window.addEventListener('converse-loaded', () => {
'jid': 'upload.montague.lit',
'name': 'HTTP File Upload'});
_converse.connection._dataRecv(test_utils.createRequest(stanza));
_converse.connection._dataRecv(mock.createRequest(stanza));
entities = await _converse.api.disco.entities.get()
@ -524,14 +523,14 @@ window.addEventListener('converse-loaded', () => {
.c('value').t('urn:xmpp:http:upload:0').up().up()
.c('field', {'var':'max-file-size'})
.c('value').t('5242880');
_converse.connection._dataRecv(test_utils.createRequest(stanza));
_converse.connection._dataRecv(mock.createRequest(stanza));
entities = await _converse.api.disco.entities.get();
expect(entities.get('montague.lit').items.get('upload.montague.lit').identities.where({'category': 'store'}).length).toBe(1);
await _converse.api.disco.supports(Strophe.NS.HTTPUPLOAD, _converse.domain);
await test_utils.waitForRoster(_converse, 'current');
await mock.waitForRoster(_converse, 'current');
const contact_jid = mock.cur_names[2].replace(/ /g,'.').toLowerCase() + '@montague.lit';
await test_utils.openChatBoxFor(_converse, contact_jid);
await mock.openChatBoxFor(_converse, contact_jid);
const view = _converse.chatboxviews.get(contact_jid);
var file = {
'type': 'image/jpeg',
@ -556,18 +555,18 @@ window.addEventListener('converse-loaded', () => {
['rosterGroupsFetched', 'chatBoxesFetched'], {},
async function (done, _converse) {
await test_utils.waitUntilDiscoConfirmed(
await mock.waitUntilDiscoConfirmed(
_converse, _converse.domain,
[{'category': 'server', 'type':'IM'}],
['http://jabber.org/protocol/disco#items'], [], 'info');
const IQ_stanzas = _converse.connection.IQ_stanzas;
await test_utils.waitUntilDiscoConfirmed(_converse, _converse.domain, [], [], ['upload.montague.tld'], 'items');
await test_utils.waitUntilDiscoConfirmed(_converse, 'upload.montague.tld', [], [Strophe.NS.HTTPUPLOAD], []);
await test_utils.waitForRoster(_converse, 'current');
await mock.waitUntilDiscoConfirmed(_converse, _converse.domain, [], [], ['upload.montague.tld'], 'items');
await mock.waitUntilDiscoConfirmed(_converse, 'upload.montague.tld', [], [Strophe.NS.HTTPUPLOAD], []);
await mock.waitForRoster(_converse, 'current');
const contact_jid = mock.cur_names[2].replace(/ /g,'.').toLowerCase() + '@montague.lit';
await test_utils.openChatBoxFor(_converse, contact_jid);
await mock.openChatBoxFor(_converse, contact_jid);
const view = _converse.chatboxviews.get(contact_jid);
const file = {
'type': 'image/jpeg',
@ -620,9 +619,8 @@ window.addEventListener('converse-loaded', () => {
done();
});
});
_converse.connection._dataRecv(test_utils.createRequest(stanza));
_converse.connection._dataRecv(mock.createRequest(stanza));
}));
});
});
});
});

View File

@ -1,9 +1,8 @@
window.addEventListener('converse-loaded', () => {
const mock = window.mock;
const test_utils = window.test_utils;
const u = converse.env.utils;
/*global mock */
describe("The Login Form", function () {
const u = converse.env.utils;
describe("The Login Form", function () {
it("contains a checkbox to indicate whether the computer is trusted or not",
mock.initConverse(
@ -12,7 +11,7 @@ window.addEventListener('converse-loaded', () => {
allow_registration: false },
async function (done, _converse) {
test_utils.openControlBox(_converse);
mock.openControlBox(_converse);
const cbview = await u.waitUntil(() => _converse.chatboxviews.get('controlbox'));
const checkboxes = cbview.el.querySelectorAll('input[type="checkbox"]');
expect(checkboxes.length).toBe(1);
@ -50,7 +49,7 @@ window.addEventListener('converse-loaded', () => {
u.waitUntil(() => _converse.chatboxviews.get('controlbox'))
.then(() => {
var cbview = _converse.chatboxviews.get('controlbox');
test_utils.openControlBox(_converse);
mock.openControlBox(_converse);
const checkboxes = cbview.el.querySelectorAll('input[type="checkbox"]');
expect(checkboxes.length).toBe(1);
@ -75,5 +74,4 @@ window.addEventListener('converse-loaded', () => {
done();
});
}));
});
});

View File

@ -1,17 +1,16 @@
window.addEventListener('converse-loaded', () => {
const mock = window.mock;
const test_utils = window.test_utils;
const Model = converse.env.Model;
const Strophe = converse.env.Strophe;
const $iq = converse.env.$iq;
const $msg = converse.env.$msg;
const dayjs = converse.env.dayjs;
const u = converse.env.utils;
const sizzle = converse.env.sizzle;
// See: https://xmpp.org/rfcs/rfc3921.html
/*global mock */
// Implements the protocol defined in https://xmpp.org/extensions/xep-0313.html#config
describe("Message Archive Management", function () {
const Model = converse.env.Model;
const Strophe = converse.env.Strophe;
const $iq = converse.env.$iq;
const $msg = converse.env.$msg;
const dayjs = converse.env.dayjs;
const u = converse.env.utils;
const sizzle = converse.env.sizzle;
// See: https://xmpp.org/rfcs/rfc3921.html
// Implements the protocol defined in https://xmpp.org/extensions/xep-0313.html#config
describe("Message Archive Management", function () {
describe("The XEP-0313 Archive", function () {
@ -20,7 +19,7 @@ window.addEventListener('converse-loaded', () => {
const sent_IQs = _converse.connection.IQ_stanzas;
const muc_jid = 'orchard@chat.shakespeare.lit';
await test_utils.openAndEnterChatRoom(_converse, muc_jid, 'romeo');
await mock.openAndEnterChatRoom(_converse, muc_jid, 'romeo');
let view = _converse.chatboxviews.get(muc_jid);
let iq_get = await u.waitUntil(() => sent_IQs.filter(iq => iq.querySelector(`iq query[xmlns="${Strophe.NS.MAM}"]`)).pop());
expect(Strophe.serialize(iq_get)).toBe(
@ -48,7 +47,7 @@ window.addEventListener('converse-loaded', () => {
</forwarded>
</result>
</message>`);
_converse.connection._dataRecv(test_utils.createRequest(message));
_converse.connection._dataRecv(mock.createRequest(message));
message = u.toStanza(
`<message xmlns="jabber:client"
@ -63,7 +62,7 @@ window.addEventListener('converse-loaded', () => {
</forwarded>
</result>
</message>`);
_converse.connection._dataRecv(test_utils.createRequest(message));
_converse.connection._dataRecv(mock.createRequest(message));
// Clear so that we don't match the older query
while (sent_IQs.length) { sent_IQs.pop(); }
@ -83,7 +82,7 @@ window.addEventListener('converse-loaded', () => {
</set>
</fin>
</iq>`);
_converse.connection._dataRecv(test_utils.createRequest(result));
_converse.connection._dataRecv(mock.createRequest(result));
await u.waitUntil(() => view.model.messages.length === 2);
view.close();
// Clear so that we don't match the older query
@ -91,7 +90,7 @@ window.addEventListener('converse-loaded', () => {
await u.waitUntil(() => _converse.chatboxes.length === 1);
await test_utils.openAndEnterChatRoom(_converse, muc_jid, 'romeo');
await mock.openAndEnterChatRoom(_converse, muc_jid, 'romeo');
view = _converse.chatboxviews.get(muc_jid);
await u.waitUntil(() => view.model.messages.length);
@ -121,7 +120,7 @@ window.addEventListener('converse-loaded', () => {
</forwarded>
</result>
</message>`);
_converse.connection._dataRecv(test_utils.createRequest(message));
_converse.connection._dataRecv(mock.createRequest(message));
message = u.toStanza(
`<message xmlns="jabber:client"
@ -136,7 +135,7 @@ window.addEventListener('converse-loaded', () => {
</forwarded>
</result>
</message>`);
_converse.connection._dataRecv(test_utils.createRequest(message));
_converse.connection._dataRecv(mock.createRequest(message));
// Clear so that we don't match the older query
while (sent_IQs.length) { sent_IQs.pop(); }
@ -151,7 +150,7 @@ window.addEventListener('converse-loaded', () => {
</set>
</fin>
</iq>`);
_converse.connection._dataRecv(test_utils.createRequest(result));
_converse.connection._dataRecv(mock.createRequest(result));
await u.waitUntil(() => view.model.messages.length === 4);
iq_get = await u.waitUntil(() => sent_IQs.filter(iq => iq.querySelector(`iq query[xmlns="${Strophe.NS.MAM}"]`)).pop());
@ -181,7 +180,7 @@ window.addEventListener('converse-loaded', () => {
</forwarded>
</result>
</message>`);
_converse.connection._dataRecv(test_utils.createRequest(message));
_converse.connection._dataRecv(mock.createRequest(message));
result = u.toStanza(
`<iq type='result' id='${iq_get.getAttribute('id')}'>
@ -193,7 +192,7 @@ window.addEventListener('converse-loaded', () => {
</set>
</fin>
</iq>`);
_converse.connection._dataRecv(test_utils.createRequest(result));
_converse.connection._dataRecv(mock.createRequest(result));
await u.waitUntil(() => view.model.messages.length === 5);
const msg_els = view.content.querySelectorAll('.chat-msg__text');
expect(Array.from(msg_els).map(e => e.textContent).join(' ')).toBe("2nd Message 3rd Message 4th Message 5th Message 6th Message");
@ -210,10 +209,10 @@ window.addEventListener('converse-loaded', () => {
['discoInitialized'], {},
async function (done, _converse) {
await test_utils.waitForRoster(_converse, 'current', 1);
await mock.waitForRoster(_converse, 'current', 1);
const contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit';
await test_utils.openChatBoxFor(_converse, contact_jid);
await test_utils.waitUntilDiscoConfirmed(_converse, _converse.bare_jid, null, [Strophe.NS.MAM]);
await mock.openChatBoxFor(_converse, contact_jid);
await mock.waitUntilDiscoConfirmed(_converse, _converse.bare_jid, null, [Strophe.NS.MAM]);
const sent_IQs = _converse.connection.IQ_stanzas;
const stanza = await u.waitUntil(() => sent_IQs.filter(iq => iq.querySelector(`iq[type="set"] query[xmlns="${Strophe.NS.MAM}"]`)).pop());
const queryid = stanza.querySelector('query').getAttribute('queryid');
@ -229,7 +228,7 @@ window.addEventListener('converse-loaded', () => {
'type':'chat'
}).c('body').t("Meet me at the dance");
spyOn(converse.env.log, 'warn');
_converse.connection._dataRecv(test_utils.createRequest(msg));
_converse.connection._dataRecv(mock.createRequest(msg));
expect(converse.env.log.warn).toHaveBeenCalledWith(`Ignoring alleged MAM message from ${msg.nodeTree.getAttribute('from')}`);
msg = $msg({'id': _converse.connection.getUniqueId(), 'to': _converse.bare_jid})
@ -243,7 +242,7 @@ window.addEventListener('converse-loaded', () => {
'from': contact_jid,
'type':'chat'
}).c('body').t("Thrice the brinded cat hath mew'd.");
_converse.connection._dataRecv(test_utils.createRequest(msg));
_converse.connection._dataRecv(mock.createRequest(msg));
const iq_result = $iq({'type': 'result', 'id': stanza.getAttribute('id')})
.c('fin', {'xmlns': 'urn:xmpp:mam:2'})
@ -251,7 +250,7 @@ window.addEventListener('converse-loaded', () => {
.c('first', {'index': '0'}).t('23452-4534-1').up()
.c('last').t('09af3-cc343-b409f').up()
.c('count').t('16');
_converse.connection._dataRecv(test_utils.createRequest(iq_result));
_converse.connection._dataRecv(mock.createRequest(iq_result));
const view = _converse.chatboxviews.get(contact_jid);
await new Promise(resolve => view.once('messageInserted', resolve));
@ -266,7 +265,7 @@ window.addEventListener('converse-loaded', () => {
['discoInitialized'], {},
async function (done, _converse) {
await test_utils.openAndEnterChatRoom(_converse, 'trek-radio@conference.lightwitch.org', 'romeo');
await mock.openAndEnterChatRoom(_converse, 'trek-radio@conference.lightwitch.org', 'romeo');
const view = _converse.chatboxviews.get('trek-radio@conference.lightwitch.org');
let stanza = u.toStanza(
@ -274,7 +273,7 @@ window.addEventListener('converse-loaded', () => {
<body>Hello</body>
<stanza-id xmlns="urn:xmpp:sid:0" id="45fbbf2a-1059-479d-9283-c8effaf05621" by="trek-radio@conference.lightwitch.org"/>
</message>`);
_converse.connection._dataRecv(test_utils.createRequest(stanza));
_converse.connection._dataRecv(mock.createRequest(stanza));
await u.waitUntil(() => view.content.querySelectorAll('.chat-msg').length);
expect(view.model.messages.length).toBe(1);
expect(view.model.messages.at(0).get('is_archived')).toBe(false);
@ -314,14 +313,14 @@ window.addEventListener('converse-loaded', () => {
['discoInitialized'], {},
async function (done, _converse) {
await test_utils.openAndEnterChatRoom(_converse, 'trek-radio@conference.lightwitch.org', 'jcbrand');
await mock.openAndEnterChatRoom(_converse, 'trek-radio@conference.lightwitch.org', 'jcbrand');
const view = _converse.chatboxviews.get('trek-radio@conference.lightwitch.org');
let stanza = u.toStanza(
`<message xmlns="jabber:client" to="jcbrand@lightwitch.org/converse.js-73057452" type="groupchat" from="trek-radio@conference.lightwitch.org/comndrdukath#0805 (STO)">
<body>negan</body>
<stanza-id xmlns="urn:xmpp:sid:0" id="45fbbf2a-1059-479d-9283-c8effaf05621" by="trek-radio@conference.lightwitch.org"/>
</message>`);
_converse.connection._dataRecv(test_utils.createRequest(stanza));
_converse.connection._dataRecv(mock.createRequest(stanza));
await u.waitUntil(() => view.content.querySelectorAll('.chat-msg').length);
// Not sure whether such a race-condition might pose a problem
// in "real-world" situations.
@ -353,7 +352,7 @@ window.addEventListener('converse-loaded', () => {
['discoInitialized'], {},
async function (done, _converse) {
await test_utils.openAndEnterChatRoom(_converse, 'discuss@conference.conversejs.org', 'romeo');
await mock.openAndEnterChatRoom(_converse, 'discuss@conference.conversejs.org', 'romeo');
const view = _converse.chatboxviews.get('discuss@conference.conversejs.org');
let stanza = u.toStanza(
`<message xmlns="jabber:client" to="romeo@montague.lit/orchard" from="discuss@conference.conversejs.org">
@ -406,7 +405,7 @@ window.addEventListener('converse-loaded', () => {
mock.initConverse(['discoInitialized'], {}, async function (done, _converse) {
const sendIQ = _converse.connection.sendIQ;
await test_utils.waitUntilDiscoConfirmed(_converse, _converse.bare_jid, null, [Strophe.NS.MAM]);
await mock.waitUntilDiscoConfirmed(_converse, _converse.bare_jid, null, [Strophe.NS.MAM]);
let sent_stanza, IQ_id;
spyOn(_converse.connection, 'sendIQ').and.callFake(function (iq, callback, errback) {
sent_stanza = iq;
@ -423,7 +422,7 @@ window.addEventListener('converse-loaded', () => {
it("can be used to query for all messages to/from a particular JID",
mock.initConverse([], {}, async function (done, _converse) {
await test_utils.waitUntilDiscoConfirmed(_converse, _converse.bare_jid, null, [Strophe.NS.MAM]);
await mock.waitUntilDiscoConfirmed(_converse, _converse.bare_jid, null, [Strophe.NS.MAM]);
let sent_stanza, IQ_id;
const sendIQ = _converse.connection.sendIQ;
spyOn(_converse.connection, 'sendIQ').and.callFake(function (iq, callback, errback) {
@ -454,7 +453,7 @@ window.addEventListener('converse-loaded', () => {
const room_jid = 'coven@chat.shakespeare.lit';
_converse.api.archive.query({'with': room_jid, 'groupchat': true});
await test_utils.waitUntilDiscoConfirmed(_converse, room_jid, null, [Strophe.NS.MAM]);
await mock.waitUntilDiscoConfirmed(_converse, room_jid, null, [Strophe.NS.MAM]);
const sent_stanzas = _converse.connection.sent_stanzas;
const stanza = await u.waitUntil(
@ -480,7 +479,7 @@ window.addEventListener('converse-loaded', () => {
const room_jid = 'coven@chat.shakespeare.lit';
const promise = _converse.api.archive.query({'with': room_jid, 'groupchat': true, 'max':'10'});
await test_utils.waitUntilDiscoConfirmed(_converse, room_jid, null, [Strophe.NS.MAM]);
await mock.waitUntilDiscoConfirmed(_converse, room_jid, null, [Strophe.NS.MAM]);
const sent_stanzas = _converse.connection.sent_stanzas;
const sent_stanza = await u.waitUntil(
@ -517,7 +516,7 @@ window.addEventListener('converse-loaded', () => {
'from':'coven@chat.shakespeare.lit/firstwitch',
'type':'groupchat' })
.c('body').t("Thrice the brinded cat hath mew'd.");
_converse.connection._dataRecv(test_utils.createRequest(msg1));
_converse.connection._dataRecv(mock.createRequest(msg1));
/* Send an <iq> stanza to indicate the end of the result set.
*
@ -536,7 +535,7 @@ window.addEventListener('converse-loaded', () => {
.c('first', {'index': '0'}).t('23452-4534-1').up()
.c('last').t('09af3-cc343-b409f').up()
.c('count').t('16');
_converse.connection._dataRecv(test_utils.createRequest(stanza));
_converse.connection._dataRecv(mock.createRequest(stanza));
const result = await promise;
expect(result.messages.length).toBe(0);
@ -546,7 +545,7 @@ window.addEventListener('converse-loaded', () => {
it("can be used to query for all messages in a certain timespan",
mock.initConverse([], {}, async function (done, _converse) {
await test_utils.waitUntilDiscoConfirmed(_converse, _converse.bare_jid, null, [Strophe.NS.MAM]);
await mock.waitUntilDiscoConfirmed(_converse, _converse.bare_jid, null, [Strophe.NS.MAM]);
let sent_stanza, IQ_id;
const sendIQ = _converse.connection.sendIQ;
spyOn(_converse.connection, 'sendIQ').and.callFake(function (iq, callback, errback) {
@ -584,7 +583,7 @@ window.addEventListener('converse-loaded', () => {
it("throws a TypeError if an invalid date is provided",
mock.initConverse([], {}, async function (done, _converse) {
await test_utils.waitUntilDiscoConfirmed(_converse, _converse.bare_jid, null, [Strophe.NS.MAM]);
await mock.waitUntilDiscoConfirmed(_converse, _converse.bare_jid, null, [Strophe.NS.MAM]);
try {
await _converse.api.archive.query({'start': 'not a real date'});
} catch (e) {
@ -596,7 +595,7 @@ window.addEventListener('converse-loaded', () => {
it("can be used to query for all messages after a certain time",
mock.initConverse([], {}, async function (done, _converse) {
await test_utils.waitUntilDiscoConfirmed(_converse, _converse.bare_jid, null, [Strophe.NS.MAM]);
await mock.waitUntilDiscoConfirmed(_converse, _converse.bare_jid, null, [Strophe.NS.MAM]);
let sent_stanza, IQ_id;
const sendIQ = _converse.connection.sendIQ;
spyOn(_converse.connection, 'sendIQ').and.callFake(function (iq, callback, errback) {
@ -630,7 +629,7 @@ window.addEventListener('converse-loaded', () => {
it("can be used to query for a limited set of results",
mock.initConverse([], {}, async function (done, _converse) {
await test_utils.waitUntilDiscoConfirmed(_converse, _converse.bare_jid, null, [Strophe.NS.MAM]);
await mock.waitUntilDiscoConfirmed(_converse, _converse.bare_jid, null, [Strophe.NS.MAM]);
let sent_stanza, IQ_id;
const sendIQ = _converse.connection.sendIQ;
spyOn(_converse.connection, 'sendIQ').and.callFake(function (iq, callback, errback) {
@ -664,7 +663,7 @@ window.addEventListener('converse-loaded', () => {
it("can be used to page through results",
mock.initConverse([], {}, async function (done, _converse) {
await test_utils.waitUntilDiscoConfirmed(_converse, _converse.bare_jid, null, [Strophe.NS.MAM]);
await mock.waitUntilDiscoConfirmed(_converse, _converse.bare_jid, null, [Strophe.NS.MAM]);
let sent_stanza, IQ_id;
const sendIQ = _converse.connection.sendIQ;
spyOn(_converse.connection, 'sendIQ').and.callFake(function (iq, callback, errback) {
@ -702,7 +701,7 @@ window.addEventListener('converse-loaded', () => {
it("accepts \"before\" with an empty string as value to reverse the order",
mock.initConverse([], {}, async function (done, _converse) {
await test_utils.waitUntilDiscoConfirmed(_converse, _converse.bare_jid, null, [Strophe.NS.MAM]);
await mock.waitUntilDiscoConfirmed(_converse, _converse.bare_jid, null, [Strophe.NS.MAM]);
let sent_stanza, IQ_id;
const sendIQ = _converse.connection.sendIQ;
spyOn(_converse.connection, 'sendIQ').and.callFake(function (iq, callback, errback) {
@ -732,7 +731,7 @@ window.addEventListener('converse-loaded', () => {
it("accepts a _converse.RSM object for the query options",
mock.initConverse([], {}, async function (done, _converse) {
await test_utils.waitUntilDiscoConfirmed(_converse, _converse.bare_jid, null, [Strophe.NS.MAM]);
await mock.waitUntilDiscoConfirmed(_converse, _converse.bare_jid, null, [Strophe.NS.MAM]);
let sent_stanza, IQ_id;
const sendIQ = _converse.connection.sendIQ;
spyOn(_converse.connection, 'sendIQ').and.callFake(function (iq, callback, errback) {
@ -774,7 +773,7 @@ window.addEventListener('converse-loaded', () => {
it("returns an object which includes the messages and a _converse.RSM object",
mock.initConverse([], {}, async function (done, _converse) {
await test_utils.waitUntilDiscoConfirmed(_converse, _converse.bare_jid, null, [Strophe.NS.MAM]);
await mock.waitUntilDiscoConfirmed(_converse, _converse.bare_jid, null, [Strophe.NS.MAM]);
let sent_stanza, IQ_id;
const sendIQ = _converse.connection.sendIQ;
spyOn(_converse.connection, 'sendIQ').and.callFake(function (iq, callback, errback) {
@ -809,7 +808,7 @@ window.addEventListener('converse-loaded', () => {
'from':'romeo@montague.lit/orchard',
'type':'chat' })
.c('body').t("Call me but love, and I'll be new baptized;");
_converse.connection._dataRecv(test_utils.createRequest(msg1));
_converse.connection._dataRecv(mock.createRequest(msg1));
const msg2 = $msg({'id':'aeb213', 'to':'juliet@capulet.lit/chamber'})
.c('result', {'xmlns': 'urn:xmpp:mam:2', 'queryid':queryid, 'id':'28482-98726-73624'})
@ -821,7 +820,7 @@ window.addEventListener('converse-loaded', () => {
'from':'romeo@montague.lit/orchard',
'type':'chat' })
.c('body').t("Henceforth I never will be Romeo.");
_converse.connection._dataRecv(test_utils.createRequest(msg2));
_converse.connection._dataRecv(mock.createRequest(msg2));
/* Send an <iq> stanza to indicate the end of the result set.
*
@ -840,7 +839,7 @@ window.addEventListener('converse-loaded', () => {
.c('first', {'index': '0'}).t('23452-4534-1').up()
.c('last').t('09af3-cc343-b409f').up()
.c('count').t('16');
_converse.connection._dataRecv(test_utils.createRequest(stanza));
_converse.connection._dataRecv(mock.createRequest(stanza));
const result = await promise;
expect(result.messages.length).toBe(2);
@ -891,7 +890,7 @@ window.addEventListener('converse-loaded', () => {
.c('prefs', {'xmlns': Strophe.NS.MAM, 'default':'roster'})
.c('always').c('jid').t('romeo@montague.lit').up().up()
.c('never').c('jid').t('montague@montague.lit');
_converse.connection._dataRecv(test_utils.createRequest(stanza));
_converse.connection._dataRecv(mock.createRequest(stanza));
await u.waitUntil(() => _converse.onMAMPreferences.calls.count());
expect(_converse.onMAMPreferences).toHaveBeenCalled();
@ -922,25 +921,25 @@ window.addEventListener('converse-loaded', () => {
.c('prefs', {'xmlns': Strophe.NS.MAM, 'default':'always'})
.c('always').up()
.c('never');
_converse.connection._dataRecv(test_utils.createRequest(stanza));
_converse.connection._dataRecv(mock.createRequest(stanza));
await u.waitUntil(() => feature.save.calls.count());
expect(feature.save).toHaveBeenCalled();
expect(feature.get('preferences')['default']).toBe('never'); // eslint-disable-line dot-notation
done();
}));
});
});
});
describe("Chatboxes", function () {
describe("Chatboxes", function () {
describe("A Chatbox", function () {
it("will fetch archived messages once it's opened",
mock.initConverse(['discoInitialized'], {}, async function (done, _converse) {
await test_utils.waitForRoster(_converse, 'current', 1);
await mock.waitForRoster(_converse, 'current', 1);
const contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit';
await test_utils.openChatBoxFor(_converse, contact_jid);
await test_utils.waitUntilDiscoConfirmed(_converse, _converse.bare_jid, null, [Strophe.NS.MAM]);
await mock.openChatBoxFor(_converse, contact_jid);
await mock.waitUntilDiscoConfirmed(_converse, _converse.bare_jid, null, [Strophe.NS.MAM]);
let sent_stanza, IQ_id;
const sendIQ = _converse.connection.sendIQ;
@ -972,7 +971,7 @@ window.addEventListener('converse-loaded', () => {
'from': _converse.bare_jid,
'type':'chat' })
.c('body').t("Call me but love, and I'll be new baptized;");
_converse.connection._dataRecv(test_utils.createRequest(msg1));
_converse.connection._dataRecv(mock.createRequest(msg1));
const msg2 = $msg({'id':'aeb213', 'to': contact_jid})
.c('result', {'xmlns': 'urn:xmpp:mam:2', 'queryid':queryid, 'id':'28482-98726-73624'})
.c('forwarded', {'xmlns':'urn:xmpp:forward:0'})
@ -983,14 +982,14 @@ window.addEventListener('converse-loaded', () => {
'from': _converse.bare_jid,
'type':'chat' })
.c('body').t("Henceforth I never will be Romeo.");
_converse.connection._dataRecv(test_utils.createRequest(msg2));
_converse.connection._dataRecv(mock.createRequest(msg2));
const stanza = $iq({'type': 'result', 'id': IQ_id})
.c('fin', {'xmlns': 'urn:xmpp:mam:2'})
.c('set', {'xmlns': 'http://jabber.org/protocol/rsm'})
.c('first', {'index': '0'}).t('23452-4534-1').up()
.c('last').t('09af3-cc343-b409f').up()
.c('count').t('16');
_converse.connection._dataRecv(test_utils.createRequest(stanza));
_converse.connection._dataRecv(mock.createRequest(stanza));
done();
}));
@ -1013,10 +1012,10 @@ window.addEventListener('converse-loaded', () => {
}
}
});
await test_utils.waitForRoster(_converse, 'current', 1);
await mock.waitForRoster(_converse, 'current', 1);
const contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit';
await test_utils.openChatBoxFor(_converse, contact_jid);
await test_utils.waitUntilDiscoConfirmed(_converse, _converse.bare_jid, null, [Strophe.NS.MAM]);
await mock.openChatBoxFor(_converse, contact_jid);
await mock.waitUntilDiscoConfirmed(_converse, _converse.bare_jid, null, [Strophe.NS.MAM]);
const IQ_stanzas = _converse.connection.IQ_stanzas;
let sent_stanza = await u.waitUntil(() => IQ_stanzas.filter(iq => sizzle('query[xmlns="urn:xmpp:mam:2"]', iq).length).pop());
@ -1069,7 +1068,7 @@ window.addEventListener('converse-loaded', () => {
'from': _converse.bare_jid,
'type':'chat' })
.c('body').t("Call me but love, and I'll be new baptized;");
_converse.connection._dataRecv(test_utils.createRequest(msg1));
_converse.connection._dataRecv(mock.createRequest(msg1));
const msg2 = $msg({'id':'aeb213', 'to': contact_jid})
.c('result', {'xmlns': 'urn:xmpp:mam:2', 'queryid': queryid, 'id':'28482-98726-73624'})
@ -1081,7 +1080,7 @@ window.addEventListener('converse-loaded', () => {
'from': _converse.bare_jid,
'type':'chat' })
.c('body').t("Henceforth I never will be Romeo.");
_converse.connection._dataRecv(test_utils.createRequest(msg2));
_converse.connection._dataRecv(mock.createRequest(msg2));
const stanza = $iq({'type': 'result', 'id': sent_stanza.getAttribute('id')})
.c('fin', {'xmlns': 'urn:xmpp:mam:2', 'complete': true})
@ -1089,12 +1088,11 @@ window.addEventListener('converse-loaded', () => {
.c('first', {'index': '0'}).t('28482-98726-73623').up()
.c('last').t('28482-98726-73624').up()
.c('count').t('2');
_converse.connection._dataRecv(test_utils.createRequest(stanza));
_converse.connection._dataRecv(mock.createRequest(stanza));
await u.waitUntil(() => view.model.messages.length === 2, 500);
err_message = view.el.querySelector('.message.chat-error');
expect(err_message).toBe(null);
done();
}));
});
});
});

View File

@ -1,21 +1,20 @@
window.addEventListener('converse-loaded', () => {
const mock = window.mock;
const test_utils = window.test_utils;
const { Promise, Strophe, $msg, dayjs, sizzle, _ } = converse.env;
const u = converse.env.utils;
/*global mock */
const { Promise, Strophe, $msg, dayjs, sizzle, _ } = converse.env;
const u = converse.env.utils;
describe("A Chat Message", function () {
describe("A Chat Message", function () {
it("is rejected if it's an unencapsulated forwarded message",
mock.initConverse(
['rosterGroupsFetched', 'chatBoxesFetched'], {},
async function (done, _converse) {
await test_utils.waitForRoster(_converse, 'current', 2);
await mock.waitForRoster(_converse, 'current', 2);
const contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit';
const forwarded_contact_jid = mock.cur_names[1].replace(/ /g,'.').toLowerCase() + '@montague.lit';
await test_utils.openChatBoxFor(_converse, contact_jid);
await mock.openChatBoxFor(_converse, contact_jid);
let models = await _converse.api.chats.get();
expect(models.length).toBe(1);
const received_stanza = u.toStanza(`
@ -36,7 +35,7 @@ window.addEventListener('converse-loaded', () => {
</forwarded>
</message>
`);
_converse.connection._dataRecv(test_utils.createRequest(received_stanza));
_converse.connection._dataRecv(mock.createRequest(received_stanza));
const sent_stanzas = _converse.connection.sent_stanzas;
const sent_stanza = await u.waitUntil(() => sent_stanzas.filter(s => s.querySelector('error')).pop());
expect(Strophe.serialize(sent_stanza)).toBe(
@ -57,10 +56,10 @@ window.addEventListener('converse-loaded', () => {
['rosterGroupsFetched', 'chatBoxesFetched'], {},
async function (done, _converse) {
await test_utils.waitForRoster(_converse, 'current', 1);
await test_utils.openControlBox(_converse);
await mock.waitForRoster(_converse, 'current', 1);
await mock.openControlBox(_converse);
const contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit';
await test_utils.openChatBoxFor(_converse, contact_jid);
await mock.openChatBoxFor(_converse, contact_jid);
const view = _converse.api.chatviews.get(contact_jid);
const textarea = view.el.querySelector('textarea.chat-textarea');
@ -185,10 +184,10 @@ window.addEventListener('converse-loaded', () => {
['rosterGroupsFetched', 'chatBoxesFetched'], {},
async function (done, _converse) {
await test_utils.waitForRoster(_converse, 'current', 1);
await test_utils.openControlBox(_converse);
await mock.waitForRoster(_converse, 'current', 1);
await mock.openControlBox(_converse);
const contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit';
await test_utils.openChatBoxFor(_converse, contact_jid)
await mock.openChatBoxFor(_converse, contact_jid)
const view = _converse.api.chatviews.get(contact_jid);
const textarea = view.el.querySelector('textarea.chat-textarea');
expect(textarea.value).toBe('');
@ -344,8 +343,8 @@ window.addEventListener('converse-loaded', () => {
['rosterGroupsFetched'], {},
async function (done, _converse) {
await test_utils.waitForRoster(_converse, 'current');
await test_utils.openControlBox(_converse);
await mock.waitForRoster(_converse, 'current');
await mock.openControlBox(_converse);
const sender_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit';
await u.waitUntil(() => _converse.rosterview.el.querySelectorAll('.roster-group').length)
@ -508,8 +507,8 @@ window.addEventListener('converse-loaded', () => {
['rosterGroupsFetched'], {},
async function (done, _converse) {
await test_utils.waitForRoster(_converse, 'current');
await test_utils.openControlBox(_converse);
await mock.waitForRoster(_converse, 'current');
await mock.openControlBox(_converse);
// Ideally we wouldn't have to filter out headline
// messages, but Prosody gives them the wrong 'type' :(
@ -543,8 +542,8 @@ window.addEventListener('converse-loaded', () => {
async function (done, _converse) {
const include_nick = false;
await test_utils.waitForRoster(_converse, 'current', 2, include_nick);
await test_utils.openControlBox(_converse);
await mock.waitForRoster(_converse, 'current', 2, include_nick);
await mock.openControlBox(_converse);
// Send a message from a different resource
const msgtext = 'This is a carbon message';
@ -593,9 +592,9 @@ window.addEventListener('converse-loaded', () => {
['rosterGroupsFetched'], {},
async function (done, _converse) {
await test_utils.waitUntilDiscoConfirmed(_converse, 'montague.lit', [], ['vcard-temp']);
await test_utils.waitForRoster(_converse, 'current');
await test_utils.openControlBox(_converse);
await mock.waitUntilDiscoConfirmed(_converse, 'montague.lit', [], ['vcard-temp']);
await mock.waitForRoster(_converse, 'current');
await mock.openControlBox(_converse);
// Send a message from a different resource
const msgtext = 'This is a sent carbon message';
@ -640,8 +639,8 @@ window.addEventListener('converse-loaded', () => {
['rosterGroupsFetched'], {},
async function (done, _converse) {
await test_utils.waitForRoster(_converse, 'current');
await test_utils.openControlBox(_converse);
await mock.waitForRoster(_converse, 'current');
await mock.openControlBox(_converse);
/* <message from="mallory@evil.example" to="b@xmpp.example">
* <received xmlns='urn:xmpp:carbons:2'>
* <forwarded xmlns='urn:xmpp:forward:0'>
@ -689,14 +688,14 @@ window.addEventListener('converse-loaded', () => {
if (_converse.view_mode === 'fullscreen') {
return done();
}
await test_utils.waitForRoster(_converse, 'current');
await mock.waitForRoster(_converse, 'current');
const contact_name = mock.cur_names[0];
const contact_jid = contact_name.replace(/ /g,'.').toLowerCase() + '@montague.lit';
await test_utils.openControlBox(_converse);
await mock.openControlBox(_converse);
spyOn(_converse.api, "trigger").and.callThrough();
await u.waitUntil(() => _converse.rosterview.el.querySelectorAll('.roster-group').length);
await test_utils.openChatBoxFor(_converse, contact_jid);
await mock.openChatBoxFor(_converse, contact_jid);
const chatview = _converse.api.chatviews.get(contact_jid);
expect(u.isVisible(chatview.el)).toBeTruthy();
expect(chatview.model.get('minimized')).toBeFalsy();
@ -749,15 +748,15 @@ window.addEventListener('converse-loaded', () => {
async function (done, _converse) {
const include_nick = false;
await test_utils.waitForRoster(_converse, 'current', 2, include_nick);
await test_utils.openControlBox(_converse);
await mock.waitForRoster(_converse, 'current', 2, include_nick);
await mock.openControlBox(_converse);
spyOn(_converse.api, "trigger").and.callThrough();
const contact_name = mock.cur_names[1];
const contact_jid = contact_name.replace(/ /g,'.').toLowerCase() + '@montague.lit';
await u.waitUntil(() => _converse.rosterview.el.querySelectorAll('.roster-group').length);
await test_utils.openChatBoxFor(_converse, contact_jid);
await test_utils.clearChatBoxMessages(_converse, contact_jid);
await mock.openChatBoxFor(_converse, contact_jid);
await mock.clearChatBoxMessages(_converse, contact_jid);
const one_day_ago = dayjs().subtract(1, 'day');
const chatbox = _converse.chatboxes.get(contact_jid);
const view = _converse.chatboxviews.get(contact_jid);
@ -840,14 +839,14 @@ window.addEventListener('converse-loaded', () => {
['rosterGroupsFetched', 'chatBoxesFetched'], {},
async function (done, _converse) {
await test_utils.waitForRoster(_converse, 'current');
await test_utils.openControlBox(_converse);
await mock.waitForRoster(_converse, 'current');
await mock.openControlBox(_converse);
const contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit';
await test_utils.openChatBoxFor(_converse, contact_jid)
await mock.openChatBoxFor(_converse, contact_jid)
const view = _converse.api.chatviews.get(contact_jid);
const message = '<p>This message contains <em>some</em> <b>markup</b></p>';
spyOn(view.model, 'sendMessage').and.callThrough();
await test_utils.sendMessage(view, message);
await mock.sendMessage(view, message);
expect(view.model.sendMessage).toHaveBeenCalled();
const msg = sizzle('.chat-content .chat-msg:last .chat-msg__text', view.el).pop();
expect(msg.textContent).toEqual(message);
@ -860,14 +859,14 @@ window.addEventListener('converse-loaded', () => {
['rosterGroupsFetched', 'chatBoxesFetched'], {},
async function (done, _converse) {
await test_utils.waitForRoster(_converse, 'current');
await test_utils.openControlBox(_converse);
await mock.waitForRoster(_converse, 'current');
await mock.openControlBox(_converse);
const contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit';
await test_utils.openChatBoxFor(_converse, contact_jid)
await mock.openChatBoxFor(_converse, contact_jid)
const view = _converse.api.chatviews.get(contact_jid);
const message = 'This message contains a hyperlink: www.opkode.com';
spyOn(view.model, 'sendMessage').and.callThrough();
test_utils.sendMessage(view, message);
mock.sendMessage(view, message);
expect(view.model.sendMessage).toHaveBeenCalled();
await new Promise(resolve => view.once('messageInserted', resolve));
const msg = sizzle('.chat-content .chat-msg:last .chat-msg__text', view.el).pop();
@ -882,16 +881,16 @@ window.addEventListener('converse-loaded', () => {
['rosterGroupsFetched', 'chatBoxesFetched'], {},
async function (done, _converse) {
await test_utils.waitForRoster(_converse, 'current');
await mock.waitForRoster(_converse, 'current');
const contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit';
const view = await test_utils.openChatBoxFor(_converse, contact_jid);
const view = await mock.openChatBoxFor(_converse, contact_jid);
let stanza = u.toStanza(`
<message from="${contact_jid}"
type="chat"
to="romeo@montague.lit/orchard">
<body>Hey\nHave you heard the news?</body>
</message>`);
_converse.connection._dataRecv(test_utils.createRequest(stanza));
_converse.connection._dataRecv(mock.createRequest(stanza));
await new Promise(resolve => view.once('messageInserted', resolve));
expect(view.content.querySelector('.chat-msg__text').innerHTML).toBe('Hey<br>Have you heard the news?');
stanza = u.toStanza(`
@ -900,7 +899,7 @@ window.addEventListener('converse-loaded', () => {
to="romeo@montague.lit/orchard">
<body>Hey\n\n\nHave you heard the news?</body>
</message>`);
_converse.connection._dataRecv(test_utils.createRequest(stanza));
_converse.connection._dataRecv(mock.createRequest(stanza));
await new Promise(resolve => view.once('messageInserted', resolve));
expect(view.content.querySelector('.message:last-child .chat-msg__text').innerHTML).toBe('Hey<br><br>Have you heard the news?');
stanza = u.toStanza(`
@ -909,7 +908,7 @@ window.addEventListener('converse-loaded', () => {
to="romeo@montague.lit/orchard">
<body>Hey\nHave you heard\nthe news?</body>
</message>`);
_converse.connection._dataRecv(test_utils.createRequest(stanza));
_converse.connection._dataRecv(mock.createRequest(stanza));
await new Promise(resolve => view.once('messageInserted', resolve));
expect(view.content.querySelector('.message:last-child .chat-msg__text').innerHTML).toBe('Hey<br>Have you heard<br>the news?');
done();
@ -920,21 +919,21 @@ window.addEventListener('converse-loaded', () => {
['rosterGroupsFetched', 'chatBoxesFetched'], {},
async function (done, _converse) {
await test_utils.waitForRoster(_converse, 'current');
await mock.waitForRoster(_converse, 'current');
const base_url = 'https://conversejs.org';
let message = base_url+"/logo/conversejs-filled.svg";
const contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit';
await test_utils.openChatBoxFor(_converse, contact_jid);
await mock.openChatBoxFor(_converse, contact_jid);
const view = _converse.api.chatviews.get(contact_jid);
spyOn(view.model, 'sendMessage').and.callThrough();
test_utils.sendMessage(view, message);
mock.sendMessage(view, message);
await u.waitUntil(() => view.el.querySelectorAll('.chat-content .chat-image').length, 1000)
expect(view.model.sendMessage).toHaveBeenCalled();
let msg = sizzle('.chat-content .chat-msg:last .chat-msg__text').pop();
expect(msg.innerHTML.trim()).toEqual(
`<a target="_blank" rel="noopener" href="${base_url}/logo/conversejs-filled.svg" class="chat-image__link"><img src="${message}" class="chat-image img-thumbnail"></a>`);
message += "?param1=val1&param2=val2";
test_utils.sendMessage(view, message);
mock.sendMessage(view, message);
await u.waitUntil(() => view.el.querySelectorAll('.chat-content .chat-image').length === 2, 1000);
expect(view.model.sendMessage).toHaveBeenCalled();
msg = sizzle('.chat-content .chat-msg:last .chat-msg__text').pop();
@ -944,7 +943,7 @@ window.addEventListener('converse-loaded', () => {
// Test now with two images in one message
message += ' hello world '+base_url+"/logo/conversejs-filled.svg";
test_utils.sendMessage(view, message);
mock.sendMessage(view, message);
await u.waitUntil(() => view.el.querySelectorAll('.chat-content .chat-image').length === 4, 1000);
expect(view.model.sendMessage).toHaveBeenCalled();
msg = sizzle('.chat-content .chat-msg:last .chat-msg__text').pop();
@ -954,7 +953,7 @@ window.addEventListener('converse-loaded', () => {
// Non-https images aren't rendered
message = base_url+"/logo/conversejs-filled.svg";
expect(view.content.querySelectorAll('img').length).toBe(4);
test_utils.sendMessage(view, message);
mock.sendMessage(view, message);
expect(view.content.querySelectorAll('img').length).toBe(4);
done();
}));
@ -964,13 +963,13 @@ window.addEventListener('converse-loaded', () => {
['rosterGroupsFetched', 'chatBoxesFetched'], {},
async function (done, _converse) {
await test_utils.waitForRoster(_converse, 'current');
await mock.waitForRoster(_converse, 'current');
_converse.time_format = 'hh:mm';
const contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit';
await test_utils.openChatBoxFor(_converse, contact_jid)
await mock.openChatBoxFor(_converse, contact_jid)
const view = _converse.api.chatviews.get(contact_jid);
const message = 'This message is sent from this chatbox';
await test_utils.sendMessage(view, message);
await mock.sendMessage(view, message);
const chatbox = await _converse.api.chats.get(contact_jid);
expect(chatbox.messages.models.length, 1);
@ -990,8 +989,8 @@ window.addEventListener('converse-loaded', () => {
['rosterGroupsFetched'], {},
async function (done, _converse) {
await test_utils.waitForRoster(_converse, 'current');
await test_utils.openControlBox(_converse);
await mock.waitForRoster(_converse, 'current');
await mock.openControlBox(_converse);
const base_time = new Date();
const ONE_MINUTE_LATER = 60000;
@ -1046,7 +1045,7 @@ window.addEventListener('converse-loaded', () => {
await new Promise(resolve => view.once('messageInserted', resolve));
jasmine.clock().tick(1*ONE_MINUTE_LATER);
await test_utils.sendMessage(view, "Another message within 10 minutes, but from a different person");
await mock.sendMessage(view, "Another message within 10 minutes, but from a different person");
expect(view.content.querySelectorAll('.message').length).toBe(6);
expect(view.content.querySelectorAll('.chat-msg').length).toBe(5);
@ -1141,7 +1140,7 @@ window.addEventListener('converse-loaded', () => {
['rosterGroupsFetched', 'chatBoxesFetched'], {},
async function (done, _converse) {
await test_utils.waitForRoster(_converse, 'current');
await mock.waitForRoster(_converse, 'current');
const sender_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit';
const msg_id = u.getUniqueId();
const sent_stanzas = [];
@ -1166,10 +1165,10 @@ window.addEventListener('converse-loaded', () => {
mock.initConverse(
['rosterGroupsFetched', 'chatBoxesFetched'], {},
async function (done, _converse) {
await test_utils.waitForRoster(_converse, 'current', 1);
await mock.waitForRoster(_converse, 'current', 1);
const sender_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit';
const msg_id = u.getUniqueId();
const view = await test_utils.openChatBoxFor(_converse, sender_jid);
const view = await mock.openChatBoxFor(_converse, sender_jid);
spyOn(view.model, 'sendReceiptStanza').and.callThrough();
const msg = $msg({
'from': sender_jid,
@ -1198,9 +1197,9 @@ window.addEventListener('converse-loaded', () => {
['rosterGroupsFetched', 'chatBoxesFetched'], {},
async function (done, _converse) {
await test_utils.waitForRoster(_converse, 'current', 1);
await mock.waitForRoster(_converse, 'current', 1);
const contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit';
await test_utils.openChatBoxFor(_converse, contact_jid);
await mock.openChatBoxFor(_converse, contact_jid);
const view = _converse.chatboxviews.get(contact_jid);
const textarea = view.el.querySelector('textarea.chat-textarea');
textarea.value = 'But soft, what light through yonder airlock breaks?';
@ -1219,7 +1218,7 @@ window.addEventListener('converse-loaded', () => {
'to': _converse.connection.jid,
'id': u.getUniqueId(),
}).c('received', {'id': msg_id, xmlns: Strophe.NS.RECEIPTS}).up().tree();
_converse.connection._dataRecv(test_utils.createRequest(msg));
_converse.connection._dataRecv(mock.createRequest(msg));
await new Promise(resolve => view.model.messages.once('rendered', resolve));
expect(view.el.querySelectorAll('.chat-msg__receipt').length).toBe(1);
@ -1241,7 +1240,7 @@ window.addEventListener('converse-loaded', () => {
'to': _converse.connection.jid,
'id': u.getUniqueId(),
}).c('received', {'id': msg_id, xmlns: Strophe.NS.RECEIPTS}).up().tree();
_converse.connection._dataRecv(test_utils.createRequest(msg));
_converse.connection._dataRecv(mock.createRequest(msg));
await new Promise(resolve => view.model.messages.once('rendered', resolve));
expect(view.el.querySelectorAll('.chat-msg__receipt').length).toBe(2);
expect(_converse.handleMessageStanza.calls.count()).toBe(1);
@ -1254,15 +1253,15 @@ window.addEventListener('converse-loaded', () => {
['rosterGroupsFetched', 'chatBoxesFetched'], {},
async function (done, _converse) {
await test_utils.waitForRoster(_converse, 'current');
await test_utils.openControlBox(_converse);
await mock.waitForRoster(_converse, 'current');
await mock.openControlBox(_converse);
spyOn(_converse.api, "trigger").and.callThrough();
const contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit';
await test_utils.openChatBoxFor(_converse, contact_jid)
await mock.openChatBoxFor(_converse, contact_jid)
const view = _converse.chatboxviews.get(contact_jid);
const message = 'This message is sent from this chatbox';
spyOn(view.model, 'sendMessage').and.callThrough();
await test_utils.sendMessage(view, message);
await mock.sendMessage(view, message);
expect(view.model.sendMessage).toHaveBeenCalled();
expect(view.model.messages.length, 2);
expect(_converse.api.trigger.calls.mostRecent().args, ['messageSend', message]);
@ -1276,12 +1275,12 @@ window.addEventListener('converse-loaded', () => {
['rosterGroupsFetched', 'chatBoxesFetched'], {},
async function (done, _converse) {
await test_utils.waitForRoster(_converse, 'current', 1);
await mock.waitForRoster(_converse, 'current', 1);
const contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit';
await test_utils.openChatBoxFor(_converse, contact_jid)
await mock.openChatBoxFor(_converse, contact_jid)
const view = _converse.chatboxviews.get(contact_jid);
const message = ' \nThis message is sent from this chatbox \n \n';
await test_utils.sendMessage(view, message);
await mock.sendMessage(view, message);
expect(view.model.messages.at(0).get('message')).toEqual(message.trim());
const message_el = sizzle('.chat-content .chat-msg:last .chat-msg__text', view.el).pop();
expect(message_el.textContent).toEqual(message.trim());
@ -1298,8 +1297,8 @@ window.addEventListener('converse-loaded', () => {
async function (done, _converse) {
const include_nick = false;
await test_utils.waitForRoster(_converse, 'current', 1, include_nick);
await test_utils.openControlBox(_converse);
await mock.waitForRoster(_converse, 'current', 1, include_nick);
await mock.openControlBox(_converse);
await u.waitUntil(() => _converse.rosterview.el.querySelectorAll('.roster-group').length, 300);
spyOn(_converse.api, "trigger").and.callThrough();
const message = 'This is a received message';
@ -1343,7 +1342,7 @@ window.addEventListener('converse-loaded', () => {
['rosterGroupsFetched'], {},
async function (done, _converse) {
await test_utils.waitForRoster(_converse, 'current', 1, false);
await mock.waitForRoster(_converse, 'current', 1, false);
await u.waitUntil(() => _converse.rosterview.el.querySelectorAll('.roster-group').length, 300);
const message = '\n\n This is a received message \n\n';
const sender_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit';
@ -1372,11 +1371,11 @@ window.addEventListener('converse-loaded', () => {
['rosterGroupsFetched', 'chatBoxesFetched'], {},
async function (done, _converse) {
await test_utils.waitForRoster(_converse, 'current', 1);
await test_utils.openControlBox(_converse);
await mock.waitForRoster(_converse, 'current', 1);
await mock.openControlBox(_converse);
const sender_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit';
const msg_id = u.getUniqueId();
const view = await test_utils.openChatBoxFor(_converse, sender_jid);
const view = await mock.openChatBoxFor(_converse, sender_jid);
_converse.handleMessageStanza($msg({
'from': sender_jid,
'to': _converse.connection.jid,
@ -1435,7 +1434,7 @@ window.addEventListener('converse-loaded', () => {
['rosterGroupsFetched'], {'allow_non_roster_messaging': true},
async function (done, _converse) {
await test_utils.waitForRoster(_converse, 'current', 0);
await mock.waitForRoster(_converse, 'current', 0);
spyOn(_converse.api, "trigger").and.callThrough();
const sender_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit';
@ -1489,7 +1488,7 @@ window.addEventListener('converse-loaded', () => {
['rosterGroupsFetched'], {'allow_non_roster_messaging': false},
async function (done, _converse) {
await test_utils.waitForRoster(_converse, 'current', 0);
await mock.waitForRoster(_converse, 'current', 0);
spyOn(_converse.api, "trigger").and.callThrough();
const message = 'This is a received message from someone not on the roster';
@ -1545,7 +1544,7 @@ window.addEventListener('converse-loaded', () => {
['rosterGroupsFetched', 'chatBoxesFetched'], {},
async function (done, _converse) {
await test_utils.waitForRoster(_converse, 'current', 1);
await mock.waitForRoster(_converse, 'current', 1);
// TODO: what could still be done for error
// messages... if the <error> element has type
@ -1603,7 +1602,7 @@ window.addEventListener('converse-loaded', () => {
.c('remote-server-not-found', { 'xmlns': "urn:ietf:params:xml:ns:xmpp-stanzas" }).up()
.c('text', { 'xmlns': "urn:ietf:params:xml:ns:xmpp-stanzas" })
.t('Server-to-server connection failed: Connecting failed: connection timeout');
_converse.connection._dataRecv(test_utils.createRequest(stanza));
_converse.connection._dataRecv(mock.createRequest(stanza));
await new Promise(resolve => view.once('messageInserted', resolve));
expect(view.content.querySelector('.chat-error').textContent.trim()).toEqual(error_txt);
stanza = $msg({
@ -1616,7 +1615,7 @@ window.addEventListener('converse-loaded', () => {
.c('remote-server-not-found', { 'xmlns': "urn:ietf:params:xml:ns:xmpp-stanzas" }).up()
.c('text', { 'xmlns': "urn:ietf:params:xml:ns:xmpp-stanzas" })
.t('Server-to-server connection failed: Connecting failed: connection timeout');
_converse.connection._dataRecv(test_utils.createRequest(stanza));
_converse.connection._dataRecv(mock.createRequest(stanza));
await new Promise(resolve => view.once('messageInserted', resolve));
expect(view.content.querySelectorAll('.chat-error').length).toEqual(2);
@ -1631,7 +1630,7 @@ window.addEventListener('converse-loaded', () => {
.c('remote-server-not-found', { 'xmlns': "urn:ietf:params:xml:ns:xmpp-stanzas" }).up()
.c('text', { 'xmlns': "urn:ietf:params:xml:ns:xmpp-stanzas" })
.t('Server-to-server connection failed: Connecting failed: connection timeout');
_converse.connection._dataRecv(test_utils.createRequest(stanza));
_converse.connection._dataRecv(mock.createRequest(stanza));
expect(view.content.querySelectorAll('.chat-error').length).toEqual(2);
msg_text = 'This message will be sent, and also receive an error';
@ -1651,7 +1650,7 @@ window.addEventListener('converse-loaded', () => {
.c('not-allowed', { 'xmlns': "urn:ietf:params:xml:ns:xmpp-stanzas" }).up()
.c('text', { 'xmlns': "urn:ietf:params:xml:ns:xmpp-stanzas" })
.t('Something else went wrong as well');
_converse.connection._dataRecv(test_utils.createRequest(stanza));
_converse.connection._dataRecv(mock.createRequest(stanza));
await u.waitUntil(() => view.model.messages.length > 3);
await new Promise(resolve => view.once('messageInserted', resolve));
expect(view.content.querySelectorAll('.chat-error').length).toEqual(3);
@ -1665,11 +1664,11 @@ window.addEventListener('converse-loaded', () => {
// See #1317
// https://github.com/conversejs/converse.js/issues/1317
await test_utils.waitForRoster(_converse, 'current');
await test_utils.openControlBox(_converse);
await mock.waitForRoster(_converse, 'current');
await mock.openControlBox(_converse);
const contact_jid = mock.cur_names[5].replace(/ /g,'.').toLowerCase() + '@montague.lit';
await test_utils.openChatBoxFor(_converse, contact_jid);
await mock.openChatBoxFor(_converse, contact_jid);
const messages = _converse.connection.sent_stanzas.filter(s => s.nodeName === 'message');
expect(messages.length).toBe(1);
@ -1688,7 +1687,7 @@ window.addEventListener('converse-loaded', () => {
.c('service-unavailable', { 'xmlns': 'urn:ietf:params:xml:ns:xmpp-stanzas' }).up()
.c('text', { 'xmlns': 'urn:ietf:params:xml:ns:xmpp-stanzas' })
.t('User session not found')
_converse.connection._dataRecv(test_utils.createRequest(stanza));
_converse.connection._dataRecv(mock.createRequest(stanza));
const view = _converse.chatboxviews.get(contact_jid);
expect(view.content.querySelectorAll('.chat-error').length).toEqual(0);
done();
@ -1701,9 +1700,9 @@ window.addEventListener('converse-loaded', () => {
['rosterGroupsFetched', 'chatBoxesFetched'], {},
async function (done, _converse) {
await test_utils.waitForRoster(_converse, 'current');
await mock.waitForRoster(_converse, 'current');
const sender_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit';
await test_utils.openChatBoxFor(_converse, sender_jid)
await mock.openChatBoxFor(_converse, sender_jid)
const view = _converse.api.chatviews.get(sender_jid);
// Create enough messages so that there's a scrollbar.
const promises = [];
@ -1755,7 +1754,7 @@ window.addEventListener('converse-loaded', () => {
['rosterGroupsFetched'], {},
async function (done, _converse) {
await test_utils.waitForRoster(_converse, 'current');
await mock.waitForRoster(_converse, 'current');
await u.waitUntil(() => _converse.rosterview.el.querySelectorAll('.roster-group').length)
// Send a message from a different resource
spyOn(converse.env.log, 'info');
@ -1805,9 +1804,9 @@ window.addEventListener('converse-loaded', () => {
['rosterGroupsFetched', 'chatBoxesFetched'], {},
async function (done, _converse) {
await test_utils.waitForRoster(_converse, 'current', 1);
await mock.waitForRoster(_converse, 'current', 1);
const contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit';
await test_utils.openChatBoxFor(_converse, contact_jid);
await mock.openChatBoxFor(_converse, contact_jid);
const view = _converse.api.chatviews.get(contact_jid);
spyOn(view.model, 'sendMessage').and.callThrough();
@ -1818,7 +1817,7 @@ window.addEventListener('converse-loaded', () => {
<body>Have you heard this funny audio?</body>
<x xmlns="jabber:x:oob"><url>https://montague.lit/audio.mp3</url></x>
</message>`)
_converse.connection._dataRecv(test_utils.createRequest(stanza));
_converse.connection._dataRecv(mock.createRequest(stanza));
await new Promise(resolve => view.once('messageInserted', resolve));
await u.waitUntil(() => view.el.querySelectorAll('.chat-content .chat-msg audio').length, 1000);
let msg = view.el.querySelector('.chat-msg .chat-msg__text');
@ -1838,7 +1837,7 @@ window.addEventListener('converse-loaded', () => {
<body>https://montague.lit/audio.mp3</body>
<x xmlns="jabber:x:oob"><url>https://montague.lit/audio.mp3</url></x>
</message>`);
_converse.connection._dataRecv(test_utils.createRequest(stanza));
_converse.connection._dataRecv(mock.createRequest(stanza));
await new Promise(resolve => view.once('messageInserted', resolve));
msg = view.el.querySelector('.chat-msg:last-child .chat-msg__text');
expect(msg.innerHTML).toEqual('<!-- message gets added here via renderMessage -->'); // Emtpy
@ -1855,9 +1854,9 @@ window.addEventListener('converse-loaded', () => {
['rosterGroupsFetched', 'chatBoxesFetched'], {},
async function (done, _converse) {
await test_utils.waitForRoster(_converse, 'current', 1);
await mock.waitForRoster(_converse, 'current', 1);
const contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit';
await test_utils.openChatBoxFor(_converse, contact_jid)
await mock.openChatBoxFor(_converse, contact_jid)
const view = _converse.api.chatviews.get(contact_jid);
spyOn(view.model, 'sendMessage').and.callThrough();
@ -1868,7 +1867,7 @@ window.addEventListener('converse-loaded', () => {
<body>Have you seen this funny video?</body>
<x xmlns="jabber:x:oob"><url>https://montague.lit/video.mp4</url></x>
</message>`);
_converse.connection._dataRecv(test_utils.createRequest(stanza));
_converse.connection._dataRecv(mock.createRequest(stanza));
await u.waitUntil(() => view.el.querySelectorAll('.chat-content .chat-msg video').length, 2000)
let msg = view.el.querySelector('.chat-msg .chat-msg__text');
expect(msg.classList.length).toBe(1);
@ -1886,7 +1885,7 @@ window.addEventListener('converse-loaded', () => {
<body>https://montague.lit/video.mp4</body>
<x xmlns="jabber:x:oob"><url>https://montague.lit/video.mp4</url></x>
</message>`);
_converse.connection._dataRecv(test_utils.createRequest(stanza));
_converse.connection._dataRecv(mock.createRequest(stanza));
await new Promise(resolve => view.once('messageInserted', resolve));
msg = view.el.querySelector('.chat-msg:last-child .chat-msg__text');
expect(msg.innerHTML).toEqual('<!-- message gets added here via renderMessage -->'); // Emtpy
@ -1901,9 +1900,9 @@ window.addEventListener('converse-loaded', () => {
['rosterGroupsFetched', 'chatBoxesFetched'], {},
async function (done, _converse) {
await test_utils.waitForRoster(_converse, 'current', 1);
await mock.waitForRoster(_converse, 'current', 1);
const contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit';
await test_utils.openChatBoxFor(_converse, contact_jid);
await mock.openChatBoxFor(_converse, contact_jid);
const view = _converse.api.chatviews.get(contact_jid);
spyOn(view.model, 'sendMessage').and.callThrough();
const stanza = u.toStanza(`
@ -1913,7 +1912,7 @@ window.addEventListener('converse-loaded', () => {
<body>Have you downloaded this funny file?</body>
<x xmlns="jabber:x:oob"><url>https://montague.lit/funny.pdf</url></x>
</message>`);
_converse.connection._dataRecv(test_utils.createRequest(stanza));
_converse.connection._dataRecv(mock.createRequest(stanza));
await new Promise(resolve => view.once('messageInserted', resolve));
await u.waitUntil(() => view.el.querySelectorAll('.chat-content .chat-msg a').length, 1000);
const msg = view.el.querySelector('.chat-msg .chat-msg__text');
@ -1931,9 +1930,9 @@ window.addEventListener('converse-loaded', () => {
async function (done, _converse) {
const base_url = 'https://conversejs.org';
await test_utils.waitForRoster(_converse, 'current', 1);
await mock.waitForRoster(_converse, 'current', 1);
const contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit';
await test_utils.openChatBoxFor(_converse, contact_jid)
await mock.openChatBoxFor(_converse, contact_jid)
const view = _converse.api.chatviews.get(contact_jid);
spyOn(view.model, 'sendMessage').and.callThrough();
const url = base_url+"/logo/conversejs-filled.svg";
@ -1945,7 +1944,7 @@ window.addEventListener('converse-loaded', () => {
<body>Have you seen this funny image?</body>
<x xmlns="jabber:x:oob"><url>${url}</url></x>
</message>`);
_converse.connection._dataRecv(test_utils.createRequest(stanza));
_converse.connection._dataRecv(mock.createRequest(stanza));
await u.waitUntil(() => view.el.querySelectorAll('.chat-content .chat-msg img').length, 2000);
const msg = view.el.querySelector('.chat-msg .chat-msg__text');
@ -1958,18 +1957,18 @@ window.addEventListener('converse-loaded', () => {
done();
}));
});
});
});
describe("A XEP-0333 Chat Marker", function () {
describe("A XEP-0333 Chat Marker", function () {
it("is sent when a markable message is received from a roster contact",
mock.initConverse(
['rosterGroupsFetched'], {},
async function (done, _converse) {
await test_utils.waitForRoster(_converse, 'current', 1);
await mock.waitForRoster(_converse, 'current', 1);
const contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit';
await test_utils.openChatBoxFor(_converse, contact_jid);
await mock.openChatBoxFor(_converse, contact_jid);
const view = _converse.api.chatviews.get(contact_jid);
const msgid = u.getUniqueId();
const stanza = u.toStanza(`
@ -1984,7 +1983,7 @@ window.addEventListener('converse-loaded', () => {
const sent_stanzas = [];
spyOn(_converse.connection, 'send').and.callFake(s => sent_stanzas.push(s));
spyOn(view.model, 'sendMarker').and.callThrough();
_converse.connection._dataRecv(test_utils.createRequest(stanza));
_converse.connection._dataRecv(mock.createRequest(stanza));
await u.waitUntil(() => view.model.sendMarker.calls.count() === 1);
expect(Strophe.serialize(sent_stanzas[0])).toBe(
`<message from="romeo@montague.lit/orchard" `+
@ -2000,7 +1999,7 @@ window.addEventListener('converse-loaded', () => {
['rosterGroupsFetched'], {'allow_non_roster_messaging': true},
async function (done, _converse) {
await test_utils.waitForRoster(_converse, 'current', 0);
await mock.waitForRoster(_converse, 'current', 0);
const contact_jid = 'someone@montague.lit';
const msgid = u.getUniqueId();
const stanza = u.toStanza(`
@ -2035,11 +2034,11 @@ window.addEventListener('converse-loaded', () => {
['rosterGroupsFetched'], {},
async function (done, _converse) {
await test_utils.waitForRoster(_converse, 'current', 1);
await test_utils.waitUntilDiscoConfirmed(_converse, _converse.bare_jid, [], [Strophe.NS.SID]);
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';
await test_utils.openChatBoxFor(_converse, contact_jid);
await mock.openChatBoxFor(_converse, contact_jid);
const view = _converse.api.chatviews.get(contact_jid);
let stanza = u.toStanza(`
@ -2053,7 +2052,7 @@ window.addEventListener('converse-loaded', () => {
<origin-id xmlns="urn:xmpp:sid:0" id="2e972ea0-0050-44b7-a830-f6638a2595b3"/>
<stanza-id xmlns="urn:xmpp:sid:0" id="IxVDLJ0RYbWcWvqC" by="${_converse.bare_jid}"/>
</message>`);
_converse.connection._dataRecv(test_utils.createRequest(stanza));
_converse.connection._dataRecv(mock.createRequest(stanza));
await new Promise(resolve => view.once('messageInserted', resolve));
expect(view.el.querySelectorAll('.chat-msg').length).toBe(1);
expect(view.model.messages.length).toBe(1);
@ -2071,11 +2070,10 @@ window.addEventListener('converse-loaded', () => {
</sent>
</message>`);
spyOn(_converse.api, "trigger").and.callThrough();
_converse.connection._dataRecv(test_utils.createRequest(stanza));
_converse.connection._dataRecv(mock.createRequest(stanza));
await u.waitUntil(() => _converse.api.trigger.calls.count(), 500);
expect(view.el.querySelectorAll('.chat-msg').length).toBe(1);
expect(view.model.messages.length).toBe(1);
done();
}));
});
});

View File

@ -1,23 +1,22 @@
window.addEventListener('converse-loaded', () => {
const mock = window.mock;
const test_utils = window.test_utils;
const _ = converse.env._;
const $msg = converse.env.$msg;
const u = converse.env.utils;
/*global mock */
describe("The Minimized Chats Widget", function () {
const _ = converse.env._;
const $msg = converse.env.$msg;
const u = converse.env.utils;
describe("The Minimized Chats Widget", function () {
it("shows chats that have been minimized",
mock.initConverse(
['rosterGroupsFetched'], {},
async function (done, _converse) {
await test_utils.waitForRoster(_converse, 'current');
await test_utils.openControlBox(_converse);
await mock.waitForRoster(_converse, 'current');
await mock.openControlBox(_converse);
_converse.minimized_chats.initToggle();
let contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit';
await test_utils.openChatBoxFor(_converse, contact_jid)
await mock.openChatBoxFor(_converse, contact_jid)
let chatview = _converse.chatboxviews.get(contact_jid);
expect(chatview.model.get('minimized')).toBeFalsy();
expect(u.isVisible(_converse.minimized_chats.el)).toBe(false);
@ -28,7 +27,7 @@ window.addEventListener('converse-loaded', () => {
expect(_converse.minimized_chats.keys()[0]).toBe(contact_jid);
contact_jid = mock.cur_names[1].replace(/ /g,'.').toLowerCase() + '@montague.lit';
await test_utils.openChatBoxFor(_converse, contact_jid);
await mock.openChatBoxFor(_converse, contact_jid);
chatview = _converse.chatboxviews.get(contact_jid);
expect(chatview.model.get('minimized')).toBeFalsy();
chatview.el.querySelector('.toggle-chatbox-button').click();
@ -44,12 +43,12 @@ window.addEventListener('converse-loaded', () => {
['rosterGroupsFetched'], {},
async function (done, _converse) {
await test_utils.waitForRoster(_converse, 'current');
await test_utils.openControlBox(_converse);
await mock.waitForRoster(_converse, 'current');
await mock.openControlBox(_converse);
_converse.minimized_chats.initToggle();
const contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit';
await test_utils.openChatBoxFor(_converse, contact_jid);
await mock.openChatBoxFor(_converse, contact_jid);
const chatview = _converse.chatboxviews.get(contact_jid);
expect(u.isVisible(_converse.minimized_chats.el)).toBeFalsy();
chatview.model.set({'minimized': true});
@ -69,8 +68,8 @@ window.addEventListener('converse-loaded', () => {
['rosterGroupsFetched', 'chatBoxesFetched'], {},
async function (done, _converse) {
await test_utils.waitForRoster(_converse, 'current', 4);
await test_utils.openControlBox(_converse);
await mock.waitForRoster(_converse, 'current', 4);
await mock.openControlBox(_converse);
_converse.minimized_chats.initToggle();
var i, contact_jid, chatview, msg;
@ -81,7 +80,7 @@ window.addEventListener('converse-loaded', () => {
for (i=0; i<3; i++) {
contact_jid = mock.cur_names[i].replace(/ /g,'.').toLowerCase() + '@montague.lit';
test_utils.openChatBoxFor(_converse, contact_jid);
mock.openChatBoxFor(_converse, contact_jid);
}
await u.waitUntil(() => _converse.chatboxes.length == 4);
@ -146,7 +145,7 @@ window.addEventListener('converse-loaded', () => {
async function (done, _converse) {
const muc_jid = 'kitchen@conference.shakespeare.lit';
await test_utils.openAndEnterChatRoom(_converse, 'kitchen@conference.shakespeare.lit', 'fires');
await mock.openAndEnterChatRoom(_converse, 'kitchen@conference.shakespeare.lit', 'fires');
const view = _converse.chatboxviews.get(muc_jid);
view.model.set({'minimized': true});
const message = 'fires: Your attention is required';
@ -163,5 +162,4 @@ window.addEventListener('converse-loaded', () => {
expect(_converse.minimized_chats.toggleview.el.querySelector('.unread-message-count').textContent).toBe('1');
done();
}));
});
});

View File

@ -1,14 +1,13 @@
window.addEventListener('converse-loaded', () => {
const mock = window.mock;
const test_utils = window.test_utils;
const _ = converse.env._;
const $iq = converse.env.$iq;
const $pres = converse.env.$pres;
const sizzle = converse.env.sizzle;
const Strophe = converse.env.Strophe;
const u = converse.env.utils;
/*global mock */
describe("The groupchat moderator tool", function () {
const _ = converse.env._;
const $iq = converse.env.$iq;
const $pres = converse.env.$pres;
const sizzle = converse.env.sizzle;
const Strophe = converse.env.Strophe;
const u = converse.env.utils;
describe("The groupchat moderator tool", function () {
it("allows you to set affiliations and roles",
mock.initConverse(
@ -25,7 +24,7 @@ window.addEventListener('converse-loaded', () => {
{'jid': 'crone1@shakespeare.lit', 'nick': 'thirdwitch', 'affiliation': 'owner'},
{'jid': 'romeo@montague.lit', 'nick': 'romeo', 'affiliation': 'owner'},
];
await test_utils.openAndEnterChatRoom(_converse, muc_jid, 'romeo', [], members);
await mock.openAndEnterChatRoom(_converse, muc_jid, 'romeo', [], members);
const view = _converse.chatboxviews.get(muc_jid);
await u.waitUntil(() => (view.model.occupants.length === 5), 1000);
@ -98,7 +97,7 @@ window.addEventListener('converse-loaded', () => {
'from': view.model.get('jid'),
'to': _converse.connection.jid
});
_converse.connection._dataRecv(test_utils.createRequest(stanza));
_converse.connection._dataRecv(mock.createRequest(stanza));
await u.waitUntil(() => view.model.occupants.fetchMembers.calls.count());
members = [
@ -108,7 +107,7 @@ window.addEventListener('converse-loaded', () => {
{'jid': 'crone1@shakespeare.lit', 'nick': 'thirdwitch', 'affiliation': 'admin'},
{'jid': 'romeo@montague.lit', 'nick': 'romeo', 'affiliation': 'owner'},
];
await test_utils.returnMemberLists(_converse, muc_jid, members);
await mock.returnMemberLists(_converse, muc_jid, members);
await u.waitUntil(() => view.model.occupants.pluck('affiliation').filter(o => o === 'owner').length === 1);
const alert = modal.el.querySelector('.alert-primary');
expect(alert.textContent.trim()).toBe('Affiliation changed');
@ -153,7 +152,7 @@ window.addEventListener('converse-loaded', () => {
{'jid': 'romeo@montague.lit', 'nick': 'romeo', 'affiliation': 'member'},
{'jid': 'juliet@capulet.lit', 'nick': 'juliet', 'affiliation': 'member'},
];
await test_utils.openAndEnterChatRoom(_converse, muc_jid, 'romeo', [], members);
await mock.openAndEnterChatRoom(_converse, muc_jid, 'romeo', [], members);
const view = _converse.chatboxviews.get(muc_jid);
await u.waitUntil(() => (view.model.occupants.length === 6), 1000);
@ -203,10 +202,10 @@ window.addEventListener('converse-loaded', () => {
spyOn(_converse.ChatRoomView.prototype, 'showModeratorToolsModal').and.callThrough();
const muc_jid = 'lounge@montague.lit';
await test_utils.openAndEnterChatRoom(_converse, muc_jid, 'romeo', []);
await mock.openAndEnterChatRoom(_converse, muc_jid, 'romeo', []);
const view = _converse.chatboxviews.get(muc_jid);
_converse.connection._dataRecv(test_utils.createRequest(
_converse.connection._dataRecv(mock.createRequest(
$pres({to: _converse.jid, from: `${muc_jid}/nomorenicks`})
.c('x', {xmlns: Strophe.NS.MUC_USER})
.c('item', {
@ -215,7 +214,7 @@ window.addEventListener('converse-loaded', () => {
'role': 'participant'
})
));
_converse.connection._dataRecv(test_utils.createRequest(
_converse.connection._dataRecv(mock.createRequest(
$pres({to: _converse.jid, from: `${muc_jid}/newb`})
.c('x', {xmlns: Strophe.NS.MUC_USER})
.c('item', {
@ -224,7 +223,7 @@ window.addEventListener('converse-loaded', () => {
'role': 'participant'
})
));
_converse.connection._dataRecv(test_utils.createRequest(
_converse.connection._dataRecv(mock.createRequest(
$pres({to: _converse.jid, from: `${muc_jid}/some1`})
.c('x', {xmlns: Strophe.NS.MUC_USER})
.c('item', {
@ -233,7 +232,7 @@ window.addEventListener('converse-loaded', () => {
'role': 'participant'
})
));
_converse.connection._dataRecv(test_utils.createRequest(
_converse.connection._dataRecv(mock.createRequest(
$pres({to: _converse.jid, from: `${muc_jid}/oldhag`})
.c('x', {xmlns: Strophe.NS.MUC_USER})
.c('item', {
@ -242,7 +241,7 @@ window.addEventListener('converse-loaded', () => {
'role': 'participant'
})
));
_converse.connection._dataRecv(test_utils.createRequest(
_converse.connection._dataRecv(mock.createRequest(
$pres({to: _converse.jid, from: `${muc_jid}/crone`})
.c('x', {xmlns: Strophe.NS.MUC_USER})
.c('item', {
@ -251,7 +250,7 @@ window.addEventListener('converse-loaded', () => {
'role': 'participant'
})
));
_converse.connection._dataRecv(test_utils.createRequest(
_converse.connection._dataRecv(mock.createRequest(
$pres({to: _converse.jid, from: `${muc_jid}/tux`})
.c('x', {xmlns: Strophe.NS.MUC_USER})
.c('item', {
@ -321,7 +320,7 @@ window.addEventListener('converse-loaded', () => {
{'jid': 'crone1@shakespeare.lit', 'nick': 'thirdwitch', 'affiliation': 'owner'},
{'jid': 'romeo@montague.lit', 'nick': 'romeo', 'affiliation': 'owner'},
];
await test_utils.openAndEnterChatRoom(_converse, muc_jid, 'romeo', [], members);
await mock.openAndEnterChatRoom(_converse, muc_jid, 'romeo', [], members);
const view = _converse.chatboxviews.get(muc_jid);
await u.waitUntil(() => (view.model.occupants.length === 5));
@ -358,7 +357,7 @@ window.addEventListener('converse-loaded', () => {
<forbidden xmlns="${Strophe.NS.STANZAS}"/>
</error>
</iq>`);
_converse.connection._dataRecv(test_utils.createRequest(error));
_converse.connection._dataRecv(mock.createRequest(error));
await u.waitUntil(() => !modal.loading_users_with_affiliation);
const user_els = modal.el.querySelectorAll('.list-group--users > li');
@ -366,5 +365,4 @@ window.addEventListener('converse-loaded', () => {
expect(user_els[0].textContent.trim()).toBe('Error: not allowed to fetch outcast list for MUC lounge@montague.lit');
done();
}));
});
});

File diff suppressed because it is too large Load Diff

View File

@ -1,10 +1,9 @@
window.addEventListener('converse-loaded', () => {
const mock = window.mock;
const test_utils = window.test_utils;
const { Promise, Strophe, $msg, $pres, sizzle, stanza_utils } = converse.env;
const u = converse.env.utils;
/*global mock */
describe("A Groupchat Message", function () {
const { Promise, Strophe, $msg, $pres, sizzle, stanza_utils } = converse.env;
const u = converse.env.utils;
describe("A Groupchat Message", function () {
describe("an info message", function () {
@ -14,7 +13,7 @@ window.addEventListener('converse-loaded', () => {
async function (done, _converse) {
const muc_jid = 'lounge@montague.lit';
await test_utils.openAndEnterChatRoom(_converse, muc_jid, 'romeo');
await mock.openAndEnterChatRoom(_converse, muc_jid, 'romeo');
const view = _converse.api.chatviews.get(muc_jid);
let presence = u.toStanza(`
<presence xmlns="jabber:client" to="${_converse.jid}" from="${muc_jid}/romeo">
@ -25,7 +24,7 @@ window.addEventListener('converse-loaded', () => {
</x>
</presence>
`);
_converse.connection._dataRecv(test_utils.createRequest(presence));
_converse.connection._dataRecv(mock.createRequest(presence));
await u.waitUntil(() => view.el.querySelectorAll('.chat-info').length === 1);
presence = u.toStanza(`
@ -37,7 +36,7 @@ window.addEventListener('converse-loaded', () => {
</x>
</presence>
`);
_converse.connection._dataRecv(test_utils.createRequest(presence));
_converse.connection._dataRecv(mock.createRequest(presence));
await u.waitUntil(() => view.el.querySelectorAll('.chat-info').length === 2);
const messages = view.el.querySelectorAll('.chat-info');
@ -52,7 +51,7 @@ window.addEventListener('converse-loaded', () => {
async function (done, _converse) {
const muc_jid = 'lounge@montague.lit';
await test_utils.openAndEnterChatRoom(_converse, muc_jid, 'romeo');
await mock.openAndEnterChatRoom(_converse, muc_jid, 'romeo');
const view = _converse.api.chatviews.get(muc_jid);
const presence = u.toStanza(`
<presence xmlns="jabber:client" to="${_converse.jid}" from="${muc_jid}/romeo">
@ -69,11 +68,11 @@ window.addEventListener('converse-loaded', () => {
// sequentially (i.e. by waiting for promises to resolve)
// like we do with message stanzas.
spyOn(view.model, 'createInfoMessages').and.callThrough();
_converse.connection._dataRecv(test_utils.createRequest(presence));
_converse.connection._dataRecv(mock.createRequest(presence));
await u.waitUntil(() => view.model.createInfoMessages.calls.count());
await u.waitUntil(() => view.el.querySelectorAll('.chat-info').length === 1);
_converse.connection._dataRecv(test_utils.createRequest(presence));
_converse.connection._dataRecv(mock.createRequest(presence));
await u.waitUntil(() => view.model.createInfoMessages.calls.count() === 2);
expect(view.el.querySelectorAll('.chat-info').length).toBe(1);
done();
@ -87,7 +86,7 @@ window.addEventListener('converse-loaded', () => {
async function (done, _converse) {
const muc_jid = 'lounge@montague.lit';
await test_utils.openAndEnterChatRoom(_converse, muc_jid, 'romeo');
await mock.openAndEnterChatRoom(_converse, muc_jid, 'romeo');
const impersonated_jid = `${muc_jid}/alice`;
const received_stanza = u.toStanza(`
<message to='${_converse.jid}' from='${muc_jid}/mallory' type='groupchat' id='${_converse.connection.getUniqueId()}'>
@ -109,7 +108,7 @@ window.addEventListener('converse-loaded', () => {
await view.model.queueMessage(received_stanza);
spyOn(converse.env.log, 'warn');
_converse.connection._dataRecv(test_utils.createRequest(received_stanza));
_converse.connection._dataRecv(mock.createRequest(received_stanza));
await u.waitUntil(() => view.model.onMessage.calls.count());
expect(converse.env.log.warn).toHaveBeenCalledWith(
'onMessage: Ignoring unencapsulated forwarded groupchat message'
@ -125,7 +124,7 @@ window.addEventListener('converse-loaded', () => {
async function (done, _converse) {
const muc_jid = 'lounge@montague.lit';
await test_utils.openAndEnterChatRoom(_converse, muc_jid, 'romeo');
await mock.openAndEnterChatRoom(_converse, muc_jid, 'romeo');
const view = _converse.api.chatviews.get(muc_jid);
if (!view.el.querySelectorAll('.chat-area').length) { view.renderChatArea(); }
const message = 'romeo: Your attention is required';
@ -150,7 +149,7 @@ window.addEventListener('converse-loaded', () => {
async function (done, _converse) {
const muc_jid = 'lounge@montague.lit';
await test_utils.openAndEnterChatRoom(_converse, muc_jid, 'romeo');
await mock.openAndEnterChatRoom(_converse, muc_jid, 'romeo');
const view = _converse.api.chatviews.get(muc_jid);
if (!view.el.querySelectorAll('.chat-area').length) { view.renderChatArea(); }
const message = 'romeo: Your attention is required';
@ -173,7 +172,7 @@ window.addEventListener('converse-loaded', () => {
async function (done, _converse) {
const muc_jid = 'lounge@montague.lit';
await test_utils.openAndEnterChatRoom(_converse, muc_jid, 'romeo');
await mock.openAndEnterChatRoom(_converse, muc_jid, 'romeo');
const view = _converse.api.chatviews.get(muc_jid);
if (!view.el.querySelectorAll('.chat-area').length) { view.renderChatArea(); }
const id = u.getUniqueId();
@ -204,7 +203,7 @@ window.addEventListener('converse-loaded', () => {
async function (done, _converse) {
const muc_jid = 'room@muc.example.com';
await test_utils.openAndEnterChatRoom(_converse, muc_jid, 'romeo');
await mock.openAndEnterChatRoom(_converse, muc_jid, 'romeo');
const view = _converse.api.chatviews.get(muc_jid);
spyOn(view.model, 'getDuplicateMessage').and.callThrough();
let stanza = u.toStanza(`
@ -217,7 +216,7 @@ window.addEventListener('converse-loaded', () => {
id="5f3dbc5e-e1d3-4077-a492-693f3769c7ad"
by="room@muc.example.com"/>
</message>`);
_converse.connection._dataRecv(test_utils.createRequest(stanza));
_converse.connection._dataRecv(mock.createRequest(stanza));
await u.waitUntil(() => view.model.messages.length === 1);
await u.waitUntil(() => view.model.getDuplicateMessage.calls.count() === 1);
let result = await view.model.getDuplicateMessage.calls.all()[0].returnValue;
@ -253,7 +252,7 @@ window.addEventListener('converse-loaded', () => {
async function (done, _converse) {
const muc_jid = 'room@muc.example.com';
await test_utils.openAndEnterChatRoom(_converse, muc_jid, 'romeo');
await mock.openAndEnterChatRoom(_converse, muc_jid, 'romeo');
const view = _converse.api.chatviews.get(muc_jid);
spyOn(view.model, 'getStanzaIdQueryAttrs').and.callThrough();
let stanza = u.toStanza(`
@ -266,7 +265,7 @@ window.addEventListener('converse-loaded', () => {
id="5f3dbc5e-e1d3-4077-a492-693f3769c7ad"
by="room@muc.example.com"/>
</message>`);
_converse.connection._dataRecv(test_utils.createRequest(stanza));
_converse.connection._dataRecv(mock.createRequest(stanza));
await u.waitUntil(() => view.model.messages.length === 1);
await u.waitUntil(() => view.model.getStanzaIdQueryAttrs.calls.count() === 1);
let result = await view.model.getStanzaIdQueryAttrs.calls.all()[0].returnValue;
@ -286,7 +285,7 @@ window.addEventListener('converse-loaded', () => {
</message>`);
spyOn(view.model, 'updateMessage');
spyOn(view.model, 'getDuplicateMessage').and.callThrough();
_converse.connection._dataRecv(test_utils.createRequest(stanza));
_converse.connection._dataRecv(mock.createRequest(stanza));
await u.waitUntil(() => view.model.getDuplicateMessage.calls.count());
result = await view.model.getDuplicateMessage.calls.all()[0].returnValue;
expect(result instanceof _converse.Message).toBe(true);
@ -300,12 +299,12 @@ window.addEventListener('converse-loaded', () => {
['rosterGroupsFetched'], {},
async function (done, _converse) {
await test_utils.waitForRoster(_converse, 'current');
await test_utils.openControlBox(_converse);
await mock.waitForRoster(_converse, 'current');
await mock.openControlBox(_converse);
const muc_jid = 'xsf@muc.xmpp.org';
const sender_jid = `${muc_jid}/romeo`;
const impersonated_jid = `${muc_jid}/i_am_groot`
await test_utils.openAndEnterChatRoom(_converse, muc_jid, 'romeo');
await mock.openAndEnterChatRoom(_converse, muc_jid, 'romeo');
const stanza = $pres({
to: 'romeo@montague.lit/_converse.js-29092160',
from: sender_jid
@ -316,7 +315,7 @@ window.addEventListener('converse-loaded', () => {
'jid': 'newguy@montague.lit/_converse.js-290929789',
'role': 'participant'
}).tree();
_converse.connection._dataRecv(test_utils.createRequest(stanza));
_converse.connection._dataRecv(mock.createRequest(stanza));
/*
* <message to="romeo@montague.im/poezio" id="718d40df-3948-4798-a99b-35cc9f03cc4f-641" type="groupchat" from="xsf@muc.xmpp.org/romeo">
* <received xmlns="urn:xmpp:carbons:2">
@ -360,7 +359,7 @@ window.addEventListener('converse-loaded', () => {
async function (done, _converse) {
const muc_jid = 'lounge@montague.lit';
await test_utils.openAndEnterChatRoom(_converse, muc_jid, 'romeo');
await mock.openAndEnterChatRoom(_converse, muc_jid, 'romeo');
const view = _converse.api.chatviews.get(muc_jid);
let msg = $msg({
from: 'lounge@montague.lit/romeo',
@ -386,7 +385,7 @@ window.addEventListener('converse-loaded', () => {
}).up()
.c('status').attrs({code:'110'}).up()
.c('status').attrs({code:'210'}).nodeTree;
_converse.connection._dataRecv(test_utils.createRequest(presence));
_converse.connection._dataRecv(mock.createRequest(presence));
msg = $msg({
from: 'lounge@montague.lit/romeo',
@ -413,7 +412,7 @@ window.addEventListener('converse-loaded', () => {
}).up()
.c('status').attrs({code:'110'}).up()
.c('status').attrs({code:'210'}).nodeTree;
_converse.connection._dataRecv(test_utils.createRequest(presence));
_converse.connection._dataRecv(mock.createRequest(presence));
view.model.sendMessage('hello world');
await u.waitUntil(() => view.el.querySelectorAll('.chat-msg').length === 3);
@ -445,7 +444,7 @@ window.addEventListener('converse-loaded', () => {
id: u.getUniqueId()
}).c('x').attrs({xmlns:'http://jabber.org/protocol/muc#user'})
.c('item').attrs({jid: 'some1@montague.lit/orchard'});
_converse.connection._dataRecv(test_utils.createRequest(presence));
_converse.connection._dataRecv(mock.createRequest(presence));
await u.waitUntil(() => view.model.messages.last().occupant);
expect(view.model.messages.last().get('message')).toBe('Message from someone not in the MUC right now');
expect(view.model.messages.last().occupant.get('nick')).toBe('some1');
@ -459,7 +458,7 @@ window.addEventListener('converse-loaded', () => {
id: u.getUniqueId()
}).c('x').attrs({xmlns:'http://jabber.org/protocol/muc#user'})
.c('item').attrs({jid: 'some1@montague.lit/orchard'});
_converse.connection._dataRecv(test_utils.createRequest(presence));
_converse.connection._dataRecv(mock.createRequest(presence));
await u.waitUntil(() => !view.model.messages.last().occupant);
expect(view.model.messages.last().get('message')).toBe('Message from someone not in the MUC right now');
expect(view.model.messages.last().occupant).toBeUndefined();
@ -472,7 +471,7 @@ window.addEventListener('converse-loaded', () => {
id: u.getUniqueId()
}).c('x').attrs({xmlns:'http://jabber.org/protocol/muc#user'})
.c('item').attrs({jid: 'some1@montague.lit/orchard'});
_converse.connection._dataRecv(test_utils.createRequest(presence));
_converse.connection._dataRecv(mock.createRequest(presence));
await u.waitUntil(() => view.model.messages.last().occupant);
expect(view.model.messages.last().get('message')).toBe('Message from someone not in the MUC right now');
expect(view.model.messages.last().occupant.get('nick')).toBe('some1');
@ -488,7 +487,7 @@ window.addEventListener('converse-loaded', () => {
async function (done, _converse) {
const muc_jid = 'lounge@montague.lit';
await test_utils.openAndEnterChatRoom(_converse, muc_jid, 'romeo');
await mock.openAndEnterChatRoom(_converse, muc_jid, 'romeo');
const view = _converse.api.chatviews.get(muc_jid);
const msg = $msg({
from: 'lounge@montague.lit/romeo',
@ -507,7 +506,7 @@ window.addEventListener('converse-loaded', () => {
async function (done, _converse) {
const muc_jid = 'lounge@montague.lit';
await test_utils.openAndEnterChatRoom(_converse, muc_jid, 'romeo');
await mock.openAndEnterChatRoom(_converse, muc_jid, 'romeo');
const view = _converse.api.chatviews.get(muc_jid);
const stanza = $pres({
to: 'romeo@montague.lit/_converse.js-29092160',
@ -519,7 +518,7 @@ window.addEventListener('converse-loaded', () => {
'jid': 'newguy@montague.lit/_converse.js-290929789',
'role': 'participant'
}).tree();
_converse.connection._dataRecv(test_utils.createRequest(stanza));
_converse.connection._dataRecv(mock.createRequest(stanza));
const msg_id = u.getUniqueId();
await view.model.queueMessage($msg({
'from': 'lounge@montague.lit/newguy',
@ -575,7 +574,7 @@ window.addEventListener('converse-loaded', () => {
async function (done, _converse) {
const muc_jid = 'lounge@montague.lit';
await test_utils.openAndEnterChatRoom(_converse, muc_jid, 'romeo');
await mock.openAndEnterChatRoom(_converse, muc_jid, 'romeo');
const view = _converse.api.chatviews.get(muc_jid);
const textarea = view.el.querySelector('textarea.chat-textarea');
expect(textarea.value).toBe('');
@ -678,9 +677,9 @@ window.addEventListener('converse-loaded', () => {
['rosterGroupsFetched'], {},
async function (done, _converse) {
await test_utils.waitForRoster(_converse, 'current');
await mock.waitForRoster(_converse, 'current');
const muc_jid = 'lounge@montague.lit';
await test_utils.openAndEnterChatRoom(_converse, muc_jid, 'romeo');
await mock.openAndEnterChatRoom(_converse, muc_jid, 'romeo');
const view = _converse.api.chatviews.get(muc_jid);
const textarea = view.el.querySelector('textarea.chat-textarea');
textarea.value = 'But soft, what light through yonder airlock breaks?';
@ -722,7 +721,7 @@ window.addEventListener('converse-loaded', () => {
async function (done, _converse) {
const muc_jid = 'room@muc.example.com';
await test_utils.openAndEnterChatRoom(_converse, muc_jid, 'romeo');
await mock.openAndEnterChatRoom(_converse, muc_jid, 'romeo');
const view = _converse.api.chatviews.get(muc_jid);
view.model.sendMessage('hello world');
@ -743,7 +742,7 @@ window.addEventListener('converse-loaded', () => {
<origin-id xmlns="urn:xmpp:sid:0" id="${msg.get('origin_id')}"/>
</message>`);
spyOn(view.model, 'updateMessage').and.callThrough();
_converse.connection._dataRecv(test_utils.createRequest(stanza));
_converse.connection._dataRecv(mock.createRequest(stanza));
await u.waitUntil(() => view.model.updateMessage.calls.count() === 1);
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");
@ -756,9 +755,9 @@ window.addEventListener('converse-loaded', () => {
['rosterGroupsFetched'], {},
async function (done, _converse) {
await test_utils.waitForRoster(_converse, 'current');
await mock.waitForRoster(_converse, 'current');
const muc_jid = 'lounge@montague.lit';
await test_utils.openAndEnterChatRoom(_converse, muc_jid, 'romeo');
await mock.openAndEnterChatRoom(_converse, muc_jid, 'romeo');
const view = _converse.api.chatviews.get(muc_jid);
const textarea = view.el.querySelector('textarea.chat-textarea');
textarea.value = 'But soft, what light through yonder airlock breaks?';
@ -779,7 +778,7 @@ window.addEventListener('converse-loaded', () => {
</message>`);
spyOn(_converse.api, "trigger").and.callThrough();
spyOn(stanza_utils, "isReceipt").and.callThrough();
_converse.connection._dataRecv(test_utils.createRequest(stanza));
_converse.connection._dataRecv(mock.createRequest(stanza));
await u.waitUntil(() => stanza_utils.isReceipt.calls.count() === 1);
expect(view.el.querySelectorAll('.chat-msg').length).toBe(1);
expect(view.el.querySelectorAll('.chat-msg__receipt').length).toBe(0);
@ -792,9 +791,9 @@ window.addEventListener('converse-loaded', () => {
['rosterGroupsFetched'], {},
async function (done, _converse) {
await test_utils.waitForRoster(_converse, 'current');
await mock.waitForRoster(_converse, 'current');
const muc_jid = 'lounge@montague.lit';
await test_utils.openAndEnterChatRoom(_converse, muc_jid, 'romeo');
await mock.openAndEnterChatRoom(_converse, muc_jid, 'romeo');
const view = _converse.api.chatviews.get(muc_jid);
const textarea = view.el.querySelector('textarea.chat-textarea');
textarea.value = 'But soft, what light through yonder airlock breaks?';
@ -816,7 +815,7 @@ window.addEventListener('converse-loaded', () => {
</message>`);
const stanza_utils = converse.env.stanza_utils;
spyOn(stanza_utils, "isChatMarker").and.callThrough();
_converse.connection._dataRecv(test_utils.createRequest(stanza));
_converse.connection._dataRecv(mock.createRequest(stanza));
await u.waitUntil(() => stanza_utils.isChatMarker.calls.count() === 1);
expect(view.el.querySelectorAll('.chat-msg').length).toBe(1);
expect(view.el.querySelectorAll('.chat-msg__receipt').length).toBe(0);
@ -826,7 +825,7 @@ window.addEventListener('converse-loaded', () => {
from="lounge@montague.lit/some1" type="groupchat" xmlns="jabber:client">
<displayed xmlns="urn:xmpp:chat-markers:0" id="${msg_obj.get('msgid')}"/>
</message>`);
_converse.connection._dataRecv(test_utils.createRequest(stanza));
_converse.connection._dataRecv(mock.createRequest(stanza));
await u.waitUntil(() => stanza_utils.isChatMarker.calls.count() === 2);
expect(view.el.querySelectorAll('.chat-msg').length).toBe(1);
expect(view.el.querySelectorAll('.chat-msg__receipt').length).toBe(0);
@ -836,7 +835,7 @@ window.addEventListener('converse-loaded', () => {
from="lounge@montague.lit/some1" type="groupchat" xmlns="jabber:client">
<acknowledged xmlns="urn:xmpp:chat-markers:0" id="${msg_obj.get('msgid')}"/>
</message>`);
_converse.connection._dataRecv(test_utils.createRequest(stanza));
_converse.connection._dataRecv(mock.createRequest(stanza));
await u.waitUntil(() => stanza_utils.isChatMarker.calls.count() === 3);
expect(view.el.querySelectorAll('.chat-msg').length).toBe(1);
@ -848,7 +847,7 @@ window.addEventListener('converse-loaded', () => {
<body>'tis I!</body>
<markable xmlns="urn:xmpp:chat-markers:0"/>
</message>`);
_converse.connection._dataRecv(test_utils.createRequest(stanza));
_converse.connection._dataRecv(mock.createRequest(stanza));
await u.waitUntil(() => stanza_utils.isChatMarker.calls.count() === 4);
expect(view.el.querySelectorAll('.chat-msg').length).toBe(2);
expect(view.el.querySelectorAll('.chat-msg__receipt').length).toBe(0);
@ -863,10 +862,10 @@ window.addEventListener('converse-loaded', () => {
async function (done, _converse) {
const muc_jid = 'lounge@montague.lit';
await test_utils.openAndEnterChatRoom(_converse, muc_jid, 'tom');
await mock.openAndEnterChatRoom(_converse, muc_jid, 'tom');
const view = _converse.api.chatviews.get(muc_jid);
['z3r0', 'mr.robot', 'gibson', 'sw0rdf1sh'].forEach((nick) => {
_converse.connection._dataRecv(test_utils.createRequest(
_converse.connection._dataRecv(mock.createRequest(
$pres({
'to': 'tom@montague.lit/resource',
'from': `lounge@montague.lit/${nick}`
@ -904,10 +903,10 @@ window.addEventListener('converse-loaded', () => {
async function (done, _converse) {
const muc_jid = 'lounge@montague.lit';
await test_utils.openAndEnterChatRoom(_converse, muc_jid, 'tom');
await mock.openAndEnterChatRoom(_converse, muc_jid, 'tom');
const view = _converse.api.chatviews.get(muc_jid);
['z3r0', 'mr.robot', 'gibson', 'sw0rdf1sh'].forEach((nick) => {
_converse.connection._dataRecv(test_utils.createRequest(
_converse.connection._dataRecv(mock.createRequest(
$pres({
'to': 'tom@montague.lit/resource',
'from': `lounge@montague.lit/${nick}`
@ -948,10 +947,10 @@ window.addEventListener('converse-loaded', () => {
async function (done, _converse) {
const muc_jid = 'lounge@montague.lit';
await test_utils.openAndEnterChatRoom(_converse, muc_jid, 'tom');
await mock.openAndEnterChatRoom(_converse, muc_jid, 'tom');
const view = _converse.api.chatviews.get(muc_jid);
['z3r0', 'mr.robot', 'gibson', 'sw0rdf1sh', 'Link Mauve'].forEach((nick) => {
_converse.connection._dataRecv(test_utils.createRequest(
_converse.connection._dataRecv(mock.createRequest(
$pres({
'to': 'tom@montague.lit/resource',
'from': `lounge@montague.lit/${nick}`
@ -1047,10 +1046,10 @@ window.addEventListener('converse-loaded', () => {
async function (done, _converse) {
const muc_jid = 'lounge@montague.lit';
await test_utils.openAndEnterChatRoom(_converse, muc_jid, 'tom');
await mock.openAndEnterChatRoom(_converse, muc_jid, 'tom');
const view = _converse.api.chatviews.get(muc_jid);
['NotAnAdress', 'darnuria'].forEach((nick) => {
_converse.connection._dataRecv(test_utils.createRequest(
_converse.connection._dataRecv(mock.createRequest(
$pres({
'to': 'tom@montague.lit/resource',
'from': `lounge@montague.lit/${nick}`
@ -1082,9 +1081,9 @@ window.addEventListener('converse-loaded', () => {
async function (done, _converse) {
const muc_jid = 'lounge@montague.lit';
await test_utils.openAndEnterChatRoom(_converse, muc_jid, 'tom');
await mock.openAndEnterChatRoom(_converse, muc_jid, 'tom');
const view = _converse.api.roomviews.get(muc_jid);
_converse.connection._dataRecv(test_utils.createRequest(
_converse.connection._dataRecv(mock.createRequest(
$pres({
'to': 'tom@montague.lit/resource',
'from': `lounge@montague.lit/Link Mauve`
@ -1126,10 +1125,10 @@ window.addEventListener('converse-loaded', () => {
async function (done, _converse) {
const muc_jid = 'lounge@montague.lit';
await test_utils.openAndEnterChatRoom(_converse, muc_jid, 'tom');
await mock.openAndEnterChatRoom(_converse, muc_jid, 'tom');
const view = _converse.api.chatviews.get(muc_jid);
['z3r0', 'mr.robot', 'gibson', 'sw0rdf1sh'].forEach((nick) => {
_converse.connection._dataRecv(test_utils.createRequest(
_converse.connection._dataRecv(mock.createRequest(
$pres({
'to': 'tom@montague.lit/resource',
'from': `lounge@montague.lit/${nick}`
@ -1204,10 +1203,10 @@ window.addEventListener('converse-loaded', () => {
async function (done, _converse) {
const muc_jid = 'lounge@montague.lit';
await test_utils.openAndEnterChatRoom(_converse, muc_jid, 'romeo');
await mock.openAndEnterChatRoom(_converse, muc_jid, 'romeo');
const view = _converse.api.chatviews.get(muc_jid);
['z3r0', 'mr.robot', 'gibson', 'sw0rdf1sh'].forEach((nick) => {
_converse.connection._dataRecv(test_utils.createRequest(
_converse.connection._dataRecv(mock.createRequest(
$pres({
'to': 'tom@montague.lit/resource',
'from': `lounge@montague.lit/${nick}`
@ -1248,5 +1247,4 @@ window.addEventListener('converse-loaded', () => {
done();
}));
});
});
});

View File

@ -1,11 +1,10 @@
window.addEventListener('converse-loaded', () => {
const mock = window.mock;
const test_utils = window.test_utils;
const _ = converse.env._;
const $msg = converse.env.$msg;
const u = converse.env.utils;
/*global mock */
describe("Notifications", function () {
const _ = converse.env._;
const $msg = converse.env.$msg;
const u = converse.env.utils;
describe("Notifications", function () {
// Implement the protocol defined in https://xmpp.org/extensions/xep-0313.html#config
describe("When show_desktop_notifications is set to true", function () {
@ -15,7 +14,7 @@ window.addEventListener('converse-loaded', () => {
it("is shown when a new private message is received",
mock.initConverse(['rosterGroupsFetched'], {}, async (done, _converse) => {
await test_utils.waitForRoster(_converse, 'current');
await mock.waitForRoster(_converse, 'current');
spyOn(_converse, 'showMessageNotification').and.callThrough();
spyOn(_converse, 'areDesktopNotificationsEnabled').and.returnValue(true);
spyOn(_converse, 'isMessageToHiddenChat').and.returnValue(true);
@ -39,8 +38,8 @@ window.addEventListener('converse-loaded', () => {
it("is shown when you are mentioned in a groupchat",
mock.initConverse(['rosterGroupsFetched'], {}, async (done, _converse) => {
await test_utils.waitForRoster(_converse, 'current');
await test_utils.openAndEnterChatRoom(_converse, 'lounge@montague.lit', 'romeo');
await mock.waitForRoster(_converse, 'current');
await mock.openAndEnterChatRoom(_converse, 'lounge@montague.lit', 'romeo');
const view = _converse.api.chatviews.get('lounge@montague.lit');
if (!view.el.querySelectorAll('.chat-area').length) {
view.renderChatArea();
@ -65,7 +64,7 @@ window.addEventListener('converse-loaded', () => {
to: 'romeo@montague.lit',
type: 'groupchat'
}).c('body').t(message).tree();
_converse.connection._dataRecv(test_utils.createRequest(msg));
_converse.connection._dataRecv(mock.createRequest(msg));
await new Promise(resolve => view.once('messageInserted', resolve));
await u.waitUntil(() => _converse.areDesktopNotificationsEnabled.calls.count() === 1);
@ -92,7 +91,7 @@ window.addEventListener('converse-loaded', () => {
.c('body').t('&lt;juliet@example.com&gt; You got mail.').up()
.c('x', {'xmlns': 'jabber:x:oob'})
.c('url').t('imap://romeo@example.com/INBOX;UIDVALIDITY=385759043/;UID=18');
_converse.connection._dataRecv(test_utils.createRequest(stanza));
_converse.connection._dataRecv(mock.createRequest(stanza));
await u.waitUntil(() => _converse.chatboxviews.keys().length);
const view = _converse.chatboxviews.get('notify.example.com');
await new Promise(resolve => view.once('messageInserted', resolve));
@ -118,7 +117,7 @@ window.addEventListener('converse-loaded', () => {
.c('body').t('&lt;juliet@example.com&gt; You got mail.').up()
.c('x', {'xmlns': 'jabber:x:oob'})
.c('url').t('imap://romeo@example.com/INBOX;UIDVALIDITY=385759043/;UID=18');
_converse.connection._dataRecv(test_utils.createRequest(stanza));
_converse.connection._dataRecv(mock.createRequest(stanza));
expect(
_.includes(_converse.chatboxviews.keys(),
'someone@notify.example.com')
@ -131,7 +130,7 @@ window.addEventListener('converse-loaded', () => {
mock.initConverse(['rosterGroupsFetched'], {show_chat_state_notifications: true},
async (done, _converse) => {
await test_utils.waitForRoster(_converse, 'current', 3);
await mock.waitForRoster(_converse, 'current', 3);
spyOn(_converse, 'areDesktopNotificationsEnabled').and.returnValue(true);
spyOn(_converse, 'showChatStateNotification');
const jid = mock.cur_names[2].replace(/ /g,'.').toLowerCase() + '@montague.lit';
@ -161,8 +160,8 @@ window.addEventListener('converse-loaded', () => {
it("is played when the current user is mentioned in a groupchat",
mock.initConverse(['rosterGroupsFetched'], {}, async (done, _converse) => {
test_utils.createContacts(_converse, 'current');
await test_utils.openAndEnterChatRoom(_converse, 'lounge@montague.lit', 'romeo');
mock.createContacts(_converse, 'current');
await mock.openAndEnterChatRoom(_converse, 'lounge@montague.lit', 'romeo');
_converse.play_sounds = true;
spyOn(_converse, 'playSoundNotification');
const view = _converse.chatboxviews.get('lounge@montague.lit');
@ -205,5 +204,4 @@ window.addEventListener('converse-loaded', () => {
}));
});
});
});
});

View File

@ -1,39 +1,38 @@
window.addEventListener('converse-loaded', () => {
const mock = window.mock;
const test_utils = window.test_utils;
const { $iq, $pres, $msg, _, Strophe } = converse.env;
const u = converse.env.utils;
/*global mock */
async function deviceListFetched (_converse, jid) {
const { $iq, $pres, $msg, _, Strophe } = converse.env;
const u = converse.env.utils;
async function deviceListFetched (_converse, jid) {
const selector = `iq[to="${jid}"] items[node="eu.siacs.conversations.axolotl.devicelist"]`;
const stanza = await u.waitUntil(
() => Array.from(_converse.connection.IQ_stanzas).filter(iq => iq.querySelector(selector)).pop()
);
await u.waitUntil(() => _converse.devicelists.get(jid));
return stanza;
}
}
function ownDeviceHasBeenPublished (_converse) {
function ownDeviceHasBeenPublished (_converse) {
return _.filter(
Array.from(_converse.connection.IQ_stanzas),
iq => iq.querySelector('iq[from="'+_converse.bare_jid+'"] publish[node="eu.siacs.conversations.axolotl.devicelist"]')
).pop();
}
}
function bundleHasBeenPublished (_converse) {
function bundleHasBeenPublished (_converse) {
const selector = 'publish[node="eu.siacs.conversations.axolotl.bundles:123456789"]';
return Array.from(_converse.connection.IQ_stanzas).filter(iq => iq.querySelector(selector)).pop();
}
}
function bundleFetched (_converse, jid, device_id) {
function bundleFetched (_converse, jid, device_id) {
return _.filter(
Array.from(_converse.connection.IQ_stanzas),
iq => iq.querySelector(`iq[to="${jid}"] items[node="eu.siacs.conversations.axolotl.bundles:${device_id}"]`)
).pop();
}
}
async function initializedOMEMO (_converse) {
await test_utils.waitUntilDiscoConfirmed(
async function initializedOMEMO (_converse) {
await mock.waitUntilDiscoConfirmed(
_converse, _converse.bare_jid,
[{'category': 'pubsub', 'type': 'pep'}],
['http://jabber.org/protocol/pubsub#publish-options']
@ -49,7 +48,7 @@ window.addEventListener('converse-loaded', () => {
.c('item', {'xmlns': "http://jabber.org/protocol/pubsub"}) // TODO: must have an id attribute
.c('list', {'xmlns': "eu.siacs.conversations.axolotl"})
.c('device', {'id': '482886413b977930064a5888b92134fe'});
_converse.connection._dataRecv(test_utils.createRequest(stanza));
_converse.connection._dataRecv(mock.createRequest(stanza));
iq_stanza = await u.waitUntil(() => ownDeviceHasBeenPublished(_converse))
stanza = $iq({
@ -57,7 +56,7 @@ window.addEventListener('converse-loaded', () => {
'id': iq_stanza.getAttribute('id'),
'to': _converse.bare_jid,
'type': 'result'});
_converse.connection._dataRecv(test_utils.createRequest(stanza));
_converse.connection._dataRecv(mock.createRequest(stanza));
iq_stanza = await u.waitUntil(() => bundleHasBeenPublished(_converse))
stanza = $iq({
@ -65,12 +64,12 @@ window.addEventListener('converse-loaded', () => {
'id': iq_stanza.getAttribute('id'),
'to': _converse.bare_jid,
'type': 'result'});
_converse.connection._dataRecv(test_utils.createRequest(stanza));
_converse.connection._dataRecv(mock.createRequest(stanza));
await _converse.api.waitUntil('OMEMOInitialized');
}
}
describe("The OMEMO module", function() {
describe("The OMEMO module", function() {
it("adds methods for encrypting and decrypting messages via AES GCM",
mock.initConverse(
@ -78,9 +77,9 @@ window.addEventListener('converse-loaded', () => {
async function (done, _converse) {
const message = 'This message will be encrypted'
await test_utils.waitForRoster(_converse, 'current', 1);
await mock.waitForRoster(_converse, 'current', 1);
const contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit';
const view = await test_utils.openChatBoxFor(_converse, contact_jid);
const view = await mock.openChatBoxFor(_converse, contact_jid);
const payload = await view.model.encryptMessage(message);
const result = await view.model.decryptMessage(payload);
expect(result).toBe(message);
@ -94,10 +93,10 @@ window.addEventListener('converse-loaded', () => {
async function (done, _converse) {
let sent_stanza;
await test_utils.waitForRoster(_converse, 'current', 1);
await mock.waitForRoster(_converse, 'current', 1);
const contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit';
await u.waitUntil(() => initializedOMEMO(_converse));
await test_utils.openChatBoxFor(_converse, contact_jid);
await mock.openChatBoxFor(_converse, contact_jid);
let iq_stanza = await u.waitUntil(() => deviceListFetched(_converse, contact_jid));
let stanza = $iq({
'from': contact_jid,
@ -109,7 +108,7 @@ window.addEventListener('converse-loaded', () => {
.c('item', {'xmlns': "http://jabber.org/protocol/pubsub"}) // TODO: must have an id attribute
.c('list', {'xmlns': "eu.siacs.conversations.axolotl"})
.c('device', {'id': '555'});
_converse.connection._dataRecv(test_utils.createRequest(stanza));
_converse.connection._dataRecv(mock.createRequest(stanza));
await u.waitUntil(() => _converse.omemo_store);
const devicelist = _converse.devicelists.get({'jid': contact_jid});
await u.waitUntil(() => devicelist.devices.length === 1);
@ -142,7 +141,7 @@ window.addEventListener('converse-loaded', () => {
.c('preKeyPublic', {'preKeyId': '1'}).t(btoa('1001')).up()
.c('preKeyPublic', {'preKeyId': '2'}).t(btoa('1002')).up()
.c('preKeyPublic', {'preKeyId': '3'}).t(btoa('1003'));
_converse.connection._dataRecv(test_utils.createRequest(stanza));
_converse.connection._dataRecv(mock.createRequest(stanza));
iq_stanza = await u.waitUntil(() => bundleFetched(_converse, _converse.bare_jid, '482886413b977930064a5888b92134fe'));
stanza = $iq({
'from': _converse.bare_jid,
@ -163,7 +162,7 @@ window.addEventListener('converse-loaded', () => {
.c('preKeyPublic', {'preKeyId': '3'}).t(btoa('1993'));
spyOn(_converse.connection, 'send').and.callFake(stanza => { sent_stanza = stanza });
_converse.connection._dataRecv(test_utils.createRequest(stanza));
_converse.connection._dataRecv(mock.createRequest(stanza));
await u.waitUntil(() => sent_stanza);
expect(sent_stanza.toLocaleString()).toBe(
`<message from="romeo@montague.lit/orchard" id="${sent_stanza.nodeTree.getAttribute("id")}" `+
@ -199,7 +198,7 @@ window.addEventListener('converse-loaded', () => {
.c('iv').t(obj.iv)
.up().up()
.c('payload').t(obj.payload);
_converse.connection._dataRecv(test_utils.createRequest(stanza));
_converse.connection._dataRecv(mock.createRequest(stanza));
await new Promise(resolve => view.once('messageInserted', resolve));
expect(view.model.messages.length).toBe(2);
expect(view.el.querySelectorAll('.chat-msg__body')[1].textContent.trim())
@ -218,7 +217,7 @@ window.addEventListener('converse-loaded', () => {
.c('iv').t(obj.iv)
.up().up()
.c('payload').t(obj.payload);
_converse.connection._dataRecv(test_utils.createRequest(stanza));
_converse.connection._dataRecv(mock.createRequest(stanza));
await new Promise(resolve => view.once('messageInserted', resolve));
await u.waitUntil(() => view.model.messages.length > 1);
expect(view.model.messages.length).toBe(3);
@ -244,7 +243,7 @@ window.addEventListener('converse-loaded', () => {
'muc_unmoderated',
'muc_nonanonymous'
];
await test_utils.openAndEnterChatRoom(_converse, 'lounge@montague.lit', 'romeo', features);
await mock.openAndEnterChatRoom(_converse, 'lounge@montague.lit', 'romeo', features);
const view = _converse.chatboxviews.get('lounge@montague.lit');
await u.waitUntil(() => initializedOMEMO(_converse));
@ -265,7 +264,7 @@ window.addEventListener('converse-loaded', () => {
'jid': 'newguy@montague.lit/_converse.js-290929789',
'role': 'participant'
}).tree();
_converse.connection._dataRecv(test_utils.createRequest(stanza));
_converse.connection._dataRecv(mock.createRequest(stanza));
// Wait for Converse to fetch newguy's device list
let iq_stanza = await u.waitUntil(() => deviceListFetched(_converse, contact_jid));
@ -287,7 +286,7 @@ window.addEventListener('converse-loaded', () => {
.c('item', {'xmlns': "http://jabber.org/protocol/pubsub"}) // TODO: must have an id attribute
.c('list', {'xmlns': "eu.siacs.conversations.axolotl"})
.c('device', {'id': '4e30f35051b7b8b42abe083742187228'}).up()
_converse.connection._dataRecv(test_utils.createRequest(stanza));
_converse.connection._dataRecv(mock.createRequest(stanza));
await u.waitUntil(() => _converse.omemo_store);
expect(_converse.devicelists.length).toBe(2);
@ -327,7 +326,7 @@ window.addEventListener('converse-loaded', () => {
.c('preKeyPublic', {'preKeyId': '1'}).t(btoa('1001')).up()
.c('preKeyPublic', {'preKeyId': '2'}).t(btoa('1002')).up()
.c('preKeyPublic', {'preKeyId': '3'}).t(btoa('1003'));
_converse.connection._dataRecv(test_utils.createRequest(stanza));
_converse.connection._dataRecv(mock.createRequest(stanza));
iq_stanza = await u.waitUntil(() => bundleFetched(_converse, _converse.bare_jid, '482886413b977930064a5888b92134fe'), 1000);
console.log("Bundle fetched 482886413b977930064a5888b92134fe");
@ -350,7 +349,7 @@ window.addEventListener('converse-loaded', () => {
.c('preKeyPublic', {'preKeyId': '3'}).t(btoa('1993'));
spyOn(_converse.connection, 'send');
_converse.connection._dataRecv(test_utils.createRequest(stanza));
_converse.connection._dataRecv(mock.createRequest(stanza));
await u.waitUntil(() => _converse.connection.send.calls.count(), 1000);
const sent_stanza = _converse.connection.send.calls.all()[0].args[0];
@ -379,11 +378,11 @@ window.addEventListener('converse-loaded', () => {
['rosterGroupsFetched', 'chatBoxesFetched'], {},
async function (done, _converse) {
await test_utils.waitUntilDiscoConfirmed(_converse, _converse.bare_jid, [], [Strophe.NS.SID]);
await test_utils.waitForRoster(_converse, 'current', 1);
await mock.waitUntilDiscoConfirmed(_converse, _converse.bare_jid, [], [Strophe.NS.SID]);
await mock.waitForRoster(_converse, 'current', 1);
const contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit';
await u.waitUntil(() => initializedOMEMO(_converse));
await test_utils.openChatBoxFor(_converse, contact_jid);
await mock.openChatBoxFor(_converse, contact_jid);
let iq_stanza = await u.waitUntil(() => deviceListFetched(_converse, contact_jid));
const stanza = $iq({
'from': contact_jid,
@ -395,7 +394,7 @@ window.addEventListener('converse-loaded', () => {
.c('item', {'xmlns': "http://jabber.org/protocol/pubsub"}) // TODO: must have an id attribute
.c('list', {'xmlns': "eu.siacs.conversations.axolotl"})
.c('device', {'id': '555'});
_converse.connection._dataRecv(test_utils.createRequest(stanza));
_converse.connection._dataRecv(mock.createRequest(stanza));
await u.waitUntil(() => _converse.omemo_store);
const devicelist = _converse.devicelists.get({'jid': contact_jid});
await u.waitUntil(() => devicelist.devices.length === 1);
@ -435,7 +434,7 @@ window.addEventListener('converse-loaded', () => {
</sent>
</message>
`);
_converse.connection._dataRecv(test_utils.createRequest(carbon));
_converse.connection._dataRecv(mock.createRequest(carbon));
await new Promise(resolve => view.once('messageInserted', resolve));
expect(view.model.messages.length).toBe(1);
expect(view.el.querySelector('.chat-msg__body').textContent.trim())
@ -480,7 +479,7 @@ window.addEventListener('converse-loaded', () => {
'muc_unmoderated',
'muc_nonanonymous'
];
await test_utils.openAndEnterChatRoom(_converse, 'lounge@montague.lit', 'romeo', features);
await mock.openAndEnterChatRoom(_converse, 'lounge@montague.lit', 'romeo', features);
const view = _converse.chatboxviews.get('lounge@montague.lit');
await u.waitUntil(() => initializedOMEMO(_converse));
@ -495,7 +494,7 @@ window.addEventListener('converse-loaded', () => {
'jid': 'newguy@montague.lit/_converse.js-290929789',
'role': 'participant'
}).tree();
_converse.connection._dataRecv(test_utils.createRequest(stanza));
_converse.connection._dataRecv(mock.createRequest(stanza));
const toolbar = view.el.querySelector('.chat-toolbar');
const toggle = toolbar.querySelector('.toggle-omemo');
@ -529,7 +528,7 @@ window.addEventListener('converse-loaded', () => {
.c('list', {'xmlns': "eu.siacs.conversations.axolotl"})
.c('device', {'id': '4e30f35051b7b8b42abe083742187228'}).up()
_converse.connection._dataRecv(test_utils.createRequest(stanza));
_converse.connection._dataRecv(mock.createRequest(stanza));
await u.waitUntil(() => _converse.omemo_store);
expect(_converse.devicelists.length).toBe(2);
@ -578,7 +577,7 @@ window.addEventListener('converse-loaded', () => {
.c('error', {'code': '401', 'type': 'auth'})
.c('presence-subscription-required', {'xmlns':"http://jabber.org/protocol/pubsub#errors" }).up()
.c('not-authorized', {'xmlns': "urn:ietf:params:xml:ns:xmpp-stanzas"});
_converse.connection._dataRecv(test_utils.createRequest(stanza));
_converse.connection._dataRecv(mock.createRequest(stanza));
await u.waitUntil(() => document.querySelectorAll('.alert-danger').length, 2000);
const header = document.querySelector('.alert-danger .modal-title');
@ -598,7 +597,7 @@ window.addEventListener('converse-loaded', () => {
async function (done, _converse) {
_converse.NUM_PREKEYS = 5; // Restrict to 5, otherwise the resulting stanza is too large to easily test
await test_utils.waitForRoster(_converse, 'current', 1);
await mock.waitForRoster(_converse, 'current', 1);
const contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit';
await u.waitUntil(() => initializedOMEMO(_converse));
@ -631,7 +630,7 @@ window.addEventListener('converse-loaded', () => {
_converse.omemo_store.removePreKey(1);
return generateMissingPreKeys.apply(_converse.omemo_store, arguments);
});
_converse.connection._dataRecv(test_utils.createRequest(stanza));
_converse.connection._dataRecv(mock.createRequest(stanza));
let iq_stanza = await u.waitUntil(() => _converse.chatboxviews.get(contact_jid));
iq_stanza = await deviceListFetched(_converse, contact_jid);
stanza = $iq({
@ -649,7 +648,7 @@ window.addEventListener('converse-loaded', () => {
// that we wait for the 2nd, so we clear all the already sent
// stanzas.
_converse.connection.IQ_stanzas = [];
_converse.connection._dataRecv(test_utils.createRequest(stanza));
_converse.connection._dataRecv(mock.createRequest(stanza));
await u.waitUntil(() => _converse.omemo_store);
iq_stanza = await u.waitUntil(() => bundleHasBeenPublished(_converse));
@ -696,13 +695,13 @@ window.addEventListener('converse-loaded', () => {
['rosterGroupsFetched'], {'allow_non_roster_messaging': true},
async function (done, _converse) {
await test_utils.waitUntilDiscoConfirmed(
await mock.waitUntilDiscoConfirmed(
_converse, _converse.bare_jid,
[{'category': 'pubsub', 'type': 'pep'}],
['http://jabber.org/protocol/pubsub#publish-options']
);
await test_utils.waitForRoster(_converse, 'current', 1);
await mock.waitForRoster(_converse, 'current', 1);
const contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit';
// Wait until own devices are fetched
@ -724,7 +723,7 @@ window.addEventListener('converse-loaded', () => {
.c('item', {'xmlns': "http://jabber.org/protocol/pubsub"}) // TODO: must have an id attribute
.c('list', {'xmlns': "eu.siacs.conversations.axolotl"})
.c('device', {'id': '555'});
_converse.connection._dataRecv(test_utils.createRequest(stanza));
_converse.connection._dataRecv(mock.createRequest(stanza));
await u.waitUntil(() => _converse.omemo_store);
expect(_converse.chatboxes.length).toBe(1);
expect(_converse.devicelists.length).toBe(1);
@ -738,7 +737,7 @@ window.addEventListener('converse-loaded', () => {
'id': iq_stanza.getAttribute('id'),
'to': _converse.bare_jid,
'type': 'result'});
_converse.connection._dataRecv(test_utils.createRequest(stanza));
_converse.connection._dataRecv(mock.createRequest(stanza));
iq_stanza = await u.waitUntil(() => bundleHasBeenPublished(_converse));
stanza = $iq({
@ -746,7 +745,7 @@ window.addEventListener('converse-loaded', () => {
'id': iq_stanza.getAttribute('id'),
'to': _converse.bare_jid,
'type': 'result'});
_converse.connection._dataRecv(test_utils.createRequest(stanza));
_converse.connection._dataRecv(mock.createRequest(stanza));
await _converse.api.waitUntil('OMEMOInitialized');
stanza = $msg({
@ -760,7 +759,7 @@ window.addEventListener('converse-loaded', () => {
.c('list', {'xmlns': 'eu.siacs.conversations.axolotl'})
.c('device', {'id': '1234'})
.c('device', {'id': '4223'})
_converse.connection._dataRecv(test_utils.createRequest(stanza));
_converse.connection._dataRecv(mock.createRequest(stanza));
expect(_converse.devicelists.length).toBe(2);
let devices = _converse.devicelists.get(contact_jid).devices;
@ -778,7 +777,7 @@ window.addEventListener('converse-loaded', () => {
.c('list', {'xmlns': 'eu.siacs.conversations.axolotl'})
.c('device', {'id': '4223'})
.c('device', {'id': '4224'})
_converse.connection._dataRecv(test_utils.createRequest(stanza));
_converse.connection._dataRecv(mock.createRequest(stanza));
expect(_converse.devicelists.length).toBe(2);
expect(devices.length).toBe(3);
@ -800,7 +799,7 @@ window.addEventListener('converse-loaded', () => {
.c('device', {'id': '123456789'})
.c('device', {'id': '555'})
.c('device', {'id': '777'})
_converse.connection._dataRecv(test_utils.createRequest(stanza));
_converse.connection._dataRecv(mock.createRequest(stanza));
expect(_converse.devicelists.length).toBe(2);
devices = _converse.devicelists.get(_converse.bare_jid).devices;
@ -823,7 +822,7 @@ window.addEventListener('converse-loaded', () => {
.c('item')
.c('list', {'xmlns': 'eu.siacs.conversations.axolotl'})
.c('device', {'id': '444'})
_converse.connection._dataRecv(test_utils.createRequest(stanza));
_converse.connection._dataRecv(mock.createRequest(stanza));
iq_stanza = await u.waitUntil(() => ownDeviceHasBeenPublished(_converse));
// Check that our own device is added again, but that removed
@ -870,13 +869,13 @@ window.addEventListener('converse-loaded', () => {
['rosterGroupsFetched'], {},
async function (done, _converse) {
await test_utils.waitUntilDiscoConfirmed(
await mock.waitUntilDiscoConfirmed(
_converse, _converse.bare_jid,
[{'category': 'pubsub', 'type': 'pep'}],
['http://jabber.org/protocol/pubsub#publish-options']
);
await test_utils.waitForRoster(_converse, 'current');
await mock.waitForRoster(_converse, 'current');
const contact_jid = mock.cur_names[3].replace(/ /g,'.').toLowerCase() + '@montague.lit';
let iq_stanza = await u.waitUntil(() => deviceListFetched(_converse, _converse.bare_jid));
expect(Strophe.serialize(iq_stanza)).toBe(
@ -896,7 +895,7 @@ window.addEventListener('converse-loaded', () => {
.c('item', {'xmlns': "http://jabber.org/protocol/pubsub"}) // TODO: must have an id attribute
.c('list', {'xmlns': "eu.siacs.conversations.axolotl"})
.c('device', {'id': '555'});
_converse.connection._dataRecv(test_utils.createRequest(stanza));
_converse.connection._dataRecv(mock.createRequest(stanza));
await await u.waitUntil(() => _converse.omemo_store);
expect(_converse.devicelists.length).toBe(1);
let devicelist = _converse.devicelists.get(_converse.bare_jid);
@ -909,14 +908,14 @@ window.addEventListener('converse-loaded', () => {
'id': iq_stanza.getAttribute('id'),
'to': _converse.bare_jid,
'type': 'result'});
_converse.connection._dataRecv(test_utils.createRequest(stanza));
_converse.connection._dataRecv(mock.createRequest(stanza));
iq_stanza = await u.waitUntil(() => bundleHasBeenPublished(_converse));
stanza = $iq({
'from': _converse.bare_jid,
'id': iq_stanza.getAttribute('id'),
'to': _converse.bare_jid,
'type': 'result'});
_converse.connection._dataRecv(test_utils.createRequest(stanza));
_converse.connection._dataRecv(mock.createRequest(stanza));
await _converse.api.waitUntil('OMEMOInitialized');
stanza = $msg({
'from': contact_jid,
@ -934,7 +933,7 @@ window.addEventListener('converse-loaded', () => {
.c('preKeyPublic', {'preKeyId': '1001'}).up()
.c('preKeyPublic', {'preKeyId': '1002'}).up()
.c('preKeyPublic', {'preKeyId': '1003'});
_converse.connection._dataRecv(test_utils.createRequest(stanza));
_converse.connection._dataRecv(mock.createRequest(stanza));
expect(_converse.devicelists.length).toBe(2);
devicelist = _converse.devicelists.get(contact_jid);
@ -965,7 +964,7 @@ window.addEventListener('converse-loaded', () => {
.c('preKeyPublic', {'preKeyId': '2001'}).up()
.c('preKeyPublic', {'preKeyId': '2002'}).up()
.c('preKeyPublic', {'preKeyId': '2003'});
_converse.connection._dataRecv(test_utils.createRequest(stanza));
_converse.connection._dataRecv(mock.createRequest(stanza));
expect(_converse.devicelists.length).toBe(2);
devicelist = _converse.devicelists.get(contact_jid);
@ -996,7 +995,7 @@ window.addEventListener('converse-loaded', () => {
.c('preKeyPublic', {'preKeyId': '3001'}).up()
.c('preKeyPublic', {'preKeyId': '3002'}).up()
.c('preKeyPublic', {'preKeyId': '3003'});
_converse.connection._dataRecv(test_utils.createRequest(stanza));
_converse.connection._dataRecv(mock.createRequest(stanza));
expect(_converse.devicelists.length).toBe(2);
devicelist = _converse.devicelists.get(_converse.bare_jid);
@ -1020,7 +1019,7 @@ window.addEventListener('converse-loaded', () => {
['rosterGroupsFetched', 'chatBoxesFetched'], {},
async function (done, _converse) {
await test_utils.waitUntilDiscoConfirmed(
await mock.waitUntilDiscoConfirmed(
_converse, _converse.bare_jid,
[{'category': 'pubsub', 'type': 'pep'}],
['http://jabber.org/protocol/pubsub#publish-options']
@ -1028,7 +1027,7 @@ window.addEventListener('converse-loaded', () => {
_converse.NUM_PREKEYS = 2; // Restrict to 2, otherwise the resulting stanza is too large to easily test
await test_utils.waitForRoster(_converse, 'current', 1);
await mock.waitForRoster(_converse, 'current', 1);
const contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit';
let iq_stanza = await u.waitUntil(() => deviceListFetched(_converse, _converse.bare_jid));
let stanza = $iq({
@ -1041,16 +1040,16 @@ window.addEventListener('converse-loaded', () => {
.c('item', {'xmlns': "http://jabber.org/protocol/pubsub"}) // TODO: must have an id attribute
.c('list', {'xmlns': "eu.siacs.conversations.axolotl"})
.c('device', {'id': '482886413b977930064a5888b92134fe'});
_converse.connection._dataRecv(test_utils.createRequest(stanza));
_converse.connection._dataRecv(mock.createRequest(stanza));
expect(_converse.devicelists.length).toBe(1);
await test_utils.openChatBoxFor(_converse, contact_jid);
await mock.openChatBoxFor(_converse, contact_jid);
iq_stanza = await ownDeviceHasBeenPublished(_converse);
stanza = $iq({
'from': _converse.bare_jid,
'id': iq_stanza.getAttribute('id'),
'to': _converse.bare_jid,
'type': 'result'});
_converse.connection._dataRecv(test_utils.createRequest(stanza));
_converse.connection._dataRecv(mock.createRequest(stanza));
iq_stanza = await u.waitUntil(() => bundleHasBeenPublished(_converse));
expect(Strophe.serialize(iq_stanza)).toBe(
@ -1087,7 +1086,7 @@ window.addEventListener('converse-loaded', () => {
'id': iq_stanza.getAttribute('id'),
'to': _converse.bare_jid,
'type': 'result'});
_converse.connection._dataRecv(test_utils.createRequest(stanza));
_converse.connection._dataRecv(mock.createRequest(stanza));
await _converse.api.waitUntil('OMEMOInitialized');
done();
}));
@ -1098,13 +1097,13 @@ window.addEventListener('converse-loaded', () => {
['rosterGroupsFetched', 'chatBoxesFetched'], {},
async function (done, _converse) {
await test_utils.waitUntilDiscoConfirmed(
await mock.waitUntilDiscoConfirmed(
_converse, _converse.bare_jid,
[{'category': 'pubsub', 'type': 'pep'}],
['http://jabber.org/protocol/pubsub#publish-options']
);
await test_utils.waitForRoster(_converse, 'current', 1);
await mock.waitForRoster(_converse, 'current', 1);
const contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit';
let iq_stanza = await u.waitUntil(() => deviceListFetched(_converse, _converse.bare_jid));
@ -1125,7 +1124,7 @@ window.addEventListener('converse-loaded', () => {
.c('item', {'xmlns': "http://jabber.org/protocol/pubsub"}) // TODO: must have an id attribute
.c('list', {'xmlns': "eu.siacs.conversations.axolotl"})
.c('device', {'id': '482886413b977930064a5888b92134fe'});
_converse.connection._dataRecv(test_utils.createRequest(stanza));
_converse.connection._dataRecv(mock.createRequest(stanza));
await u.waitUntil(() => _converse.omemo_store);
expect(_converse.devicelists.length).toBe(1);
let devicelist = _converse.devicelists.get(_converse.bare_jid);
@ -1163,7 +1162,7 @@ window.addEventListener('converse-loaded', () => {
'id': iq_stanza.getAttribute('id'),
'to': _converse.bare_jid,
'type': 'result'});
_converse.connection._dataRecv(test_utils.createRequest(stanza));
_converse.connection._dataRecv(mock.createRequest(stanza));
const iq_el = await u.waitUntil(() => bundleHasBeenPublished(_converse));
expect(iq_el.getAttributeNames().sort().join()).toBe(["from", "type", "xmlns", "id"].sort().join());
@ -1181,9 +1180,9 @@ window.addEventListener('converse-loaded', () => {
'id': iq_el.getAttribute('id'),
'to': _converse.bare_jid,
'type': 'result'});
_converse.connection._dataRecv(test_utils.createRequest(stanza));
_converse.connection._dataRecv(mock.createRequest(stanza));
await _converse.api.waitUntil('OMEMOInitialized', 1000);
await test_utils.openChatBoxFor(_converse, contact_jid);
await mock.openChatBoxFor(_converse, contact_jid);
iq_stanza = await u.waitUntil(() => deviceListFetched(_converse, contact_jid));
expect(Strophe.serialize(iq_stanza)).toBe(
`<iq from="romeo@montague.lit" id="${iq_stanza.getAttribute("id")}" to="${contact_jid}" type="get" xmlns="jabber:client">`+
@ -1205,7 +1204,7 @@ window.addEventListener('converse-loaded', () => {
.c('device', {'id': '3300659945416e274474e469a1f0154c'}).up()
.c('device', {'id': '4e30f35051b7b8b42abe083742187228'}).up()
.c('device', {'id': 'ae890ac52d0df67ed7cfdf51b644e901'});
_converse.connection._dataRecv(test_utils.createRequest(stanza));
_converse.connection._dataRecv(mock.createRequest(stanza));
devicelist = _converse.devicelists.get(contact_jid);
await u.waitUntil(() => devicelist.devices.length);
expect(_converse.devicelists.length).toBe(2);
@ -1262,7 +1261,7 @@ window.addEventListener('converse-loaded', () => {
['rosterGroupsFetched', 'chatBoxesFetched'], {'view_mode': 'fullscreen'},
async function (done, _converse) {
await test_utils.waitUntilDiscoConfirmed(
await mock.waitUntilDiscoConfirmed(
_converse, _converse.bare_jid,
[{'category': 'pubsub', 'type': 'pep'}],
['http://jabber.org/protocol/pubsub#publish-options']
@ -1279,7 +1278,7 @@ window.addEventListener('converse-loaded', () => {
'muc_unmoderated',
'muc_nonanonymous'
];
await test_utils.openAndEnterChatRoom(_converse, 'lounge@montague.lit', 'romeo', features);
await mock.openAndEnterChatRoom(_converse, 'lounge@montague.lit', 'romeo', features);
const view = _converse.chatboxviews.get('lounge@montague.lit');
await u.waitUntil(() => initializedOMEMO(_converse));
@ -1311,7 +1310,7 @@ window.addEventListener('converse-loaded', () => {
'jid': 'newguy@montague.lit/_converse.js-290929789',
'role': 'participant'
}).tree();
_converse.connection._dataRecv(test_utils.createRequest(stanza));
_converse.connection._dataRecv(mock.createRequest(stanza));
let iq_stanza = await u.waitUntil(() => deviceListFetched(_converse, contact_jid));
expect(Strophe.serialize(iq_stanza)).toBe(
@ -1332,7 +1331,7 @@ window.addEventListener('converse-loaded', () => {
.c('list', {'xmlns': "eu.siacs.conversations.axolotl"})
.c('device', {'id': '4e30f35051b7b8b42abe083742187228'}).up()
.c('device', {'id': 'ae890ac52d0df67ed7cfdf51b644e901'});
_converse.connection._dataRecv(test_utils.createRequest(stanza));
_converse.connection._dataRecv(mock.createRequest(stanza));
await u.waitUntil(() => _converse.omemo_store);
expect(_converse.devicelists.length).toBe(2);
@ -1398,7 +1397,7 @@ window.addEventListener('converse-loaded', () => {
'jid': `${contact_jid}/_converse.js-290929788`,
'role': 'participant'
}).tree();
_converse.connection._dataRecv(test_utils.createRequest(stanza));
_converse.connection._dataRecv(mock.createRequest(stanza));
iq_stanza = await u.waitUntil(() => deviceListFetched(_converse, contact_jid));
expect(Strophe.serialize(iq_stanza)).toBe(
`<iq from="romeo@montague.lit" id="${iq_stanza.getAttribute("id")}" to="${contact_jid}" type="get" xmlns="jabber:client">`+
@ -1414,7 +1413,7 @@ window.addEventListener('converse-loaded', () => {
'type': 'error'
}).c('error', {'type': 'cancel'})
.c('item-not-found', {'xmlns': "urn:ietf:params:xml:ns:xmpp-stanzas"});
_converse.connection._dataRecv(test_utils.createRequest(stanza));
_converse.connection._dataRecv(mock.createRequest(stanza));
await u.waitUntil(() => !view.model.get('omemo_supported'));
@ -1444,15 +1443,15 @@ window.addEventListener('converse-loaded', () => {
['rosterGroupsFetched', 'chatBoxesFetched'], {},
async function (done, _converse) {
await test_utils.waitUntilDiscoConfirmed(
await mock.waitUntilDiscoConfirmed(
_converse, _converse.bare_jid,
[{'category': 'pubsub', 'type': 'pep'}],
['http://jabber.org/protocol/pubsub#publish-options']
);
await test_utils.waitForRoster(_converse, 'current', 1);
await mock.waitForRoster(_converse, 'current', 1);
const contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit';
await test_utils.openChatBoxFor(_converse, contact_jid)
await mock.openChatBoxFor(_converse, contact_jid)
// We simply emit, to avoid doing all the setup work
_converse.api.trigger('OMEMOInitialized');
@ -1476,7 +1475,7 @@ window.addEventListener('converse-loaded', () => {
.c('item', {'xmlns': "http://jabber.org/protocol/pubsub"}) // TODO: must have an id attribute
.c('list', {'xmlns': "eu.siacs.conversations.axolotl"})
.c('device', {'id': '555'});
_converse.connection._dataRecv(test_utils.createRequest(stanza));
_converse.connection._dataRecv(mock.createRequest(stanza));
await u.waitUntil(() => u.isVisible(modal.el), 1000);
iq_stanza = await u.waitUntil(() => bundleFetched(_converse, contact_jid, '555'));
expect(Strophe.serialize(iq_stanza)).toBe(
@ -1502,7 +1501,7 @@ window.addEventListener('converse-loaded', () => {
.c('preKeyPublic', {'preKeyId': '1'}).t(btoa('1001')).up()
.c('preKeyPublic', {'preKeyId': '2'}).t(btoa('1002')).up()
.c('preKeyPublic', {'preKeyId': '3'}).t(btoa('1003'));
_converse.connection._dataRecv(test_utils.createRequest(stanza));
_converse.connection._dataRecv(mock.createRequest(stanza));
await u.waitUntil(() => modal.el.querySelectorAll('.fingerprints .fingerprint').length);
expect(modal.el.querySelectorAll('.fingerprints .fingerprint').length).toBe(1);
@ -1534,5 +1533,4 @@ window.addEventListener('converse-loaded', () => {
expect(devicelist.devices.get('555').get('trusted')).toBe(1);
done();
}));
});
});

View File

@ -1,11 +1,10 @@
window.addEventListener('converse-loaded', () => {
const mock = window.mock;
const test_utils = window.test_utils;
const Strophe = converse.env.Strophe;
const u = converse.env.utils;
/*global mock */
const Strophe = converse.env.Strophe;
const u = converse.env.utils;
describe("XMPP Ping", function () {
describe("XMPP Ping", function () {
describe("An IQ stanza", function () {
@ -15,7 +14,7 @@ window.addEventListener('converse-loaded', () => {
to="${_converse.jid}" id="s2c1" type="get">
<ping xmlns="urn:xmpp:ping"/>
</iq>`);
_converse.connection._dataRecv(test_utils.createRequest(ping));
_converse.connection._dataRecv(mock.createRequest(ping));
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"/>`);
@ -32,5 +31,4 @@ window.addEventListener('converse-loaded', () => {
done();
}));
});
});
});

View File

@ -1,11 +1,7 @@
window.addEventListener('converse-loaded', () => {
const mock = window.mock;
const test_utils = window.test_utils;
const Strophe = converse.env.Strophe;
const u = converse.env.utils;
// See: https://xmpp.org/rfcs/rfc3921.html
/*global mock */
// See: https://xmpp.org/rfcs/rfc3921.html
describe("A sent presence stanza", function () {
describe("A sent presence stanza", function () {
it("includes a entity capabilities node",
mock.initConverse(
@ -68,7 +64,8 @@ window.addEventListener('converse-loaded', () => {
['rosterGroupsFetched'], {},
async (done, _converse) => {
test_utils.openControlBox(_converse);
const { u, Strophe } = converse.env;
mock.openControlBox(_converse);
spyOn(_converse.connection, 'send').and.callThrough();
const cbview = _converse.chatboxviews.get('controlbox');
@ -106,17 +103,18 @@ window.addEventListener('converse-loaded', () => {
`</presence>`)
done();
}));
});
});
describe("A received presence stanza", function () {
describe("A received presence stanza", function () {
it("has its priority taken into account",
mock.initConverse(
['rosterGroupsFetched'], {},
async (done, _converse) => {
test_utils.openControlBox(_converse);
await test_utils.waitForRoster(_converse, 'current');
const u = converse.env.utils;
mock.openControlBox(_converse);
await mock.waitForRoster(_converse, 'current');
const contact_jid = mock.cur_names[8].replace(/ /g,'.').toLowerCase() + '@montague.lit';
const contact = await _converse.api.contacts.get(contact_jid);
let stanza = u.toStanza(`
@ -131,7 +129,7 @@ window.addEventListener('converse-loaded', () => {
</x>
<delay xmlns="urn:xmpp:delay" stamp="2017-02-15T20:26:05Z" from="${contact_jid}/priority-1-resource"/>
</presence>`);
_converse.connection._dataRecv(test_utils.createRequest(stanza));
_converse.connection._dataRecv(mock.createRequest(stanza));
expect(contact.presence.get('show')).toBe('online');
expect(contact.presence.resources.length).toBe(1);
expect(contact.presence.resources.get('priority-1-resource').get('priority')).toBe(1);
@ -148,7 +146,7 @@ window.addEventListener('converse-loaded', () => {
' node="http://www.igniterealtime.org/projects/smack/"/>'+
' <delay xmlns="urn:xmpp:delay" stamp="2017-02-15T17:02:24Z" from="'+contact_jid+'/priority-0-resource"/>'+
'</presence>');
_converse.connection._dataRecv(test_utils.createRequest(stanza));
_converse.connection._dataRecv(mock.createRequest(stanza));
expect(contact.presence.get('show')).toBe('online');
expect(contact.presence.resources.length).toBe(2);
@ -164,7 +162,7 @@ window.addEventListener('converse-loaded', () => {
' <priority>2</priority>'+
' <show>dnd</show>'+
'</presence>');
_converse.connection._dataRecv(test_utils.createRequest(stanza));
_converse.connection._dataRecv(mock.createRequest(stanza));
expect(contact.presence.get('show')).toBe('dnd');
expect(contact.presence.resources.length).toBe(3);
expect(contact.presence.resources.get('priority-0-resource').get('priority')).toBe(0);
@ -181,7 +179,7 @@ window.addEventListener('converse-loaded', () => {
' <priority>3</priority>'+
' <show>away</show>'+
'</presence>');
_converse.connection._dataRecv(test_utils.createRequest(stanza));
_converse.connection._dataRecv(mock.createRequest(stanza));
expect(_converse.roster.get(contact_jid).presence.get('show')).toBe('away');
expect(contact.presence.resources.length).toBe(4);
expect(contact.presence.resources.get('priority-0-resource').get('priority')).toBe(0);
@ -201,7 +199,7 @@ window.addEventListener('converse-loaded', () => {
' <show>dnd</show>'+
' <delay xmlns="urn:xmpp:delay" stamp="2017-02-15T15:02:24Z" from="'+contact_jid+'/older-priority-1-resource"/>'+
'</presence>');
_converse.connection._dataRecv(test_utils.createRequest(stanza));
_converse.connection._dataRecv(mock.createRequest(stanza));
expect(_converse.roster.get(contact_jid).presence.get('show')).toBe('away');
expect(contact.presence.resources.length).toBe(5);
expect(contact.presence.resources.get('older-priority-1-resource').get('priority')).toBe(1);
@ -221,7 +219,7 @@ window.addEventListener('converse-loaded', () => {
' type="unavailable"'+
' from="'+contact_jid+'/priority-3-resource">'+
'</presence>');
_converse.connection._dataRecv(test_utils.createRequest(stanza));
_converse.connection._dataRecv(mock.createRequest(stanza));
expect(_converse.roster.get(contact_jid).presence.get('show')).toBe('dnd');
expect(contact.presence.resources.length).toBe(4);
expect(contact.presence.resources.get('priority-0-resource').get('priority')).toBe(0);
@ -239,7 +237,7 @@ window.addEventListener('converse-loaded', () => {
' type="unavailable"'+
' from="'+contact_jid+'/priority-2-resource">'+
'</presence>');
_converse.connection._dataRecv(test_utils.createRequest(stanza));
_converse.connection._dataRecv(mock.createRequest(stanza));
expect(_converse.roster.get(contact_jid).presence.get('show')).toBe('online');
expect(contact.presence.resources.length).toBe(3);
expect(contact.presence.resources.get('priority-0-resource').get('priority')).toBe(0);
@ -255,7 +253,7 @@ window.addEventListener('converse-loaded', () => {
' type="unavailable"'+
' from="'+contact_jid+'/priority-1-resource">'+
'</presence>');
_converse.connection._dataRecv(test_utils.createRequest(stanza));
_converse.connection._dataRecv(mock.createRequest(stanza));
expect(_converse.roster.get(contact_jid).presence.get('show')).toBe('dnd');
expect(contact.presence.resources.length).toBe(2);
expect(contact.presence.resources.get('priority-0-resource').get('priority')).toBe(0);
@ -269,7 +267,7 @@ window.addEventListener('converse-loaded', () => {
' type="unavailable"'+
' from="'+contact_jid+'/older-priority-1-resource">'+
'</presence>');
_converse.connection._dataRecv(test_utils.createRequest(stanza));
_converse.connection._dataRecv(mock.createRequest(stanza));
expect(_converse.roster.get(contact_jid).presence.get('show')).toBe('xa');
expect(contact.presence.resources.length).toBe(1);
expect(contact.presence.resources.get('priority-0-resource').get('priority')).toBe(0);
@ -281,10 +279,9 @@ window.addEventListener('converse-loaded', () => {
' type="unavailable"'+
' from="'+contact_jid+'/priority-0-resource">'+
'</presence>');
_converse.connection._dataRecv(test_utils.createRequest(stanza));
_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

@ -1,131 +0,0 @@
(function (root, factory) {
define(["jasmine", "mock", "test-utils"], factory);
} (this, function (jasmine, mock, test_utils) {
var _ = converse.env._;
var $iq = converse.env.$iq;
var $pres = converse.env.$pres;
var u = converse.env.utils;
describe("Profiling", function() {
it("shows users currently present in the groupchat",
mock.initConverse(
['rosterGroupsFetched'], {'muc_show_join_leave': false},
async function (done, _converse) {
test_utils.openControlBox(_converse);
await test_utils.openAndEnterChatRoom(_converse, 'lounge@montague.lit', 'romeo');
_.rangeRight(3000, 0).forEach(i => {
const name = `User ${i.toString().padStart(5, '0')}`;
const presence = $pres({
'to': 'romeo@montague.lit/orchard',
'from': 'lounge@montague.lit/'+name
}).c('x').attrs({xmlns:'http://jabber.org/protocol/muc#user'})
.c('item').attrs({
affiliation: 'none',
jid: name.replace(/ /g,'.').toLowerCase() + '@montague.lit',
});
_converse.connection._dataRecv(test_utils.createRequest(presence));
// expect(occupants.querySelectorAll('li').length).toBe(1+i);
// const model = view.model.occupants.where({'nick': name})[0];
// const index = view.model.occupants.indexOf(model);
// expect(occupants.querySelectorAll('li .occupant-nick')[index].textContent.trim()).toBe(name);
});
done();
}));
xit("adds hundreds of contacts to the roster",
mock.initConverse(
['rosterGroupsFetched'], {},
function (done, _converse) {
_converse.roster_groups = false;
test_utils.openControlBox(_converse);
expect(_converse.roster.pluck('jid').length).toBe(0);
var stanza = $iq({
to: _converse.connection.jid,
type: 'result',
id: 'roster_1'
}).c('query', {
xmlns: 'jabber:iq:roster'
});
_.each(['Friends', 'Colleagues', 'Family', 'Acquaintances'], function (group) {
var i;
for (i=0; i<50; i++) {
stanza = stanza.c('item', {
jid: Math.random().toString().replace('0.', '')+'@example.net',
subscription:'both'
}).c('group').t(group).up().up();
}
});
_converse.roster.onReceivedFromServer(stanza.tree());
return u.waitUntil(function () {
var $group = _converse.rosterview.$el.find('.roster-group')
return $group.length && u.isVisible($group[0]);
}).then(function () {
var count = 0;
_converse.roster.each(function (contact) {
if (count < 10) {
contact.set('chat_status', 'online');
count += 1;
}
});
return u.waitUntil(function () {
return _converse.rosterview.$el.find('li.online').length
})
}).then(done);
}));
xit("adds hundreds of contacts to the roster, with roster groups",
mock.initConverse(
['rosterGroupsFetched'], {},
function (done, _converse) {
// _converse.show_only_online_users = true;
_converse.roster_groups = true;
test_utils.openControlBox(_converse);
expect(_converse.roster.pluck('jid').length).toBe(0);
var stanza = $iq({
to: _converse.connection.jid,
type: 'result',
id: 'roster_1'
}).c('query', {
xmlns: 'jabber:iq:roster'
});
_.each(['Friends', 'Colleagues', 'Family', 'Acquaintances'], function (group) {
var i;
for (i=0; i<100; i++) {
stanza = stanza.c('item', {
jid: Math.random().toString().replace('0.', '')+'@example.net',
subscription:'both'
}).c('group').t(group).up().up();
}
});
_converse.roster.onReceivedFromServer(stanza.tree());
return u.waitUntil(function () {
var $group = _converse.rosterview.$el.find('.roster-group')
return $group.length && u.isVisible($group[0]);
}).then(function () {
_.each(['Friends', 'Colleagues', 'Family', 'Acquaintances'], function (group) {
var count = 0;
_converse.roster.each(function (contact) {
if (_.includes(contact.get('groups'), group)) {
if (count < 10) {
contact.set('chat_status', 'online');
count += 1;
}
}
});
});
return u.waitUntil(function () {
return _converse.rosterview.$el.find('li.online').length
})
}).then(done);
}));
});
}));

View File

@ -1,16 +1,8 @@
window.addEventListener('converse-loaded', () => {
const mock = window.mock;
const test_utils = window.test_utils;
const $iq = converse.env.$iq;
const $pres = converse.env.$pres;
const Strophe = converse.env.Strophe;
const _ = converse.env._;
const sizzle = converse.env.sizzle;
const u = converse.env.utils;
// See:
// https://xmpp.org/rfcs/rfc3921.html
/*global mock */
describe("The Protocol", function () {
// See: https://xmpp.org/rfcs/rfc3921.html
describe("The Protocol", function () {
describe("Integration of Roster Items and Presence Subscriptions", function () {
// Stub the trimChat method. It causes havoc when running with
@ -50,13 +42,14 @@ window.addEventListener('converse-loaded', () => {
{ roster_groups: false },
async function (done, _converse) {
const { u, $iq, $pres, sizzle, Strophe } = converse.env;
let contact, sent_stanza, IQ_id, stanza;
await test_utils.waitUntilDiscoConfirmed(_converse, 'montague.lit', [], ['vcard-temp']);
await mock.waitUntilDiscoConfirmed(_converse, 'montague.lit', [], ['vcard-temp']);
await u.waitUntil(() => _converse.xmppstatus.vcard.get('fullname'), 300);
/* The process by which a user subscribes to a contact, including
* the interaction between roster items and subscription states.
*/
test_utils.openControlBox(_converse);
mock.openControlBox(_converse);
const cbview = _converse.chatboxviews.get('controlbox');
spyOn(_converse.roster, "addAndSubscribe").and.callThrough();
@ -108,7 +101,7 @@ window.addEventListener('converse-loaded', () => {
* </query>
* </iq>
*/
await test_utils.waitForRoster(_converse, 'all', 0);
await mock.waitForRoster(_converse, 'all', 0);
expect(_converse.roster.sendContactAddIQ).toHaveBeenCalled();
expect(sent_stanza.toLocaleString()).toBe(
`<iq id="${IQ_id}" type="set" xmlns="jabber:client">`+
@ -151,11 +144,11 @@ window.addEventListener('converse-loaded', () => {
'jid': 'contact@example.org',
'subscription': 'none',
'name': 'contact@example.org'});
_converse.connection._dataRecv(test_utils.createRequest(stanza));
_converse.connection._dataRecv(mock.createRequest(stanza));
/* <iq type='result' id='set1'/>
*/
stanza = $iq({'type': 'result', 'id':IQ_id});
_converse.connection._dataRecv(test_utils.createRequest(stanza));
_converse.connection._dataRecv(mock.createRequest(stanza));
await u.waitUntil(() => _converse.roster.create.calls.count());
@ -204,13 +197,13 @@ window.addEventListener('converse-loaded', () => {
'subscription': 'none',
'ask': 'subscribe',
'name': 'contact@example.org'});
_converse.connection._dataRecv(test_utils.createRequest(stanza));
_converse.connection._dataRecv(mock.createRequest(stanza));
expect(_converse.roster.updateContact).toHaveBeenCalled();
// Check that the user is now properly shown as a pending
// contact in the roster.
await u.waitUntil(() => {
const header = sizzle('a:contains("Pending contacts")', _converse.rosterview.el).pop();
const contacts = _.filter(header.parentElement.querySelectorAll('li'), u.isVisible);
const contacts = Array.from(header.parentElement.querySelectorAll('li')).filter(u.isVisible);
return contacts.length;
}, 600);
@ -234,7 +227,7 @@ window.addEventListener('converse-loaded', () => {
'type': 'subscribed'
});
sent_stanza = ""; // Reset
_converse.connection._dataRecv(test_utils.createRequest(stanza));
_converse.connection._dataRecv(mock.createRequest(stanza));
/* Upon receiving the presence stanza of type "subscribed",
* the user SHOULD acknowledge receipt of that
* subscription state notification by sending a presence
@ -269,7 +262,7 @@ window.addEventListener('converse-loaded', () => {
'subscription': 'to',
'name': 'Nicky'});
_converse.connection._dataRecv(test_utils.createRequest(stanza));
_converse.connection._dataRecv(mock.createRequest(stanza));
// Check that the IQ set was acknowledged.
expect(Strophe.serialize(sent_stanza)).toBe( // Strophe adds the xmlns attr (although not in spec)
`<iq from="romeo@montague.lit/orchard" id="${IQ_id}" type="result" xmlns="jabber:client"/>`
@ -300,7 +293,7 @@ window.addEventListener('converse-loaded', () => {
* to='user@example.com/resource'/>
*/
stanza = $pres({'to': _converse.bare_jid, 'from': 'contact@example.org/resource'});
_converse.connection._dataRecv(test_utils.createRequest(stanza));
_converse.connection._dataRecv(mock.createRequest(stanza));
// Now the contact should also be online.
expect(contact.presence.get('show')).toBe('online');
@ -318,7 +311,7 @@ window.addEventListener('converse-loaded', () => {
'to': _converse.bare_jid,
'from': 'contact@example.org/resource',
'type': 'subscribe'});
_converse.connection._dataRecv(test_utils.createRequest(stanza));
_converse.connection._dataRecv(mock.createRequest(stanza));
expect(_converse.roster.handleIncomingSubscription).toHaveBeenCalled();
/* The user's client MUST send a presence stanza of type
@ -353,7 +346,7 @@ window.addEventListener('converse-loaded', () => {
'jid': 'contact@example.org',
'subscription': 'both',
'name': 'contact@example.org'});
_converse.connection._dataRecv(test_utils.createRequest(stanza));
_converse.connection._dataRecv(mock.createRequest(stanza));
expect(_converse.roster.updateContact).toHaveBeenCalled();
// The class on the contact will now have switched.
@ -368,11 +361,12 @@ window.addEventListener('converse-loaded', () => {
['rosterGroupsFetched'], {},
function (done, _converse) {
const { $iq, $pres } = converse.env;
/* The process by which a user subscribes to a contact, including
* the interaction between roster items and subscription states.
*/
var contact, stanza, sent_stanza, sent_IQ;
test_utils.openControlBox(_converse);
mock.openControlBox(_converse);
// Add a new roster contact via roster push
stanza = $iq({'type': 'set'}).c('query', {'xmlns': 'jabber:iq:roster'})
.c('item', {
@ -380,7 +374,7 @@ window.addEventListener('converse-loaded', () => {
'subscription': 'none',
'ask': 'subscribe',
'name': 'contact@example.org'});
_converse.connection._dataRecv(test_utils.createRequest(stanza));
_converse.connection._dataRecv(mock.createRequest(stanza));
// A pending contact should now exist.
contact = _converse.roster.get('contact@example.org');
expect(_converse.roster.get('contact@example.org') instanceof _converse.RosterContact).toBeTruthy();
@ -421,7 +415,7 @@ window.addEventListener('converse-loaded', () => {
'from': 'contact@example.org',
'type': 'unsubscribed'
});
_converse.connection._dataRecv(test_utils.createRequest(stanza));
_converse.connection._dataRecv(mock.createRequest(stanza));
/* Upon receiving the presence stanza of type "unsubscribed",
* the user SHOULD acknowledge receipt of that subscription
@ -452,9 +446,10 @@ window.addEventListener('converse-loaded', () => {
{ roster_groups: false },
async function (done, _converse) {
const { u, $iq, sizzle, Strophe } = converse.env;
const jid = 'abram@montague.lit';
await test_utils.openControlBox(_converse);
await test_utils.waitForRoster(_converse, 'current');
await mock.openControlBox(_converse);
await mock.waitForRoster(_converse, 'current');
spyOn(window, 'confirm').and.returnValue(true);
// We now have a contact we want to remove
expect(_converse.roster.get(jid) instanceof _converse.RosterContact).toBeTruthy();
@ -496,7 +491,7 @@ window.addEventListener('converse-loaded', () => {
// Receive confirmation from the contact's server
// <iq type='result' id='remove1'/>
const stanza = $iq({'type': 'result', 'id': sent_iq.getAttribute('id')});
_converse.connection._dataRecv(test_utils.createRequest(stanza));
_converse.connection._dataRecv(mock.createRequest(stanza));
// Our contact has now been removed
await u.waitUntil(() => typeof _converse.roster.get(jid) === "undefined");
done();
@ -506,9 +501,10 @@ window.addEventListener('converse-loaded', () => {
['rosterGroupsFetched'], {},
async function (done, _converse) {
const { u, $pres, sizzle, Strophe } = converse.env;
spyOn(_converse.api, "trigger").and.callThrough();
await test_utils.openControlBox(_converse);
await test_utils.waitForRoster(_converse, 'current');
await mock.openControlBox(_converse);
await mock.waitForRoster(_converse, 'current');
/* <presence
* from='user@example.com'
* to='contact@example.org'
@ -521,10 +517,10 @@ window.addEventListener('converse-loaded', () => {
}).c('nick', {
'xmlns': Strophe.NS.NICK,
}).t('Clint Contact');
_converse.connection._dataRecv(test_utils.createRequest(stanza));
_converse.connection._dataRecv(mock.createRequest(stanza));
await u.waitUntil(() => {
const header = sizzle('a:contains("Contact requests")', _converse.rosterview.el).pop();
const contacts = _.filter(header.parentElement.querySelectorAll('li'), u.isVisible);
const contacts = Array.from(header.parentElement.querySelectorAll('li')).filter(u.isVisible);
return contacts.length;
}, 500);
expect(_converse.api.trigger).toHaveBeenCalledWith('contactRequest', jasmine.any(Object));
@ -535,5 +531,4 @@ window.addEventListener('converse-loaded', () => {
done();
}));
});
});
});

View File

@ -1,13 +1,12 @@
window.addEventListener('converse-loaded', () => {
const mock = window.mock;
const test_utils = window.test_utils;
const $iq = converse.env.$iq;
const Strophe = converse.env.Strophe;
const _ = converse.env._;
const sizzle = converse.env.sizzle;
const u = converse.env.utils;
/*global mock */
describe("XEP-0357 Push Notifications", function () {
const $iq = converse.env.$iq;
const Strophe = converse.env.Strophe;
const _ = converse.env._;
const sizzle = converse.env.sizzle;
const u = converse.env.utils;
describe("XEP-0357 Push Notifications", function () {
it("can be enabled",
mock.initConverse(
@ -21,11 +20,11 @@ window.addEventListener('converse-loaded', () => {
const IQ_stanzas = _converse.connection.IQ_stanzas;
expect(_converse.session.get('push_enabled')).toBeFalsy();
await test_utils.waitUntilDiscoConfirmed(
await mock.waitUntilDiscoConfirmed(
_converse, _converse.push_app_servers[0].jid,
[{'category': 'pubsub', 'type':'push'}],
['urn:xmpp:push:0'], [], 'info');
await test_utils.waitUntilDiscoConfirmed(
await mock.waitUntilDiscoConfirmed(
_converse,
_converse.bare_jid,
[{'category': 'account', 'type':'registered'}],
@ -38,7 +37,7 @@ window.addEventListener('converse-loaded', () => {
'<enable jid="push-5@client.example" node="yxs32uqsflafdk3iuqo" xmlns="urn:xmpp:push:0"/>'+
'</iq>'
)
_converse.connection._dataRecv(test_utils.createRequest($iq({
_converse.connection._dataRecv(mock.createRequest($iq({
'to': _converse.connection.jid,
'type': 'result',
'id': stanza.getAttribute('id')
@ -58,11 +57,11 @@ window.addEventListener('converse-loaded', () => {
}, async function (done, _converse) {
const IQ_stanzas = _converse.connection.IQ_stanzas;
await test_utils.waitUntilDiscoConfirmed(
await mock.waitUntilDiscoConfirmed(
_converse, _converse.push_app_servers[0].jid,
[{'category': 'pubsub', 'type':'push'}],
['urn:xmpp:push:0'], [], 'info');
await test_utils.waitUntilDiscoConfirmed(
await mock.waitUntilDiscoConfirmed(
_converse, _converse.bare_jid, [],
['urn:xmpp:push:0']);
@ -77,14 +76,14 @@ window.addEventListener('converse-loaded', () => {
`</iq>`
);
const result = u.toStanza(`<iq type="result" id="${iq.getAttribute('id')}" to="romeo@montague.lit" />`);
_converse.connection._dataRecv(test_utils.createRequest(result));
_converse.connection._dataRecv(mock.createRequest(result));
await u.waitUntil(() => _converse.session.get('push_enabled'));
expect(_converse.session.get('push_enabled').length).toBe(1);
expect(_.includes(_converse.session.get('push_enabled'), 'romeo@montague.lit')).toBe(true);
test_utils.openAndEnterChatRoom(_converse, 'coven@chat.shakespeare.lit', 'oldhag');
await test_utils.waitUntilDiscoConfirmed(
mock.openAndEnterChatRoom(_converse, 'coven@chat.shakespeare.lit', 'oldhag');
await mock.waitUntilDiscoConfirmed(
_converse, 'chat.shakespeare.lit',
[{'category': 'account', 'type':'registered'}],
['urn:xmpp:push:0'], [], 'info');
@ -98,7 +97,7 @@ window.addEventListener('converse-loaded', () => {
'<enable jid="push-5@client.example" node="yxs32uqsflafdk3iuqo" xmlns="urn:xmpp:push:0"/>'+
'</iq>'
);
_converse.connection._dataRecv(test_utils.createRequest($iq({
_converse.connection._dataRecv(mock.createRequest($iq({
'to': _converse.connection.jid,
'type': 'result',
'id': iq.getAttribute('id')
@ -120,7 +119,7 @@ window.addEventListener('converse-loaded', () => {
const IQ_stanzas = _converse.connection.IQ_stanzas;
expect(_converse.session.get('push_enabled')).toBeFalsy();
await test_utils.waitUntilDiscoConfirmed(
await mock.waitUntilDiscoConfirmed(
_converse,
_converse.bare_jid,
[{'category': 'account', 'type':'registered'}],
@ -133,7 +132,7 @@ window.addEventListener('converse-loaded', () => {
'<disable jid="push-5@client.example" node="yxs32uqsflafdk3iuqo" xmlns="urn:xmpp:push:0"/>'+
'</iq>'
);
_converse.connection._dataRecv(test_utils.createRequest($iq({
_converse.connection._dataRecv(mock.createRequest($iq({
'to': _converse.connection.jid,
'type': 'result',
'id': stanza.getAttribute('id')
@ -156,11 +155,11 @@ window.addEventListener('converse-loaded', () => {
const IQ_stanzas = _converse.connection.IQ_stanzas;
expect(_converse.session.get('push_enabled')).toBeFalsy();
await test_utils.waitUntilDiscoConfirmed(
await mock.waitUntilDiscoConfirmed(
_converse, _converse.push_app_servers[0].jid,
[{'category': 'pubsub', 'type':'push'}],
['urn:xmpp:push:0'], [], 'info');
await test_utils.waitUntilDiscoConfirmed(
await mock.waitUntilDiscoConfirmed(
_converse,
_converse.bare_jid,
[{'category': 'account', 'type':'registered'}],
@ -179,7 +178,7 @@ window.addEventListener('converse-loaded', () => {
'</enable>'+
'</iq>'
)
_converse.connection._dataRecv(test_utils.createRequest($iq({
_converse.connection._dataRecv(mock.createRequest($iq({
'to': _converse.connection.jid,
'type': 'result',
'id': stanza.getAttribute('id')
@ -187,5 +186,4 @@ window.addEventListener('converse-loaded', () => {
await u.waitUntil(() => _converse.session.get('push_enabled'))
done();
}));
});
});

View File

@ -1,12 +1,11 @@
window.addEventListener('converse-loaded', () => {
const mock = window.mock;
const test_utils = window.test_utils;
const Strophe = converse.env.Strophe;
const $iq = converse.env.$iq;
const { _, sizzle} = converse.env;
const u = converse.env.utils;
/*global mock */
describe("The Registration Panel", function () {
const Strophe = converse.env.Strophe;
const $iq = converse.env.$iq;
const { _, sizzle} = converse.env;
const u = converse.env.utils;
describe("The Registration Panel", function () {
it("is not available unless allow_registration=true",
mock.initConverse(
@ -124,7 +123,7 @@ window.addEventListener('converse-loaded', () => {
})
.c('register', {xmlns: "http://jabber.org/features/iq-register"}).up()
.c('mechanisms', {xmlns: "urn:ietf:params:xml:ns:xmpp-sasl"});
_converse.connection._connect_cb(test_utils.createRequest(stanza));
_converse.connection._connect_cb(mock.createRequest(stanza));
expect(registerview.getRegistrationFields).toHaveBeenCalled();
@ -137,7 +136,7 @@ window.addEventListener('converse-loaded', () => {
.c('username').up()
.c('password').up()
.c('email');
_converse.connection._dataRecv(test_utils.createRequest(stanza));
_converse.connection._dataRecv(mock.createRequest(stanza));
expect(registerview.onRegistrationFields).toHaveBeenCalled();
expect(registerview.renderRegistrationForm).toHaveBeenCalled();
expect(registerview.el.querySelectorAll('input').length).toBe(5);
@ -181,7 +180,7 @@ window.addEventListener('converse-loaded', () => {
})
.c('register', {xmlns: "http://jabber.org/features/iq-register"}).up()
.c('mechanisms', {xmlns: "urn:ietf:params:xml:ns:xmpp-sasl"});
_converse.connection._connect_cb(test_utils.createRequest(stanza));
_converse.connection._connect_cb(mock.createRequest(stanza));
stanza = $iq({
'type': 'result',
'id': 'reg1'
@ -191,7 +190,7 @@ window.addEventListener('converse-loaded', () => {
.c('username').up()
.c('password').up()
.c('email');
_converse.connection._dataRecv(test_utils.createRequest(stanza));
_converse.connection._dataRecv(mock.createRequest(stanza));
expect(registerview.form_type).toBe('legacy');
registerview.el.querySelector('input[name=username]').value = 'testusername';
@ -244,7 +243,7 @@ window.addEventListener('converse-loaded', () => {
})
.c('register', {xmlns: "http://jabber.org/features/iq-register"}).up()
.c('mechanisms', {xmlns: "urn:ietf:params:xml:ns:xmpp-sasl"});
_converse.connection._connect_cb(test_utils.createRequest(stanza));
_converse.connection._connect_cb(mock.createRequest(stanza));
stanza = $iq({
'type': 'result',
'id': 'reg1'
@ -256,7 +255,7 @@ window.addEventListener('converse-loaded', () => {
.c('field', {'type': 'text-single', 'var': 'username'}).c('required').up().up()
.c('field', {'type': 'text-private', 'var': 'password'}).c('required').up().up()
.c('field', {'type': 'text-single', 'var': 'email'}).c('required').up().up();
_converse.connection._dataRecv(test_utils.createRequest(stanza));
_converse.connection._dataRecv(mock.createRequest(stanza));
expect(registerview.form_type).toBe('xform');
registerview.el.querySelector('input[name=username]').value = 'testusername';
@ -326,7 +325,7 @@ window.addEventListener('converse-loaded', () => {
})
.c('register', {xmlns: "http://jabber.org/features/iq-register"}).up()
.c('mechanisms', {xmlns: "urn:ietf:params:xml:ns:xmpp-sasl"});
_converse.connection._connect_cb(test_utils.createRequest(stanza));
_converse.connection._connect_cb(mock.createRequest(stanza));
stanza = u.toStanza(`
<iq xmlns="jabber:client" type="result" from="conversations.im" id="ad1e0d50-5adb-4397-a997-5feab56fe418:sendIQ" xml:lang="en">
@ -352,7 +351,7 @@ window.addEventListener('converse-loaded', () => {
<instructions>You need a client that supports x:data and CAPTCHA to register</instructions>
</query>
</iq>`);
_converse.connection._dataRecv(test_utils.createRequest(stanza));
_converse.connection._dataRecv(mock.createRequest(stanza));
expect(registerview.form_type).toBe('xform');
expect(registerview.el.querySelectorAll('#converse-register input[required="required"]').length).toBe(3);
// Hide the controlbox so that we can see whether the test
@ -361,5 +360,4 @@ window.addEventListener('converse-loaded', () => {
delete _converse.connection;
done();
}));
});
});

View File

@ -1,11 +1,10 @@
window.addEventListener('converse-loaded', () => {
const mock = window.mock;
const test_utils = window.test_utils;
const { Strophe, $iq } = converse.env;
const u = converse.env.utils;
/*global mock */
const { Strophe, $iq } = converse.env;
const u = converse.env.utils;
async function sendAndThenRetractMessage (_converse, view) {
async function sendAndThenRetractMessage (_converse, view) {
view.model.sendMessage('hello world');
await u.waitUntil(() => view.el.querySelectorAll('.chat-msg__text').length === 1);
const msg_obj = view.model.messages.last();
@ -30,10 +29,10 @@ window.addEventListener('converse-loaded', () => {
submit_button.click();
const sent_stanzas = _converse.connection.sent_stanzas;
return u.waitUntil(() => sent_stanzas.filter(s => s.querySelector('message apply-to[xmlns="urn:xmpp:fasten:0"]')).pop());
}
}
describe("Message Retractions", function () {
describe("Message Retractions", function () {
describe("A groupchat message retraction", function () {
@ -44,7 +43,7 @@ window.addEventListener('converse-loaded', () => {
const muc_jid = 'lounge@montague.lit';
const features = [...mock.default_muc_features, Strophe.NS.MODERATE];
await test_utils.openAndEnterChatRoom(_converse, muc_jid, 'romeo', features);
await mock.openAndEnterChatRoom(_converse, muc_jid, 'romeo', features);
const received_stanza = u.toStanza(`
<message to='${_converse.jid}' from='${muc_jid}/eve' type='groupchat' id='${_converse.connection.getUniqueId()}'>
@ -67,7 +66,7 @@ window.addEventListener('converse-loaded', () => {
`);
spyOn(view.model, 'handleRetraction').and.callThrough();
_converse.connection._dataRecv(test_utils.createRequest(retraction_stanza));
_converse.connection._dataRecv(mock.createRequest(retraction_stanza));
await u.waitUntil(() => view.model.handleRetraction.calls.count() === 1);
expect(await view.model.handleRetraction.calls.first().returnValue).toBe(true);
expect(view.el.querySelectorAll('.chat-msg').length).toBe(1);
@ -89,7 +88,7 @@ window.addEventListener('converse-loaded', () => {
const date = (new Date()).toISOString();
const muc_jid = 'lounge@montague.lit';
const features = [...mock.default_muc_features, Strophe.NS.MODERATE];
await test_utils.openAndEnterChatRoom(_converse, muc_jid, 'romeo', features);
await mock.openAndEnterChatRoom(_converse, muc_jid, 'romeo', features);
const retraction_stanza = u.toStanza(`
<message type="groupchat" id='retraction-id-1' from="${muc_jid}/eve" to="${muc_jid}/romeo">
@ -101,7 +100,7 @@ window.addEventListener('converse-loaded', () => {
const view = _converse.api.chatviews.get(muc_jid);
spyOn(converse.env.log, 'warn');
spyOn(view.model, 'handleRetraction').and.callThrough();
_converse.connection._dataRecv(test_utils.createRequest(retraction_stanza));
_converse.connection._dataRecv(mock.createRequest(retraction_stanza));
await u.waitUntil(() => view.model.handleRetraction.calls.count() === 1);
await u.waitUntil(() => view.model.messages.length === 1);
@ -118,7 +117,7 @@ window.addEventListener('converse-loaded', () => {
<origin-id xmlns="urn:xmpp:sid:0" id="origin-id-1"/>
</message>
`);
_converse.connection._dataRecv(test_utils.createRequest(received_stanza));
_converse.connection._dataRecv(mock.createRequest(received_stanza));
await u.waitUntil(() => view.model.handleRetraction.calls.count() === 2);
expect(view.el.querySelectorAll('.chat-msg').length).toBe(0);
@ -146,7 +145,7 @@ window.addEventListener('converse-loaded', () => {
const date = (new Date()).toISOString();
const muc_jid = 'lounge@montague.lit';
const features = [...mock.default_muc_features, Strophe.NS.MODERATE];
await test_utils.openAndEnterChatRoom(_converse, muc_jid, 'romeo', features);
await mock.openAndEnterChatRoom(_converse, muc_jid, 'romeo', features);
const retraction_stanza = u.toStanza(`
<message xmlns="jabber:client" from="${muc_jid}" type="groupchat" id="retraction-id-1">
<apply-to xmlns="urn:xmpp:fasten:0" id="stanza-id-1">
@ -160,7 +159,7 @@ window.addEventListener('converse-loaded', () => {
const view = _converse.api.chatviews.get(muc_jid);
spyOn(converse.env.log, 'warn');
spyOn(view.model, 'handleModeration').and.callThrough();
_converse.connection._dataRecv(test_utils.createRequest(retraction_stanza));
_converse.connection._dataRecv(mock.createRequest(retraction_stanza));
await u.waitUntil(() => view.model.handleModeration.calls.count() === 1);
await u.waitUntil(() => view.model.messages.length === 1);
@ -178,7 +177,7 @@ window.addEventListener('converse-loaded', () => {
`);
_converse.connection._dataRecv(test_utils.createRequest(received_stanza));
_converse.connection._dataRecv(mock.createRequest(received_stanza));
await u.waitUntil(() => view.model.handleModeration.calls.count() === 2);
expect(view.el.querySelectorAll('.chat-msg').length).toBe(1);
@ -204,10 +203,10 @@ window.addEventListener('converse-loaded', () => {
async function (done, _converse) {
const date = (new Date()).toISOString();
await test_utils.waitForRoster(_converse, 'current', 1);
await test_utils.waitUntilDiscoConfirmed(_converse, _converse.bare_jid, [], [Strophe.NS.SID]);
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';
const view = await test_utils.openChatBoxFor(_converse, contact_jid);
const view = await mock.openChatBoxFor(_converse, contact_jid);
spyOn(view.model, 'handleRetraction').and.callThrough();
const retraction_stanza = u.toStanza(`
@ -223,7 +222,7 @@ window.addEventListener('converse-loaded', () => {
`);
const promise = new Promise(resolve => _converse.api.listen.on('messageAdded', resolve));
_converse.connection._dataRecv(test_utils.createRequest(retraction_stanza));
_converse.connection._dataRecv(mock.createRequest(retraction_stanza));
await u.waitUntil(() => view.model.messages.length === 1);
await promise;
const message = view.model.messages.at(0);
@ -244,7 +243,7 @@ window.addEventListener('converse-loaded', () => {
<origin-id xmlns="urn:xmpp:sid:0" id="2e972ea0-0050-44b7-a830-f6638a2595b3"/>
<stanza-id xmlns="urn:xmpp:sid:0" id="IxVDLJ0RYbWcWvqC" by="${_converse.bare_jid}"/>
</message>`);
_converse.connection._dataRecv(test_utils.createRequest(stanza));
_converse.connection._dataRecv(mock.createRequest(stanza));
await u.waitUntil(() => view.model.handleRetraction.calls.count() === 2);
expect(view.model.messages.length).toBe(1);
expect(message.get('retracted')).toBeTruthy();
@ -263,10 +262,10 @@ window.addEventListener('converse-loaded', () => {
['rosterGroupsFetched', 'chatBoxesFetched'], {},
async function (done, _converse) {
await test_utils.waitForRoster(_converse, 'current', 1);
await test_utils.waitUntilDiscoConfirmed(_converse, _converse.bare_jid, [], [Strophe.NS.SID]);
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';
const view = await test_utils.openChatBoxFor(_converse, contact_jid);
const view = await mock.openChatBoxFor(_converse, contact_jid);
let stanza = u.toStanza(`
<message xmlns="jabber:client"
@ -280,7 +279,7 @@ window.addEventListener('converse-loaded', () => {
<stanza-id xmlns="urn:xmpp:sid:0" id="kxViLhgbnNMcWv10" by="${_converse.bare_jid}"/>
</message>`);
_converse.connection._dataRecv(test_utils.createRequest(stanza));
_converse.connection._dataRecv(mock.createRequest(stanza));
await u.waitUntil(() => view.model.messages.length === 1);
await u.waitUntil(() => view.el.querySelectorAll('.chat-msg').length === 1);
@ -296,7 +295,7 @@ window.addEventListener('converse-loaded', () => {
<stanza-id xmlns="urn:xmpp:sid:0" id="IxVDLJ0RYbWcWvqC" by="${_converse.bare_jid}"/>
</message>`);
_converse.connection._dataRecv(test_utils.createRequest(stanza));
_converse.connection._dataRecv(mock.createRequest(stanza));
await u.waitUntil(() => view.model.messages.length === 2);
await u.waitUntil(() => view.el.querySelectorAll('.chat-msg').length === 2);
@ -311,7 +310,7 @@ window.addEventListener('converse-loaded', () => {
</apply-to>
</message>
`);
_converse.connection._dataRecv(test_utils.createRequest(retraction_stanza));
_converse.connection._dataRecv(mock.createRequest(retraction_stanza));
await u.waitUntil(() => view.el.querySelectorAll('.chat-msg--retracted').length === 1);
expect(view.model.messages.length).toBe(2);
@ -333,9 +332,9 @@ window.addEventListener('converse-loaded', () => {
['rosterGroupsFetched', 'chatBoxesFetched'], {},
async function (done, _converse) {
await test_utils.waitForRoster(_converse, 'current', 1);
await mock.waitForRoster(_converse, 'current', 1);
const contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit';
const view = await test_utils.openChatBoxFor(_converse, contact_jid);
const view = await mock.openChatBoxFor(_converse, contact_jid);
view.model.sendMessage('hello world');
await u.waitUntil(() => view.el.querySelectorAll('.chat-msg').length === 1);
@ -385,7 +384,7 @@ window.addEventListener('converse-loaded', () => {
const muc_jid = 'lounge@montague.lit';
const features = [...mock.default_muc_features, Strophe.NS.MODERATE];
await test_utils.openAndEnterChatRoom(_converse, muc_jid, 'romeo', features);
await mock.openAndEnterChatRoom(_converse, muc_jid, 'romeo', features);
const received_stanza = u.toStanza(`
<message to='${_converse.jid}' from='${muc_jid}/eve' type='groupchat' id='${_converse.connection.getUniqueId()}'>
@ -407,7 +406,7 @@ window.addEventListener('converse-loaded', () => {
</apply-to>
</message>
`);
_converse.connection._dataRecv(test_utils.createRequest(retraction_stanza));
_converse.connection._dataRecv(mock.createRequest(retraction_stanza));
// We opportunistically save the message as retracted, even before receiving the retraction message
await u.waitUntil(() => view.el.querySelectorAll('.chat-msg--retracted').length === 1);
@ -429,7 +428,7 @@ window.addEventListener('converse-loaded', () => {
const muc_jid = 'lounge@montague.lit';
const features = [...mock.default_muc_features, Strophe.NS.MODERATE];
await test_utils.openAndEnterChatRoom(_converse, muc_jid, 'romeo', features);
await mock.openAndEnterChatRoom(_converse, muc_jid, 'romeo', features);
const view = _converse.api.chatviews.get(muc_jid);
const occupant = view.model.getOwnOccupant();
@ -472,7 +471,7 @@ window.addEventListener('converse-loaded', () => {
`</iq>`);
const result_iq = $iq({'from': muc_jid, 'id': stanza.getAttribute('id'), 'to': _converse.bare_jid, 'type': 'result'});
_converse.connection._dataRecv(test_utils.createRequest(result_iq));
_converse.connection._dataRecv(mock.createRequest(result_iq));
// We opportunistically save the message as retracted, even before receiving the retraction message
await u.waitUntil(() => view.el.querySelectorAll('.chat-msg--retracted').length === 1);
@ -514,7 +513,7 @@ window.addEventListener('converse-loaded', () => {
async function (done, _converse) {
const muc_jid = 'lounge@montague.lit';
await test_utils.openAndEnterChatRoom(_converse, muc_jid, 'romeo');
await mock.openAndEnterChatRoom(_converse, muc_jid, 'romeo');
const view = _converse.api.chatviews.get(muc_jid);
const occupant = view.model.getOwnOccupant();
expect(occupant.get('role')).toBe('moderator');
@ -541,7 +540,7 @@ window.addEventListener('converse-loaded', () => {
const muc_jid = 'lounge@montague.lit';
const features = [...mock.default_muc_features, Strophe.NS.MODERATE];
await test_utils.openAndEnterChatRoom(_converse, muc_jid, 'romeo', features);
await mock.openAndEnterChatRoom(_converse, muc_jid, 'romeo', features);
const view = _converse.api.chatviews.get(muc_jid);
const occupant = view.model.getOwnOccupant();
expect(occupant.get('role')).toBe('moderator');
@ -592,7 +591,7 @@ window.addEventListener('converse-loaded', () => {
expect(qel.textContent).toBe('This content is inappropriate for this forum!');
const result_iq = $iq({'from': muc_jid, 'id': stanza.getAttribute('id'), 'to': _converse.bare_jid, 'type': 'result'});
_converse.connection._dataRecv(test_utils.createRequest(result_iq));
_converse.connection._dataRecv(mock.createRequest(result_iq));
expect(view.model.messages.length).toBe(1);
expect(view.model.messages.at(0).get('moderated')).toBe('retracted');
expect(view.model.messages.at(0).get('moderated_by')).toBe(_converse.bare_jid);
@ -612,7 +611,7 @@ window.addEventListener('converse-loaded', () => {
const muc_jid = 'lounge@montague.lit';
const features = [...mock.default_muc_features, Strophe.NS.MODERATE];
await test_utils.openAndEnterChatRoom(_converse, muc_jid, 'romeo', features);
await mock.openAndEnterChatRoom(_converse, muc_jid, 'romeo', features);
const view = _converse.api.chatviews.get(muc_jid);
const occupant = view.model.getOwnOccupant();
expect(occupant.get('role')).toBe('moderator');
@ -646,7 +645,7 @@ window.addEventListener('converse-loaded', () => {
</message>`);
spyOn(view.model, 'handleRetraction').and.callThrough();
_converse.connection._dataRecv(test_utils.createRequest(reflection));
_converse.connection._dataRecv(mock.createRequest(reflection));
await u.waitUntil(() => view.model.handleRetraction.calls.count() === 1);
expect(view.model.messages.length).toBe(2);
@ -666,7 +665,7 @@ window.addEventListener('converse-loaded', () => {
const muc_jid = 'lounge@montague.lit';
const features = [...mock.default_muc_features, Strophe.NS.MODERATE];
await test_utils.openAndEnterChatRoom(_converse, muc_jid, 'romeo', features);
await mock.openAndEnterChatRoom(_converse, muc_jid, 'romeo', features);
const view = _converse.api.chatviews.get(muc_jid);
const occupant = view.model.getOwnOccupant();
expect(occupant.get('role')).toBe('moderator');
@ -698,7 +697,7 @@ window.addEventListener('converse-loaded', () => {
</apply-to>
</message>`);
_converse.connection._dataRecv(test_utils.createRequest(error));
_converse.connection._dataRecv(mock.createRequest(error));
await u.waitUntil(() => view.el.querySelectorAll('.chat-error').length === 1);
await u.waitUntil(() => view.el.querySelectorAll('.chat-msg--retracted').length === 0);
expect(view.model.messages.length).toBe(3);
@ -725,7 +724,7 @@ window.addEventListener('converse-loaded', () => {
const muc_jid = 'lounge@montague.lit';
const features = [...mock.default_muc_features, Strophe.NS.MODERATE];
await test_utils.openAndEnterChatRoom(_converse, muc_jid, 'romeo', features);
await mock.openAndEnterChatRoom(_converse, muc_jid, 'romeo', features);
const view = _converse.api.chatviews.get(muc_jid);
const occupant = view.model.getOwnOccupant();
expect(occupant.get('role')).toBe('moderator');
@ -765,7 +764,7 @@ window.addEventListener('converse-loaded', () => {
const muc_jid = 'lounge@montague.lit';
const features = [...mock.default_muc_features, Strophe.NS.MODERATE];
await test_utils.openAndEnterChatRoom(_converse, muc_jid, 'romeo', features);
await mock.openAndEnterChatRoom(_converse, muc_jid, 'romeo', features);
const view = _converse.api.chatviews.get(muc_jid);
const occupant = view.model.getOwnOccupant();
expect(occupant.get('role')).toBe('moderator');
@ -817,7 +816,7 @@ window.addEventListener('converse-loaded', () => {
const muc_jid = 'lounge@montague.lit';
const features = [...mock.default_muc_features, Strophe.NS.MODERATE];
await test_utils.openAndEnterChatRoom(_converse, muc_jid, 'romeo', features);
await mock.openAndEnterChatRoom(_converse, muc_jid, 'romeo', features);
const view = _converse.api.chatviews.get(muc_jid);
const occupant = view.model.getOwnOccupant();
expect(occupant.get('role')).toBe('moderator');
@ -862,7 +861,7 @@ window.addEventListener('converse-loaded', () => {
`</iq>`);
const result_iq = $iq({'from': muc_jid, 'id': stanza.getAttribute('id'), 'to': _converse.bare_jid, 'type': 'result'});
_converse.connection._dataRecv(test_utils.createRequest(result_iq));
_converse.connection._dataRecv(mock.createRequest(result_iq));
// We opportunistically save the message as retracted, even before receiving the retraction message
await u.waitUntil(() => view.el.querySelectorAll('.chat-msg--retracted').length === 1);
@ -904,10 +903,10 @@ window.addEventListener('converse-loaded', () => {
['discoInitialized'], {},
async function (done, _converse) {
await test_utils.waitForRoster(_converse, 'current', 1);
await mock.waitForRoster(_converse, 'current', 1);
const contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit';
await test_utils.openChatBoxFor(_converse, contact_jid);
await test_utils.waitUntilDiscoConfirmed(_converse, _converse.bare_jid, null, [Strophe.NS.MAM]);
await mock.openChatBoxFor(_converse, contact_jid);
await mock.waitUntilDiscoConfirmed(_converse, _converse.bare_jid, null, [Strophe.NS.MAM]);
const sent_IQs = _converse.connection.IQ_stanzas;
const stanza = await u.waitUntil(() => sent_IQs.filter(iq => iq.querySelector(`iq[type="set"] query[xmlns="${Strophe.NS.MAM}"]`)).pop());
const queryid = stanza.querySelector('query').getAttribute('queryid');
@ -928,7 +927,7 @@ window.addEventListener('converse-loaded', () => {
</result>
</message>
`);
_converse.connection._dataRecv(test_utils.createRequest(first_message));
_converse.connection._dataRecv(mock.createRequest(first_message));
const tombstone = u.toStanza(`
<message id='${u.getUniqueId()}' to='${_converse.jid}'>
@ -943,7 +942,7 @@ window.addEventListener('converse-loaded', () => {
</result>
</message>
`);
_converse.connection._dataRecv(test_utils.createRequest(tombstone));
_converse.connection._dataRecv(mock.createRequest(tombstone));
const last_id = u.getUniqueId();
const retraction = u.toStanza(`
@ -960,7 +959,7 @@ window.addEventListener('converse-loaded', () => {
</result>
</message>
`);
_converse.connection._dataRecv(test_utils.createRequest(retraction));
_converse.connection._dataRecv(mock.createRequest(retraction));
const iq_result = $iq({'type': 'result', 'id': stanza.getAttribute('id')})
.c('fin', {'xmlns': 'urn:xmpp:mam:2'})
@ -968,7 +967,7 @@ window.addEventListener('converse-loaded', () => {
.c('first', {'index': '0'}).t(first_id).up()
.c('last').t(last_id).up()
.c('count').t('2');
_converse.connection._dataRecv(test_utils.createRequest(iq_result));
_converse.connection._dataRecv(mock.createRequest(iq_result));
await u.waitUntil(() => view.model.handleRetraction.calls.count() === 3);
@ -994,7 +993,7 @@ window.addEventListener('converse-loaded', () => {
const muc_jid = 'lounge@montague.lit';
const features = [...mock.default_muc_features, Strophe.NS.MODERATE];
await test_utils.openAndEnterChatRoom(_converse, muc_jid, 'romeo', features);
await mock.openAndEnterChatRoom(_converse, muc_jid, 'romeo', features);
const view = _converse.chatboxviews.get(muc_jid);
const sent_IQs = _converse.connection.IQ_stanzas;
@ -1017,7 +1016,7 @@ window.addEventListener('converse-loaded', () => {
`);
spyOn(view.model, 'handleRetraction').and.callThrough();
const promise = new Promise(resolve => _converse.api.listen.once('messageAdded', resolve));
_converse.connection._dataRecv(test_utils.createRequest(tombstone));
_converse.connection._dataRecv(mock.createRequest(tombstone));
const last_id = u.getUniqueId();
const retraction = u.toStanza(`
@ -1034,7 +1033,7 @@ window.addEventListener('converse-loaded', () => {
</result>
</message>
`);
_converse.connection._dataRecv(test_utils.createRequest(retraction));
_converse.connection._dataRecv(mock.createRequest(retraction));
const iq_result = $iq({'type': 'result', 'id': stanza.getAttribute('id')})
.c('fin', {'xmlns': 'urn:xmpp:mam:2'})
@ -1042,7 +1041,7 @@ window.addEventListener('converse-loaded', () => {
.c('first', {'index': '0'}).t(first_id).up()
.c('last').t(last_id).up()
.c('count').t('2');
_converse.connection._dataRecv(test_utils.createRequest(iq_result));
_converse.connection._dataRecv(mock.createRequest(iq_result));
await promise;
expect(view.model.messages.length).toBe(1);
@ -1071,7 +1070,7 @@ window.addEventListener('converse-loaded', () => {
const muc_jid = 'lounge@montague.lit';
const features = [...mock.default_muc_features, Strophe.NS.MODERATE];
await test_utils.openAndEnterChatRoom(_converse, muc_jid, 'romeo', features);
await mock.openAndEnterChatRoom(_converse, muc_jid, 'romeo', features);
const view = _converse.chatboxviews.get(muc_jid);
const sent_IQs = _converse.connection.IQ_stanzas;
@ -1096,7 +1095,7 @@ window.addEventListener('converse-loaded', () => {
`);
spyOn(view.model, 'handleModeration').and.callThrough();
const promise = new Promise(resolve => _converse.api.listen.once('messageAdded', resolve));
_converse.connection._dataRecv(test_utils.createRequest(tombstone));
_converse.connection._dataRecv(mock.createRequest(tombstone));
const last_id = u.getUniqueId();
const retraction = u.toStanza(`
@ -1116,7 +1115,7 @@ window.addEventListener('converse-loaded', () => {
</result>
</message>
`);
_converse.connection._dataRecv(test_utils.createRequest(retraction));
_converse.connection._dataRecv(mock.createRequest(retraction));
const iq_result = $iq({'type': 'result', 'id': stanza.getAttribute('id')})
.c('fin', {'xmlns': 'urn:xmpp:mam:2'})
@ -1124,7 +1123,7 @@ window.addEventListener('converse-loaded', () => {
.c('first', {'index': '0'}).t(first_id).up()
.c('last').t(last_id).up()
.c('count').t('2');
_converse.connection._dataRecv(test_utils.createRequest(iq_result));
_converse.connection._dataRecv(mock.createRequest(iq_result));
await promise;
expect(view.model.messages.length).toBe(1);
@ -1151,5 +1150,4 @@ window.addEventListener('converse-loaded', () => {
done();
}));
});
})
});
})

View File

@ -1,13 +1,12 @@
window.addEventListener('converse-loaded', () => {
const mock = window.mock;
const test_utils = window.test_utils;
const _ = converse.env._,
/*global mock */
const _ = converse.env._,
$iq = converse.env.$iq,
Strophe = converse.env.Strophe,
sizzle = converse.env.sizzle,
u = converse.env.utils;
describe("Chatrooms", function () {
describe("Chatrooms", function () {
describe("The /register commmand", function () {
@ -18,7 +17,7 @@ window.addEventListener('converse-loaded', () => {
async function (done, _converse) {
const muc_jid = 'coven@chat.shakespeare.lit';
await test_utils.openAndEnterChatRoom(_converse, muc_jid, 'romeo')
await mock.openAndEnterChatRoom(_converse, muc_jid, 'romeo')
const view = _converse.chatboxviews.get(muc_jid);
const textarea = view.el.querySelector('.chat-textarea')
textarea.value = '/register';
@ -47,7 +46,7 @@ window.addEventListener('converse-loaded', () => {
'type': 'text-single',
'var': 'muc#register_roomnick'
}).c('required');
_converse.connection._dataRecv(test_utils.createRequest(result));
_converse.connection._dataRecv(mock.createRequest(result));
stanza = await u.waitUntil(() => _.filter(
_converse.connection.IQ_stanzas,
iq => sizzle(`iq[to="${muc_jid}"][type="set"] query[xmlns="jabber:iq:register"]`, iq).length
@ -75,7 +74,7 @@ window.addEventListener('converse-loaded', () => {
async function (done, _converse) {
const muc_jid = 'coven@chat.shakespeare.lit';
await test_utils.openAndEnterChatRoom(_converse, muc_jid, 'romeo');
await mock.openAndEnterChatRoom(_converse, muc_jid, 'romeo');
const view = _converse.chatboxviews.get(muc_jid);
let stanza = await u.waitUntil(() => _.filter(
@ -99,7 +98,7 @@ window.addEventListener('converse-loaded', () => {
'type': 'text-single',
'var': 'muc#register_roomnick'
}).c('required');
_converse.connection._dataRecv(test_utils.createRequest(result));
_converse.connection._dataRecv(mock.createRequest(result));
stanza = await u.waitUntil(() => _.filter(
_converse.connection.IQ_stanzas,
iq => sizzle(`iq[to="coven@chat.shakespeare.lit"][type="set"] query[xmlns="jabber:iq:register"]`, iq).length
@ -117,5 +116,4 @@ window.addEventListener('converse-loaded', () => {
done();
}));
});
});
});

View File

@ -1,11 +1,6 @@
window.addEventListener('converse-loaded', () => {
const mock = window.mock;
const test_utils = window.test_utils;
const { Strophe, $iq, $msg, $pres, sizzle, _ } = converse.env;
const u = converse.env.utils;
/* global mock */
describe("A list of open groupchats", function () {
describe("A list of open groupchats", function () {
it("is shown in controlbox", mock.initConverse(
['rosterGroupsFetched', 'chatBoxesFetched'],
@ -13,11 +8,13 @@ window.addEventListener('converse-loaded', () => {
// have to mock stanza traffic.
}, async function (done, _converse) {
await test_utils.openControlBox(_converse);
const u = converse.env.utils;
await mock.openControlBox(_converse);
const controlbox = _converse.chatboxviews.get('controlbox');
let list = controlbox.el.querySelector('.list-container--openrooms');
expect(u.hasClass('hidden', list)).toBeTruthy();
await test_utils.openChatRoom(_converse, 'room', 'conference.shakespeare.lit', 'JC');
await mock.openChatRoom(_converse, 'room', 'conference.shakespeare.lit', 'JC');
const lview = _converse.rooms_list_view
await u.waitUntil(() => lview.el.querySelectorAll(".open-room").length);
@ -25,7 +22,7 @@ window.addEventListener('converse-loaded', () => {
expect(room_els.length).toBe(1);
expect(room_els[0].innerText).toBe('room@conference.shakespeare.lit');
await test_utils.openChatRoom(_converse, 'lounge', 'montague.lit', 'romeo');
await mock.openChatRoom(_converse, 'lounge', 'montague.lit', 'romeo');
await u.waitUntil(() => lview.el.querySelectorAll(".open-room").length > 1);
room_els = _converse.rooms_list_view.el.querySelectorAll(".open-room");
expect(room_els.length).toBe(2);
@ -36,7 +33,7 @@ window.addEventListener('converse-loaded', () => {
expect(room_els.length).toBe(1);
expect(room_els[0].innerText).toBe('lounge@montague.lit');
list = controlbox.el.querySelector('.list-container--openrooms');
u.waitUntil(() => _.includes(list.classList, 'hidden'));
u.waitUntil(() => Array.from(list.classList).includes('hidden'));
view = _converse.chatboxviews.get('lounge@montague.lit');
await view.close();
@ -44,7 +41,7 @@ window.addEventListener('converse-loaded', () => {
expect(room_els.length).toBe(0);
list = controlbox.el.querySelector('.list-container--openrooms');
expect(_.includes(list.classList, 'hidden')).toBeTruthy();
expect(Array.from(list.classList).includes('hidden')).toBeTruthy();
done();
}));
@ -54,7 +51,10 @@ window.addEventListener('converse-loaded', () => {
{'view_mode': 'fullscreen'},
async function (done, _converse) {
await test_utils.openAndEnterChatRoom(_converse, 'lounge@montague.lit', 'romeo');
const { Strophe, $iq, $pres, sizzle } = converse.env;
const u = converse.env.utils;
await mock.openAndEnterChatRoom(_converse, 'lounge@montague.lit', 'romeo');
let stanza = $pres({
to: 'romeo@montague.lit/orchard',
from: 'lounge@montague.lit/newguy'
@ -65,11 +65,11 @@ window.addEventListener('converse-loaded', () => {
'jid': 'newguy@montague.lit/_converse.js-290929789',
'role': 'participant'
}).tree();
_converse.connection._dataRecv(test_utils.createRequest(stanza));
_converse.connection._dataRecv(mock.createRequest(stanza));
spyOn(_converse.Bookmarks.prototype, 'fetchBookmarks').and.callThrough();
await test_utils.waitUntilDiscoConfirmed(
await mock.waitUntilDiscoConfirmed(
_converse, _converse.bare_jid,
[{'category': 'pubsub', 'type':'pep'}],
[`${Strophe.NS.PUBSUB}#publish-options`]
@ -93,21 +93,21 @@ window.addEventListener('converse-loaded', () => {
'name': 'Bookmarked Lounge',
'jid': 'lounge@montague.lit'
});
_converse.connection._dataRecv(test_utils.createRequest(stanza));
_converse.connection._dataRecv(mock.createRequest(stanza));
await _converse.api.waitUntil('roomsListInitialized');
const controlbox = _converse.chatboxviews.get('controlbox');
const list = controlbox.el.querySelector('.list-container--openrooms');
expect(_.includes(list.classList, 'hidden')).toBeFalsy();
expect(Array.from(list.classList).includes('hidden')).toBeFalsy();
const items = list.querySelectorAll('.list-item');
expect(items.length).toBe(1);
expect(items[0].textContent.trim()).toBe('Bookmarked Lounge');
expect(_converse.bookmarks.fetchBookmarks).toHaveBeenCalled();
done();
}));
});
});
describe("A groupchat shown in the groupchats list", function () {
describe("A groupchat shown in the groupchats list", function () {
it("is highlighted if it's currently open", mock.initConverse(
['rosterGroupsFetched', 'chatBoxesFetched'],
@ -115,6 +115,7 @@ window.addEventListener('converse-loaded', () => {
allow_bookmarks: false // Makes testing easier, otherwise we have to mock stanza traffic.
}, async function (done, _converse) {
const u = converse.env.utils;
const muc_jid = 'coven@chat.shakespeare.lit';
await _converse.api.rooms.open(muc_jid, {'nick': 'some1'}, true);
const lview = _converse.rooms_list_view
@ -145,9 +146,11 @@ window.addEventListener('converse-loaded', () => {
// have to mock stanza traffic.
}, async function (done, _converse) {
const { Strophe, $iq, $pres } = converse.env;
const u = converse.env.utils;
const IQ_stanzas = _converse.connection.IQ_stanzas;
const room_jid = 'coven@chat.shakespeare.lit';
await test_utils.openControlBox(_converse);
await mock.openControlBox(_converse);
await _converse.api.rooms.open(room_jid, {'nick': 'some1'});
const view = _converse.chatboxviews.get(room_jid);
@ -180,7 +183,7 @@ window.addEventListener('converse-loaded', () => {
.c('value').t('This is the description').up().up()
.c('field', {'type':'text-single', 'var':'muc#roominfo_occupants', 'label':'Number of occupants'})
.c('value').t(0);
_converse.connection._dataRecv(test_utils.createRequest(features_stanza));
_converse.connection._dataRecv(mock.createRequest(features_stanza));
await u.waitUntil(() => view.model.session.get('connection_status') === converse.ROOMSTATUS.CONNECTING)
let presence = $pres({
to: _converse.connection.jid,
@ -193,7 +196,7 @@ window.addEventListener('converse-loaded', () => {
role: 'participant'
}).up()
.c('status').attrs({code:'110'});
_converse.connection._dataRecv(test_utils.createRequest(presence));
_converse.connection._dataRecv(mock.createRequest(presence));
await u.waitUntil(() => _converse.rooms_list_view.el.querySelectorAll(".open-room").length, 500);
const room_els = _converse.rooms_list_view.el.querySelectorAll(".open-room");
@ -227,7 +230,7 @@ window.addEventListener('converse-loaded', () => {
'jid': 'newguy@montague.lit/_converse.js-290929789',
'role': 'participant'
});
_converse.connection._dataRecv(test_utils.createRequest(presence));
_converse.connection._dataRecv(mock.createRequest(presence));
els = modal.el.querySelectorAll('p.room-info');
expect(els[3].textContent).toBe("Online users: 2")
@ -250,9 +253,10 @@ window.addEventListener('converse-loaded', () => {
},
async function (done, _converse) {
const u = converse.env.utils;
spyOn(window, 'confirm').and.callFake(() => true);
expect(_converse.chatboxes.length).toBe(1);
await test_utils.openChatRoom(_converse, 'lounge', 'conference.shakespeare.lit', 'JC');
await mock.openChatRoom(_converse, 'lounge', 'conference.shakespeare.lit', 'JC');
expect(_converse.chatboxes.length).toBe(2);
const lview = _converse.rooms_list_view
await u.waitUntil(() => lview.el.querySelectorAll(".open-room").length);
@ -276,10 +280,12 @@ window.addEventListener('converse-loaded', () => {
allow_bookmarks: false // Makes testing easier, otherwise we have to mock stanza traffic.
}, async (done, _converse) => {
await test_utils.openControlBox(_converse);
const { $msg } = converse.env;
const u = converse.env.utils;
await mock.openControlBox(_converse);
const room_jid = 'kitchen@conference.shakespeare.lit';
await u.waitUntil(() => _converse.rooms_list_view !== undefined, 500);
await test_utils.openAndEnterChatRoom(_converse, room_jid, 'romeo');
await mock.openAndEnterChatRoom(_converse, room_jid, 'romeo');
const view = _converse.chatboxviews.get(room_jid);
view.model.set({'minimized': true});
const nick = mock.chatroom_names[0];
@ -326,8 +332,7 @@ window.addEventListener('converse-loaded', () => {
indicator_el = lview.el.querySelector(".msgs-indicator");
expect(indicator_el === null);
room_el = lview.el.querySelector(".available-chatroom");
expect(_.includes(room_el.classList, 'unread-msgs')).toBeFalsy();
expect(Array.from(room_el.classList).includes('unread-msgs')).toBeFalsy();
done();
}));
});
});

View File

@ -1,14 +1,13 @@
window.addEventListener('converse-loaded', () => {
const mock = window.mock;
const test_utils = window.test_utils;
const $iq = converse.env.$iq;
const $pres = converse.env.$pres;
const Strophe = converse.env.Strophe;
const _ = converse.env._;
const sizzle = converse.env.sizzle;
const u = converse.env.utils;
/*global mock */
const checkHeaderToggling = async function (group) {
const $iq = converse.env.$iq;
const $pres = converse.env.$pres;
const Strophe = converse.env.Strophe;
const _ = converse.env._;
const sizzle = converse.env.sizzle;
const u = converse.env.utils;
const checkHeaderToggling = async function (group) {
const toggle = group.querySelector('a.group-toggle');
expect(u.isVisible(group)).toBeTruthy();
expect(group.querySelectorAll('ul.collapsed').length).toBe(0);
@ -23,10 +22,10 @@ window.addEventListener('converse-loaded', () => {
await u.waitUntil(() => group.querySelectorAll('li').length === _.filter(group.querySelectorAll('li'), u.isVisible).length);
expect(u.hasClass('fa-caret-right', toggle.firstElementChild)).toBeFalsy();
expect(u.hasClass('fa-caret-down', toggle.firstElementChild)).toBeTruthy();
};
};
describe("The Contacts Roster", function () {
describe("The Contacts Roster", function () {
it("verifies the origin of roster pushes",
mock.initConverse(
@ -35,7 +34,7 @@ window.addEventListener('converse-loaded', () => {
// See: https://gultsch.de/gajim_roster_push_and_message_interception.html
const contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit';
await test_utils.waitForRoster(_converse, 'current', 1);
await mock.waitForRoster(_converse, 'current', 1);
expect(_converse.roster.models.length).toBe(1);
expect(_converse.roster.at(0).get('jid')).toBe(contact_jid);
@ -46,7 +45,7 @@ window.addEventListener('converse-loaded', () => {
<item subscription="remove" jid="${contact_jid}"/>
</query>
</iq>`);
_converse.connection._dataRecv(test_utils.createRequest(roster_push));
_converse.connection._dataRecv(mock.createRequest(roster_push));
expect(converse.env.log.warn.calls.count()).toBe(1);
expect(converse.env.log.warn).toHaveBeenCalledWith(
`Ignoring roster illegitimate roster push message from ${roster_push.getAttribute('from')}`
@ -57,7 +56,7 @@ window.addEventListener('converse-loaded', () => {
<item subscription="both" jid="eve@siacs.eu" name="${mock.cur_names[0]}" />
</query>
</iq>`);
_converse.connection._dataRecv(test_utils.createRequest(roster_push));
_converse.connection._dataRecv(mock.createRequest(roster_push));
expect(converse.env.log.warn.calls.count()).toBe(2);
expect(converse.env.log.warn).toHaveBeenCalledWith(
`Ignoring roster illegitimate roster push message from ${roster_push.getAttribute('from')}`
@ -88,7 +87,7 @@ window.addEventListener('converse-loaded', () => {
'xmlns': 'jabber:iq:roster'
}).c('item', {'jid': 'nurse@example.com'}).up()
.c('item', {'jid': 'romeo@example.com'})
_converse.connection._dataRecv(test_utils.createRequest(result));
_converse.connection._dataRecv(mock.createRequest(result));
await u.waitUntil(() => _converse.promises['rosterContactsFetched'].isResolved === true);
done();
}));
@ -116,7 +115,7 @@ window.addEventListener('converse-loaded', () => {
'ver': 'ver7'
}).c('item', {'jid': 'nurse@example.com'}).up()
.c('item', {'jid': 'romeo@example.com'})
_converse.connection._dataRecv(test_utils.createRequest(result));
_converse.connection._dataRecv(mock.createRequest(result));
await u.waitUntil(() => _converse.roster.models.length > 1);
expect(_converse.roster.data.get('version')).toBe('ver7');
@ -134,14 +133,14 @@ window.addEventListener('converse-loaded', () => {
'type': 'result',
'id': stanza.getAttribute('id')
});
_converse.connection._dataRecv(test_utils.createRequest(result));
_converse.connection._dataRecv(mock.createRequest(result));
const roster_push = $iq({
'to': _converse.connection.jid,
'type': 'set',
}).c('query', {'xmlns': 'jabber:iq:roster', 'ver': 'ver34'})
.c('item', {'jid': 'romeo@example.com', 'subscription': 'remove'});
_converse.connection._dataRecv(test_utils.createRequest(roster_push));
_converse.connection._dataRecv(mock.createRequest(roster_push));
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');
@ -157,8 +156,8 @@ window.addEventListener('converse-loaded', () => {
const filter = _converse.rosterview.el.querySelector('.roster-filter');
expect(filter === null).toBe(false);
await test_utils.waitForRoster(_converse, 'current');
await test_utils.openControlBox(_converse);
await mock.waitForRoster(_converse, 'current');
await mock.openControlBox(_converse);
const view = _converse.chatboxviews.get('controlbox');
const flyout = view.el.querySelector('.box-flyout');
@ -176,8 +175,8 @@ window.addEventListener('converse-loaded', () => {
['rosterGroupsFetched'], {'roster_groups': true},
async function (done, _converse) {
await test_utils.openControlBox(_converse);
await test_utils.waitForRoster(_converse, 'current');
await mock.openControlBox(_converse);
await mock.waitForRoster(_converse, 'current');
let filter = _converse.rosterview.el.querySelector('.roster-filter');
const roster = _converse.rosterview.roster_el;
_converse.rosterview.filter_view.delegateEvents();
@ -229,8 +228,8 @@ window.addEventListener('converse-loaded', () => {
['rosterGroupsFetched'], {},
async function (done, _converse) {
await test_utils.openControlBox(_converse);
await test_utils.waitForRoster(_converse, 'current');
await mock.openControlBox(_converse);
await mock.waitForRoster(_converse, 'current');
const filter = _converse.rosterview.el.querySelector('.roster-filter');
const roster = _converse.rosterview.roster_el;
@ -275,8 +274,8 @@ window.addEventListener('converse-loaded', () => {
['rosterGroupsFetched'], {'roster_groups': true},
async function (done, _converse) {
await test_utils.openControlBox(_converse);
await test_utils.waitForRoster(_converse, 'current');
await mock.openControlBox(_converse);
await mock.waitForRoster(_converse, 'current');
_converse.rosterview.filter_view.delegateEvents();
var roster = _converse.rosterview.roster_el;
@ -317,8 +316,8 @@ window.addEventListener('converse-loaded', () => {
['rosterGroupsFetched'], {'roster_groups': true},
async function (done, _converse) {
await test_utils.openControlBox(_converse);
await test_utils.waitForRoster(_converse, 'current');
await mock.openControlBox(_converse);
await mock.waitForRoster(_converse, 'current');
const filter = _converse.rosterview.el.querySelector('.roster-filter');
filter.value = "xxx";
@ -340,12 +339,12 @@ window.addEventListener('converse-loaded', () => {
['rosterGroupsFetched'], {},
async function (done, _converse) {
test_utils.waitForRoster(_converse, 'all');
mock.waitForRoster(_converse, 'all');
let jid = mock.cur_names[3].replace(/ /g,'.').toLowerCase() + '@montague.lit';
_converse.roster.get(jid).presence.set('show', 'online');
jid = mock.cur_names[4].replace(/ /g,'.').toLowerCase() + '@montague.lit';
_converse.roster.get(jid).presence.set('show', 'dnd');
test_utils.openControlBox(_converse);
mock.openControlBox(_converse);
const button = _converse.rosterview.el.querySelector('span[data-type="state"]');
button.click();
const roster = _converse.rosterview.roster_el;
@ -377,9 +376,9 @@ window.addEventListener('converse-loaded', () => {
spyOn(_converse.rosterview, 'update').and.callThrough();
_converse.rosterview.render();
await test_utils.openControlBox(_converse);
await test_utils.waitForRoster(_converse, 'all');
await test_utils.createContacts(_converse, 'requesting');
await mock.openControlBox(_converse);
await mock.waitForRoster(_converse, 'all');
await mock.createContacts(_converse, 'requesting');
// Check that the groups appear alphabetically and that
@ -441,9 +440,9 @@ window.addEventListener('converse-loaded', () => {
spyOn(_converse.rosterview, 'update').and.callThrough();
_converse.rosterview.render();
await test_utils.openControlBox(_converse);
await test_utils.waitForRoster(_converse, 'all');
await test_utils.createContacts(_converse, 'requesting');
await mock.openControlBox(_converse);
await mock.waitForRoster(_converse, 'all');
await mock.createContacts(_converse, 'requesting');
// Check that the groups appear alphabetically and that
// requesting and pending contacts are last.
await u.waitUntil(() => sizzle('.roster-group a.group-toggle', _converse.rosterview.el).length);
@ -474,8 +473,8 @@ window.addEventListener('converse-loaded', () => {
spyOn(_converse.rosterview, 'update').and.callThrough();
_converse.rosterview.render();
await test_utils.openControlBox(_converse);
await test_utils.waitForRoster(_converse, 'current', 0);
await mock.openControlBox(_converse);
await mock.waitForRoster(_converse, 'current', 0);
_converse.roster.create({
jid: 'groupchanger@montague.lit',
@ -518,7 +517,7 @@ window.addEventListener('converse-loaded', () => {
const groups = ['Colleagues', 'friends'];
spyOn(_converse.rosterview, 'update').and.callThrough();
test_utils.openControlBox(_converse);
mock.openControlBox(_converse);
_converse.rosterview.render();
for (var i=0; i<mock.cur_names.length; i++) {
_converse.roster.create({
@ -546,7 +545,7 @@ window.addEventListener('converse-loaded', () => {
async function (done, _converse) {
_converse.roster_groups = true;
test_utils.openControlBox(_converse);
mock.openControlBox(_converse);
var i=0, j=0;
var groups = {
@ -584,8 +583,8 @@ window.addEventListener('converse-loaded', () => {
['rosterGroupsFetched'], {},
async function (done, _converse) {
await test_utils.openControlBox(_converse);
await test_utils.waitForRoster(_converse, 'all');
await mock.openControlBox(_converse);
await mock.waitForRoster(_converse, 'all');
await Promise.all(_converse.roster.map(contact => u.waitUntil(() => contact.vcard.get('fullname'))));
await u.waitUntil(() => sizzle('.roster-group', _converse.rosterview.el).filter(u.isVisible).map(e => e.querySelector('li')).length, 1000);
await checkHeaderToggling.apply(
@ -601,7 +600,7 @@ window.addEventListener('converse-loaded', () => {
async function (done, _converse) {
spyOn(_converse.rosterview, 'update').and.callThrough();
await test_utils.openControlBox(_converse);
await mock.openControlBox(_converse);
_converse.roster.create({
jid: mock.pend_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit',
subscription: 'none',
@ -618,8 +617,8 @@ window.addEventListener('converse-loaded', () => {
async function (done, _converse) {
spyOn(_converse.rosterview, 'update').and.callThrough();
await test_utils.openControlBox(_converse);
await test_utils.waitForRoster(_converse, 'pending');
await mock.openControlBox(_converse);
await mock.waitForRoster(_converse, 'pending');
await Promise.all(_converse.roster.map(contact => u.waitUntil(() => contact.vcard.get('fullname'))));
await u.waitUntil(() => sizzle('li', _converse.rosterview.el).filter(u.isVisible).length, 500)
expect(_converse.rosterview.update).toHaveBeenCalled();
@ -634,7 +633,7 @@ window.addEventListener('converse-loaded', () => {
['rosterGroupsFetched'], {},
async function (done, _converse) {
await test_utils.waitForRoster(_converse, 'all');
await mock.waitForRoster(_converse, 'all');
await Promise.all(_converse.roster.map(contact => u.waitUntil(() => contact.vcard.get('fullname'))));
const name = mock.pend_names[0];
const jid = name.replace(/ /g,'.').toLowerCase() + '@montague.lit';
@ -666,8 +665,8 @@ window.addEventListener('converse-loaded', () => {
['rosterGroupsFetched', 'VCardsInitialized'], {},
async function (done, _converse) {
await test_utils.openControlBox(_converse);
await test_utils.waitForRoster(_converse, 'current', 0);
await mock.openControlBox(_converse);
await mock.waitForRoster(_converse, 'current', 0);
const name = mock.pend_names[0];
_converse.roster.create({
jid: name.replace(/ /g,'.').toLowerCase() + '@montague.lit',
@ -694,7 +693,7 @@ window.addEventListener('converse-loaded', () => {
`</iq>`);
const stanza = u.toStanza(`<iq id="${iq.getAttribute('id')}" to="romeo@montague.lit/orchard" type="result"/>`);
_converse.connection._dataRecv(test_utils.createRequest(stanza));
_converse.connection._dataRecv(mock.createRequest(stanza));
await u.waitUntil(() => !u.isVisible(_converse.rosterview.get('Pending contacts').el));
done();
}));
@ -704,7 +703,7 @@ window.addEventListener('converse-loaded', () => {
['rosterGroupsFetched'], {},
async function (done, _converse) {
await test_utils.waitForRoster(_converse, 'all');
await mock.waitForRoster(_converse, 'all');
await Promise.all(_converse.roster.map(contact => u.waitUntil(() => contact.vcard.get('fullname'))));
await u.waitUntil(() => _converse.roster.at(0).vcard.get('fullname'))
spyOn(window, 'confirm').and.returnValue(true);
@ -721,8 +720,8 @@ window.addEventListener('converse-loaded', () => {
['rosterGroupsFetched'], {},
async function (done, _converse) {
await test_utils.openControlBox(_converse);
await test_utils.waitForRoster(_converse, 'current');
await mock.openControlBox(_converse);
await mock.waitForRoster(_converse, 'current');
await Promise.all(_converse.roster.map(contact => u.waitUntil(() => contact.vcard.get('fullname'))));
spyOn(_converse.rosterview, 'update').and.callThrough();
let i;
@ -747,8 +746,8 @@ window.addEventListener('converse-loaded', () => {
describe("Existing Contacts", function () {
async function _addContacts (_converse) {
await test_utils.waitForRoster(_converse, 'current');
await test_utils.openControlBox(_converse);
await mock.waitForRoster(_converse, 'current');
await mock.openControlBox(_converse);
await Promise.all(_converse.roster.map(contact => u.waitUntil(() => contact.vcard.get('fullname'))));
}
@ -791,7 +790,7 @@ window.addEventListener('converse-loaded', () => {
['rosterGroupsFetched'], {},
async function (done, _converse) {
await test_utils.openControlBox(_converse);
await mock.openControlBox(_converse);
spyOn(_converse.rosterview, 'update').and.callThrough();
await Promise.all(mock.cur_names.map(name => {
const contact = _converse.roster.create({
@ -844,8 +843,8 @@ window.addEventListener('converse-loaded', () => {
['rosterGroupsFetched'], {},
async function (done, _converse) {
await test_utils.openControlBox(_converse);
await test_utils.waitForRoster(_converse, 'current', 0);
await mock.openControlBox(_converse);
await mock.waitForRoster(_converse, 'current', 0);
const name = mock.cur_names[0];
const contact = _converse.roster.create({
jid: name.replace(/ /g,'.').toLowerCase() + '@montague.lit',
@ -1086,7 +1085,7 @@ window.addEventListener('converse-loaded', () => {
['rosterGroupsFetched'], {},
async function (done, _converse) {
test_utils.openControlBox(_converse);
mock.openControlBox(_converse);
let names = [];
const addName = function (item) {
if (!u.hasClass('request-actions', item)) {
@ -1119,8 +1118,8 @@ window.addEventListener('converse-loaded', () => {
['rosterGroupsFetched'], {},
async function (done, _converse) {
await test_utils.openControlBox(_converse);
await test_utils.waitForRoster(_converse, "current", 0);
await mock.openControlBox(_converse);
await mock.waitForRoster(_converse, "current", 0);
const name = mock.req_names[0];
spyOn(window, 'confirm').and.returnValue(true);
_converse.roster.create({
@ -1144,9 +1143,9 @@ window.addEventListener('converse-loaded', () => {
['rosterGroupsFetched'], {},
async function (done, _converse) {
await test_utils.waitForRoster(_converse, 'current', 0);
test_utils.createContacts(_converse, 'requesting');
await test_utils.openControlBox(_converse);
await mock.waitForRoster(_converse, 'current', 0);
mock.createContacts(_converse, 'requesting');
await mock.openControlBox(_converse);
await u.waitUntil(() => sizzle('.roster-group', _converse.rosterview.el).filter(u.isVisible).length, 700);
await checkHeaderToggling.apply(
_converse,
@ -1160,9 +1159,9 @@ window.addEventListener('converse-loaded', () => {
['rosterGroupsFetched'], {},
async function (done, _converse) {
await test_utils.openControlBox(_converse);
await test_utils.waitForRoster(_converse, 'current', 0);
await test_utils.createContacts(_converse, 'requesting');
await mock.openControlBox(_converse);
await mock.waitForRoster(_converse, 'current', 0);
await mock.createContacts(_converse, 'requesting');
const name = mock.req_names.sort()[0];
const jid = name.replace(/ /g,'.').toLowerCase() + '@montague.lit';
const contact = _converse.roster.get(jid);
@ -1185,9 +1184,9 @@ window.addEventListener('converse-loaded', () => {
['rosterGroupsFetched'], {},
async function (done, _converse) {
await test_utils.waitForRoster(_converse, 'current', 0);
await test_utils.createContacts(_converse, 'requesting');
await test_utils.openControlBox(_converse);
await mock.waitForRoster(_converse, 'current', 0);
await mock.createContacts(_converse, 'requesting');
await mock.openControlBox(_converse);
await u.waitUntil(() => sizzle('.roster-group li', _converse.rosterview.el).length, 700);
_converse.rosterview.update(); // XXX: Hack to make sure $roster element is attaced.
const name = mock.req_names.sort()[1];
@ -1232,10 +1231,10 @@ window.addEventListener('converse-loaded', () => {
name: 'Mercutio',
subscription:'from'
}).c('group').t('Friends').up().up()
_converse.connection._dataRecv(test_utils.createRequest(result));
_converse.connection._dataRecv(mock.createRequest(result));
const pres = $pres({from: 'data@enterprise/resource', type: 'subscribe'});
_converse.connection._dataRecv(test_utils.createRequest(pres));
_converse.connection._dataRecv(mock.createRequest(pres));
expect(_converse.roster.pluck('jid').length).toBe(1);
await u.waitUntil(() => sizzle('a:contains("Contact requests")', _converse.rosterview.el).length, 700);
expect(_converse.roster.pluck('jid').includes('data@enterprise')).toBeTruthy();
@ -1249,7 +1248,7 @@ window.addEventListener('converse-loaded', () => {
name: 'Benvolio',
subscription:'both'
}).c('group').t('Friends');
_converse.connection._dataRecv(test_utils.createRequest(roster_push));
_converse.connection._dataRecv(mock.createRequest(roster_push));
expect(_converse.roster.data.get('version')).toBe('ver34');
expect(_converse.roster.models.length).toBe(4);
expect(_converse.roster.pluck('jid').includes('data@enterprise')).toBeTruthy();
@ -1264,9 +1263,9 @@ window.addEventListener('converse-loaded', () => {
['rosterGroupsFetched'], {},
async function (done, _converse) {
await test_utils.waitForRoster(_converse, 'current', 0);
await test_utils.createContacts(_converse, 'requesting');
await test_utils.openControlBox(_converse);
await mock.waitForRoster(_converse, 'current', 0);
await mock.createContacts(_converse, 'requesting');
await mock.openControlBox(_converse);
var new_attrs, old_attrs, attrs;
var num_contacts = _converse.roster.length;
var new_roster = new _converse.RosterContacts();
@ -1294,9 +1293,9 @@ window.addEventListener('converse-loaded', () => {
['rosterGroupsFetched'], {},
async function (done, _converse) {
await test_utils.waitForRoster(_converse, 'current', 'all');
await test_utils.createContacts(_converse, 'requesting');
await test_utils.openControlBox(_converse);
await mock.waitForRoster(_converse, 'current', 'all');
await mock.createContacts(_converse, 'requesting');
await mock.openControlBox(_converse);
await u.waitUntil(() => sizzle('.roster-group li', _converse.rosterview.el).length, 700);
await Promise.all(mock.cur_names.map(async name => {
const jid = name.replace(/ /g,'.').toLowerCase() + '@montague.lit';
@ -1316,5 +1315,4 @@ window.addEventListener('converse-loaded', () => {
done();
}));
});
});
});

View File

@ -1,13 +1,12 @@
window.addEventListener('converse-loaded', () => {
const mock = window.mock;
const test_utils = window.test_utils;
const $iq = converse.env.$iq;
const $msg = converse.env.$msg;
const Strophe = converse.env.Strophe;
const sizzle = converse.env.sizzle;
const u = converse.env.utils;
/*global mock */
describe("XEP-0198 Stream Management", function () {
const $iq = converse.env.$iq;
const $msg = converse.env.$msg;
const Strophe = converse.env.Strophe;
const sizzle = converse.env.sizzle;
const u = converse.env.utils;
describe("XEP-0198 Stream Management", function () {
it("gets enabled with an <enable> stanza and resumed with a <resume> stanza",
mock.initConverse(
@ -31,7 +30,7 @@ window.addEventListener('converse-loaded', () => {
expect(Strophe.serialize(stanza)).toEqual('<enable resume="true" xmlns="urn:xmpp:sm:3"/>');
let result = u.toStanza(`<enabled xmlns="urn:xmpp:sm:3" id="some-long-sm-id" resume="true"/>`);
_converse.connection._dataRecv(test_utils.createRequest(result));
_converse.connection._dataRecv(mock.createRequest(result));
expect(_converse.session.get('smacks_enabled')).toBe(true);
await u.waitUntil(() => view.renderControlBoxPane.calls.count());
@ -42,7 +41,7 @@ window.addEventListener('converse-loaded', () => {
let iq = IQ_stanzas[IQ_stanzas.length-1];
expect(Strophe.serialize(iq)).toBe(
`<iq id="${iq.getAttribute('id')}" type="get" xmlns="jabber:client"><query xmlns="jabber:iq:roster"/></iq>`);
await test_utils.waitForRoster(_converse, 'current', 1);
await mock.waitForRoster(_converse, 'current', 1);
IQ_stanzas.pop();
const expected_IQs = disco_iq => ([
@ -67,12 +66,12 @@ window.addEventListener('converse-loaded', () => {
// test handling of acks
let ack = u.toStanza(`<a xmlns="urn:xmpp:sm:3" h="2"/>`);
_converse.connection._dataRecv(test_utils.createRequest(ack));
_converse.connection._dataRecv(mock.createRequest(ack));
expect(_converse.session.get('unacked_stanzas').length).toBe(3);
// test handling of ack requests
let r = u.toStanza(`<r xmlns="urn:xmpp:sm:3"/>`);
_converse.connection._dataRecv(test_utils.createRequest(r));
_converse.connection._dataRecv(mock.createRequest(r));
ack = await u.waitUntil(() => sent_stanzas.filter(s => (s.nodeName === 'a')).pop());
expect(Strophe.serialize(ack)).toBe('<a h="1" xmlns="urn:xmpp:sm:3"/>');
@ -90,14 +89,14 @@ window.addEventListener('converse-loaded', () => {
}).up()
.c('feature', {'var': 'http://jabber.org/protocol/disco#info'}).up()
.c('feature', {'var': 'http://jabber.org/protocol/disco#items'});
_converse.connection._dataRecv(test_utils.createRequest(disco_result));
_converse.connection._dataRecv(mock.createRequest(disco_result));
ack = u.toStanza(`<a xmlns="urn:xmpp:sm:3" h="3"/>`);
_converse.connection._dataRecv(test_utils.createRequest(ack));
_converse.connection._dataRecv(mock.createRequest(ack));
expect(_converse.session.get('unacked_stanzas').length).toBe(2);
r = u.toStanza(`<r xmlns="urn:xmpp:sm:3"/>`);
_converse.connection._dataRecv(test_utils.createRequest(r));
_converse.connection._dataRecv(mock.createRequest(r));
ack = await u.waitUntil(() => sent_stanzas.filter(s => (s.nodeName === 'a' && s.getAttribute('h') === '1')).pop());
expect(Strophe.serialize(ack)).toBe('<a h="1" xmlns="urn:xmpp:sm:3"/>');
await _converse.api.waitUntil('rosterInitialized');
@ -110,7 +109,7 @@ window.addEventListener('converse-loaded', () => {
expect(Strophe.serialize(stanza)).toEqual('<resume h="2" previd="some-long-sm-id" xmlns="urn:xmpp:sm:3"/>');
result = u.toStanza(`<resumed xmlns="urn:xmpp:sm:3" h="another-sequence-number" previd="some-long-sm-id"/>`);
_converse.connection._dataRecv(test_utils.createRequest(result));
_converse.connection._dataRecv(mock.createRequest(result));
// Another <enable> stanza doesn't get sent out
expect(sent_stanzas.filter(s => (s.tagName === 'enable')).length).toBe(1);
@ -143,9 +142,9 @@ window.addEventListener('converse-loaded', () => {
let stanza = await u.waitUntil(() => sent_stanzas.filter(s => (s.tagName === 'enable')).pop());
expect(Strophe.serialize(stanza)).toEqual('<enable resume="true" xmlns="urn:xmpp:sm:3"/>');
let result = u.toStanza(`<enabled xmlns="urn:xmpp:sm:3" id="some-long-sm-id" resume="true"/>`);
_converse.connection._dataRecv(test_utils.createRequest(result));
_converse.connection._dataRecv(mock.createRequest(result));
await test_utils.waitForRoster(_converse, 'current', 1);
await mock.waitForRoster(_converse, 'current', 1);
// test session resumption
await _converse.api.connection.reconnect();
@ -156,7 +155,7 @@ window.addEventListener('converse-loaded', () => {
`<failed xmlns="urn:xmpp:sm:3" h="another-sequence-number">`+
`<item-not-found xmlns="urn:ietf:params:xml:ns:xmpp-stanzas"/>`+
`</failed>`);
_converse.connection._dataRecv(test_utils.createRequest(result));
_converse.connection._dataRecv(mock.createRequest(result));
// Session data gets reset
expect(_converse.session.get('smacks_enabled')).toBe(false);
@ -172,11 +171,11 @@ window.addEventListener('converse-loaded', () => {
expect(Strophe.serialize(stanza)).toEqual('<enable resume="true" xmlns="urn:xmpp:sm:3"/>');
result = u.toStanza(`<enabled xmlns="urn:xmpp:sm:3" id="another-long-sm-id" resume="true"/>`);
_converse.connection._dataRecv(test_utils.createRequest(result));
_converse.connection._dataRecv(mock.createRequest(result));
expect(_converse.session.get('smacks_enabled')).toBe(true);
// Check that the roster gets fetched
await test_utils.waitForRoster(_converse, 'current', 1);
await mock.waitForRoster(_converse, 'current', 1);
await new Promise(resolve => _converse.api.listen.once('reconnected', resolve));
done();
}));
@ -242,7 +241,7 @@ window.addEventListener('converse-loaded', () => {
expect(Strophe.serialize(stanza)).toEqual('<resume h="580" previd="some-long-sm-id" xmlns="urn:xmpp:sm:3"/>');
const result = u.toStanza(`<resumed xmlns="urn:xmpp:sm:3" h="another-sequence-number" previd="some-long-sm-id"/>`);
_converse.connection._dataRecv(test_utils.createRequest(result));
_converse.connection._dataRecv(mock.createRequest(result));
expect(_converse.session.get('smacks_enabled')).toBe(true);
@ -262,15 +261,15 @@ window.addEventListener('converse-loaded', () => {
type: 'groupchat'
}).c('body').t('First message').tree();
_converse.connection._dataRecv(test_utils.createRequest(msg));
_converse.connection._dataRecv(mock.createRequest(msg));
await _converse.api.waitUntil('chatBoxesFetched');
const muc = _converse.chatboxes.get(muc_jid);
await u.waitUntil(() => muc.message_queue.length === 1);
const view = _converse.chatboxviews.get(muc_jid);
await test_utils.getRoomFeatures(_converse, muc_jid);
await test_utils.receiveOwnMUCPresence(_converse, muc_jid, nick);
await mock.getRoomFeatures(_converse, muc_jid);
await mock.receiveOwnMUCPresence(_converse, muc_jid, nick);
await u.waitUntil(() => (view.model.session.get('connection_status') === converse.ROOMSTATUS.ENTERED));
await view.model.messages.fetched;
@ -278,5 +277,4 @@ window.addEventListener('converse-loaded', () => {
expect(muc.messages.at(0).get('message')).toBe('First message')
done();
}));
});
});

View File

@ -1,20 +1,13 @@
window.addEventListener('converse-loaded', () => {
const mock = window.mock;
const test_utils = window.test_utils;
const _ = converse.env._;
const Strophe = converse.env.Strophe;
const $msg = converse.env.$msg;
const $pres = converse.env.$pres;
const u = converse.env.utils;
/* global mock */
describe("A spoiler message", function () {
describe("A spoiler message", function () {
it("can be received with a hint",
mock.initConverse(
['rosterGroupsFetched', 'chatBoxesFetched'], {},
async (done, _converse) => {
await test_utils.waitForRoster(_converse, 'current');
await mock.waitForRoster(_converse, 'current');
const sender_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit';
/* <message to='romeo@montague.net/orchard' from='juliet@capulet.net/balcony' id='spoiler2'>
@ -24,6 +17,8 @@ window.addEventListener('converse-loaded', () => {
*/
const spoiler_hint = "Love story end"
const spoiler = "And at the end of the story, both of them die! It is so tragic!";
const $msg = converse.env.$msg;
const u = converse.env.utils;
const msg = $msg({
'xmlns': 'jabber:client',
'to': _converse.bare_jid,
@ -34,7 +29,7 @@ window.addEventListener('converse-loaded', () => {
'xmlns': 'urn:xmpp:spoiler:0',
}).t(spoiler_hint)
.tree();
_converse.connection._dataRecv(test_utils.createRequest(msg));
_converse.connection._dataRecv(mock.createRequest(msg));
await new Promise(resolve => _converse.api.listen.once('chatBoxViewInitialized', resolve));
const view = _converse.chatboxviews.get(sender_jid);
await new Promise(resolve => view.once('messageInserted', resolve));
@ -52,13 +47,15 @@ window.addEventListener('converse-loaded', () => {
['rosterGroupsFetched', 'chatBoxesFetched'], {},
async (done, _converse) => {
await test_utils.waitForRoster(_converse, 'current');
await mock.waitForRoster(_converse, 'current');
const sender_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit';
/* <message to='romeo@montague.net/orchard' from='juliet@capulet.net/balcony' id='spoiler2'>
* <body>And at the end of the story, both of them die! It is so tragic!</body>
* <spoiler xmlns='urn:xmpp:spoiler:0'>Love story end</spoiler>
* </message>
*/
const $msg = converse.env.$msg;
const u = converse.env.utils;
const spoiler = "And at the end of the story, both of them die! It is so tragic!";
const msg = $msg({
'xmlns': 'jabber:client',
@ -69,7 +66,7 @@ window.addEventListener('converse-loaded', () => {
.c('spoiler', {
'xmlns': 'urn:xmpp:spoiler:0',
}).tree();
_converse.connection._dataRecv(test_utils.createRequest(msg));
_converse.connection._dataRecv(mock.createRequest(msg));
await new Promise(resolve => _converse.api.listen.once('chatBoxViewInitialized', resolve));
const view = _converse.chatboxviews.get(sender_jid);
await new Promise(resolve => view.model.messages.once('rendered', resolve));
@ -88,10 +85,13 @@ window.addEventListener('converse-loaded', () => {
['rosterGroupsFetched', 'chatBoxesFetched'], {},
async (done, _converse) => {
await test_utils.waitForRoster(_converse, 'current', 1);
test_utils.openControlBox(_converse);
await mock.waitForRoster(_converse, 'current', 1);
mock.openControlBox(_converse);
const contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit';
const { $pres, Strophe} = converse.env;
const u = converse.env.utils;
// XXX: We need to send a presence from the contact, so that we
// have a resource, that resource is then queried to see
// whether Strophe.NS.SPOILER is supported, in which case
@ -100,9 +100,9 @@ window.addEventListener('converse-loaded', () => {
'from': contact_jid+'/phone',
'to': 'romeo@montague.lit'
});
_converse.connection._dataRecv(test_utils.createRequest(presence));
await test_utils.openChatBoxFor(_converse, contact_jid);
await test_utils.waitUntilDiscoConfirmed(_converse, contact_jid+'/phone', [], [Strophe.NS.SPOILER]);
_converse.connection._dataRecv(mock.createRequest(presence));
await mock.openChatBoxFor(_converse, contact_jid);
await mock.waitUntilDiscoConfirmed(_converse, contact_jid+'/phone', [], [Strophe.NS.SPOILER]);
const view = _converse.api.chatviews.get(contact_jid);
spyOn(_converse.connection, 'send');
@ -144,15 +144,15 @@ window.addEventListener('converse-loaded', () => {
const spoiler_msg_el = view.el.querySelector('.chat-msg__text.spoiler');
expect(spoiler_msg_el.textContent).toBe('This is the spoiler');
expect(_.includes(spoiler_msg_el.classList, 'collapsed')).toBeTruthy();
expect(Array.from(spoiler_msg_el.classList).includes('collapsed')).toBeTruthy();
spoiler_toggle = view.el.querySelector('.spoiler-toggle');
expect(spoiler_toggle.textContent).toBe('Show more');
spoiler_toggle.click();
expect(_.includes(spoiler_msg_el.classList, 'collapsed')).toBeFalsy();
expect(Array.from(spoiler_msg_el.classList).includes('collapsed')).toBeFalsy();
expect(spoiler_toggle.textContent).toBe('Show less');
spoiler_toggle.click();
expect(_.includes(spoiler_msg_el.classList, 'collapsed')).toBeTruthy();
expect(Array.from(spoiler_msg_el.classList).includes('collapsed')).toBeTruthy();
done();
}));
@ -161,10 +161,13 @@ window.addEventListener('converse-loaded', () => {
['rosterGroupsFetched', 'chatBoxesFetched'], {},
async (done, _converse) => {
await test_utils.waitForRoster(_converse, 'current', 1);
test_utils.openControlBox(_converse);
await mock.waitForRoster(_converse, 'current', 1);
mock.openControlBox(_converse);
const contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit';
const { $pres, Strophe} = converse.env;
const u = converse.env.utils;
// XXX: We need to send a presence from the contact, so that we
// have a resource, that resource is then queried to see
// whether Strophe.NS.SPOILER is supported, in which case
@ -173,9 +176,9 @@ window.addEventListener('converse-loaded', () => {
'from': contact_jid+'/phone',
'to': 'romeo@montague.lit'
});
_converse.connection._dataRecv(test_utils.createRequest(presence));
await test_utils.openChatBoxFor(_converse, contact_jid);
await test_utils.waitUntilDiscoConfirmed(_converse, contact_jid+'/phone', [], [Strophe.NS.SPOILER]);
_converse.connection._dataRecv(mock.createRequest(presence));
await mock.openChatBoxFor(_converse, contact_jid);
await mock.waitUntilDiscoConfirmed(_converse, contact_jid+'/phone', [], [Strophe.NS.SPOILER]);
const view = _converse.api.chatviews.get(contact_jid);
await u.waitUntil(() => view.el.querySelector('.toggle-compose-spoiler'));
@ -222,16 +225,15 @@ window.addEventListener('converse-loaded', () => {
const spoiler_msg_el = view.el.querySelector('.chat-msg__text.spoiler');
expect(spoiler_msg_el.textContent).toBe('This is the spoiler');
expect(_.includes(spoiler_msg_el.classList, 'collapsed')).toBeTruthy();
expect(Array.from(spoiler_msg_el.classList).includes('collapsed')).toBeTruthy();
spoiler_toggle = view.el.querySelector('.spoiler-toggle');
expect(spoiler_toggle.textContent).toBe('Show more');
spoiler_toggle.click();
expect(_.includes(spoiler_msg_el.classList, 'collapsed')).toBeFalsy();
expect(Array.from(spoiler_msg_el.classList).includes('collapsed')).toBeFalsy();
expect(spoiler_toggle.textContent).toBe('Show less');
spoiler_toggle.click();
expect(_.includes(spoiler_msg_el.classList, 'collapsed')).toBeTruthy();
expect(Array.from(spoiler_msg_el.classList).includes('collapsed')).toBeTruthy();
done();
}));
});
});

View File

@ -1,77 +0,0 @@
(function (root, factory) {
define([
"jasmine",
"mock",
"test-utils",
"utils",
"transcripts"
], factory
);
} (this, function (jasmine, mock, test_utils, utils, transcripts) {
var Strophe = converse.env.Strophe;
var _ = converse.env._;
var IGNORED_TAGS = [
'stream:features',
'auth',
'challenge',
'success',
'stream:features',
'response'
];
function traverseElement (el, _stanza) {
if (typeof _stanza !== 'undefined') {
if (el.nodeType === 3) {
_stanza.t(el.nodeValue);
return _stanza;
} else {
_stanza = _stanza.c(el.nodeName.toLowerCase(), getAttributes(el));
}
} else {
_stanza = new Strophe.Builder(
el.nodeName.toLowerCase(),
getAttributes(el)
);
}
_.each(el.childNodes, _.partial(traverseElement, _, _stanza));
return _stanza.up();
}
function getAttributes (el) {
var attributes = {};
_.each(el.attributes, function (att) {
attributes[att.nodeName] = att.nodeValue;
});
return attributes;
}
return describe("Transcripts of chat logs", function () {
it("can be used to replay conversations",
mock.initConverse(
['rosterGroupsFetched'], {},
async function (done, _converse) {
_converse.allow_non_roster_messaging = true;
await test_utils.openAndEnterChatRoom(_converse, 'discuss@conference.conversejs.org', 'romeo');
spyOn(_converse, 'areDesktopNotificationsEnabled').and.returnValue(true);
_.each(transcripts, function (transcript) {
const text = transcript();
const xml = Strophe.xmlHtmlNode(text);
_.each(xml.firstElementChild.children, function (el) {
_.each(el.children, function (el) {
if (el.nodeType === 3) {
return; // Ignore text
}
if (_.includes(IGNORED_TAGS, el.nodeName.toLowerCase())) {
return;
}
const _stanza = traverseElement(el);
_converse.connection._dataRecv(test_utils.createRequest(_stanza));
});
});
});
done();
}));
});
}));

View File

@ -1,20 +1,19 @@
window.addEventListener('converse-loaded', () => {
const mock = window.mock;
const test_utils = window.test_utils;
const u = converse.env.utils;
/*global mock */
return describe("The User Details Modal", function () {
const u = converse.env.utils;
describe("The User Details Modal", function () {
it("can be used to remove a contact",
mock.initConverse(
['rosterGroupsFetched', 'chatBoxesFetched'], {},
async function (done, _converse) {
await test_utils.waitForRoster(_converse, 'current', 1);
await mock.waitForRoster(_converse, 'current', 1);
_converse.api.trigger('rosterContactsFetched');
const contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit';
await test_utils.openChatBoxFor(_converse, contact_jid);
await mock.openChatBoxFor(_converse, contact_jid);
await u.waitUntil(() => _converse.chatboxes.length > 1);
const view = _converse.chatboxviews.get(contact_jid);
let show_modal_button = view.el.querySelector('.show-user-details-modal');
@ -38,11 +37,11 @@ window.addEventListener('converse-loaded', () => {
it("shows an alert when an error happened while removing the contact",
mock.initConverse(['rosterGroupsFetched'], {}, async function (done, _converse) {
await test_utils.waitForRoster(_converse, 'current', 1);
await mock.waitForRoster(_converse, 'current', 1);
_converse.api.trigger('rosterContactsFetched');
const contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit';
await test_utils.openChatBoxFor(_converse, contact_jid)
await mock.openChatBoxFor(_converse, contact_jid)
const view = _converse.chatboxviews.get(contact_jid);
let show_modal_button = view.el.querySelector('.show-user-details-modal');
show_modal_button.click();
@ -73,5 +72,4 @@ window.addEventListener('converse-loaded', () => {
expect(u.isVisible(remove_contact_button)).toBeTruthy();
done();
}));
});
});

View File

@ -1,12 +1,8 @@
window.addEventListener('converse-loaded', () => {
const utils = converse.env.utils;
const _ = converse.env._;
return describe("Converse.js Utilities", function() {
describe("Converse.js Utilities", function() {
it("applySiteSettings: recursively applies user settings", function () {
var context = {};
var settings = {
const context = {};
const settings = {
show_toolbar: true,
chatview_avatar_width: 32,
chatview_avatar_height: 32,
@ -18,9 +14,9 @@ window.addEventListener('converse-loaded', () => {
'toggle_occupants': true
}
};
_.extend(context, settings);
Object.assign(context, settings);
var user_settings = {
let user_settings = {
something_else: 'xxx',
show_toolbar: false,
chatview_avatar_width: 32,
@ -35,13 +31,14 @@ window.addEventListener('converse-loaded', () => {
'invalid': false
}
};
const utils = converse.env.utils;
utils.applySiteSettings(context, settings, user_settings);
expect(context.something_else).toBeUndefined();
expect(context.show_toolbar).toBeFalsy();
expect(context.chatview_avatar_width).toBe(32);
expect(context.chatview_avatar_height).toBe(48);
expect(_.keys(context.visible_toolbar_buttons)).toEqual(_.keys(settings.visible_toolbar_buttons));
expect(Object.keys(context.visible_toolbar_buttons)).toEqual(Object.keys(settings.visible_toolbar_buttons));
expect(context.visible_toolbar_buttons.emojis).toBeFalsy();
expect(context.visible_toolbar_buttons.call).toBeFalsy();
expect(context.visible_toolbar_buttons.toggle_occupants).toBeFalsy();
@ -55,8 +52,7 @@ window.addEventListener('converse-loaded', () => {
}
};
utils.applySiteSettings(context, settings, user_settings);
expect(_.keys(context.visible_toolbar_buttons)).toEqual(_.keys(settings.visible_toolbar_buttons));
expect(Object.keys(context.visible_toolbar_buttons)).toEqual(Object.keys(settings.visible_toolbar_buttons));
expect(context.visible_toolbar_buttons.toggle_occupants).toBeTruthy();
});
});
});

View File

@ -1,8 +1,8 @@
window.addEventListener('converse-loaded', () => {
const mock = window.mock;
const u = converse.env.utils;
/*global mock */
return describe("The XMPPStatus model", function () {
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) => {
@ -19,5 +19,4 @@ window.addEventListener('converse-loaded', () => {
expect(stanza.querySelector('priority').textContent).toBe('0');
done();
}));
});
});

View File

@ -1,11 +1,10 @@
window.addEventListener('converse-loaded', () => {
const mock = window.mock;
const test_utils = window.test_utils;
const $pres = converse.env.$pres;
const sizzle = converse.env.sizzle;
const u = converse.env.utils;
/*global mock */
describe("XSS", function () {
const $pres = converse.env.$pres;
const sizzle = converse.env.sizzle;
const u = converse.env.utils;
describe("XSS", function () {
describe("A Chat Message", function () {
it("will escape IMG payload XSS attempts",
@ -14,52 +13,52 @@ window.addEventListener('converse-loaded', () => {
async function (done, _converse) {
spyOn(window, 'alert').and.callThrough();
await test_utils.waitForRoster(_converse, 'current');
await test_utils.openControlBox(_converse);
await mock.waitForRoster(_converse, 'current');
await mock.openControlBox(_converse);
const contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit';
await test_utils.openChatBoxFor(_converse, contact_jid)
await mock.openChatBoxFor(_converse, contact_jid)
const view = _converse.api.chatviews.get(contact_jid);
let message = "<img src=x onerror=alert('XSS');>";
await test_utils.sendMessage(view, message);
await mock.sendMessage(view, message);
let msg = sizzle('.chat-content .chat-msg:last .chat-msg__text', view.el).pop();
expect(msg.textContent).toEqual(message);
expect(msg.innerHTML).toEqual("&lt;img src=x onerror=alert('XSS');&gt;");
expect(window.alert).not.toHaveBeenCalled();
message = "<img src=x onerror=alert('XSS')//";
await test_utils.sendMessage(view, message);
await mock.sendMessage(view, message);
msg = sizzle('.chat-content .chat-msg:last .chat-msg__text', view.el).pop();
expect(msg.textContent).toEqual(message);
expect(msg.innerHTML).toEqual("&lt;img src=x onerror=alert('XSS')//");
message = "<img src=x onerror=alert(String.fromCharCode(88,83,83));>";
await test_utils.sendMessage(view, message);
await mock.sendMessage(view, message);
msg = sizzle('.chat-content .chat-msg:last .chat-msg__text', view.el).pop();
expect(msg.textContent).toEqual(message);
expect(msg.innerHTML).toEqual("&lt;img src=x onerror=alert(String.fromCharCode(88,83,83));&gt;");
message = "<img src=x oneonerrorrror=alert(String.fromCharCode(88,83,83));>";
await test_utils.sendMessage(view, message);
await mock.sendMessage(view, message);
msg = sizzle('.chat-content .chat-msg:last .chat-msg__text', view.el).pop();
expect(msg.textContent).toEqual(message);
expect(msg.innerHTML).toEqual("&lt;img src=x oneonerrorrror=alert(String.fromCharCode(88,83,83));&gt;");
message = "<img src=x:alert(alt) onerror=eval(src) alt=xss>";
await test_utils.sendMessage(view, message);
await mock.sendMessage(view, message);
msg = sizzle('.chat-content .chat-msg:last .chat-msg__text', view.el).pop();
expect(msg.textContent).toEqual(message);
expect(msg.innerHTML).toEqual("&lt;img src=x:alert(alt) onerror=eval(src) alt=xss&gt;");
message = "><img src=x onerror=alert('XSS');>";
await test_utils.sendMessage(view, message);
await mock.sendMessage(view, message);
msg = sizzle('.chat-content .chat-msg:last .chat-msg__text', view.el).pop();
expect(msg.textContent).toEqual(message);
expect(msg.innerHTML).toEqual("&gt;&lt;img src=x onerror=alert('XSS');&gt;");
message = "><img src=x onerror=alert(String.fromCharCode(88,83,83));>";
await test_utils.sendMessage(view, message);
await mock.sendMessage(view, message);
msg = sizzle('.chat-content .chat-msg:last .chat-msg__text', view.el).pop();
expect(msg.textContent).toEqual(message);
expect(msg.innerHTML).toEqual("&gt;&lt;img src=x onerror=alert(String.fromCharCode(88,83,83));&gt;");
@ -74,51 +73,51 @@ window.addEventListener('converse-loaded', () => {
async function (done, _converse) {
spyOn(window, 'alert').and.callThrough();
await test_utils.waitForRoster(_converse, 'current');
await test_utils.openControlBox(_converse);
await mock.waitForRoster(_converse, 'current');
await mock.openControlBox(_converse);
const contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit';
await test_utils.openChatBoxFor(_converse, contact_jid)
await mock.openChatBoxFor(_converse, contact_jid)
const view = _converse.api.chatviews.get(contact_jid);
let message = "<svg onload=alert(1)>";
await test_utils.sendMessage(view, message);
await mock.sendMessage(view, message);
let msg = sizzle('.chat-content .chat-msg:last .chat-msg__text', view.el).pop();
expect(msg.textContent).toEqual(message);
expect(msg.innerHTML).toEqual('&lt;svg onload=alert(1)&gt;');
message = "<svg/onload=alert('XSS')>";
await test_utils.sendMessage(view, message);
await mock.sendMessage(view, message);
msg = sizzle('.chat-content .chat-msg:last .chat-msg__text', view.el).pop();
expect(msg.textContent).toEqual(message);
expect(msg.innerHTML).toEqual("&lt;svg/onload=alert('XSS')&gt;");
message = "<svg onload=alert(1)//";
await test_utils.sendMessage(view, message);
await mock.sendMessage(view, message);
msg = sizzle('.chat-content .chat-msg:last .chat-msg__text', view.el).pop();
expect(msg.textContent).toEqual(message);
expect(msg.innerHTML).toEqual("&lt;svg onload=alert(1)//");
message = "<svg/onload=alert(String.fromCharCode(88,83,83))>";
await test_utils.sendMessage(view, message);
await mock.sendMessage(view, message);
msg = sizzle('.chat-content .chat-msg:last .chat-msg__text', view.el).pop();
expect(msg.textContent).toEqual(message);
expect(msg.innerHTML).toEqual("&lt;svg/onload=alert(String.fromCharCode(88,83,83))&gt;");
message = "<svg id=alert(1) onload=eval(id)>";
await test_utils.sendMessage(view, message);
await mock.sendMessage(view, message);
msg = sizzle('.chat-content .chat-msg:last .chat-msg__text', view.el).pop();
expect(msg.textContent).toEqual(message);
expect(msg.innerHTML).toEqual("&lt;svg id=alert(1) onload=eval(id)&gt;");
message = '"><svg/onload=alert(String.fromCharCode(88,83,83))>';
await test_utils.sendMessage(view, message);
await mock.sendMessage(view, message);
msg = sizzle('.chat-content .chat-msg:last .chat-msg__text', view.el).pop();
expect(msg.textContent).toEqual(message);
expect(msg.innerHTML).toEqual('"&gt;&lt;svg/onload=alert(String.fromCharCode(88,83,83))&gt;');
message = '"><svg/onload=alert(/XSS/)';
await test_utils.sendMessage(view, message);
await mock.sendMessage(view, message);
msg = sizzle('.chat-content .chat-msg:last .chat-msg__text', view.el).pop();
expect(msg.textContent).toEqual(message);
expect(msg.innerHTML).toEqual('"&gt;&lt;svg/onload=alert(/XSS/)');
@ -132,15 +131,15 @@ window.addEventListener('converse-loaded', () => {
['rosterGroupsFetched', 'chatBoxesFetched'], {},
async function (done, _converse) {
await test_utils.waitForRoster(_converse, 'current');
await test_utils.openControlBox(_converse);
await mock.waitForRoster(_converse, 'current');
await mock.openControlBox(_converse);
const contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit';
await test_utils.openChatBoxFor(_converse, contact_jid)
await mock.openChatBoxFor(_converse, contact_jid)
const view = _converse.api.chatviews.get(contact_jid);
let message = "http://www.opkode.com/'onmouseover='alert(1)'whatever";
await test_utils.sendMessage(view, message);
await mock.sendMessage(view, message);
let msg = sizzle('.chat-content .chat-msg:last .chat-msg__text', view.el).pop();
expect(msg.textContent).toEqual(message);
@ -148,21 +147,21 @@ window.addEventListener('converse-loaded', () => {
.toEqual('<a target="_blank" rel="noopener" href="http://www.opkode.com/%27onmouseover=%27alert%281%29%27whatever">http://www.opkode.com/\'onmouseover=\'alert(1)\'whatever</a>');
message = 'http://www.opkode.com/"onmouseover="alert(1)"whatever';
await test_utils.sendMessage(view, message);
await mock.sendMessage(view, message);
msg = sizzle('.chat-content .chat-msg:last .chat-msg__text', view.el).pop();
expect(msg.textContent).toEqual(message);
expect(msg.innerHTML).toEqual('<a target="_blank" rel="noopener" href="http://www.opkode.com/%22onmouseover=%22alert%281%29%22whatever">http://www.opkode.com/"onmouseover="alert(1)"whatever</a>');
message = "https://en.wikipedia.org/wiki/Ender's_Game";
await test_utils.sendMessage(view, message);
await mock.sendMessage(view, message);
msg = sizzle('.chat-content .chat-msg:last .chat-msg__text', view.el).pop();
expect(msg.textContent).toEqual(message);
expect(msg.innerHTML).toEqual('<a target="_blank" rel="noopener" href="https://en.wikipedia.org/wiki/Ender%27s_Game">'+message+'</a>');
message = "<https://bugs.documentfoundation.org/show_bug.cgi?id=123737>";
await test_utils.sendMessage(view, message);
await mock.sendMessage(view, message);
msg = sizzle('.chat-content .chat-msg:last .chat-msg__text', view.el).pop();
expect(msg.textContent).toEqual(message);
@ -170,7 +169,7 @@ window.addEventListener('converse-loaded', () => {
`&lt;<a target="_blank" rel="noopener" href="https://bugs.documentfoundation.org/show_bug.cgi?id=123737">https://bugs.documentfoundation.org/show_bug.cgi?id=123737</a>&gt;`);
message = '<http://www.opkode.com/"onmouseover="alert(1)"whatever>';
await test_utils.sendMessage(view, message);
await mock.sendMessage(view, message);
msg = sizzle('.chat-content .chat-msg:last .chat-msg__text', view.el).pop();
expect(msg.textContent).toEqual(message);
@ -178,7 +177,7 @@ window.addEventListener('converse-loaded', () => {
'&lt;<a target="_blank" rel="noopener" href="http://www.opkode.com/%22onmouseover=%22alert%281%29%22whatever">http://www.opkode.com/"onmouseover="alert(1)"whatever</a>&gt;');
message = `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`
await test_utils.sendMessage(view, message);
await mock.sendMessage(view, message);
msg = sizzle('.chat-content .chat-msg:last .chat-msg__text', view.el).pop();
expect(msg.textContent).toEqual(message);
@ -194,7 +193,7 @@ window.addEventListener('converse-loaded', () => {
mock.initConverse(['rosterGroupsFetched'], {},
async function (done, _converse) {
await test_utils.openAndEnterChatRoom(_converse, 'lounge@montague.lit', 'romeo');
await mock.openAndEnterChatRoom(_converse, 'lounge@montague.lit', 'romeo');
/* <presence xmlns="jabber:client" to="jc@chat.example.org/converse.js-17184538"
* from="oo@conference.chat.example.org/&lt;img src=&quot;x&quot; onerror=&quot;alert(123)&quot;/&gt;">
* <x xmlns="http://jabber.org/protocol/muc#user">
@ -213,7 +212,7 @@ window.addEventListener('converse-loaded', () => {
}).up()
.c('status').attrs({code:'110'}).nodeTree;
_converse.connection._dataRecv(test_utils.createRequest(presence));
_converse.connection._dataRecv(mock.createRequest(presence));
const view = _converse.chatboxviews.get('lounge@montague.lit');
await u.waitUntil(() => view.el.querySelectorAll('li .occupant-nick').length, 500);
const occupants = view.el.querySelector('.occupant-list').querySelectorAll('li .occupant-nick');
@ -227,7 +226,7 @@ window.addEventListener('converse-loaded', () => {
['rosterGroupsFetched'], {},
async function (done, _converse) {
await test_utils.openAndEnterChatRoom(_converse, 'jdev@conference.jabber.org', 'jc');
await mock.openAndEnterChatRoom(_converse, 'jdev@conference.jabber.org', 'jc');
spyOn(window, 'alert');
const subject = '<img src="x" onerror="alert(\'XSS\');"/>';
const view = _converse.chatboxviews.get('jdev@conference.jabber.org');
@ -240,5 +239,4 @@ window.addEventListener('converse-loaded', () => {
done();
}));
});
});
});

View File

@ -1,140 +0,0 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title>Converse Tests</title>
<meta name="description" content="Converse XMPP Chat" />
<link rel="shortcut icon" type="image/png" href="node_modules/jasmine-core/images/jasmine_favicon.png">
<link rel="stylesheet" type="text/css" media="screen" href="node_modules/jasmine-core/lib/jasmine-core/jasmine.css">
<link type="text/css" rel="stylesheet" media="screen" href="dist/website.css" />
<script src="tests/mock.js"></script>
<script src="tests/utils.js"></script>
<script src="node_modules/jasmine-core/lib/jasmine-core/jasmine.js"></script>
<script src="node_modules/jasmine-core/lib/jasmine-core/jasmine-html.js"></script>
<script src="node_modules/jasmine-core/lib/jasmine-core/boot.js"></script>
<script src="node_modules/sinon/pkg/sinon.js"></script>
<script src="tests/console-reporter.js"script>
<script src="spec/spoilers.js"></script>
<script src="spec/roomslist.js"></script>
<script src="spec/utils.js"></script>
<script src="spec/converse.js"></script>
<script src="spec/bookmarks.js"></script>
<script src="spec/headline.js"></script>
<script src="spec/disco.js"></script>
<script src="spec/protocol.js"></script>
<script src="spec/presence.js"></script>
<script src="spec/eventemitter.js"></script>
<script src="spec/smacks.js"></script>
<script src="spec/ping.js"></script>
<script src="spec/push.js"></script>
<script src="spec/xmppstatus.js"></script>
<script src="spec/mam.js"></script>
<script src="spec/omemo.js"></script>
<script src="spec/controlbox.js"></script>
<script src="spec/roster.js"></script>
<script src="spec/chatbox.js"></script>
<script src="spec/user-details-modal.js"></script>
<script src="spec/messages.js"></script>
<script src="spec/muc_messages.js"></script>
<script src="spec/retractions.js"></script>
<script src="spec/muc.js"></script>
<script src="spec/modtools.js"></script>
<script src="spec/room_registration.js"></script>
<script src="spec/autocomplete.js"></script>
<script src="spec/minchats.js"></script>
<script src="spec/notification.js"></script>
<script src="spec/login.js"></script>
<script src="spec/register.js"></script>
<script src="spec/hats.js"></script>
<script src="spec/http-file-upload.js"></script>
<script src="spec/emojis.js"></script>
<script src="spec/xss.js"></script>
<style>
.tests-brand-heading {
margin-top: 1em;
font-size: 200%;
}
.jasmine_html-reporter {
text-align: left;
width: 100vw;
background-color: rgba(255, 255, 255, .5);
}
.intro {
background: unset;
background-color: #397491;
}
</style>
</head>
<body id="page-top" data-spy="scroll" class="converse-website">
<section class="section-wrapper">
<section id="intro" class="intro" class="container">
<div class="row">
<div class="col-md-12 col-md-offset-2">
<h1 class="brand-heading fade-in">
<svg class="converse-svg-logo"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
viewBox="0 0 364 364">
<title>Converse</title>
<g class="cls-1" id="g904">
<g data-name="Layer 2">
<g data-name="Layer 7">
<path
class="cls-3"
d="M221.46,103.71c0,18.83-29.36,18.83-29.12,0C192.1,84.88,221.46,84.88,221.46,103.71Z" />
<path
class="cls-4"
d="M179.9,4.15A175.48,175.48,0,1,0,355.38,179.63,175.48,175.48,0,0,0,179.9,4.15Zm-40.79,264.5c-.23-17.82,27.58-17.82,27.58,0S138.88,286.48,139.11,268.65ZM218.6,168.24A79.65,79.65,0,0,1,205.15,174a12.76,12.76,0,0,0-6.29,4.65L167.54,222a1.36,1.36,0,0,1-2.46-.8v-35.8a2.58,2.58,0,0,0-3.06-2.53c-15.43,3-30.23,7.7-42.73,19.94-38.8,38-29.42,105.69,16.09,133.16a162.25,162.25,0,0,1-91.47-67.27C-3.86,182.26,34.5,47.25,138.37,25.66c46.89-9.75,118.25,5.16,123.73,62.83C265.15,120.64,246.56,152.89,218.6,168.24Z" />
</g>
</g>
</g>
</svg>
<span class="brand-heading__text">
<span>converse<span class="subdued">.js</span></span>
<p class="byline">messaging freedom</p>
</span>
</h1>
<h2 id="project_tagline">Tests</h2>
</div>
</div>
<div class="row jasmine-output-container"></div>
</section>
</body>
<script>
jasmine.DEFAULT_TIMEOUT_INTERVAL = 7000;
const env = jasmine.getEnv();
const queryString = new jasmine.QueryString({
getWindowLocation: () => window.location
});
env.clearReporters();
const htmlReporter = new jasmine.HtmlReporter({
env,
onRaiseExceptionsClick: () => { queryString.navigateWithNewParam("catch", !env.catchingExceptions()); },
onThrowExpectationsClick: () => { queryString.navigateWithNewParam("throwFailures", !env.throwingExpectationFailures()); },
onRandomClick: () => { queryString.navigateWithNewParam("random", !env.randomTests()); },
addToExistingQueryString: function(key, value) { return queryString.fullStringWithNewParam(key, value); },
getContainer: () => document.querySelector('.jasmine-output-container'),
createElement: function () { return document.createElement.apply(document, arguments); },
createTextNode: function () { return document.createTextNode.apply(document, arguments); },
timer: new jasmine.Timer(),
filterSpecs: !!queryString.getParam("spec")
});
//The `jsApiReporter` also receives spec results, and is used by any environment that needs to extract the results from JavaScript.
const jasmineInterface = jasmineRequire.interface(jasmine, env);
env.addReporter(jasmineInterface.jsApiReporter);
env.addReporter(htmlReporter);
env.addReporter(new ConsoleReporter());
converse.load();
</script>
</html>

View File

@ -1,142 +0,0 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title>Converse Tests</title>
<meta name="description" content="Converse XMPP Chat" />
<link rel="shortcut icon" type="image/png" href="../node_modules/jasmine-core/images/jasmine_favicon.png">
<link rel="stylesheet" type="text/css" media="screen" href="../node_modules/jasmine-core/lib/jasmine-core/jasmine.css">
<link type="text/css" rel="stylesheet" media="screen" href="../dist/converse.css" />
<script src="../dist/converse.js"></script>
<link type="text/css" rel="stylesheet" media="screen" href="../dist/website.css" />
<script src="../node_modules/jasmine-core/lib/jasmine-core/jasmine.js"></script>
<script src="../node_modules/jasmine-core/lib/jasmine-core/jasmine-html.js"></script>
<script src="../node_modules/jasmine-core/lib/jasmine-core/boot.js"></script>
<script src="../node_modules/sinon/pkg/sinon.js"></script>
<script src="console-reporter.js"></script>
<script src="../tests/mock.js"></script>
<script src="../tests/utils.js"></script>
<script src="../spec/spoilers.js"></script>
<script src="../spec/roomslist.js"></script>
<script src="../spec/utils.js"></script>
<script src="../spec/converse.js"></script>
<script src="../spec/bookmarks.js"></script>
<script src="../spec/headline.js"></script>
<script src="../spec/disco.js"></script>
<script src="../spec/protocol.js"></script>
<script src="../spec/presence.js"></script>
<script src="../spec/eventemitter.js"></script>
<script src="../spec/smacks.js"></script>
<script src="../spec/ping.js"></script>
<script src="../spec/push.js"></script>
<script src="../spec/xmppstatus.js"></script>
<script src="../spec/mam.js"></script>
<script src="../spec/omemo.js"></script>
<script src="../spec/controlbox.js"></script>
<script src="../spec/roster.js"></script>
<script src="../spec/chatbox.js"></script>
<script src="../spec/user-details-modal.js"></script>
<script src="../spec/messages.js"></script>
<script src="../spec/muc_messages.js"></script>
<script src="../spec/retractions.js"></script>
<script src="../spec/muc.js"></script>
<script src="../spec/modtools.js"></script>
<script src="../spec/room_registration.js"></script>
<script src="../spec/autocomplete.js"></script>
<script src="../spec/minchats.js"></script>
<script src="../spec/notification.js"></script>
<script src="../spec/login.js"></script>
<script src="../spec/register.js"></script>
<script src="../spec/hats.js"></script>
<script src="../spec/http-file-upload.js"></script>
<script src="../spec/emojis.js"></script>
<script src="../spec/xss.js"></script>
<style>
.tests-brand-heading {
margin-top: 1em;
font-size: 200%;
}
.jasmine_html-reporter {
text-align: left;
width: 100vw;
background-color: rgba(255, 255, 255, .5);
}
.intro {
background: unset;
background-color: #397491;
}
</style>
</head>
<body id="page-top" data-spy="scroll" class="converse-website">
<section class="section-wrapper">
<section id="intro" class="intro" class="container">
<div class="row">
<div class="col-md-12 col-md-offset-2">
<h1 class="brand-heading fade-in">
<svg class="converse-svg-logo"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
viewBox="0 0 364 364">
<title>Converse</title>
<g class="cls-1" id="g904">
<g data-name="Layer 2">
<g data-name="Layer 7">
<path
class="cls-3"
d="M221.46,103.71c0,18.83-29.36,18.83-29.12,0C192.1,84.88,221.46,84.88,221.46,103.71Z" />
<path
class="cls-4"
d="M179.9,4.15A175.48,175.48,0,1,0,355.38,179.63,175.48,175.48,0,0,0,179.9,4.15Zm-40.79,264.5c-.23-17.82,27.58-17.82,27.58,0S138.88,286.48,139.11,268.65ZM218.6,168.24A79.65,79.65,0,0,1,205.15,174a12.76,12.76,0,0,0-6.29,4.65L167.54,222a1.36,1.36,0,0,1-2.46-.8v-35.8a2.58,2.58,0,0,0-3.06-2.53c-15.43,3-30.23,7.7-42.73,19.94-38.8,38-29.42,105.69,16.09,133.16a162.25,162.25,0,0,1-91.47-67.27C-3.86,182.26,34.5,47.25,138.37,25.66c46.89-9.75,118.25,5.16,123.73,62.83C265.15,120.64,246.56,152.89,218.6,168.24Z" />
</g>
</g>
</g>
</svg>
<span class="brand-heading__text">
<span>converse<span class="subdued">.js</span></span>
<p class="byline">messaging freedom</p>
</span>
</h1>
<h2 id="project_tagline">Tests</h2>
</div>
</div>
<div class="row jasmine-output-container"></div>
</section>
</body>
<script>
jasmine.DEFAULT_TIMEOUT_INTERVAL = 7000;
const env = jasmine.getEnv();
const queryString = new jasmine.QueryString({
getWindowLocation: () => window.location
});
env.clearReporters();
const htmlReporter = new jasmine.HtmlReporter({
env,
onRaiseExceptionsClick: () => { queryString.navigateWithNewParam("catch", !env.catchingExceptions()); },
onThrowExpectationsClick: () => { queryString.navigateWithNewParam("throwFailures", !env.throwingExpectationFailures()); },
onRandomClick: () => { queryString.navigateWithNewParam("random", !env.randomTests()); },
addToExistingQueryString: function(key, value) { return queryString.fullStringWithNewParam(key, value); },
getContainer: () => document.querySelector('.jasmine-output-container'),
createElement: function () { return document.createElement.apply(document, arguments); },
createTextNode: function () { return document.createTextNode.apply(document, arguments); },
timer: new jasmine.Timer(),
filterSpecs: !!queryString.getParam("spec")
});
//The `jsApiReporter` also receives spec results, and is used by any environment that needs to extract the results from JavaScript.
const jasmineInterface = jasmineRequire.interface(jasmine, env);
env.addReporter(jasmineInterface.jsApiReporter);
env.addReporter(htmlReporter);
env.addReporter(new ConsoleReporter());
converse.load();
</script>
</html>

View File

@ -2,6 +2,8 @@ const mock = {};
window.mock = mock;
let _converse, initConverse;
const converseLoaded = new Promise(resolve => window.addEventListener('converse-loaded', resolve));
mock.initConverse = function (promise_names=[], settings=null, func) {
if (typeof promise_names === "function") {
func = promise_names;
@ -19,6 +21,7 @@ mock.initConverse = function (promise_names=[], settings=null, func) {
}
document.title = "Converse Tests";
await converseLoaded;
await initConverse(settings);
await Promise.all((promise_names || []).map(_converse.api.waitUntil));
try {
@ -32,12 +35,432 @@ mock.initConverse = function (promise_names=[], settings=null, func) {
};
window.addEventListener('converse-loaded', () => {
const _ = converse.env._;
const u = converse.env.utils;
const Promise = converse.env.Promise;
const Strophe = converse.env.Strophe;
const dayjs = converse.env.dayjs;
const $iq = converse.env.$iq;
const { _, u, sizzle, Strophe, dayjs, $iq, $msg, $pres } = converse.env;
mock.waitUntilDiscoConfirmed = async function (_converse, entity_jid, identities, features=[], items=[], type='info') {
const iq = await u.waitUntil(() => {
return _.filter(
_converse.connection.IQ_stanzas,
(iq) => sizzle(`iq[to="${entity_jid}"] query[xmlns="http://jabber.org/protocol/disco#${type}"]`, iq).length
).pop();
}, 300);
const stanza = $iq({
'type': 'result',
'from': entity_jid,
'to': 'romeo@montague.lit/orchard',
'id': iq.getAttribute('id'),
}).c('query', {'xmlns': 'http://jabber.org/protocol/disco#'+type});
_.forEach(identities, function (identity) {
stanza.c('identity', {'category': identity.category, 'type': identity.type}).up()
});
_.forEach(features, function (feature) {
stanza.c('feature', {'var': feature}).up();
});
_.forEach(items, function (item) {
stanza.c('item', {'jid': item}).up();
});
_converse.connection._dataRecv(mock.createRequest(stanza));
}
mock.createRequest = function (iq) {
iq = typeof iq.tree == "function" ? iq.tree() : iq;
var req = new Strophe.Request(iq, function() {});
req.getResponse = function () {
var env = new Strophe.Builder('env', {type: 'mock'}).tree();
env.appendChild(iq);
return env;
};
return req;
};
mock.closeAllChatBoxes = function (_converse) {
return Promise.all(_converse.chatboxviews.map(view => view.close()));
};
mock.openControlBox = async function (_converse) {
const model = await _converse.api.controlbox.open();
await u.waitUntil(() => model.get('connected'));
var toggle = document.querySelector(".toggle-controlbox");
if (!u.isVisible(document.querySelector("#controlbox"))) {
if (!u.isVisible(toggle)) {
u.removeClass('hidden', toggle);
}
toggle.click();
}
return this;
};
mock.closeControlBox = function () {
const controlbox = document.querySelector("#controlbox");
if (u.isVisible(controlbox)) {
const button = controlbox.querySelector(".close-chatbox-button");
if (!_.isNull(button)) {
button.click();
}
}
return this;
};
mock.waitUntilBookmarksReturned = async function (_converse, bookmarks=[]) {
await mock.waitUntilDiscoConfirmed(
_converse, _converse.bare_jid,
[{'category': 'pubsub', 'type': 'pep'}],
['http://jabber.org/protocol/pubsub#publish-options']
);
const IQ_stanzas = _converse.connection.IQ_stanzas;
const sent_stanza = await u.waitUntil(
() => IQ_stanzas.filter(s => sizzle('items[node="storage:bookmarks"]', s).length).pop()
);
const stanza = $iq({
'to': _converse.connection.jid,
'type':'result',
'id':sent_stanza.getAttribute('id')
}).c('pubsub', {'xmlns': Strophe.NS.PUBSUB})
.c('items', {'node': 'storage:bookmarks'})
.c('item', {'id': 'current'})
.c('storage', {'xmlns': 'storage:bookmarks'});
bookmarks.forEach(bookmark => {
stanza.c('conference', {
'name': bookmark.name,
'autojoin': bookmark.autojoin,
'jid': bookmark.jid
}).c('nick').t(bookmark.nick).up().up()
});
_converse.connection._dataRecv(mock.createRequest(stanza));
await _converse.api.waitUntil('bookmarksInitialized');
};
mock.openChatBoxes = function (converse, amount) {
const views = [];
for (let i=0; i<amount; i++) {
const jid = mock.cur_names[i].replace(/ /g,'.').toLowerCase() + '@montague.lit';
views.push(converse.roster.get(jid).trigger("open"));
}
return views;
};
mock.openChatBoxFor = async function (_converse, jid) {
await _converse.api.waitUntil('rosterContactsFetched');
_converse.roster.get(jid).trigger("open");
return u.waitUntil(() => _converse.chatboxviews.get(jid), 1000);
};
mock.openChatRoomViaModal = async function (_converse, jid, nick='') {
// Opens a new chatroom
const model = await _converse.api.controlbox.open('controlbox');
await u.waitUntil(() => model.get('connected'));
await mock.openControlBox(_converse);
const view = await _converse.chatboxviews.get('controlbox');
const roomspanel = view.roomspanel;
roomspanel.el.querySelector('.show-add-muc-modal').click();
mock.closeControlBox(_converse);
const modal = roomspanel.add_room_modal;
await u.waitUntil(() => u.isVisible(modal.el), 1500)
modal.el.querySelector('input[name="chatroom"]').value = jid;
if (nick) {
modal.el.querySelector('input[name="nickname"]').value = nick;
}
modal.el.querySelector('form input[type="submit"]').click();
await u.waitUntil(() => _converse.chatboxviews.get(jid), 1000);
return _converse.chatboxviews.get(jid);
};
mock.openChatRoom = function (_converse, room, server) {
return _converse.api.rooms.open(`${room}@${server}`);
};
mock.getRoomFeatures = async function (_converse, muc_jid, features=[]) {
const room = Strophe.getNodeFromJid(muc_jid);
muc_jid = muc_jid.toLowerCase();
const stanzas = _converse.connection.IQ_stanzas;
const stanza = await u.waitUntil(() => stanzas.filter(
iq => iq.querySelector(
`iq[to="${muc_jid}"] query[xmlns="http://jabber.org/protocol/disco#info"]`
)).pop()
);
const features_stanza = $iq({
'from': muc_jid,
'id': stanza.getAttribute('id'),
'to': 'romeo@montague.lit/desktop',
'type': 'result'
}).c('query', { 'xmlns': 'http://jabber.org/protocol/disco#info'})
.c('identity', {
'category': 'conference',
'name': room[0].toUpperCase() + room.slice(1),
'type': 'text'
}).up();
features = features.length ? features : mock.default_muc_features;
features.forEach(f => features_stanza.c('feature', {'var': f}).up());
features_stanza.c('x', { 'xmlns':'jabber:x:data', 'type':'result'})
.c('field', {'var':'FORM_TYPE', 'type':'hidden'})
.c('value').t('http://jabber.org/protocol/muc#roominfo').up().up()
.c('field', {'type':'text-single', 'var':'muc#roominfo_description', 'label':'Description'})
.c('value').t('This is the description').up().up()
.c('field', {'type':'text-single', 'var':'muc#roominfo_occupants', 'label':'Number of occupants'})
.c('value').t(0);
_converse.connection._dataRecv(mock.createRequest(features_stanza));
};
mock.waitForReservedNick = async function (_converse, muc_jid, nick) {
const stanzas = _converse.connection.IQ_stanzas;
const selector = `iq[to="${muc_jid.toLowerCase()}"] query[node="x-roomuser-item"]`;
const iq = await u.waitUntil(() => stanzas.filter(s => sizzle(selector, s).length).pop());
// We remove the stanza, otherwise we might get stale stanzas returned in our filter above.
stanzas.splice(stanzas.indexOf(iq), 1)
// The XMPP server returns the reserved nick for this user.
const IQ_id = iq.getAttribute('id');
const stanza = $iq({
'type': 'result',
'id': IQ_id,
'from': muc_jid,
'to': _converse.connection.jid
}).c('query', {'xmlns': 'http://jabber.org/protocol/disco#info', 'node': 'x-roomuser-item'});
if (nick) {
stanza.c('identity', {'category': 'conference', 'name': nick, 'type': 'text'});
}
_converse.connection._dataRecv(mock.createRequest(stanza));
if (nick) {
return u.waitUntil(() => nick);
}
};
mock.returnMemberLists = async function (_converse, muc_jid, members=[], affiliations=['member', 'owner', 'admin']) {
if (affiliations.length === 0) {
return;
}
const stanzas = _converse.connection.IQ_stanzas;
if (affiliations.includes('member')) {
const member_IQ = await u.waitUntil(() => _.filter(
stanzas,
s => sizzle(`iq[to="${muc_jid}"] query[xmlns="${Strophe.NS.MUC_ADMIN}"] item[affiliation="member"]`, s).length
).pop());
const member_list_stanza = $iq({
'from': 'coven@chat.shakespeare.lit',
'id': member_IQ.getAttribute('id'),
'to': 'romeo@montague.lit/orchard',
'type': 'result'
}).c('query', {'xmlns': Strophe.NS.MUC_ADMIN});
members.filter(m => m.affiliation === 'member').forEach(m => {
member_list_stanza.c('item', {
'affiliation': m.affiliation,
'jid': m.jid,
'nick': m.nick
});
});
_converse.connection._dataRecv(mock.createRequest(member_list_stanza));
}
if (affiliations.includes('admin')) {
const admin_IQ = await u.waitUntil(() => _.filter(
stanzas,
s => sizzle(`iq[to="${muc_jid}"] query[xmlns="${Strophe.NS.MUC_ADMIN}"] item[affiliation="admin"]`, s).length
).pop());
const admin_list_stanza = $iq({
'from': 'coven@chat.shakespeare.lit',
'id': admin_IQ.getAttribute('id'),
'to': 'romeo@montague.lit/orchard',
'type': 'result'
}).c('query', {'xmlns': Strophe.NS.MUC_ADMIN});
members.filter(m => m.affiliation === 'admin').forEach(m => {
admin_list_stanza.c('item', {
'affiliation': m.affiliation,
'jid': m.jid,
'nick': m.nick
});
});
_converse.connection._dataRecv(mock.createRequest(admin_list_stanza));
}
if (affiliations.includes('owner')) {
const owner_IQ = await u.waitUntil(() => _.filter(
stanzas,
s => sizzle(`iq[to="${muc_jid}"] query[xmlns="${Strophe.NS.MUC_ADMIN}"] item[affiliation="owner"]`, s).length
).pop());
const owner_list_stanza = $iq({
'from': 'coven@chat.shakespeare.lit',
'id': owner_IQ.getAttribute('id'),
'to': 'romeo@montague.lit/orchard',
'type': 'result'
}).c('query', {'xmlns': Strophe.NS.MUC_ADMIN});
members.filter(m => m.affiliation === 'owner').forEach(m => {
owner_list_stanza.c('item', {
'affiliation': m.affiliation,
'jid': m.jid,
'nick': m.nick
});
});
_converse.connection._dataRecv(mock.createRequest(owner_list_stanza));
}
return new Promise(resolve => _converse.api.listen.on('membersFetched', resolve));
};
mock.receiveOwnMUCPresence = async function (_converse, muc_jid, nick) {
const sent_stanzas = _converse.connection.sent_stanzas;
await u.waitUntil(() => sent_stanzas.filter(iq => sizzle('presence history', iq).length).pop());
const presence = $pres({
to: _converse.connection.jid,
from: `${muc_jid}/${nick}`,
id: u.getUniqueId()
}).c('x').attrs({xmlns:'http://jabber.org/protocol/muc#user'})
.c('item').attrs({
affiliation: 'owner',
jid: _converse.bare_jid,
role: 'moderator'
}).up()
.c('status').attrs({code:'110'});
_converse.connection._dataRecv(mock.createRequest(presence));
};
mock.openAndEnterChatRoom = async function (_converse, muc_jid, nick, features=[], members=[]) {
muc_jid = muc_jid.toLowerCase();
const room_creation_promise = _converse.api.rooms.open(muc_jid);
await mock.getRoomFeatures(_converse, muc_jid, features);
await mock.waitForReservedNick(_converse, muc_jid, nick);
// The user has just entered the room (because join was called)
// and receives their own presence from the server.
// See example 24: https://xmpp.org/extensions/xep-0045.html#enter-pres
await mock.receiveOwnMUCPresence(_converse, muc_jid, nick);
await room_creation_promise;
const view = _converse.chatboxviews.get(muc_jid);
await u.waitUntil(() => (view.model.session.get('connection_status') === converse.ROOMSTATUS.ENTERED));
const affs = _converse.muc_fetch_members;
const all_affiliations = Array.isArray(affs) ? affs : (affs ? ['member', 'admin', 'owner'] : []);
await mock.returnMemberLists(_converse, muc_jid, members, all_affiliations);
await view.model.messages.fetched;
};
mock.clearChatBoxMessages = function (converse, jid) {
const view = converse.chatboxviews.get(jid);
view.msgs_container.innerHTML = '';
return view.model.messages.clearStore();
};
mock.createContact = async function (_converse, name, ask, requesting, subscription) {
const jid = name.replace(/ /g,'.').toLowerCase() + '@montague.lit';
if (_converse.roster.get(jid)) {
return Promise.resolve();
}
const contact = await new Promise((success, error) => {
_converse.roster.create({
'ask': ask,
'fullname': name,
'jid': jid,
'requesting': requesting,
'subscription': subscription
}, {success, error});
});
return contact;
};
mock.createContacts = async function (_converse, type, length) {
/* Create current (as opposed to requesting or pending) contacts
* for the user's roster.
*
* These contacts are not grouped. See below.
*/
await _converse.api.waitUntil('rosterContactsFetched');
let names, subscription, requesting, ask;
if (type === 'requesting') {
names = mock.req_names;
subscription = 'none';
requesting = true;
ask = null;
} else if (type === 'pending') {
names = mock.pend_names;
subscription = 'none';
requesting = false;
ask = 'subscribe';
} else if (type === 'current') {
names = mock.cur_names;
subscription = 'both';
requesting = false;
ask = null;
} else if (type === 'all') {
await this.createContacts(_converse, 'current');
await this.createContacts(_converse, 'requesting')
await this.createContacts(_converse, 'pending');
return this;
} else {
throw Error("Need to specify the type of contact to create");
}
const promises = names.slice(0, length).map(n => this.createContact(_converse, n, ask, requesting, subscription));
await Promise.all(promises);
};
mock.waitForRoster = async function (_converse, type='current', length=-1, include_nick=true, grouped=true) {
const s = `iq[type="get"] query[xmlns="${Strophe.NS.ROSTER}"]`;
const iq = await u.waitUntil(() => _converse.connection.IQ_stanzas.filter(iq => sizzle(s, iq).length).pop());
const result = $iq({
'to': _converse.connection.jid,
'type': 'result',
'id': iq.getAttribute('id')
}).c('query', {
'xmlns': 'jabber:iq:roster'
});
if (type === 'pending' || type === 'all') {
const pend_names = (length > -1) ? mock.pend_names.slice(0, length) : mock.pend_names;
pend_names.map(name =>
result.c('item', {
jid: name.replace(/ /g,'.').toLowerCase() + '@montague.lit',
name: include_nick ? name : undefined,
subscription: 'none',
ask: 'subscribe'
}).up()
);
}
if (type === 'current' || type === 'all') {
const cur_names = Object.keys(mock.current_contacts_map);
const names = (length > -1) ? cur_names.slice(0, length) : cur_names;
names.forEach(name => {
result.c('item', {
jid: name.replace(/ /g,'.').toLowerCase() + '@montague.lit',
name: include_nick ? name : undefined,
subscription: 'both',
ask: null
});
if (grouped) {
mock.current_contacts_map[name].forEach(g => result.c('group').t(g).up());
}
result.up();
});
}
_converse.connection._dataRecv(mock.createRequest(result));
await _converse.api.waitUntil('rosterContactsFetched');
};
mock.createChatMessage = function (_converse, sender_jid, message) {
return $msg({
from: sender_jid,
to: _converse.connection.jid,
type: 'chat',
id: (new Date()).getTime()
})
.c('body').t(message).up()
.c('active', {'xmlns': Strophe.NS.CHATSTATES}).tree();
}
mock.sendMessage = function (view, message) {
const promise = new Promise(resolve => view.once('messageInserted', resolve));
view.el.querySelector('.chat-textarea').value = message;
view.onKeyDown({
target: view.el.querySelector('textarea.chat-textarea'),
preventDefault: _.noop,
keyCode: 13
});
return promise;
};
window.libsignal = {
'SignalProtocolAddress': function (name, device_id) {
@ -335,3 +758,5 @@ window.addEventListener('converse-loaded', () => {
return _converse;
}
});
converse.load();

View File

@ -1,34 +0,0 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title>Converse.js Tests</title>
<meta name="description" content="Converse.js: A chat client for your website" />
<link rel="shortcut icon" type="image/png" href="../node_modules/jasmine-core/images/jasmine_favicon.png">
<link rel="stylesheet" type="text/css" media="screen" href="../node_modules/jasmine-core/lib/jasmine-core/jasmine.css">
<link rel="stylesheet" type="text/css" media="screen" href="../css/jasmine.css">
<link type="text/css" rel="stylesheet" media="screen" href="../css/website.css" />
<link type="text/css" rel="stylesheet" media="screen" href="../css/converse.css" />
<script src="../src/config.js"></script>
<script data-main="runner-transpiled" src="../node_modules/requirejs/require.js"></script>
<style>
.tests-brand-heading {
margin-top: 1em;
font-size: 200%;
}
</style>
</head>
<body>
<div id="header_wrap" class="outer">
<header class="inner">
<h1 class="brand-heading tests-brand-heading">
<i class="icon-conversejs"></i> Converse.js</h1>
<h2 id="project_tagline">Tests</h2>
</header>
</div>
</body>
</html>

View File

@ -1,437 +0,0 @@
window.addEventListener('converse-loaded', () => {
const _ = converse.env._;
const $msg = converse.env.$msg;
const $pres = converse.env.$pres;
const $iq = converse.env.$iq;
const Strophe = converse.env.Strophe;
const sizzle = converse.env.sizzle;
const u = converse.env.utils;
const mock = window.mock;
const utils = {};
window.test_utils = utils;
utils.waitUntilDiscoConfirmed = async function (_converse, entity_jid, identities, features=[], items=[], type='info') {
const iq = await u.waitUntil(() => {
return _.filter(
_converse.connection.IQ_stanzas,
(iq) => sizzle(`iq[to="${entity_jid}"] query[xmlns="http://jabber.org/protocol/disco#${type}"]`, iq).length
).pop();
}, 300);
const stanza = $iq({
'type': 'result',
'from': entity_jid,
'to': 'romeo@montague.lit/orchard',
'id': iq.getAttribute('id'),
}).c('query', {'xmlns': 'http://jabber.org/protocol/disco#'+type});
_.forEach(identities, function (identity) {
stanza.c('identity', {'category': identity.category, 'type': identity.type}).up()
});
_.forEach(features, function (feature) {
stanza.c('feature', {'var': feature}).up();
});
_.forEach(items, function (item) {
stanza.c('item', {'jid': item}).up();
});
_converse.connection._dataRecv(utils.createRequest(stanza));
}
utils.createRequest = function (iq) {
iq = typeof iq.tree == "function" ? iq.tree() : iq;
var req = new Strophe.Request(iq, function() {});
req.getResponse = function () {
var env = new Strophe.Builder('env', {type: 'mock'}).tree();
env.appendChild(iq);
return env;
};
return req;
};
utils.closeAllChatBoxes = function (_converse) {
return Promise.all(_converse.chatboxviews.map(view => view.close()));
};
utils.openControlBox = async function (_converse) {
const model = await _converse.api.controlbox.open();
await u.waitUntil(() => model.get('connected'));
var toggle = document.querySelector(".toggle-controlbox");
if (!u.isVisible(document.querySelector("#controlbox"))) {
if (!u.isVisible(toggle)) {
u.removeClass('hidden', toggle);
}
toggle.click();
}
return this;
};
utils.closeControlBox = function () {
const controlbox = document.querySelector("#controlbox");
if (u.isVisible(controlbox)) {
const button = controlbox.querySelector(".close-chatbox-button");
if (!_.isNull(button)) {
button.click();
}
}
return this;
};
utils.waitUntilBookmarksReturned = async function (_converse, bookmarks=[]) {
await utils.waitUntilDiscoConfirmed(
_converse, _converse.bare_jid,
[{'category': 'pubsub', 'type': 'pep'}],
['http://jabber.org/protocol/pubsub#publish-options']
);
const IQ_stanzas = _converse.connection.IQ_stanzas;
const sent_stanza = await u.waitUntil(
() => IQ_stanzas.filter(s => sizzle('items[node="storage:bookmarks"]', s).length).pop()
);
const stanza = $iq({
'to': _converse.connection.jid,
'type':'result',
'id':sent_stanza.getAttribute('id')
}).c('pubsub', {'xmlns': Strophe.NS.PUBSUB})
.c('items', {'node': 'storage:bookmarks'})
.c('item', {'id': 'current'})
.c('storage', {'xmlns': 'storage:bookmarks'});
bookmarks.forEach(bookmark => {
stanza.c('conference', {
'name': bookmark.name,
'autojoin': bookmark.autojoin,
'jid': bookmark.jid
}).c('nick').t(bookmark.nick).up().up()
});
_converse.connection._dataRecv(utils.createRequest(stanza));
await _converse.api.waitUntil('bookmarksInitialized');
};
utils.openChatBoxes = function (converse, amount) {
const views = [];
for (let i=0; i<amount; i++) {
const jid = mock.cur_names[i].replace(/ /g,'.').toLowerCase() + '@montague.lit';
views.push(converse.roster.get(jid).trigger("open"));
}
return views;
};
utils.openChatBoxFor = async function (_converse, jid) {
await _converse.api.waitUntil('rosterContactsFetched');
_converse.roster.get(jid).trigger("open");
return u.waitUntil(() => _converse.chatboxviews.get(jid), 1000);
};
utils.openChatRoomViaModal = async function (_converse, jid, nick='') {
// Opens a new chatroom
const model = await _converse.api.controlbox.open('controlbox');
await u.waitUntil(() => model.get('connected'));
await utils.openControlBox(_converse);
const view = await _converse.chatboxviews.get('controlbox');
const roomspanel = view.roomspanel;
roomspanel.el.querySelector('.show-add-muc-modal').click();
utils.closeControlBox(_converse);
const modal = roomspanel.add_room_modal;
await u.waitUntil(() => u.isVisible(modal.el), 1500)
modal.el.querySelector('input[name="chatroom"]').value = jid;
if (nick) {
modal.el.querySelector('input[name="nickname"]').value = nick;
}
modal.el.querySelector('form input[type="submit"]').click();
await u.waitUntil(() => _converse.chatboxviews.get(jid), 1000);
return _converse.chatboxviews.get(jid);
};
utils.openChatRoom = function (_converse, room, server) {
return _converse.api.rooms.open(`${room}@${server}`);
};
utils.getRoomFeatures = async function (_converse, muc_jid, features=[]) {
const room = Strophe.getNodeFromJid(muc_jid);
muc_jid = muc_jid.toLowerCase();
const stanzas = _converse.connection.IQ_stanzas;
const stanza = await u.waitUntil(() => stanzas.filter(
iq => iq.querySelector(
`iq[to="${muc_jid}"] query[xmlns="http://jabber.org/protocol/disco#info"]`
)).pop()
);
const features_stanza = $iq({
'from': muc_jid,
'id': stanza.getAttribute('id'),
'to': 'romeo@montague.lit/desktop',
'type': 'result'
}).c('query', { 'xmlns': 'http://jabber.org/protocol/disco#info'})
.c('identity', {
'category': 'conference',
'name': room[0].toUpperCase() + room.slice(1),
'type': 'text'
}).up();
features = features.length ? features : mock.default_muc_features;
features.forEach(f => features_stanza.c('feature', {'var': f}).up());
features_stanza.c('x', { 'xmlns':'jabber:x:data', 'type':'result'})
.c('field', {'var':'FORM_TYPE', 'type':'hidden'})
.c('value').t('http://jabber.org/protocol/muc#roominfo').up().up()
.c('field', {'type':'text-single', 'var':'muc#roominfo_description', 'label':'Description'})
.c('value').t('This is the description').up().up()
.c('field', {'type':'text-single', 'var':'muc#roominfo_occupants', 'label':'Number of occupants'})
.c('value').t(0);
_converse.connection._dataRecv(utils.createRequest(features_stanza));
};
utils.waitForReservedNick = async function (_converse, muc_jid, nick) {
const stanzas = _converse.connection.IQ_stanzas;
const selector = `iq[to="${muc_jid.toLowerCase()}"] query[node="x-roomuser-item"]`;
const iq = await u.waitUntil(() => stanzas.filter(s => sizzle(selector, s).length).pop());
// We remove the stanza, otherwise we might get stale stanzas returned in our filter above.
stanzas.splice(stanzas.indexOf(iq), 1)
// The XMPP server returns the reserved nick for this user.
const IQ_id = iq.getAttribute('id');
const stanza = $iq({
'type': 'result',
'id': IQ_id,
'from': muc_jid,
'to': _converse.connection.jid
}).c('query', {'xmlns': 'http://jabber.org/protocol/disco#info', 'node': 'x-roomuser-item'});
if (nick) {
stanza.c('identity', {'category': 'conference', 'name': nick, 'type': 'text'});
}
_converse.connection._dataRecv(utils.createRequest(stanza));
if (nick) {
return u.waitUntil(() => nick);
}
};
utils.returnMemberLists = async function (_converse, muc_jid, members=[], affiliations=['member', 'owner', 'admin']) {
if (affiliations.length === 0) {
return;
}
const stanzas = _converse.connection.IQ_stanzas;
if (affiliations.includes('member')) {
const member_IQ = await u.waitUntil(() => _.filter(
stanzas,
s => sizzle(`iq[to="${muc_jid}"] query[xmlns="${Strophe.NS.MUC_ADMIN}"] item[affiliation="member"]`, s).length
).pop());
const member_list_stanza = $iq({
'from': 'coven@chat.shakespeare.lit',
'id': member_IQ.getAttribute('id'),
'to': 'romeo@montague.lit/orchard',
'type': 'result'
}).c('query', {'xmlns': Strophe.NS.MUC_ADMIN});
members.filter(m => m.affiliation === 'member').forEach(m => {
member_list_stanza.c('item', {
'affiliation': m.affiliation,
'jid': m.jid,
'nick': m.nick
});
});
_converse.connection._dataRecv(utils.createRequest(member_list_stanza));
}
if (affiliations.includes('admin')) {
const admin_IQ = await u.waitUntil(() => _.filter(
stanzas,
s => sizzle(`iq[to="${muc_jid}"] query[xmlns="${Strophe.NS.MUC_ADMIN}"] item[affiliation="admin"]`, s).length
).pop());
const admin_list_stanza = $iq({
'from': 'coven@chat.shakespeare.lit',
'id': admin_IQ.getAttribute('id'),
'to': 'romeo@montague.lit/orchard',
'type': 'result'
}).c('query', {'xmlns': Strophe.NS.MUC_ADMIN});
members.filter(m => m.affiliation === 'admin').forEach(m => {
admin_list_stanza.c('item', {
'affiliation': m.affiliation,
'jid': m.jid,
'nick': m.nick
});
});
_converse.connection._dataRecv(utils.createRequest(admin_list_stanza));
}
if (affiliations.includes('owner')) {
const owner_IQ = await u.waitUntil(() => _.filter(
stanzas,
s => sizzle(`iq[to="${muc_jid}"] query[xmlns="${Strophe.NS.MUC_ADMIN}"] item[affiliation="owner"]`, s).length
).pop());
const owner_list_stanza = $iq({
'from': 'coven@chat.shakespeare.lit',
'id': owner_IQ.getAttribute('id'),
'to': 'romeo@montague.lit/orchard',
'type': 'result'
}).c('query', {'xmlns': Strophe.NS.MUC_ADMIN});
members.filter(m => m.affiliation === 'owner').forEach(m => {
owner_list_stanza.c('item', {
'affiliation': m.affiliation,
'jid': m.jid,
'nick': m.nick
});
});
_converse.connection._dataRecv(utils.createRequest(owner_list_stanza));
}
return new Promise(resolve => _converse.api.listen.on('membersFetched', resolve));
};
utils.receiveOwnMUCPresence = async function (_converse, muc_jid, nick) {
const sent_stanzas = _converse.connection.sent_stanzas;
await u.waitUntil(() => sent_stanzas.filter(iq => sizzle('presence history', iq).length).pop());
const presence = $pres({
to: _converse.connection.jid,
from: `${muc_jid}/${nick}`,
id: u.getUniqueId()
}).c('x').attrs({xmlns:'http://jabber.org/protocol/muc#user'})
.c('item').attrs({
affiliation: 'owner',
jid: _converse.bare_jid,
role: 'moderator'
}).up()
.c('status').attrs({code:'110'});
_converse.connection._dataRecv(utils.createRequest(presence));
};
utils.openAndEnterChatRoom = async function (_converse, muc_jid, nick, features=[], members=[]) {
muc_jid = muc_jid.toLowerCase();
const room_creation_promise = _converse.api.rooms.open(muc_jid);
await utils.getRoomFeatures(_converse, muc_jid, features);
await utils.waitForReservedNick(_converse, muc_jid, nick);
// The user has just entered the room (because join was called)
// and receives their own presence from the server.
// See example 24: https://xmpp.org/extensions/xep-0045.html#enter-pres
await utils.receiveOwnMUCPresence(_converse, muc_jid, nick);
await room_creation_promise;
const view = _converse.chatboxviews.get(muc_jid);
await u.waitUntil(() => (view.model.session.get('connection_status') === converse.ROOMSTATUS.ENTERED));
const affs = _converse.muc_fetch_members;
const all_affiliations = Array.isArray(affs) ? affs : (affs ? ['member', 'admin', 'owner'] : []);
await utils.returnMemberLists(_converse, muc_jid, members, all_affiliations);
await view.model.messages.fetched;
};
utils.clearChatBoxMessages = function (converse, jid) {
const view = converse.chatboxviews.get(jid);
view.msgs_container.innerHTML = '';
return view.model.messages.clearStore();
};
utils.createContact = async function (_converse, name, ask, requesting, subscription) {
const jid = name.replace(/ /g,'.').toLowerCase() + '@montague.lit';
if (_converse.roster.get(jid)) {
return Promise.resolve();
}
const contact = await new Promise((success, error) => {
_converse.roster.create({
'ask': ask,
'fullname': name,
'jid': jid,
'requesting': requesting,
'subscription': subscription
}, {success, error});
});
return contact;
};
utils.createContacts = async function (_converse, type, length) {
/* Create current (as opposed to requesting or pending) contacts
* for the user's roster.
*
* These contacts are not grouped. See below.
*/
await _converse.api.waitUntil('rosterContactsFetched');
let names, subscription, requesting, ask;
if (type === 'requesting') {
names = mock.req_names;
subscription = 'none';
requesting = true;
ask = null;
} else if (type === 'pending') {
names = mock.pend_names;
subscription = 'none';
requesting = false;
ask = 'subscribe';
} else if (type === 'current') {
names = mock.cur_names;
subscription = 'both';
requesting = false;
ask = null;
} else if (type === 'all') {
await this.createContacts(_converse, 'current');
await this.createContacts(_converse, 'requesting')
await this.createContacts(_converse, 'pending');
return this;
} else {
throw Error("Need to specify the type of contact to create");
}
const promises = names.slice(0, length).map(n => this.createContact(_converse, n, ask, requesting, subscription));
await Promise.all(promises);
};
utils.waitForRoster = async function (_converse, type='current', length=-1, include_nick=true, grouped=true) {
const s = `iq[type="get"] query[xmlns="${Strophe.NS.ROSTER}"]`;
const iq = await u.waitUntil(() => _converse.connection.IQ_stanzas.filter(iq => sizzle(s, iq).length).pop());
const result = $iq({
'to': _converse.connection.jid,
'type': 'result',
'id': iq.getAttribute('id')
}).c('query', {
'xmlns': 'jabber:iq:roster'
});
if (type === 'pending' || type === 'all') {
const pend_names = (length > -1) ? mock.pend_names.slice(0, length) : mock.pend_names;
pend_names.map(name =>
result.c('item', {
jid: name.replace(/ /g,'.').toLowerCase() + '@montague.lit',
name: include_nick ? name : undefined,
subscription: 'none',
ask: 'subscribe'
}).up()
);
}
if (type === 'current' || type === 'all') {
const cur_names = Object.keys(mock.current_contacts_map);
const names = (length > -1) ? cur_names.slice(0, length) : cur_names;
names.forEach(name => {
result.c('item', {
jid: name.replace(/ /g,'.').toLowerCase() + '@montague.lit',
name: include_nick ? name : undefined,
subscription: 'both',
ask: null
});
if (grouped) {
mock.current_contacts_map[name].forEach(g => result.c('group').t(g).up());
}
result.up();
});
}
_converse.connection._dataRecv(utils.createRequest(result));
await _converse.api.waitUntil('rosterContactsFetched');
};
utils.createChatMessage = function (_converse, sender_jid, message) {
return $msg({
from: sender_jid,
to: _converse.connection.jid,
type: 'chat',
id: (new Date()).getTime()
})
.c('body').t(message).up()
.c('active', {'xmlns': Strophe.NS.CHATSTATES}).tree();
}
utils.sendMessage = function (view, message) {
const promise = new Promise(resolve => view.once('messageInserted', resolve));
view.el.querySelector('.chat-textarea').value = message;
view.onKeyDown({
target: view.el.querySelector('textarea.chat-textarea'),
preventDefault: _.noop,
keyCode: 13
});
return promise;
};
});