Use Karma as test runner
This commit is contained in:
parent
7e23adf26f
commit
4b270359f6
12
.travis.yml
12
.travis.yml
@ -1,4 +1,4 @@
|
|||||||
dist: xenial
|
dist: bionic
|
||||||
language: node_js
|
language: node_js
|
||||||
cache:
|
cache:
|
||||||
directories:
|
directories:
|
||||||
@ -6,7 +6,11 @@ cache:
|
|||||||
addons:
|
addons:
|
||||||
chrome: stable
|
chrome: stable
|
||||||
node_js:
|
node_js:
|
||||||
- "10"
|
- "14"
|
||||||
install: make node_modules
|
install: make node_modules
|
||||||
before_script: make serve_bg
|
services:
|
||||||
script: make check
|
- xvfb
|
||||||
|
before_script:
|
||||||
|
- make serve_bg
|
||||||
|
- export DISPLAY=:99.0
|
||||||
|
script: make check ARGS=--single-run
|
||||||
|
7
Makefile
7
Makefile
@ -2,6 +2,7 @@
|
|||||||
BABEL ?= node_modules/.bin/babel
|
BABEL ?= node_modules/.bin/babel
|
||||||
BOOTSTRAP = ./node_modules/
|
BOOTSTRAP = ./node_modules/
|
||||||
BUILDDIR = ./docs
|
BUILDDIR = ./docs
|
||||||
|
KARMA ?= ./node_modules/.bin/karma
|
||||||
CHROMIUM ?= ./node_modules/.bin/run-headless-chromium
|
CHROMIUM ?= ./node_modules/.bin/run-headless-chromium
|
||||||
CLEANCSS ?= ./node_modules/clean-css-cli/bin/cleancss --skip-rebase
|
CLEANCSS ?= ./node_modules/clean-css-cli/bin/cleancss --skip-rebase
|
||||||
ESLINT ?= ./node_modules/.bin/eslint
|
ESLINT ?= ./node_modules/.bin/eslint
|
||||||
@ -197,7 +198,11 @@ eslint: node_modules
|
|||||||
|
|
||||||
.PHONY: check
|
.PHONY: check
|
||||||
check: eslint dev
|
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
|
## Documentation
|
||||||
|
107
karma.conf.js
Normal file
107
karma.conf.js
Normal 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
|
||||||
|
})
|
||||||
|
}
|
905
package-lock.json
generated
905
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -84,8 +84,14 @@
|
|||||||
"http-server": "^0.12.1",
|
"http-server": "^0.12.1",
|
||||||
"imports-loader": "^0.8.0",
|
"imports-loader": "^0.8.0",
|
||||||
"install": "^0.13.0",
|
"install": "^0.13.0",
|
||||||
"jasmine-core": "2.99.1",
|
"jasmine": "^3.5.0",
|
||||||
"jsdoc": "^3.6.4",
|
"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",
|
"lerna": "^3.20.2",
|
||||||
"lit-html": "^1.2.1",
|
"lit-html": "^1.2.1",
|
||||||
"lodash-template-webpack-loader": "jcbrand/lodash-template-webpack-loader",
|
"lodash-template-webpack-loader": "jcbrand/lodash-template-webpack-loader",
|
||||||
|
@ -1,217 +1,215 @@
|
|||||||
window.addEventListener('converse-loaded', () => {
|
/*global mock */
|
||||||
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;
|
|
||||||
|
|
||||||
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;
|
||||||
|
|
||||||
it("shows all autocompletion options when the user presses @",
|
describe("The nickname autocomplete feature", function () {
|
||||||
mock.initConverse(
|
|
||||||
['rosterGroupsFetched', 'chatBoxesFetched'], {},
|
|
||||||
async function (done, _converse) {
|
|
||||||
|
|
||||||
await test_utils.openAndEnterChatRoom(_converse, 'lounge@montague.lit', 'tom');
|
it("shows all autocompletion options when the user presses @",
|
||||||
const view = _converse.chatboxviews.get('lounge@montague.lit');
|
mock.initConverse(
|
||||||
|
['rosterGroupsFetched', 'chatBoxesFetched'], {},
|
||||||
|
async function (done, _converse) {
|
||||||
|
|
||||||
// Nicknames from presences
|
await mock.openAndEnterChatRoom(_converse, 'lounge@montague.lit', 'tom');
|
||||||
['dick', 'harry'].forEach((nick) => {
|
const view = _converse.chatboxviews.get('lounge@montague.lit');
|
||||||
_converse.connection._dataRecv(test_utils.createRequest(
|
|
||||||
$pres({
|
// Nicknames from presences
|
||||||
'to': 'tom@montague.lit/resource',
|
['dick', 'harry'].forEach((nick) => {
|
||||||
'from': `lounge@montague.lit/${nick}`
|
_converse.connection._dataRecv(mock.createRequest(
|
||||||
})
|
$pres({
|
||||||
.c('x', {xmlns: Strophe.NS.MUC_USER})
|
'to': 'tom@montague.lit/resource',
|
||||||
.c('item', {
|
'from': `lounge@montague.lit/${nick}`
|
||||||
'affiliation': 'none',
|
})
|
||||||
'jid': `${nick}@montague.lit/resource`,
|
.c('x', {xmlns: Strophe.NS.MUC_USER})
|
||||||
'role': 'participant'
|
.c('item', {
|
||||||
})));
|
'affiliation': 'none',
|
||||||
|
'jid': `${nick}@montague.lit/resource`,
|
||||||
|
'role': 'participant'
|
||||||
|
})));
|
||||||
|
});
|
||||||
|
|
||||||
|
// Nicknames from messages
|
||||||
|
const msg = $msg({
|
||||||
|
from: 'lounge@montague.lit/jane',
|
||||||
|
id: u.getUniqueId(),
|
||||||
|
to: 'romeo@montague.lit',
|
||||||
|
type: 'groupchat'
|
||||||
|
}).c('body').t('Hello world').tree();
|
||||||
|
await view.model.queueMessage(msg);
|
||||||
|
|
||||||
|
// Test that pressing @ brings up all options
|
||||||
|
const textarea = view.el.querySelector('textarea.chat-textarea');
|
||||||
|
const at_event = {
|
||||||
|
'target': textarea,
|
||||||
|
'preventDefault': function preventDefault () {},
|
||||||
|
'stopPropagation': function stopPropagation () {},
|
||||||
|
'keyCode': 50,
|
||||||
|
'key': '@'
|
||||||
|
};
|
||||||
|
view.onKeyDown(at_event);
|
||||||
|
textarea.value = '@';
|
||||||
|
view.onKeyUp(at_event);
|
||||||
|
|
||||||
|
await u.waitUntil(() => view.el.querySelectorAll('.suggestion-box__results li').length === 4);
|
||||||
|
expect(view.el.querySelector('.suggestion-box__results li:first-child').textContent).toBe('dick');
|
||||||
|
expect(view.el.querySelector('.suggestion-box__results li:nth-child(2)').textContent).toBe('harry');
|
||||||
|
expect(view.el.querySelector('.suggestion-box__results li:nth-child(3)').textContent).toBe('jane');
|
||||||
|
expect(view.el.querySelector('.suggestion-box__results li:nth-child(4)').textContent).toBe('tom');
|
||||||
|
done();
|
||||||
|
}));
|
||||||
|
|
||||||
|
it("autocompletes when the user presses tab",
|
||||||
|
mock.initConverse(
|
||||||
|
['rosterGroupsFetched', 'chatBoxesFetched'], {},
|
||||||
|
async function (done, _converse) {
|
||||||
|
|
||||||
|
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({
|
||||||
|
'to': 'romeo@montague.lit/orchard',
|
||||||
|
'from': 'lounge@montague.lit/some1'
|
||||||
|
})
|
||||||
|
.c('x', {xmlns: Strophe.NS.MUC_USER})
|
||||||
|
.c('item', {
|
||||||
|
'affiliation': 'none',
|
||||||
|
'jid': 'some1@montague.lit/resource',
|
||||||
|
'role': 'participant'
|
||||||
});
|
});
|
||||||
|
_converse.connection._dataRecv(mock.createRequest(presence));
|
||||||
|
expect(view.model.occupants.length).toBe(2);
|
||||||
|
|
||||||
// Nicknames from messages
|
const textarea = view.el.querySelector('textarea.chat-textarea');
|
||||||
const msg = $msg({
|
textarea.value = "hello som";
|
||||||
from: 'lounge@montague.lit/jane',
|
|
||||||
id: u.getUniqueId(),
|
|
||||||
to: 'romeo@montague.lit',
|
|
||||||
type: 'groupchat'
|
|
||||||
}).c('body').t('Hello world').tree();
|
|
||||||
await view.model.queueMessage(msg);
|
|
||||||
|
|
||||||
// Test that pressing @ brings up all options
|
// Press tab
|
||||||
const textarea = view.el.querySelector('textarea.chat-textarea');
|
const tab_event = {
|
||||||
const at_event = {
|
'target': textarea,
|
||||||
'target': textarea,
|
'preventDefault': function preventDefault () {},
|
||||||
'preventDefault': function preventDefault () {},
|
'stopPropagation': function stopPropagation () {},
|
||||||
'stopPropagation': function stopPropagation () {},
|
'keyCode': 9,
|
||||||
'keyCode': 50,
|
'key': 'Tab'
|
||||||
'key': '@'
|
}
|
||||||
};
|
view.onKeyDown(tab_event);
|
||||||
view.onKeyDown(at_event);
|
view.onKeyUp(tab_event);
|
||||||
textarea.value = '@';
|
await u.waitUntil(() => view.el.querySelector('.suggestion-box__results').hidden === false);
|
||||||
view.onKeyUp(at_event);
|
expect(view.el.querySelectorAll('.suggestion-box__results li').length).toBe(1);
|
||||||
|
expect(view.el.querySelector('.suggestion-box__results li').textContent).toBe('some1');
|
||||||
|
|
||||||
await u.waitUntil(() => view.el.querySelectorAll('.suggestion-box__results li').length === 4);
|
const backspace_event = {
|
||||||
expect(view.el.querySelector('.suggestion-box__results li:first-child').textContent).toBe('dick');
|
'target': textarea,
|
||||||
expect(view.el.querySelector('.suggestion-box__results li:nth-child(2)').textContent).toBe('harry');
|
'preventDefault': function preventDefault () {},
|
||||||
expect(view.el.querySelector('.suggestion-box__results li:nth-child(3)').textContent).toBe('jane');
|
'keyCode': 8
|
||||||
expect(view.el.querySelector('.suggestion-box__results li:nth-child(4)').textContent).toBe('tom');
|
}
|
||||||
done();
|
for (var i=0; i<3; i++) {
|
||||||
}));
|
// Press backspace 3 times to remove "som"
|
||||||
|
|
||||||
it("autocompletes when the user presses tab",
|
|
||||||
mock.initConverse(
|
|
||||||
['rosterGroupsFetched', 'chatBoxesFetched'], {},
|
|
||||||
async function (done, _converse) {
|
|
||||||
|
|
||||||
await test_utils.openAndEnterChatRoom(_converse, 'lounge@montague.lit', 'romeo');
|
|
||||||
const view = _converse.chatboxviews.get('lounge@montague.lit');
|
|
||||||
expect(view.model.occupants.length).toBe(1);
|
|
||||||
let presence = $pres({
|
|
||||||
'to': 'romeo@montague.lit/orchard',
|
|
||||||
'from': 'lounge@montague.lit/some1'
|
|
||||||
})
|
|
||||||
.c('x', {xmlns: Strophe.NS.MUC_USER})
|
|
||||||
.c('item', {
|
|
||||||
'affiliation': 'none',
|
|
||||||
'jid': 'some1@montague.lit/resource',
|
|
||||||
'role': 'participant'
|
|
||||||
});
|
|
||||||
_converse.connection._dataRecv(test_utils.createRequest(presence));
|
|
||||||
expect(view.model.occupants.length).toBe(2);
|
|
||||||
|
|
||||||
const textarea = view.el.querySelector('textarea.chat-textarea');
|
|
||||||
textarea.value = "hello som";
|
|
||||||
|
|
||||||
// Press tab
|
|
||||||
const tab_event = {
|
|
||||||
'target': textarea,
|
|
||||||
'preventDefault': function preventDefault () {},
|
|
||||||
'stopPropagation': function stopPropagation () {},
|
|
||||||
'keyCode': 9,
|
|
||||||
'key': 'Tab'
|
|
||||||
}
|
|
||||||
view.onKeyDown(tab_event);
|
|
||||||
view.onKeyUp(tab_event);
|
|
||||||
await u.waitUntil(() => view.el.querySelector('.suggestion-box__results').hidden === false);
|
|
||||||
expect(view.el.querySelectorAll('.suggestion-box__results li').length).toBe(1);
|
|
||||||
expect(view.el.querySelector('.suggestion-box__results li').textContent).toBe('some1');
|
|
||||||
|
|
||||||
const backspace_event = {
|
|
||||||
'target': textarea,
|
|
||||||
'preventDefault': function preventDefault () {},
|
|
||||||
'keyCode': 8
|
|
||||||
}
|
|
||||||
for (var i=0; i<3; i++) {
|
|
||||||
// Press backspace 3 times to remove "som"
|
|
||||||
view.onKeyDown(backspace_event);
|
|
||||||
textarea.value = textarea.value.slice(0, textarea.value.length-1)
|
|
||||||
view.onKeyUp(backspace_event);
|
|
||||||
}
|
|
||||||
await u.waitUntil(() => view.el.querySelector('.suggestion-box__results').hidden === true);
|
|
||||||
|
|
||||||
presence = $pres({
|
|
||||||
'to': 'romeo@montague.lit/orchard',
|
|
||||||
'from': 'lounge@montague.lit/some2'
|
|
||||||
})
|
|
||||||
.c('x', {xmlns: Strophe.NS.MUC_USER})
|
|
||||||
.c('item', {
|
|
||||||
'affiliation': 'none',
|
|
||||||
'jid': 'some2@montague.lit/resource',
|
|
||||||
'role': 'participant'
|
|
||||||
});
|
|
||||||
_converse.connection._dataRecv(test_utils.createRequest(presence));
|
|
||||||
|
|
||||||
textarea.value = "hello s s";
|
|
||||||
view.onKeyDown(tab_event);
|
|
||||||
view.onKeyUp(tab_event);
|
|
||||||
await u.waitUntil(() => view.el.querySelector('.suggestion-box__results').hidden === false);
|
|
||||||
expect(view.el.querySelectorAll('.suggestion-box__results li').length).toBe(2);
|
|
||||||
|
|
||||||
const up_arrow_event = {
|
|
||||||
'target': textarea,
|
|
||||||
'preventDefault': () => (up_arrow_event.defaultPrevented = true),
|
|
||||||
'stopPropagation': function stopPropagation () {},
|
|
||||||
'keyCode': 38
|
|
||||||
}
|
|
||||||
view.onKeyDown(up_arrow_event);
|
|
||||||
view.onKeyUp(up_arrow_event);
|
|
||||||
expect(view.el.querySelectorAll('.suggestion-box__results li').length).toBe(2);
|
|
||||||
expect(view.el.querySelector('.suggestion-box__results li[aria-selected="false"]').textContent).toBe('some1');
|
|
||||||
expect(view.el.querySelector('.suggestion-box__results li[aria-selected="true"]').textContent).toBe('some2');
|
|
||||||
|
|
||||||
view.onKeyDown({
|
|
||||||
'target': textarea,
|
|
||||||
'preventDefault': function preventDefault () {},
|
|
||||||
'stopPropagation': function stopPropagation () {},
|
|
||||||
'keyCode': 13 // Enter
|
|
||||||
});
|
|
||||||
expect(textarea.value).toBe('hello s @some2 ');
|
|
||||||
|
|
||||||
// Test that pressing tab twice selects
|
|
||||||
presence = $pres({
|
|
||||||
'to': 'romeo@montague.lit/orchard',
|
|
||||||
'from': 'lounge@montague.lit/z3r0'
|
|
||||||
})
|
|
||||||
.c('x', {xmlns: Strophe.NS.MUC_USER})
|
|
||||||
.c('item', {
|
|
||||||
'affiliation': 'none',
|
|
||||||
'jid': 'z3r0@montague.lit/resource',
|
|
||||||
'role': 'participant'
|
|
||||||
});
|
|
||||||
_converse.connection._dataRecv(test_utils.createRequest(presence));
|
|
||||||
textarea.value = "hello z";
|
|
||||||
view.onKeyDown(tab_event);
|
|
||||||
view.onKeyUp(tab_event);
|
|
||||||
await u.waitUntil(() => view.el.querySelector('.suggestion-box__results').hidden === false);
|
|
||||||
|
|
||||||
view.onKeyDown(tab_event);
|
|
||||||
view.onKeyUp(tab_event);
|
|
||||||
await u.waitUntil(() => textarea.value === 'hello @z3r0 ');
|
|
||||||
done();
|
|
||||||
}));
|
|
||||||
|
|
||||||
it("autocompletes when the user presses backspace",
|
|
||||||
mock.initConverse(
|
|
||||||
['rosterGroupsFetched'], {},
|
|
||||||
async function (done, _converse) {
|
|
||||||
|
|
||||||
await test_utils.openAndEnterChatRoom(_converse, 'lounge@montague.lit', 'romeo');
|
|
||||||
const view = _converse.chatboxviews.get('lounge@montague.lit');
|
|
||||||
expect(view.model.occupants.length).toBe(1);
|
|
||||||
const presence = $pres({
|
|
||||||
'to': 'romeo@montague.lit/orchard',
|
|
||||||
'from': 'lounge@montague.lit/some1'
|
|
||||||
})
|
|
||||||
.c('x', {xmlns: Strophe.NS.MUC_USER})
|
|
||||||
.c('item', {
|
|
||||||
'affiliation': 'none',
|
|
||||||
'jid': 'some1@montague.lit/resource',
|
|
||||||
'role': 'participant'
|
|
||||||
});
|
|
||||||
_converse.connection._dataRecv(test_utils.createRequest(presence));
|
|
||||||
expect(view.model.occupants.length).toBe(2);
|
|
||||||
|
|
||||||
const textarea = view.el.querySelector('textarea.chat-textarea');
|
|
||||||
textarea.value = "hello @some1 ";
|
|
||||||
|
|
||||||
// Press backspace
|
|
||||||
const backspace_event = {
|
|
||||||
'target': textarea,
|
|
||||||
'preventDefault': function preventDefault () {},
|
|
||||||
'stopPropagation': function stopPropagation () {},
|
|
||||||
'keyCode': 8,
|
|
||||||
'key': 'Backspace'
|
|
||||||
}
|
|
||||||
view.onKeyDown(backspace_event);
|
view.onKeyDown(backspace_event);
|
||||||
textarea.value = "hello @some1"; // Mimic backspace
|
textarea.value = textarea.value.slice(0, textarea.value.length-1)
|
||||||
view.onKeyUp(backspace_event);
|
view.onKeyUp(backspace_event);
|
||||||
await u.waitUntil(() => view.el.querySelector('.suggestion-box__results').hidden === false);
|
}
|
||||||
expect(view.el.querySelectorAll('.suggestion-box__results li').length).toBe(1);
|
await u.waitUntil(() => view.el.querySelector('.suggestion-box__results').hidden === true);
|
||||||
expect(view.el.querySelector('.suggestion-box__results li').textContent).toBe('some1');
|
|
||||||
done();
|
presence = $pres({
|
||||||
}));
|
'to': 'romeo@montague.lit/orchard',
|
||||||
});
|
'from': 'lounge@montague.lit/some2'
|
||||||
|
})
|
||||||
|
.c('x', {xmlns: Strophe.NS.MUC_USER})
|
||||||
|
.c('item', {
|
||||||
|
'affiliation': 'none',
|
||||||
|
'jid': 'some2@montague.lit/resource',
|
||||||
|
'role': 'participant'
|
||||||
|
});
|
||||||
|
_converse.connection._dataRecv(mock.createRequest(presence));
|
||||||
|
|
||||||
|
textarea.value = "hello s s";
|
||||||
|
view.onKeyDown(tab_event);
|
||||||
|
view.onKeyUp(tab_event);
|
||||||
|
await u.waitUntil(() => view.el.querySelector('.suggestion-box__results').hidden === false);
|
||||||
|
expect(view.el.querySelectorAll('.suggestion-box__results li').length).toBe(2);
|
||||||
|
|
||||||
|
const up_arrow_event = {
|
||||||
|
'target': textarea,
|
||||||
|
'preventDefault': () => (up_arrow_event.defaultPrevented = true),
|
||||||
|
'stopPropagation': function stopPropagation () {},
|
||||||
|
'keyCode': 38
|
||||||
|
}
|
||||||
|
view.onKeyDown(up_arrow_event);
|
||||||
|
view.onKeyUp(up_arrow_event);
|
||||||
|
expect(view.el.querySelectorAll('.suggestion-box__results li').length).toBe(2);
|
||||||
|
expect(view.el.querySelector('.suggestion-box__results li[aria-selected="false"]').textContent).toBe('some1');
|
||||||
|
expect(view.el.querySelector('.suggestion-box__results li[aria-selected="true"]').textContent).toBe('some2');
|
||||||
|
|
||||||
|
view.onKeyDown({
|
||||||
|
'target': textarea,
|
||||||
|
'preventDefault': function preventDefault () {},
|
||||||
|
'stopPropagation': function stopPropagation () {},
|
||||||
|
'keyCode': 13 // Enter
|
||||||
|
});
|
||||||
|
expect(textarea.value).toBe('hello s @some2 ');
|
||||||
|
|
||||||
|
// Test that pressing tab twice selects
|
||||||
|
presence = $pres({
|
||||||
|
'to': 'romeo@montague.lit/orchard',
|
||||||
|
'from': 'lounge@montague.lit/z3r0'
|
||||||
|
})
|
||||||
|
.c('x', {xmlns: Strophe.NS.MUC_USER})
|
||||||
|
.c('item', {
|
||||||
|
'affiliation': 'none',
|
||||||
|
'jid': 'z3r0@montague.lit/resource',
|
||||||
|
'role': 'participant'
|
||||||
|
});
|
||||||
|
_converse.connection._dataRecv(mock.createRequest(presence));
|
||||||
|
textarea.value = "hello z";
|
||||||
|
view.onKeyDown(tab_event);
|
||||||
|
view.onKeyUp(tab_event);
|
||||||
|
await u.waitUntil(() => view.el.querySelector('.suggestion-box__results').hidden === false);
|
||||||
|
|
||||||
|
view.onKeyDown(tab_event);
|
||||||
|
view.onKeyUp(tab_event);
|
||||||
|
await u.waitUntil(() => textarea.value === 'hello @z3r0 ');
|
||||||
|
done();
|
||||||
|
}));
|
||||||
|
|
||||||
|
it("autocompletes when the user presses backspace",
|
||||||
|
mock.initConverse(
|
||||||
|
['rosterGroupsFetched'], {},
|
||||||
|
async function (done, _converse) {
|
||||||
|
|
||||||
|
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({
|
||||||
|
'to': 'romeo@montague.lit/orchard',
|
||||||
|
'from': 'lounge@montague.lit/some1'
|
||||||
|
})
|
||||||
|
.c('x', {xmlns: Strophe.NS.MUC_USER})
|
||||||
|
.c('item', {
|
||||||
|
'affiliation': 'none',
|
||||||
|
'jid': 'some1@montague.lit/resource',
|
||||||
|
'role': 'participant'
|
||||||
|
});
|
||||||
|
_converse.connection._dataRecv(mock.createRequest(presence));
|
||||||
|
expect(view.model.occupants.length).toBe(2);
|
||||||
|
|
||||||
|
const textarea = view.el.querySelector('textarea.chat-textarea');
|
||||||
|
textarea.value = "hello @some1 ";
|
||||||
|
|
||||||
|
// Press backspace
|
||||||
|
const backspace_event = {
|
||||||
|
'target': textarea,
|
||||||
|
'preventDefault': function preventDefault () {},
|
||||||
|
'stopPropagation': function stopPropagation () {},
|
||||||
|
'keyCode': 8,
|
||||||
|
'key': 'Backspace'
|
||||||
|
}
|
||||||
|
view.onKeyDown(backspace_event);
|
||||||
|
textarea.value = "hello @some1"; // Mimic backspace
|
||||||
|
view.onKeyUp(backspace_event);
|
||||||
|
await u.waitUntil(() => view.el.querySelector('.suggestion-box__results').hidden === false);
|
||||||
|
expect(view.el.querySelectorAll('.suggestion-box__results li').length).toBe(1);
|
||||||
|
expect(view.el.querySelector('.suggestion-box__results li').textContent).toBe('some1');
|
||||||
|
done();
|
||||||
|
}));
|
||||||
});
|
});
|
||||||
|
1058
spec/bookmarks.js
1058
spec/bookmarks.js
File diff suppressed because it is too large
Load Diff
3034
spec/chatbox.js
3034
spec/chatbox.js
File diff suppressed because it is too large
Load Diff
@ -1,389 +1,387 @@
|
|||||||
window.addEventListener('converse-loaded', () => {
|
/*global mock */
|
||||||
const mock = window.mock;
|
|
||||||
const test_utils = window.test_utils;
|
const _ = converse.env._,
|
||||||
const _ = converse.env._,
|
$msg = converse.env.$msg,
|
||||||
$msg = converse.env.$msg,
|
u = converse.env.utils,
|
||||||
u = converse.env.utils,
|
Strophe = converse.env.Strophe,
|
||||||
Strophe = converse.env.Strophe,
|
sizzle = converse.env.sizzle;
|
||||||
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'",
|
it("can be opened by clicking a DOM element with class 'toggle-controlbox'",
|
||||||
|
mock.initConverse(
|
||||||
|
['rosterGroupsFetched'], {},
|
||||||
|
function (done, _converse) {
|
||||||
|
|
||||||
|
// This spec will only pass if the controlbox is not currently
|
||||||
|
// open yet.
|
||||||
|
let el = document.querySelector("div#controlbox");
|
||||||
|
expect(_.isElement(el)).toBe(true);
|
||||||
|
expect(u.isVisible(el)).toBe(false);
|
||||||
|
spyOn(_converse.controlboxtoggle, 'onClick').and.callThrough();
|
||||||
|
spyOn(_converse.controlboxtoggle, 'showControlBox').and.callThrough();
|
||||||
|
spyOn(_converse.api, "trigger").and.callThrough();
|
||||||
|
// Redelegate so that the spies are now registered as the event handlers (specifically for 'onClick')
|
||||||
|
_converse.controlboxtoggle.delegateEvents();
|
||||||
|
document.querySelector('.toggle-controlbox').click();
|
||||||
|
expect(_converse.controlboxtoggle.onClick).toHaveBeenCalled();
|
||||||
|
expect(_converse.controlboxtoggle.showControlBox).toHaveBeenCalled();
|
||||||
|
expect(_converse.api.trigger).toHaveBeenCalledWith('controlBoxOpened', jasmine.any(Object));
|
||||||
|
el = document.querySelector("div#controlbox");
|
||||||
|
expect(u.isVisible(el)).toBe(true);
|
||||||
|
done();
|
||||||
|
}));
|
||||||
|
|
||||||
|
describe("The \"Contacts\" section", function () {
|
||||||
|
|
||||||
|
it("can be used to add contact and it checks for case-sensivity",
|
||||||
|
mock.initConverse(
|
||||||
|
['rosterGroupsFetched'], {},
|
||||||
|
async function (done, _converse) {
|
||||||
|
|
||||||
|
spyOn(_converse.api, "trigger").and.callThrough();
|
||||||
|
spyOn(_converse.rosterview, 'update').and.callThrough();
|
||||||
|
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',
|
||||||
|
subscription: 'none',
|
||||||
|
ask: 'subscribe',
|
||||||
|
fullname: mock.pend_names[0]
|
||||||
|
});
|
||||||
|
_converse.roster.create({
|
||||||
|
jid: mock.pend_names[0].replace(/ /g,'.') + '@montague.lit',
|
||||||
|
subscription: 'none',
|
||||||
|
ask: 'subscribe',
|
||||||
|
fullname: mock.pend_names[0]
|
||||||
|
});
|
||||||
|
await u.waitUntil(() => _.filter(_converse.rosterview.el.querySelectorAll('.roster-group li'), u.isVisible).length, 700);
|
||||||
|
// Checking that only one entry is created because both JID is same (Case sensitive check)
|
||||||
|
expect(_.filter(_converse.rosterview.el.querySelectorAll('li'), u.isVisible).length).toBe(1);
|
||||||
|
expect(_converse.rosterview.update).toHaveBeenCalled();
|
||||||
|
done();
|
||||||
|
}));
|
||||||
|
|
||||||
|
it("shows the number of unread mentions received",
|
||||||
|
mock.initConverse(
|
||||||
|
['rosterGroupsFetched', 'chatBoxesFetched'], {},
|
||||||
|
async function (done, _converse) {
|
||||||
|
|
||||||
|
await mock.waitForRoster(_converse, 'all');
|
||||||
|
await mock.openControlBox(_converse);
|
||||||
|
|
||||||
|
const sender_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit';
|
||||||
|
await mock.openChatBoxFor(_converse, sender_jid);
|
||||||
|
await u.waitUntil(() => _converse.chatboxes.length);
|
||||||
|
const chatview = _converse.chatboxviews.get(sender_jid);
|
||||||
|
chatview.model.set({'minimized': true});
|
||||||
|
|
||||||
|
expect(_converse.chatboxviews.el.querySelector('.restore-chat .message-count') === null).toBeTruthy();
|
||||||
|
expect(_converse.rosterview.el.querySelector('.msgs-indicator') === null).toBeTruthy();
|
||||||
|
|
||||||
|
let msg = $msg({
|
||||||
|
from: sender_jid,
|
||||||
|
to: _converse.connection.jid,
|
||||||
|
type: 'chat',
|
||||||
|
id: u.getUniqueId()
|
||||||
|
}).c('body').t('hello').up()
|
||||||
|
.c('active', {'xmlns': 'http://jabber.org/protocol/chatstates'}).tree();
|
||||||
|
_converse.handleMessageStanza(msg);
|
||||||
|
await u.waitUntil(() => _converse.rosterview.el.querySelectorAll(".msgs-indicator").length);
|
||||||
|
spyOn(chatview.model, 'incrementUnreadMsgCounter').and.callThrough();
|
||||||
|
expect(_converse.chatboxviews.el.querySelector('.restore-chat .message-count').textContent).toBe('1');
|
||||||
|
expect(_converse.rosterview.el.querySelector('.msgs-indicator').textContent).toBe('1');
|
||||||
|
|
||||||
|
msg = $msg({
|
||||||
|
from: sender_jid,
|
||||||
|
to: _converse.connection.jid,
|
||||||
|
type: 'chat',
|
||||||
|
id: u.getUniqueId()
|
||||||
|
}).c('body').t('hello again').up()
|
||||||
|
.c('active', {'xmlns': 'http://jabber.org/protocol/chatstates'}).tree();
|
||||||
|
_converse.handleMessageStanza(msg);
|
||||||
|
await u.waitUntil(() => chatview.model.incrementUnreadMsgCounter.calls.count());
|
||||||
|
expect(_converse.chatboxviews.el.querySelector('.restore-chat .message-count').textContent).toBe('2');
|
||||||
|
expect(_converse.rosterview.el.querySelector('.msgs-indicator').textContent).toBe('2');
|
||||||
|
chatview.model.set({'minimized': false});
|
||||||
|
expect(_converse.chatboxviews.el.querySelector('.restore-chat .message-count')).toBe(null);
|
||||||
|
await u.waitUntil(() => _converse.rosterview.el.querySelector('.msgs-indicator') === null);
|
||||||
|
done();
|
||||||
|
}));
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("The Status Widget", function () {
|
||||||
|
|
||||||
|
it("shows the user's chat status, which is online by default",
|
||||||
mock.initConverse(
|
mock.initConverse(
|
||||||
['rosterGroupsFetched'], {},
|
['rosterGroupsFetched'], {},
|
||||||
function (done, _converse) {
|
function (done, _converse) {
|
||||||
|
|
||||||
// This spec will only pass if the controlbox is not currently
|
mock.openControlBox(_converse);
|
||||||
// open yet.
|
var view = _converse.xmppstatusview;
|
||||||
let el = document.querySelector("div#controlbox");
|
expect(u.hasClass('online', view.el.querySelector('.xmpp-status span:first-child'))).toBe(true);
|
||||||
expect(_.isElement(el)).toBe(true);
|
expect(view.el.querySelector('.xmpp-status span.online').textContent.trim()).toBe('I am online');
|
||||||
expect(u.isVisible(el)).toBe(false);
|
|
||||||
spyOn(_converse.controlboxtoggle, 'onClick').and.callThrough();
|
|
||||||
spyOn(_converse.controlboxtoggle, 'showControlBox').and.callThrough();
|
|
||||||
spyOn(_converse.api, "trigger").and.callThrough();
|
|
||||||
// Redelegate so that the spies are now registered as the event handlers (specifically for 'onClick')
|
|
||||||
_converse.controlboxtoggle.delegateEvents();
|
|
||||||
document.querySelector('.toggle-controlbox').click();
|
|
||||||
expect(_converse.controlboxtoggle.onClick).toHaveBeenCalled();
|
|
||||||
expect(_converse.controlboxtoggle.showControlBox).toHaveBeenCalled();
|
|
||||||
expect(_converse.api.trigger).toHaveBeenCalledWith('controlBoxOpened', jasmine.any(Object));
|
|
||||||
el = document.querySelector("div#controlbox");
|
|
||||||
expect(u.isVisible(el)).toBe(true);
|
|
||||||
done();
|
done();
|
||||||
}));
|
}));
|
||||||
|
|
||||||
describe("The \"Contacts\" section", function () {
|
it("can be used to set the current user's chat status",
|
||||||
|
|
||||||
it("can be used to add contact and it checks for case-sensivity",
|
|
||||||
mock.initConverse(
|
|
||||||
['rosterGroupsFetched'], {},
|
|
||||||
async function (done, _converse) {
|
|
||||||
|
|
||||||
spyOn(_converse.api, "trigger").and.callThrough();
|
|
||||||
spyOn(_converse.rosterview, 'update').and.callThrough();
|
|
||||||
await test_utils.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',
|
|
||||||
subscription: 'none',
|
|
||||||
ask: 'subscribe',
|
|
||||||
fullname: mock.pend_names[0]
|
|
||||||
});
|
|
||||||
_converse.roster.create({
|
|
||||||
jid: mock.pend_names[0].replace(/ /g,'.') + '@montague.lit',
|
|
||||||
subscription: 'none',
|
|
||||||
ask: 'subscribe',
|
|
||||||
fullname: mock.pend_names[0]
|
|
||||||
});
|
|
||||||
await u.waitUntil(() => _.filter(_converse.rosterview.el.querySelectorAll('.roster-group li'), u.isVisible).length, 700);
|
|
||||||
// Checking that only one entry is created because both JID is same (Case sensitive check)
|
|
||||||
expect(_.filter(_converse.rosterview.el.querySelectorAll('li'), u.isVisible).length).toBe(1);
|
|
||||||
expect(_converse.rosterview.update).toHaveBeenCalled();
|
|
||||||
done();
|
|
||||||
}));
|
|
||||||
|
|
||||||
it("shows the number of unread mentions received",
|
|
||||||
mock.initConverse(
|
|
||||||
['rosterGroupsFetched', 'chatBoxesFetched'], {},
|
|
||||||
async function (done, _converse) {
|
|
||||||
|
|
||||||
await test_utils.waitForRoster(_converse, 'all');
|
|
||||||
await test_utils.openControlBox(_converse);
|
|
||||||
|
|
||||||
const sender_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit';
|
|
||||||
await test_utils.openChatBoxFor(_converse, sender_jid);
|
|
||||||
await u.waitUntil(() => _converse.chatboxes.length);
|
|
||||||
const chatview = _converse.chatboxviews.get(sender_jid);
|
|
||||||
chatview.model.set({'minimized': true});
|
|
||||||
|
|
||||||
expect(_converse.chatboxviews.el.querySelector('.restore-chat .message-count') === null).toBeTruthy();
|
|
||||||
expect(_converse.rosterview.el.querySelector('.msgs-indicator') === null).toBeTruthy();
|
|
||||||
|
|
||||||
let msg = $msg({
|
|
||||||
from: sender_jid,
|
|
||||||
to: _converse.connection.jid,
|
|
||||||
type: 'chat',
|
|
||||||
id: u.getUniqueId()
|
|
||||||
}).c('body').t('hello').up()
|
|
||||||
.c('active', {'xmlns': 'http://jabber.org/protocol/chatstates'}).tree();
|
|
||||||
_converse.handleMessageStanza(msg);
|
|
||||||
await u.waitUntil(() => _converse.rosterview.el.querySelectorAll(".msgs-indicator").length);
|
|
||||||
spyOn(chatview.model, 'incrementUnreadMsgCounter').and.callThrough();
|
|
||||||
expect(_converse.chatboxviews.el.querySelector('.restore-chat .message-count').textContent).toBe('1');
|
|
||||||
expect(_converse.rosterview.el.querySelector('.msgs-indicator').textContent).toBe('1');
|
|
||||||
|
|
||||||
msg = $msg({
|
|
||||||
from: sender_jid,
|
|
||||||
to: _converse.connection.jid,
|
|
||||||
type: 'chat',
|
|
||||||
id: u.getUniqueId()
|
|
||||||
}).c('body').t('hello again').up()
|
|
||||||
.c('active', {'xmlns': 'http://jabber.org/protocol/chatstates'}).tree();
|
|
||||||
_converse.handleMessageStanza(msg);
|
|
||||||
await u.waitUntil(() => chatview.model.incrementUnreadMsgCounter.calls.count());
|
|
||||||
expect(_converse.chatboxviews.el.querySelector('.restore-chat .message-count').textContent).toBe('2');
|
|
||||||
expect(_converse.rosterview.el.querySelector('.msgs-indicator').textContent).toBe('2');
|
|
||||||
chatview.model.set({'minimized': false});
|
|
||||||
expect(_converse.chatboxviews.el.querySelector('.restore-chat .message-count')).toBe(null);
|
|
||||||
await u.waitUntil(() => _converse.rosterview.el.querySelector('.msgs-indicator') === null);
|
|
||||||
done();
|
|
||||||
}));
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("The Status Widget", function () {
|
|
||||||
|
|
||||||
it("shows the user's chat status, which is online by default",
|
|
||||||
mock.initConverse(
|
|
||||||
['rosterGroupsFetched'], {},
|
|
||||||
function (done, _converse) {
|
|
||||||
|
|
||||||
test_utils.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');
|
|
||||||
done();
|
|
||||||
}));
|
|
||||||
|
|
||||||
it("can be used to set the current user's chat status",
|
|
||||||
mock.initConverse(
|
|
||||||
['rosterGroupsFetched'], {},
|
|
||||||
async function (done, _converse) {
|
|
||||||
|
|
||||||
await test_utils.openControlBox(_converse);
|
|
||||||
var cbview = _converse.chatboxviews.get('controlbox');
|
|
||||||
cbview.el.querySelector('.change-status').click()
|
|
||||||
var modal = _converse.xmppstatusview.status_modal;
|
|
||||||
|
|
||||||
await u.waitUntil(() => u.isVisible(modal.el), 1000);
|
|
||||||
const view = _converse.xmppstatusview;
|
|
||||||
modal.el.querySelector('label[for="radio-busy"]').click(); // Change status to "dnd"
|
|
||||||
modal.el.querySelector('[type="submit"]').click();
|
|
||||||
const sent_stanzas = _converse.connection.sent_stanzas;
|
|
||||||
const sent_presence = await u.waitUntil(() => sent_stanzas.filter(s => Strophe.serialize(s).match('presence')).pop());
|
|
||||||
expect(Strophe.serialize(sent_presence)).toBe(
|
|
||||||
`<presence xmlns="jabber:client">`+
|
|
||||||
`<show>dnd</show>`+
|
|
||||||
`<priority>0</priority>`+
|
|
||||||
`<c hash="sha-1" node="https://conversejs.org" ver="Hxbsr5fazs62i+O0GxIXf2OEDNs=" xmlns="http://jabber.org/protocol/caps"/>`+
|
|
||||||
`</presence>`);
|
|
||||||
const first_child = view.el.querySelector('.xmpp-status span:first-child');
|
|
||||||
expect(u.hasClass('online', first_child)).toBe(false);
|
|
||||||
expect(u.hasClass('dnd', first_child)).toBe(true);
|
|
||||||
expect(view.el.querySelector('.xmpp-status span:first-child').textContent.trim()).toBe('I am busy');
|
|
||||||
done();
|
|
||||||
}));
|
|
||||||
|
|
||||||
it("can be used to set a custom status message",
|
|
||||||
mock.initConverse(
|
|
||||||
['rosterGroupsFetched'], {},
|
|
||||||
async function (done, _converse) {
|
|
||||||
|
|
||||||
await test_utils.openControlBox(_converse);
|
|
||||||
const cbview = _converse.chatboxviews.get('controlbox');
|
|
||||||
cbview.el.querySelector('.change-status').click()
|
|
||||||
const modal = _converse.xmppstatusview.status_modal;
|
|
||||||
|
|
||||||
await u.waitUntil(() => u.isVisible(modal.el), 1000);
|
|
||||||
const view = _converse.xmppstatusview;
|
|
||||||
const msg = 'I am happy';
|
|
||||||
modal.el.querySelector('input[name="status_message"]').value = msg;
|
|
||||||
modal.el.querySelector('[type="submit"]').click();
|
|
||||||
const sent_stanzas = _converse.connection.sent_stanzas;
|
|
||||||
const sent_presence = await u.waitUntil(() => sent_stanzas.filter(s => Strophe.serialize(s).match('presence')).pop());
|
|
||||||
expect(Strophe.serialize(sent_presence)).toBe(
|
|
||||||
`<presence xmlns="jabber:client">`+
|
|
||||||
`<status>I am happy</status>`+
|
|
||||||
`<priority>0</priority>`+
|
|
||||||
`<c hash="sha-1" node="https://conversejs.org" ver="Hxbsr5fazs62i+O0GxIXf2OEDNs=" xmlns="http://jabber.org/protocol/caps"/>`+
|
|
||||||
`</presence>`);
|
|
||||||
|
|
||||||
const first_child = view.el.querySelector('.xmpp-status span:first-child');
|
|
||||||
expect(u.hasClass('online', first_child)).toBe(true);
|
|
||||||
expect(view.el.querySelector('.xmpp-status span:first-child').textContent.trim()).toBe(msg);
|
|
||||||
done();
|
|
||||||
}));
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("The 'Add Contact' widget", function () {
|
|
||||||
|
|
||||||
it("opens up an add modal when you click on it",
|
|
||||||
mock.initConverse(
|
mock.initConverse(
|
||||||
['rosterGroupsFetched'], {},
|
['rosterGroupsFetched'], {},
|
||||||
async function (done, _converse) {
|
async function (done, _converse) {
|
||||||
|
|
||||||
await test_utils.waitForRoster(_converse, 'all');
|
await mock.openControlBox(_converse);
|
||||||
await test_utils.openControlBox(_converse);
|
var cbview = _converse.chatboxviews.get('controlbox');
|
||||||
|
cbview.el.querySelector('.change-status').click()
|
||||||
|
var modal = _converse.xmppstatusview.status_modal;
|
||||||
|
|
||||||
const cbview = _converse.chatboxviews.get('controlbox');
|
|
||||||
cbview.el.querySelector('.add-contact').click()
|
|
||||||
const modal = _converse.rosterview.add_contact_modal;
|
|
||||||
await u.waitUntil(() => u.isVisible(modal.el), 1000);
|
await u.waitUntil(() => u.isVisible(modal.el), 1000);
|
||||||
expect(modal.el.querySelector('form.add-xmpp-contact')).not.toBe(null);
|
const view = _converse.xmppstatusview;
|
||||||
|
modal.el.querySelector('label[for="radio-busy"]').click(); // Change status to "dnd"
|
||||||
const input_jid = modal.el.querySelector('input[name="jid"]');
|
modal.el.querySelector('[type="submit"]').click();
|
||||||
const input_name = modal.el.querySelector('input[name="name"]');
|
const sent_stanzas = _converse.connection.sent_stanzas;
|
||||||
input_jid.value = 'someone@';
|
const sent_presence = await u.waitUntil(() => sent_stanzas.filter(s => Strophe.serialize(s).match('presence')).pop());
|
||||||
|
expect(Strophe.serialize(sent_presence)).toBe(
|
||||||
const evt = new Event('input');
|
`<presence xmlns="jabber:client">`+
|
||||||
input_jid.dispatchEvent(evt);
|
`<show>dnd</show>`+
|
||||||
expect(modal.el.querySelector('.suggestion-box li').textContent).toBe('someone@montague.lit');
|
`<priority>0</priority>`+
|
||||||
input_jid.value = 'someone@montague.lit';
|
`<c hash="sha-1" node="https://conversejs.org" ver="Hxbsr5fazs62i+O0GxIXf2OEDNs=" xmlns="http://jabber.org/protocol/caps"/>`+
|
||||||
input_name.value = 'Someone';
|
`</presence>`);
|
||||||
modal.el.querySelector('button[type="submit"]').click();
|
const first_child = view.el.querySelector('.xmpp-status span:first-child');
|
||||||
|
expect(u.hasClass('online', first_child)).toBe(false);
|
||||||
const sent_IQs = _converse.connection.IQ_stanzas;
|
expect(u.hasClass('dnd', first_child)).toBe(true);
|
||||||
const sent_stanza = await u.waitUntil(() => sent_IQs.filter(iq => iq.querySelector(`iq[type="set"] query[xmlns="${Strophe.NS.ROSTER}"]`)).pop());
|
expect(view.el.querySelector('.xmpp-status span:first-child').textContent.trim()).toBe('I am busy');
|
||||||
expect(Strophe.serialize(sent_stanza)).toEqual(
|
|
||||||
`<iq id="${sent_stanza.getAttribute('id')}" type="set" xmlns="jabber:client">`+
|
|
||||||
`<query xmlns="jabber:iq:roster"><item jid="someone@montague.lit" name="Someone"/></query>`+
|
|
||||||
`</iq>`);
|
|
||||||
done();
|
done();
|
||||||
}));
|
}));
|
||||||
|
|
||||||
it("can be configured to not provide search suggestions",
|
it("can be used to set a custom status message",
|
||||||
mock.initConverse(
|
mock.initConverse(
|
||||||
['rosterGroupsFetched'], {'autocomplete_add_contact': false},
|
['rosterGroupsFetched'], {},
|
||||||
async function (done, _converse) {
|
async function (done, _converse) {
|
||||||
|
|
||||||
await test_utils.waitForRoster(_converse, 'all', 0);
|
await mock.openControlBox(_converse);
|
||||||
test_utils.openControlBox(_converse);
|
|
||||||
const cbview = _converse.chatboxviews.get('controlbox');
|
const cbview = _converse.chatboxviews.get('controlbox');
|
||||||
cbview.el.querySelector('.add-contact').click()
|
cbview.el.querySelector('.change-status').click()
|
||||||
const modal = _converse.rosterview.add_contact_modal;
|
const modal = _converse.xmppstatusview.status_modal;
|
||||||
expect(modal.jid_auto_complete).toBe(undefined);
|
|
||||||
expect(modal.name_auto_complete).toBe(undefined);
|
|
||||||
|
|
||||||
await u.waitUntil(() => u.isVisible(modal.el), 1000);
|
await u.waitUntil(() => u.isVisible(modal.el), 1000);
|
||||||
expect(modal.el.querySelector('form.add-xmpp-contact')).not.toBe(null);
|
const view = _converse.xmppstatusview;
|
||||||
const input_jid = modal.el.querySelector('input[name="jid"]');
|
const msg = 'I am happy';
|
||||||
input_jid.value = 'someone@montague.lit';
|
modal.el.querySelector('input[name="status_message"]').value = msg;
|
||||||
modal.el.querySelector('button[type="submit"]').click();
|
modal.el.querySelector('[type="submit"]').click();
|
||||||
|
const sent_stanzas = _converse.connection.sent_stanzas;
|
||||||
|
const sent_presence = await u.waitUntil(() => sent_stanzas.filter(s => Strophe.serialize(s).match('presence')).pop());
|
||||||
|
expect(Strophe.serialize(sent_presence)).toBe(
|
||||||
|
`<presence xmlns="jabber:client">`+
|
||||||
|
`<status>I am happy</status>`+
|
||||||
|
`<priority>0</priority>`+
|
||||||
|
`<c hash="sha-1" node="https://conversejs.org" ver="Hxbsr5fazs62i+O0GxIXf2OEDNs=" xmlns="http://jabber.org/protocol/caps"/>`+
|
||||||
|
`</presence>`);
|
||||||
|
|
||||||
const IQ_stanzas = _converse.connection.IQ_stanzas;
|
const first_child = view.el.querySelector('.xmpp-status span:first-child');
|
||||||
const sent_stanza = await u.waitUntil(
|
expect(u.hasClass('online', first_child)).toBe(true);
|
||||||
() => IQ_stanzas.filter(s => sizzle(`iq[type="set"] query[xmlns="${Strophe.NS.ROSTER}"]`, s).length).pop()
|
expect(view.el.querySelector('.xmpp-status span:first-child').textContent.trim()).toBe(msg);
|
||||||
);
|
|
||||||
expect(Strophe.serialize(sent_stanza)).toEqual(
|
|
||||||
`<iq id="${sent_stanza.getAttribute('id')}" type="set" xmlns="jabber:client">`+
|
|
||||||
`<query xmlns="jabber:iq:roster"><item jid="someone@montague.lit"/></query>`+
|
|
||||||
`</iq>`
|
|
||||||
);
|
|
||||||
done();
|
|
||||||
}));
|
|
||||||
|
|
||||||
|
|
||||||
it("integrates with xhr_user_search_url to search for contacts",
|
|
||||||
mock.initConverse(
|
|
||||||
['rosterGroupsFetched'],
|
|
||||||
{ 'xhr_user_search_url': 'http://example.org/?' },
|
|
||||||
async function (done, _converse) {
|
|
||||||
|
|
||||||
await test_utils.waitForRoster(_converse, 'all', 0);
|
|
||||||
|
|
||||||
const xhr = {
|
|
||||||
'open': function open () {},
|
|
||||||
'send': function () {
|
|
||||||
xhr.responseText = JSON.stringify([
|
|
||||||
{"jid": "marty@mcfly.net", "fullname": "Marty McFly"},
|
|
||||||
{"jid": "doc@brown.com", "fullname": "Doc Brown"}
|
|
||||||
]);
|
|
||||||
xhr.onload();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
const XMLHttpRequestBackup = window.XMLHttpRequest;
|
|
||||||
window.XMLHttpRequest = jasmine.createSpy('XMLHttpRequest');
|
|
||||||
XMLHttpRequest.and.callFake(() => xhr);
|
|
||||||
|
|
||||||
const cbview = _converse.chatboxviews.get('controlbox');
|
|
||||||
cbview.el.querySelector('.add-contact').click()
|
|
||||||
const modal = _converse.rosterview.add_contact_modal;
|
|
||||||
await u.waitUntil(() => u.isVisible(modal.el), 1000);
|
|
||||||
|
|
||||||
// We only have autocomplete for the name input
|
|
||||||
expect(modal.jid_auto_complete).toBe(undefined);
|
|
||||||
expect(modal.name_auto_complete instanceof _converse.AutoComplete).toBe(true);
|
|
||||||
|
|
||||||
const input_el = modal.el.querySelector('input[name="name"]');
|
|
||||||
input_el.value = 'marty';
|
|
||||||
input_el.dispatchEvent(new Event('input'));
|
|
||||||
await u.waitUntil(() => modal.el.querySelector('.suggestion-box li'), 1000);
|
|
||||||
expect(modal.el.querySelectorAll('.suggestion-box li').length).toBe(1);
|
|
||||||
const suggestion = modal.el.querySelector('.suggestion-box li');
|
|
||||||
expect(suggestion.textContent).toBe('Marty McFly');
|
|
||||||
|
|
||||||
// Mock selection
|
|
||||||
modal.name_auto_complete.select(suggestion);
|
|
||||||
|
|
||||||
expect(input_el.value).toBe('Marty McFly');
|
|
||||||
expect(modal.el.querySelector('input[name="jid"]').value).toBe('marty@mcfly.net');
|
|
||||||
modal.el.querySelector('button[type="submit"]').click();
|
|
||||||
|
|
||||||
const sent_IQs = _converse.connection.IQ_stanzas;
|
|
||||||
const sent_stanza = await u.waitUntil(() => sent_IQs.filter(iq => iq.querySelector(`iq[type="set"] query[xmlns="${Strophe.NS.ROSTER}"]`)).pop());
|
|
||||||
expect(Strophe.serialize(sent_stanza)).toEqual(
|
|
||||||
`<iq id="${sent_stanza.getAttribute('id')}" type="set" xmlns="jabber:client">`+
|
|
||||||
`<query xmlns="jabber:iq:roster"><item jid="marty@mcfly.net" name="Marty McFly"/></query>`+
|
|
||||||
`</iq>`);
|
|
||||||
window.XMLHttpRequest = XMLHttpRequestBackup;
|
|
||||||
done();
|
|
||||||
}));
|
|
||||||
|
|
||||||
it("can be configured to not provide search suggestions for XHR search results",
|
|
||||||
mock.initConverse(
|
|
||||||
['rosterGroupsFetched'],
|
|
||||||
{ 'autocomplete_add_contact': false,
|
|
||||||
'xhr_user_search_url': 'http://example.org/?' },
|
|
||||||
async function (done, _converse) {
|
|
||||||
|
|
||||||
await test_utils.waitForRoster(_converse, 'all');
|
|
||||||
await test_utils.openControlBox(_converse);
|
|
||||||
var modal;
|
|
||||||
const xhr = {
|
|
||||||
'open': function open () {},
|
|
||||||
'send': function () {
|
|
||||||
const value = modal.el.querySelector('input[name="name"]').value;
|
|
||||||
if (value === 'existing') {
|
|
||||||
const contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit';
|
|
||||||
xhr.responseText = JSON.stringify([{"jid": contact_jid, "fullname": mock.cur_names[0]}]);
|
|
||||||
} else if (value === 'romeo') {
|
|
||||||
xhr.responseText = JSON.stringify([{"jid": "romeo@montague.lit", "fullname": "Romeo Montague"}]);
|
|
||||||
} else if (value === 'ambiguous') {
|
|
||||||
xhr.responseText = JSON.stringify([
|
|
||||||
{"jid": "marty@mcfly.net", "fullname": "Marty McFly"},
|
|
||||||
{"jid": "doc@brown.com", "fullname": "Doc Brown"}
|
|
||||||
]);
|
|
||||||
} else if (value === 'insufficient') {
|
|
||||||
xhr.responseText = JSON.stringify([]);
|
|
||||||
} else {
|
|
||||||
xhr.responseText = JSON.stringify([{"jid": "marty@mcfly.net", "fullname": "Marty McFly"}]);
|
|
||||||
}
|
|
||||||
xhr.onload();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
const XMLHttpRequestBackup = window.XMLHttpRequest;
|
|
||||||
window.XMLHttpRequest = jasmine.createSpy('XMLHttpRequest');
|
|
||||||
XMLHttpRequest.and.callFake(() => xhr);
|
|
||||||
|
|
||||||
const cbview = _converse.chatboxviews.get('controlbox');
|
|
||||||
cbview.el.querySelector('.add-contact').click()
|
|
||||||
modal = _converse.rosterview.add_contact_modal;
|
|
||||||
await u.waitUntil(() => u.isVisible(modal.el), 1000);
|
|
||||||
|
|
||||||
expect(modal.jid_auto_complete).toBe(undefined);
|
|
||||||
expect(modal.name_auto_complete).toBe(undefined);
|
|
||||||
|
|
||||||
const input_el = modal.el.querySelector('input[name="name"]');
|
|
||||||
input_el.value = 'ambiguous';
|
|
||||||
modal.el.querySelector('button[type="submit"]').click();
|
|
||||||
let feedback_el = modal.el.querySelector('.invalid-feedback');
|
|
||||||
expect(feedback_el.textContent).toBe('Sorry, could not find a contact with that name');
|
|
||||||
feedback_el.textContent = '';
|
|
||||||
|
|
||||||
input_el.value = 'insufficient';
|
|
||||||
modal.el.querySelector('button[type="submit"]').click();
|
|
||||||
feedback_el = modal.el.querySelector('.invalid-feedback');
|
|
||||||
expect(feedback_el.textContent).toBe('Sorry, could not find a contact with that name');
|
|
||||||
feedback_el.textContent = '';
|
|
||||||
|
|
||||||
input_el.value = 'existing';
|
|
||||||
modal.el.querySelector('button[type="submit"]').click();
|
|
||||||
feedback_el = modal.el.querySelector('.invalid-feedback');
|
|
||||||
expect(feedback_el.textContent).toBe('This contact has already been added');
|
|
||||||
|
|
||||||
input_el.value = 'Marty McFly';
|
|
||||||
modal.el.querySelector('button[type="submit"]').click();
|
|
||||||
|
|
||||||
const sent_IQs = _converse.connection.IQ_stanzas;
|
|
||||||
const sent_stanza = await u.waitUntil(() => sent_IQs.filter(iq => iq.querySelector(`iq[type="set"] query[xmlns="${Strophe.NS.ROSTER}"]`)).pop());
|
|
||||||
expect(Strophe.serialize(sent_stanza)).toEqual(
|
|
||||||
`<iq id="${sent_stanza.getAttribute('id')}" type="set" xmlns="jabber:client">`+
|
|
||||||
`<query xmlns="jabber:iq:roster"><item jid="marty@mcfly.net" name="Marty McFly"/></query>`+
|
|
||||||
`</iq>`);
|
|
||||||
window.XMLHttpRequest = XMLHttpRequestBackup;
|
|
||||||
done();
|
done();
|
||||||
}));
|
}));
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
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 mock.waitForRoster(_converse, 'all');
|
||||||
|
await mock.openControlBox(_converse);
|
||||||
|
|
||||||
|
const cbview = _converse.chatboxviews.get('controlbox');
|
||||||
|
cbview.el.querySelector('.add-contact').click()
|
||||||
|
const modal = _converse.rosterview.add_contact_modal;
|
||||||
|
await u.waitUntil(() => u.isVisible(modal.el), 1000);
|
||||||
|
expect(modal.el.querySelector('form.add-xmpp-contact')).not.toBe(null);
|
||||||
|
|
||||||
|
const input_jid = modal.el.querySelector('input[name="jid"]');
|
||||||
|
const input_name = modal.el.querySelector('input[name="name"]');
|
||||||
|
input_jid.value = 'someone@';
|
||||||
|
|
||||||
|
const evt = new Event('input');
|
||||||
|
input_jid.dispatchEvent(evt);
|
||||||
|
expect(modal.el.querySelector('.suggestion-box li').textContent).toBe('someone@montague.lit');
|
||||||
|
input_jid.value = 'someone@montague.lit';
|
||||||
|
input_name.value = 'Someone';
|
||||||
|
modal.el.querySelector('button[type="submit"]').click();
|
||||||
|
|
||||||
|
const sent_IQs = _converse.connection.IQ_stanzas;
|
||||||
|
const sent_stanza = await u.waitUntil(() => sent_IQs.filter(iq => iq.querySelector(`iq[type="set"] query[xmlns="${Strophe.NS.ROSTER}"]`)).pop());
|
||||||
|
expect(Strophe.serialize(sent_stanza)).toEqual(
|
||||||
|
`<iq id="${sent_stanza.getAttribute('id')}" type="set" xmlns="jabber:client">`+
|
||||||
|
`<query xmlns="jabber:iq:roster"><item jid="someone@montague.lit" name="Someone"/></query>`+
|
||||||
|
`</iq>`);
|
||||||
|
done();
|
||||||
|
}));
|
||||||
|
|
||||||
|
it("can be configured to not provide search suggestions",
|
||||||
|
mock.initConverse(
|
||||||
|
['rosterGroupsFetched'], {'autocomplete_add_contact': false},
|
||||||
|
async function (done, _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;
|
||||||
|
expect(modal.jid_auto_complete).toBe(undefined);
|
||||||
|
expect(modal.name_auto_complete).toBe(undefined);
|
||||||
|
|
||||||
|
await u.waitUntil(() => u.isVisible(modal.el), 1000);
|
||||||
|
expect(modal.el.querySelector('form.add-xmpp-contact')).not.toBe(null);
|
||||||
|
const input_jid = modal.el.querySelector('input[name="jid"]');
|
||||||
|
input_jid.value = 'someone@montague.lit';
|
||||||
|
modal.el.querySelector('button[type="submit"]').click();
|
||||||
|
|
||||||
|
const IQ_stanzas = _converse.connection.IQ_stanzas;
|
||||||
|
const sent_stanza = await u.waitUntil(
|
||||||
|
() => IQ_stanzas.filter(s => sizzle(`iq[type="set"] query[xmlns="${Strophe.NS.ROSTER}"]`, s).length).pop()
|
||||||
|
);
|
||||||
|
expect(Strophe.serialize(sent_stanza)).toEqual(
|
||||||
|
`<iq id="${sent_stanza.getAttribute('id')}" type="set" xmlns="jabber:client">`+
|
||||||
|
`<query xmlns="jabber:iq:roster"><item jid="someone@montague.lit"/></query>`+
|
||||||
|
`</iq>`
|
||||||
|
);
|
||||||
|
done();
|
||||||
|
}));
|
||||||
|
|
||||||
|
|
||||||
|
it("integrates with xhr_user_search_url to search for contacts",
|
||||||
|
mock.initConverse(
|
||||||
|
['rosterGroupsFetched'],
|
||||||
|
{ 'xhr_user_search_url': 'http://example.org/?' },
|
||||||
|
async function (done, _converse) {
|
||||||
|
|
||||||
|
await mock.waitForRoster(_converse, 'all', 0);
|
||||||
|
|
||||||
|
const xhr = {
|
||||||
|
'open': function open () {},
|
||||||
|
'send': function () {
|
||||||
|
xhr.responseText = JSON.stringify([
|
||||||
|
{"jid": "marty@mcfly.net", "fullname": "Marty McFly"},
|
||||||
|
{"jid": "doc@brown.com", "fullname": "Doc Brown"}
|
||||||
|
]);
|
||||||
|
xhr.onload();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const XMLHttpRequestBackup = window.XMLHttpRequest;
|
||||||
|
window.XMLHttpRequest = jasmine.createSpy('XMLHttpRequest');
|
||||||
|
XMLHttpRequest.and.callFake(() => xhr);
|
||||||
|
|
||||||
|
const cbview = _converse.chatboxviews.get('controlbox');
|
||||||
|
cbview.el.querySelector('.add-contact').click()
|
||||||
|
const modal = _converse.rosterview.add_contact_modal;
|
||||||
|
await u.waitUntil(() => u.isVisible(modal.el), 1000);
|
||||||
|
|
||||||
|
// We only have autocomplete for the name input
|
||||||
|
expect(modal.jid_auto_complete).toBe(undefined);
|
||||||
|
expect(modal.name_auto_complete instanceof _converse.AutoComplete).toBe(true);
|
||||||
|
|
||||||
|
const input_el = modal.el.querySelector('input[name="name"]');
|
||||||
|
input_el.value = 'marty';
|
||||||
|
input_el.dispatchEvent(new Event('input'));
|
||||||
|
await u.waitUntil(() => modal.el.querySelector('.suggestion-box li'), 1000);
|
||||||
|
expect(modal.el.querySelectorAll('.suggestion-box li').length).toBe(1);
|
||||||
|
const suggestion = modal.el.querySelector('.suggestion-box li');
|
||||||
|
expect(suggestion.textContent).toBe('Marty McFly');
|
||||||
|
|
||||||
|
// Mock selection
|
||||||
|
modal.name_auto_complete.select(suggestion);
|
||||||
|
|
||||||
|
expect(input_el.value).toBe('Marty McFly');
|
||||||
|
expect(modal.el.querySelector('input[name="jid"]').value).toBe('marty@mcfly.net');
|
||||||
|
modal.el.querySelector('button[type="submit"]').click();
|
||||||
|
|
||||||
|
const sent_IQs = _converse.connection.IQ_stanzas;
|
||||||
|
const sent_stanza = await u.waitUntil(() => sent_IQs.filter(iq => iq.querySelector(`iq[type="set"] query[xmlns="${Strophe.NS.ROSTER}"]`)).pop());
|
||||||
|
expect(Strophe.serialize(sent_stanza)).toEqual(
|
||||||
|
`<iq id="${sent_stanza.getAttribute('id')}" type="set" xmlns="jabber:client">`+
|
||||||
|
`<query xmlns="jabber:iq:roster"><item jid="marty@mcfly.net" name="Marty McFly"/></query>`+
|
||||||
|
`</iq>`);
|
||||||
|
window.XMLHttpRequest = XMLHttpRequestBackup;
|
||||||
|
done();
|
||||||
|
}));
|
||||||
|
|
||||||
|
it("can be configured to not provide search suggestions for XHR search results",
|
||||||
|
mock.initConverse(
|
||||||
|
['rosterGroupsFetched'],
|
||||||
|
{ 'autocomplete_add_contact': false,
|
||||||
|
'xhr_user_search_url': 'http://example.org/?' },
|
||||||
|
async function (done, _converse) {
|
||||||
|
|
||||||
|
await mock.waitForRoster(_converse, 'all');
|
||||||
|
await mock.openControlBox(_converse);
|
||||||
|
var modal;
|
||||||
|
const xhr = {
|
||||||
|
'open': function open () {},
|
||||||
|
'send': function () {
|
||||||
|
const value = modal.el.querySelector('input[name="name"]').value;
|
||||||
|
if (value === 'existing') {
|
||||||
|
const contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit';
|
||||||
|
xhr.responseText = JSON.stringify([{"jid": contact_jid, "fullname": mock.cur_names[0]}]);
|
||||||
|
} else if (value === 'romeo') {
|
||||||
|
xhr.responseText = JSON.stringify([{"jid": "romeo@montague.lit", "fullname": "Romeo Montague"}]);
|
||||||
|
} else if (value === 'ambiguous') {
|
||||||
|
xhr.responseText = JSON.stringify([
|
||||||
|
{"jid": "marty@mcfly.net", "fullname": "Marty McFly"},
|
||||||
|
{"jid": "doc@brown.com", "fullname": "Doc Brown"}
|
||||||
|
]);
|
||||||
|
} else if (value === 'insufficient') {
|
||||||
|
xhr.responseText = JSON.stringify([]);
|
||||||
|
} else {
|
||||||
|
xhr.responseText = JSON.stringify([{"jid": "marty@mcfly.net", "fullname": "Marty McFly"}]);
|
||||||
|
}
|
||||||
|
xhr.onload();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const XMLHttpRequestBackup = window.XMLHttpRequest;
|
||||||
|
window.XMLHttpRequest = jasmine.createSpy('XMLHttpRequest');
|
||||||
|
XMLHttpRequest.and.callFake(() => xhr);
|
||||||
|
|
||||||
|
const cbview = _converse.chatboxviews.get('controlbox');
|
||||||
|
cbview.el.querySelector('.add-contact').click()
|
||||||
|
modal = _converse.rosterview.add_contact_modal;
|
||||||
|
await u.waitUntil(() => u.isVisible(modal.el), 1000);
|
||||||
|
|
||||||
|
expect(modal.jid_auto_complete).toBe(undefined);
|
||||||
|
expect(modal.name_auto_complete).toBe(undefined);
|
||||||
|
|
||||||
|
const input_el = modal.el.querySelector('input[name="name"]');
|
||||||
|
input_el.value = 'ambiguous';
|
||||||
|
modal.el.querySelector('button[type="submit"]').click();
|
||||||
|
let feedback_el = modal.el.querySelector('.invalid-feedback');
|
||||||
|
expect(feedback_el.textContent).toBe('Sorry, could not find a contact with that name');
|
||||||
|
feedback_el.textContent = '';
|
||||||
|
|
||||||
|
input_el.value = 'insufficient';
|
||||||
|
modal.el.querySelector('button[type="submit"]').click();
|
||||||
|
feedback_el = modal.el.querySelector('.invalid-feedback');
|
||||||
|
expect(feedback_el.textContent).toBe('Sorry, could not find a contact with that name');
|
||||||
|
feedback_el.textContent = '';
|
||||||
|
|
||||||
|
input_el.value = 'existing';
|
||||||
|
modal.el.querySelector('button[type="submit"]').click();
|
||||||
|
feedback_el = modal.el.querySelector('.invalid-feedback');
|
||||||
|
expect(feedback_el.textContent).toBe('This contact has already been added');
|
||||||
|
|
||||||
|
input_el.value = 'Marty McFly';
|
||||||
|
modal.el.querySelector('button[type="submit"]').click();
|
||||||
|
|
||||||
|
const sent_IQs = _converse.connection.IQ_stanzas;
|
||||||
|
const sent_stanza = await u.waitUntil(() => sent_IQs.filter(iq => iq.querySelector(`iq[type="set"] query[xmlns="${Strophe.NS.ROSTER}"]`)).pop());
|
||||||
|
expect(Strophe.serialize(sent_stanza)).toEqual(
|
||||||
|
`<iq id="${sent_stanza.getAttribute('id')}" type="set" xmlns="jabber:client">`+
|
||||||
|
`<query xmlns="jabber:iq:roster"><item jid="marty@mcfly.net" name="Marty McFly"/></query>`+
|
||||||
|
`</iq>`);
|
||||||
|
window.XMLHttpRequest = XMLHttpRequestBackup;
|
||||||
|
done();
|
||||||
|
}));
|
||||||
|
});
|
||||||
|
648
spec/converse.js
648
spec/converse.js
@ -1,367 +1,365 @@
|
|||||||
window.addEventListener('converse-loaded', () => {
|
/* global mock */
|
||||||
const mock = window.mock;
|
|
||||||
const test_utils = window.test_utils;
|
|
||||||
const _ = converse.env._,
|
|
||||||
u = converse.env.utils;
|
|
||||||
|
|
||||||
describe("Converse", function() {
|
describe("Converse", function() {
|
||||||
|
|
||||||
describe("Authentication", function () {
|
describe("Authentication", function () {
|
||||||
|
|
||||||
it("needs either a bosh_service_url a websocket_url or both", mock.initConverse(async (done, _converse) => {
|
it("needs either a bosh_service_url a websocket_url or both", mock.initConverse(async (done, _converse) => {
|
||||||
const url = _converse.bosh_service_url;
|
const url = _converse.bosh_service_url;
|
||||||
const connection = _converse.connection;
|
const connection = _converse.connection;
|
||||||
delete _converse.bosh_service_url;
|
delete _converse.bosh_service_url;
|
||||||
delete _converse.connection;
|
delete _converse.connection;
|
||||||
try {
|
try {
|
||||||
await _converse.initConnection();
|
await _converse.initConnection();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
_converse.bosh_service_url = url;
|
_converse.bosh_service_url = url;
|
||||||
_converse.connection = connection;
|
_converse.connection = connection;
|
||||||
expect(e.message).toBe("initConnection: you must supply a value for either the bosh_service_url or websocket_url or both.");
|
expect(e.message).toBe("initConnection: you must supply a value for either the bosh_service_url or websocket_url or both.");
|
||||||
done();
|
|
||||||
}
|
|
||||||
}));
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("A chat state indication", function () {
|
|
||||||
|
|
||||||
it("are sent out when the client becomes or stops being idle",
|
|
||||||
mock.initConverse(['discoInitialized'], {}, (done, _converse) => {
|
|
||||||
|
|
||||||
spyOn(_converse, 'sendCSI').and.callThrough();
|
|
||||||
let sent_stanza;
|
|
||||||
spyOn(_converse.connection, 'send').and.callFake(function (stanza) {
|
|
||||||
sent_stanza = stanza;
|
|
||||||
});
|
|
||||||
let i = 0;
|
|
||||||
_converse.idle_seconds = 0; // Usually initialized by registerIntervalHandler
|
|
||||||
_converse.disco_entities.get(_converse.domain).features['urn:xmpp:csi:0'] = true; // Mock that the server supports CSI
|
|
||||||
|
|
||||||
_converse.api.settings.set('csi_waiting_time', 3);
|
|
||||||
while (i <= _converse.api.settings.get("csi_waiting_time")) {
|
|
||||||
expect(_converse.sendCSI).not.toHaveBeenCalled();
|
|
||||||
_converse.onEverySecond();
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
expect(_converse.sendCSI).toHaveBeenCalledWith('inactive');
|
|
||||||
expect(sent_stanza.toLocaleString()).toBe('<inactive xmlns="urn:xmpp:csi:0"/>');
|
|
||||||
_converse.onUserActivity();
|
|
||||||
expect(_converse.sendCSI).toHaveBeenCalledWith('active');
|
|
||||||
expect(sent_stanza.toLocaleString()).toBe('<active xmlns="urn:xmpp:csi:0"/>');
|
|
||||||
done();
|
done();
|
||||||
}));
|
}
|
||||||
});
|
}));
|
||||||
|
});
|
||||||
|
|
||||||
describe("Automatic status change", function () {
|
describe("A chat state indication", function () {
|
||||||
|
|
||||||
it("happens when the client is idle for long enough", mock.initConverse((done, _converse) => {
|
it("are sent out when the client becomes or stops being idle",
|
||||||
let i = 0;
|
mock.initConverse(['discoInitialized'], {}, (done, _converse) => {
|
||||||
// Usually initialized by registerIntervalHandler
|
|
||||||
_converse.idle_seconds = 0;
|
|
||||||
_converse.auto_changed_status = false;
|
|
||||||
_converse.api.settings.set('auto_away', 3);
|
|
||||||
_converse.api.settings.set('auto_xa', 6);
|
|
||||||
|
|
||||||
expect(_converse.api.user.status.get()).toBe('online');
|
spyOn(_converse, 'sendCSI').and.callThrough();
|
||||||
while (i <= _converse.api.settings.get("auto_away")) {
|
let sent_stanza;
|
||||||
_converse.onEverySecond(); i++;
|
spyOn(_converse.connection, 'send').and.callFake(function (stanza) {
|
||||||
}
|
sent_stanza = stanza;
|
||||||
expect(_converse.auto_changed_status).toBe(true);
|
|
||||||
|
|
||||||
while (i <= _converse.auto_xa) {
|
|
||||||
expect(_converse.api.user.status.get()).toBe('away');
|
|
||||||
_converse.onEverySecond();
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
expect(_converse.api.user.status.get()).toBe('xa');
|
|
||||||
expect(_converse.auto_changed_status).toBe(true);
|
|
||||||
|
|
||||||
_converse.onUserActivity();
|
|
||||||
expect(_converse.api.user.status.get()).toBe('online');
|
|
||||||
expect(_converse.auto_changed_status).toBe(false);
|
|
||||||
|
|
||||||
// Check that it also works for the chat feature
|
|
||||||
_converse.api.user.status.set('chat')
|
|
||||||
i = 0;
|
|
||||||
while (i <= _converse.api.settings.get("auto_away")) {
|
|
||||||
_converse.onEverySecond();
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
expect(_converse.auto_changed_status).toBe(true);
|
|
||||||
while (i <= _converse.auto_xa) {
|
|
||||||
expect(_converse.api.user.status.get()).toBe('away');
|
|
||||||
_converse.onEverySecond();
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
expect(_converse.api.user.status.get()).toBe('xa');
|
|
||||||
expect(_converse.auto_changed_status).toBe(true);
|
|
||||||
|
|
||||||
_converse.onUserActivity();
|
|
||||||
expect(_converse.api.user.status.get()).toBe('online');
|
|
||||||
expect(_converse.auto_changed_status).toBe(false);
|
|
||||||
|
|
||||||
// Check that it doesn't work for 'dnd'
|
|
||||||
_converse.api.user.status.set('dnd');
|
|
||||||
i = 0;
|
|
||||||
while (i <= _converse.api.settings.get("auto_away")) {
|
|
||||||
_converse.onEverySecond();
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
expect(_converse.api.user.status.get()).toBe('dnd');
|
|
||||||
expect(_converse.auto_changed_status).toBe(false);
|
|
||||||
while (i <= _converse.auto_xa) {
|
|
||||||
expect(_converse.api.user.status.get()).toBe('dnd');
|
|
||||||
_converse.onEverySecond();
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
expect(_converse.api.user.status.get()).toBe('dnd');
|
|
||||||
expect(_converse.auto_changed_status).toBe(false);
|
|
||||||
|
|
||||||
_converse.onUserActivity();
|
|
||||||
expect(_converse.api.user.status.get()).toBe('dnd');
|
|
||||||
expect(_converse.auto_changed_status).toBe(false);
|
|
||||||
done();
|
|
||||||
}));
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("The \"user\" grouping", function () {
|
|
||||||
|
|
||||||
describe("The \"status\" API", function () {
|
|
||||||
|
|
||||||
it("has a method for getting the user's availability", mock.initConverse((done, _converse) => {
|
|
||||||
_converse.xmppstatus.set('status', 'online');
|
|
||||||
expect(_converse.api.user.status.get()).toBe('online');
|
|
||||||
_converse.xmppstatus.set('status', 'dnd');
|
|
||||||
expect(_converse.api.user.status.get()).toBe('dnd');
|
|
||||||
done();
|
|
||||||
}));
|
|
||||||
|
|
||||||
it("has a method for setting the user's availability", mock.initConverse((done, _converse) => {
|
|
||||||
_converse.api.user.status.set('away');
|
|
||||||
expect(_converse.xmppstatus.get('status')).toBe('away');
|
|
||||||
_converse.api.user.status.set('dnd');
|
|
||||||
expect(_converse.xmppstatus.get('status')).toBe('dnd');
|
|
||||||
_converse.api.user.status.set('xa');
|
|
||||||
expect(_converse.xmppstatus.get('status')).toBe('xa');
|
|
||||||
_converse.api.user.status.set('chat');
|
|
||||||
expect(_converse.xmppstatus.get('status')).toBe('chat');
|
|
||||||
expect(_.partial(_converse.api.user.status.set, 'invalid')).toThrow(
|
|
||||||
new Error('Invalid availability value. See https://xmpp.org/rfcs/rfc3921.html#rfc.section.2.2.2.1')
|
|
||||||
);
|
|
||||||
done();
|
|
||||||
}));
|
|
||||||
|
|
||||||
it("allows setting the status message as well", mock.initConverse((done, _converse) => {
|
|
||||||
_converse.api.user.status.set('away', "I'm in a meeting");
|
|
||||||
expect(_converse.xmppstatus.get('status')).toBe('away');
|
|
||||||
expect(_converse.xmppstatus.get('status_message')).toBe("I'm in a meeting");
|
|
||||||
done();
|
|
||||||
}));
|
|
||||||
|
|
||||||
it("has a method for getting the user's status message", mock.initConverse((done, _converse) => {
|
|
||||||
_converse.xmppstatus.set('status_message', undefined);
|
|
||||||
expect(_converse.api.user.status.message.get()).toBe(undefined);
|
|
||||||
_converse.xmppstatus.set('status_message', "I'm in a meeting");
|
|
||||||
expect(_converse.api.user.status.message.get()).toBe("I'm in a meeting");
|
|
||||||
done();
|
|
||||||
}));
|
|
||||||
|
|
||||||
it("has a method for setting the user's status message", mock.initConverse((done, _converse) => {
|
|
||||||
_converse.xmppstatus.set('status_message', undefined);
|
|
||||||
_converse.api.user.status.message.set("I'm in a meeting");
|
|
||||||
expect(_converse.xmppstatus.get('status_message')).toBe("I'm in a meeting");
|
|
||||||
done();
|
|
||||||
}));
|
|
||||||
});
|
});
|
||||||
});
|
let i = 0;
|
||||||
|
_converse.idle_seconds = 0; // Usually initialized by registerIntervalHandler
|
||||||
|
_converse.disco_entities.get(_converse.domain).features['urn:xmpp:csi:0'] = true; // Mock that the server supports CSI
|
||||||
|
|
||||||
describe("The \"tokens\" API", function () {
|
_converse.api.settings.set('csi_waiting_time', 3);
|
||||||
|
while (i <= _converse.api.settings.get("csi_waiting_time")) {
|
||||||
|
expect(_converse.sendCSI).not.toHaveBeenCalled();
|
||||||
|
_converse.onEverySecond();
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
expect(_converse.sendCSI).toHaveBeenCalledWith('inactive');
|
||||||
|
expect(sent_stanza.toLocaleString()).toBe('<inactive xmlns="urn:xmpp:csi:0"/>');
|
||||||
|
_converse.onUserActivity();
|
||||||
|
expect(_converse.sendCSI).toHaveBeenCalledWith('active');
|
||||||
|
expect(sent_stanza.toLocaleString()).toBe('<active xmlns="urn:xmpp:csi:0"/>');
|
||||||
|
done();
|
||||||
|
}));
|
||||||
|
});
|
||||||
|
|
||||||
it("has a method for retrieving the next RID", mock.initConverse((done, _converse) => {
|
describe("Automatic status change", function () {
|
||||||
test_utils.createContacts(_converse, 'current');
|
|
||||||
const old_connection = _converse.connection;
|
it("happens when the client is idle for long enough", mock.initConverse((done, _converse) => {
|
||||||
_converse.connection._proto.rid = '1234';
|
let i = 0;
|
||||||
expect(_converse.api.tokens.get('rid')).toBe('1234');
|
// Usually initialized by registerIntervalHandler
|
||||||
_converse.connection = undefined;
|
_converse.idle_seconds = 0;
|
||||||
expect(_converse.api.tokens.get('rid')).toBe(null);
|
_converse.auto_changed_status = false;
|
||||||
// Restore the connection
|
_converse.api.settings.set('auto_away', 3);
|
||||||
_converse.connection = old_connection;
|
_converse.api.settings.set('auto_xa', 6);
|
||||||
|
|
||||||
|
expect(_converse.api.user.status.get()).toBe('online');
|
||||||
|
while (i <= _converse.api.settings.get("auto_away")) {
|
||||||
|
_converse.onEverySecond(); i++;
|
||||||
|
}
|
||||||
|
expect(_converse.auto_changed_status).toBe(true);
|
||||||
|
|
||||||
|
while (i <= _converse.auto_xa) {
|
||||||
|
expect(_converse.api.user.status.get()).toBe('away');
|
||||||
|
_converse.onEverySecond();
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
expect(_converse.api.user.status.get()).toBe('xa');
|
||||||
|
expect(_converse.auto_changed_status).toBe(true);
|
||||||
|
|
||||||
|
_converse.onUserActivity();
|
||||||
|
expect(_converse.api.user.status.get()).toBe('online');
|
||||||
|
expect(_converse.auto_changed_status).toBe(false);
|
||||||
|
|
||||||
|
// Check that it also works for the chat feature
|
||||||
|
_converse.api.user.status.set('chat')
|
||||||
|
i = 0;
|
||||||
|
while (i <= _converse.api.settings.get("auto_away")) {
|
||||||
|
_converse.onEverySecond();
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
expect(_converse.auto_changed_status).toBe(true);
|
||||||
|
while (i <= _converse.auto_xa) {
|
||||||
|
expect(_converse.api.user.status.get()).toBe('away');
|
||||||
|
_converse.onEverySecond();
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
expect(_converse.api.user.status.get()).toBe('xa');
|
||||||
|
expect(_converse.auto_changed_status).toBe(true);
|
||||||
|
|
||||||
|
_converse.onUserActivity();
|
||||||
|
expect(_converse.api.user.status.get()).toBe('online');
|
||||||
|
expect(_converse.auto_changed_status).toBe(false);
|
||||||
|
|
||||||
|
// Check that it doesn't work for 'dnd'
|
||||||
|
_converse.api.user.status.set('dnd');
|
||||||
|
i = 0;
|
||||||
|
while (i <= _converse.api.settings.get("auto_away")) {
|
||||||
|
_converse.onEverySecond();
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
expect(_converse.api.user.status.get()).toBe('dnd');
|
||||||
|
expect(_converse.auto_changed_status).toBe(false);
|
||||||
|
while (i <= _converse.auto_xa) {
|
||||||
|
expect(_converse.api.user.status.get()).toBe('dnd');
|
||||||
|
_converse.onEverySecond();
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
expect(_converse.api.user.status.get()).toBe('dnd');
|
||||||
|
expect(_converse.auto_changed_status).toBe(false);
|
||||||
|
|
||||||
|
_converse.onUserActivity();
|
||||||
|
expect(_converse.api.user.status.get()).toBe('dnd');
|
||||||
|
expect(_converse.auto_changed_status).toBe(false);
|
||||||
|
done();
|
||||||
|
}));
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("The \"user\" grouping", function () {
|
||||||
|
|
||||||
|
describe("The \"status\" API", function () {
|
||||||
|
|
||||||
|
it("has a method for getting the user's availability", mock.initConverse((done, _converse) => {
|
||||||
|
_converse.xmppstatus.set('status', 'online');
|
||||||
|
expect(_converse.api.user.status.get()).toBe('online');
|
||||||
|
_converse.xmppstatus.set('status', 'dnd');
|
||||||
|
expect(_converse.api.user.status.get()).toBe('dnd');
|
||||||
done();
|
done();
|
||||||
}));
|
}));
|
||||||
|
|
||||||
it("has a method for retrieving the SID", mock.initConverse((done, _converse) => {
|
it("has a method for setting the user's availability", mock.initConverse((done, _converse) => {
|
||||||
test_utils.createContacts(_converse, 'current');
|
_converse.api.user.status.set('away');
|
||||||
const old_connection = _converse.connection;
|
expect(_converse.xmppstatus.get('status')).toBe('away');
|
||||||
_converse.connection._proto.sid = '1234';
|
_converse.api.user.status.set('dnd');
|
||||||
expect(_converse.api.tokens.get('sid')).toBe('1234');
|
expect(_converse.xmppstatus.get('status')).toBe('dnd');
|
||||||
_converse.connection = undefined;
|
_converse.api.user.status.set('xa');
|
||||||
expect(_converse.api.tokens.get('sid')).toBe(null);
|
expect(_converse.xmppstatus.get('status')).toBe('xa');
|
||||||
// Restore the connection
|
_converse.api.user.status.set('chat');
|
||||||
_converse.connection = old_connection;
|
expect(_converse.xmppstatus.get('status')).toBe('chat');
|
||||||
|
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();
|
||||||
|
}));
|
||||||
|
|
||||||
|
it("allows setting the status message as well", mock.initConverse((done, _converse) => {
|
||||||
|
_converse.api.user.status.set('away', "I'm in a meeting");
|
||||||
|
expect(_converse.xmppstatus.get('status')).toBe('away');
|
||||||
|
expect(_converse.xmppstatus.get('status_message')).toBe("I'm in a meeting");
|
||||||
|
done();
|
||||||
|
}));
|
||||||
|
|
||||||
|
it("has a method for getting the user's status message", mock.initConverse((done, _converse) => {
|
||||||
|
_converse.xmppstatus.set('status_message', undefined);
|
||||||
|
expect(_converse.api.user.status.message.get()).toBe(undefined);
|
||||||
|
_converse.xmppstatus.set('status_message', "I'm in a meeting");
|
||||||
|
expect(_converse.api.user.status.message.get()).toBe("I'm in a meeting");
|
||||||
|
done();
|
||||||
|
}));
|
||||||
|
|
||||||
|
it("has a method for setting the user's status message", mock.initConverse((done, _converse) => {
|
||||||
|
_converse.xmppstatus.set('status_message', undefined);
|
||||||
|
_converse.api.user.status.message.set("I'm in a meeting");
|
||||||
|
expect(_converse.xmppstatus.get('status_message')).toBe("I'm in a meeting");
|
||||||
done();
|
done();
|
||||||
}));
|
}));
|
||||||
});
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe("The \"contacts\" API", function () {
|
describe("The \"tokens\" API", function () {
|
||||||
|
|
||||||
it("has a method 'get' which returns wrapped contacts",
|
it("has a method for retrieving the next RID", mock.initConverse((done, _converse) => {
|
||||||
mock.initConverse([], {}, async function (done, _converse) {
|
mock.createContacts(_converse, 'current');
|
||||||
|
const old_connection = _converse.connection;
|
||||||
|
_converse.connection._proto.rid = '1234';
|
||||||
|
expect(_converse.api.tokens.get('rid')).toBe('1234');
|
||||||
|
_converse.connection = undefined;
|
||||||
|
expect(_converse.api.tokens.get('rid')).toBe(null);
|
||||||
|
// Restore the connection
|
||||||
|
_converse.connection = old_connection;
|
||||||
|
done();
|
||||||
|
}));
|
||||||
|
|
||||||
await test_utils.waitForRoster(_converse, 'current');
|
it("has a method for retrieving the SID", mock.initConverse((done, _converse) => {
|
||||||
let contact = await _converse.api.contacts.get('non-existing@jabber.org');
|
mock.createContacts(_converse, 'current');
|
||||||
expect(contact).toBeFalsy();
|
const old_connection = _converse.connection;
|
||||||
// Check when a single jid is given
|
_converse.connection._proto.sid = '1234';
|
||||||
const jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit';
|
expect(_converse.api.tokens.get('sid')).toBe('1234');
|
||||||
contact = await _converse.api.contacts.get(jid);
|
_converse.connection = undefined;
|
||||||
expect(contact.getDisplayName()).toBe(mock.cur_names[0]);
|
expect(_converse.api.tokens.get('sid')).toBe(null);
|
||||||
expect(contact.get('jid')).toBe(jid);
|
// Restore the connection
|
||||||
// You can retrieve multiple contacts by passing in an array
|
_converse.connection = old_connection;
|
||||||
const jid2 = mock.cur_names[1].replace(/ /g,'.').toLowerCase() + '@montague.lit';
|
done();
|
||||||
let list = await _converse.api.contacts.get([jid, jid2]);
|
}));
|
||||||
expect(Array.isArray(list)).toBeTruthy();
|
});
|
||||||
expect(list[0].getDisplayName()).toBe(mock.cur_names[0]);
|
|
||||||
expect(list[1].getDisplayName()).toBe(mock.cur_names[1]);
|
|
||||||
// Check that all JIDs are returned if you call without any parameters
|
|
||||||
list = await _converse.api.contacts.get();
|
|
||||||
expect(list.length).toBe(mock.cur_names.length);
|
|
||||||
done();
|
|
||||||
}));
|
|
||||||
|
|
||||||
it("has a method 'add' with which contacts can be added",
|
describe("The \"contacts\" API", function () {
|
||||||
mock.initConverse(['rosterInitialized'], {}, async (done, _converse) => {
|
|
||||||
|
|
||||||
await test_utils.waitForRoster(_converse, 'current', 0);
|
it("has a method 'get' which returns wrapped contacts",
|
||||||
try {
|
mock.initConverse([], {}, async function (done, _converse) {
|
||||||
await _converse.api.contacts.add();
|
|
||||||
throw new Error('Call should have failed');
|
|
||||||
} catch (e) {
|
|
||||||
expect(e.message).toBe('contacts.add: invalid jid');
|
|
||||||
|
|
||||||
}
|
await mock.waitForRoster(_converse, 'current');
|
||||||
try {
|
let contact = await _converse.api.contacts.get('non-existing@jabber.org');
|
||||||
await _converse.api.contacts.add("invalid jid");
|
expect(contact).toBeFalsy();
|
||||||
throw new Error('Call should have failed');
|
// Check when a single jid is given
|
||||||
} catch (e) {
|
const jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit';
|
||||||
expect(e.message).toBe('contacts.add: invalid jid');
|
contact = await _converse.api.contacts.get(jid);
|
||||||
}
|
expect(contact.getDisplayName()).toBe(mock.cur_names[0]);
|
||||||
spyOn(_converse.roster, 'addAndSubscribe');
|
expect(contact.get('jid')).toBe(jid);
|
||||||
await _converse.api.contacts.add("newcontact@example.org");
|
// You can retrieve multiple contacts by passing in an array
|
||||||
expect(_converse.roster.addAndSubscribe).toHaveBeenCalled();
|
const jid2 = mock.cur_names[1].replace(/ /g,'.').toLowerCase() + '@montague.lit';
|
||||||
done();
|
let list = await _converse.api.contacts.get([jid, jid2]);
|
||||||
}));
|
expect(Array.isArray(list)).toBeTruthy();
|
||||||
});
|
expect(list[0].getDisplayName()).toBe(mock.cur_names[0]);
|
||||||
|
expect(list[1].getDisplayName()).toBe(mock.cur_names[1]);
|
||||||
|
// Check that all JIDs are returned if you call without any parameters
|
||||||
|
list = await _converse.api.contacts.get();
|
||||||
|
expect(list.length).toBe(mock.cur_names.length);
|
||||||
|
done();
|
||||||
|
}));
|
||||||
|
|
||||||
describe("The \"chats\" API", function() {
|
it("has a method 'add' with which contacts can be added",
|
||||||
|
mock.initConverse(['rosterInitialized'], {}, async (done, _converse) => {
|
||||||
|
|
||||||
it("has a method 'get' which returns the promise that resolves to a chat model", mock.initConverse(
|
await mock.waitForRoster(_converse, 'current', 0);
|
||||||
|
try {
|
||||||
|
await _converse.api.contacts.add();
|
||||||
|
throw new Error('Call should have failed');
|
||||||
|
} catch (e) {
|
||||||
|
expect(e.message).toBe('contacts.add: invalid jid');
|
||||||
|
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
await _converse.api.contacts.add("invalid jid");
|
||||||
|
throw new Error('Call should have failed');
|
||||||
|
} catch (e) {
|
||||||
|
expect(e.message).toBe('contacts.add: invalid jid');
|
||||||
|
}
|
||||||
|
spyOn(_converse.roster, 'addAndSubscribe');
|
||||||
|
await _converse.api.contacts.add("newcontact@example.org");
|
||||||
|
expect(_converse.roster.addAndSubscribe).toHaveBeenCalled();
|
||||||
|
done();
|
||||||
|
}));
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("The \"chats\" API", function() {
|
||||||
|
|
||||||
|
it("has a method 'get' which returns the promise that resolves to a chat model", mock.initConverse(
|
||||||
['rosterInitialized', 'chatBoxesInitialized'], {},
|
['rosterInitialized', 'chatBoxesInitialized'], {},
|
||||||
async (done, _converse) => {
|
async (done, _converse) => {
|
||||||
|
|
||||||
await test_utils.openControlBox(_converse);
|
const u = converse.env.utils;
|
||||||
await test_utils.waitForRoster(_converse, 'current', 2);
|
|
||||||
|
|
||||||
// Test on chat that doesn't exist.
|
await mock.openControlBox(_converse);
|
||||||
let chat = await _converse.api.chats.get('non-existing@jabber.org');
|
await mock.waitForRoster(_converse, 'current', 2);
|
||||||
expect(chat).toBeFalsy();
|
|
||||||
const jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit';
|
|
||||||
const jid2 = mock.cur_names[1].replace(/ /g,'.').toLowerCase() + '@montague.lit';
|
|
||||||
|
|
||||||
// Test on chat that's not open
|
// Test on chat that doesn't exist.
|
||||||
chat = await _converse.api.chats.get(jid);
|
let chat = await _converse.api.chats.get('non-existing@jabber.org');
|
||||||
expect(chat === null).toBeTruthy();
|
expect(chat).toBeFalsy();
|
||||||
expect(_converse.chatboxes.length).toBe(1);
|
const jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit';
|
||||||
|
const jid2 = mock.cur_names[1].replace(/ /g,'.').toLowerCase() + '@montague.lit';
|
||||||
|
|
||||||
// Test for one JID
|
// Test on chat that's not open
|
||||||
chat = await _converse.api.chats.open(jid);
|
chat = await _converse.api.chats.get(jid);
|
||||||
expect(chat instanceof Object).toBeTruthy();
|
expect(chat === null).toBeTruthy();
|
||||||
expect(chat.get('box_id')).toBe(`box-${btoa(jid)}`);
|
expect(_converse.chatboxes.length).toBe(1);
|
||||||
|
|
||||||
const view = _converse.chatboxviews.get(jid);
|
// Test for one JID
|
||||||
await u.waitUntil(() => u.isVisible(view.el));
|
chat = await _converse.api.chats.open(jid);
|
||||||
// Test for multiple JIDs
|
expect(chat instanceof Object).toBeTruthy();
|
||||||
test_utils.openChatBoxFor(_converse, jid2);
|
expect(chat.get('box_id')).toBe(`box-${btoa(jid)}`);
|
||||||
await u.waitUntil(() => _converse.chatboxes.length == 3);
|
|
||||||
const list = await _converse.api.chats.get([jid, jid2]);
|
|
||||||
expect(Array.isArray(list)).toBeTruthy();
|
|
||||||
expect(list[0].get('box_id')).toBe(`box-${btoa(jid)}`);
|
|
||||||
expect(list[1].get('box_id')).toBe(`box-${btoa(jid2)}`);
|
|
||||||
done();
|
|
||||||
}));
|
|
||||||
|
|
||||||
it("has a method 'open' which opens and returns a promise that resolves to a chat model", mock.initConverse(
|
const view = _converse.chatboxviews.get(jid);
|
||||||
|
await u.waitUntil(() => u.isVisible(view.el));
|
||||||
|
// Test for multiple JIDs
|
||||||
|
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();
|
||||||
|
expect(list[0].get('box_id')).toBe(`box-${btoa(jid)}`);
|
||||||
|
expect(list[1].get('box_id')).toBe(`box-${btoa(jid2)}`);
|
||||||
|
done();
|
||||||
|
}));
|
||||||
|
|
||||||
|
it("has a method 'open' which opens and returns a promise that resolves to a chat model", mock.initConverse(
|
||||||
['rosterGroupsFetched', 'chatBoxesInitialized'], {},
|
['rosterGroupsFetched', 'chatBoxesInitialized'], {},
|
||||||
async (done, _converse) => {
|
async (done, _converse) => {
|
||||||
|
|
||||||
await test_utils.openControlBox(_converse);
|
const u = converse.env.utils;
|
||||||
await test_utils.waitForRoster(_converse, 'current', 2);
|
await mock.openControlBox(_converse);
|
||||||
|
await mock.waitForRoster(_converse, 'current', 2);
|
||||||
|
|
||||||
const jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit';
|
const jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit';
|
||||||
const jid2 = mock.cur_names[1].replace(/ /g,'.').toLowerCase() + '@montague.lit';
|
const jid2 = mock.cur_names[1].replace(/ /g,'.').toLowerCase() + '@montague.lit';
|
||||||
// Test on chat that doesn't exist.
|
// Test on chat that doesn't exist.
|
||||||
let chat = await _converse.api.chats.get('non-existing@jabber.org');
|
let chat = await _converse.api.chats.get('non-existing@jabber.org');
|
||||||
expect(chat).toBeFalsy();
|
expect(chat).toBeFalsy();
|
||||||
|
|
||||||
chat = await _converse.api.chats.open(jid);
|
chat = await _converse.api.chats.open(jid);
|
||||||
expect(chat instanceof Object).toBeTruthy();
|
expect(chat instanceof Object).toBeTruthy();
|
||||||
expect(chat.get('box_id')).toBe(`box-${btoa(jid)}`);
|
expect(chat.get('box_id')).toBe(`box-${btoa(jid)}`);
|
||||||
expect(
|
expect(
|
||||||
Object.keys(chat),
|
Object.keys(chat),
|
||||||
['close', 'endOTR', 'focus', 'get', 'initiateOTR', 'is_chatroom', 'maximize', 'minimize', 'open', 'set']
|
['close', 'endOTR', 'focus', 'get', 'initiateOTR', 'is_chatroom', 'maximize', 'minimize', 'open', 'set']
|
||||||
);
|
);
|
||||||
const view = _converse.chatboxviews.get(jid);
|
const view = _converse.chatboxviews.get(jid);
|
||||||
await u.waitUntil(() => u.isVisible(view.el));
|
await u.waitUntil(() => u.isVisible(view.el));
|
||||||
// Test for multiple JIDs
|
// Test for multiple JIDs
|
||||||
const list = await _converse.api.chats.open([jid, jid2]);
|
const list = await _converse.api.chats.open([jid, jid2]);
|
||||||
expect(Array.isArray(list)).toBeTruthy();
|
expect(Array.isArray(list)).toBeTruthy();
|
||||||
expect(list[0].get('box_id')).toBe(`box-${btoa(jid)}`);
|
expect(list[0].get('box_id')).toBe(`box-${btoa(jid)}`);
|
||||||
expect(list[1].get('box_id')).toBe(`box-${btoa(jid2)}`);
|
expect(list[1].get('box_id')).toBe(`box-${btoa(jid2)}`);
|
||||||
|
done();
|
||||||
|
}));
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("The \"settings\" API", function() {
|
||||||
|
it("has methods 'get' and 'set' to set configuration settings",
|
||||||
|
mock.initConverse(null, {'play_sounds': true}, (done, _converse) => {
|
||||||
|
|
||||||
|
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);
|
||||||
|
_converse.api.settings.set({"play_sounds": true});
|
||||||
|
expect(_converse.api.settings.get("play_sounds")).toBe(true);
|
||||||
|
// Only whitelisted settings allowed.
|
||||||
|
expect(typeof _converse.api.settings.get("non_existing")).toBe("undefined");
|
||||||
|
_converse.api.settings.set("non_existing", true);
|
||||||
|
expect(typeof _converse.api.settings.get("non_existing")).toBe("undefined");
|
||||||
|
done();
|
||||||
|
}));
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("The \"plugins\" API", function() {
|
||||||
|
it("only has a method 'add' for registering plugins", mock.initConverse((done, _converse) => {
|
||||||
|
expect(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(Object.keys(_converse.pluggable.plugins)).toEqual(['plugin1']);
|
||||||
|
converse.plugins.add('plugin2', {});
|
||||||
|
expect(Object.keys(_converse.pluggable.plugins)).toEqual(['plugin1', 'plugin2']);
|
||||||
|
_converse.pluggable.plugins = _old_plugins;
|
||||||
|
done();
|
||||||
|
}));
|
||||||
|
|
||||||
|
describe("The \"plugins.add\" method", function() {
|
||||||
|
it("throws an error when multiple plugins attempt to register with the same name",
|
||||||
|
mock.initConverse((done, _converse) => { // eslint-disable-line no-unused-vars
|
||||||
|
|
||||||
|
converse.plugins.add('myplugin', {});
|
||||||
|
const error = new TypeError('Error: plugin with name "myplugin" has already been registered!');
|
||||||
|
expect(() => converse.plugins.add('myplugin', {})).toThrow(error);
|
||||||
done();
|
done();
|
||||||
}));
|
}));
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("The \"settings\" API", function() {
|
|
||||||
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(_converse.api.settings.get("play_sounds")).toBe(true);
|
|
||||||
_converse.api.settings.set("play_sounds", false);
|
|
||||||
expect(_converse.api.settings.get("play_sounds")).toBe(false);
|
|
||||||
_converse.api.settings.set({"play_sounds": true});
|
|
||||||
expect(_converse.api.settings.get("play_sounds")).toBe(true);
|
|
||||||
// Only whitelisted settings allowed.
|
|
||||||
expect(typeof _converse.api.settings.get("non_existing")).toBe("undefined");
|
|
||||||
_converse.api.settings.set("non_existing", true);
|
|
||||||
expect(typeof _converse.api.settings.get("non_existing")).toBe("undefined");
|
|
||||||
done();
|
|
||||||
}));
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("The \"plugins\" API", function() {
|
|
||||||
it("only has a method 'add' for registering plugins", mock.initConverse((done, _converse) => {
|
|
||||||
expect(_.keys(converse.plugins)).toEqual(["add"]);
|
|
||||||
// Cheating a little bit. We clear the plugins to test more easily.
|
|
||||||
const _old_plugins = _converse.pluggable.plugins;
|
|
||||||
_converse.pluggable.plugins = [];
|
|
||||||
converse.plugins.add('plugin1', {});
|
|
||||||
expect(_.keys(_converse.pluggable.plugins)).toEqual(['plugin1']);
|
|
||||||
converse.plugins.add('plugin2', {});
|
|
||||||
expect(_.keys(_converse.pluggable.plugins)).toEqual(['plugin1', 'plugin2']);
|
|
||||||
_converse.pluggable.plugins = _old_plugins;
|
|
||||||
done();
|
|
||||||
}));
|
|
||||||
|
|
||||||
describe("The \"plugins.add\" method", function() {
|
|
||||||
it("throws an error when multiple plugins attempt to register with the same name",
|
|
||||||
mock.initConverse((done, _converse) => { // eslint-disable-line no-unused-vars
|
|
||||||
|
|
||||||
converse.plugins.add('myplugin', {});
|
|
||||||
const error = new TypeError('Error: plugin with name "myplugin" has already been registered!');
|
|
||||||
expect(_.partial(converse.plugins.add, 'myplugin', {})).toThrow(error);
|
|
||||||
done();
|
|
||||||
}));
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
353
spec/disco.js
353
spec/disco.js
@ -1,190 +1,183 @@
|
|||||||
window.addEventListener('converse-loaded', () => {
|
/*global mock */
|
||||||
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;
|
|
||||||
|
|
||||||
describe("Service Discovery", function () {
|
describe("Service Discovery", function () {
|
||||||
|
|
||||||
describe("Whenever converse.js queries a server for its features", function () {
|
describe("Whenever converse.js queries a server for its features", function () {
|
||||||
|
|
||||||
it("stores the features it receives",
|
it("stores the features it receives",
|
||||||
mock.initConverse(
|
mock.initConverse(
|
||||||
['discoInitialized'], {},
|
['discoInitialized'], {},
|
||||||
async function (done, _converse) {
|
async function (done, _converse) {
|
||||||
|
|
||||||
const IQ_stanzas = _converse.connection.IQ_stanzas;
|
const { u, $iq } = converse.env;
|
||||||
const IQ_ids = _converse.connection.IQ_ids;
|
const IQ_stanzas = _converse.connection.IQ_stanzas;
|
||||||
await u.waitUntil(function () {
|
const IQ_ids = _converse.connection.IQ_ids;
|
||||||
return _.filter(IQ_stanzas, function (iq) {
|
await u.waitUntil(function () {
|
||||||
return iq.querySelector('iq[to="montague.lit"] query[xmlns="http://jabber.org/protocol/disco#info"]');
|
return IQ_stanzas.filter(function (iq) {
|
||||||
}).length > 0;
|
|
||||||
});
|
|
||||||
/* <iq type='result'
|
|
||||||
* from='plays.shakespeare.lit'
|
|
||||||
* to='romeo@montague.net/orchard'
|
|
||||||
* id='info1'>
|
|
||||||
* <query xmlns='http://jabber.org/protocol/disco#info'>
|
|
||||||
* <identity
|
|
||||||
* category='server'
|
|
||||||
* type='im'/>
|
|
||||||
* <identity
|
|
||||||
* category='conference'
|
|
||||||
* type='text'
|
|
||||||
* name='Play-Specific Chatrooms'/>
|
|
||||||
* <identity
|
|
||||||
* category='directory'
|
|
||||||
* type='chatroom'
|
|
||||||
* name='Play-Specific Chatrooms'/>
|
|
||||||
* <feature var='http://jabber.org/protocol/disco#info'/>
|
|
||||||
* <feature var='http://jabber.org/protocol/disco#items'/>
|
|
||||||
* <feature var='http://jabber.org/protocol/muc'/>
|
|
||||||
* <feature var='jabber:iq:register'/>
|
|
||||||
* <feature var='jabber:iq:search'/>
|
|
||||||
* <feature var='jabber:iq:time'/>
|
|
||||||
* <feature var='jabber:iq:version'/>
|
|
||||||
* </query>
|
|
||||||
* </iq>
|
|
||||||
*/
|
|
||||||
let stanza = _.find(IQ_stanzas, function (iq) {
|
|
||||||
return iq.querySelector('iq[to="montague.lit"] query[xmlns="http://jabber.org/protocol/disco#info"]');
|
return iq.querySelector('iq[to="montague.lit"] query[xmlns="http://jabber.org/protocol/disco#info"]');
|
||||||
|
}).length > 0;
|
||||||
|
});
|
||||||
|
/* <iq type='result'
|
||||||
|
* from='plays.shakespeare.lit'
|
||||||
|
* to='romeo@montague.net/orchard'
|
||||||
|
* id='info1'>
|
||||||
|
* <query xmlns='http://jabber.org/protocol/disco#info'>
|
||||||
|
* <identity
|
||||||
|
* category='server'
|
||||||
|
* type='im'/>
|
||||||
|
* <identity
|
||||||
|
* category='conference'
|
||||||
|
* type='text'
|
||||||
|
* name='Play-Specific Chatrooms'/>
|
||||||
|
* <identity
|
||||||
|
* category='directory'
|
||||||
|
* type='chatroom'
|
||||||
|
* name='Play-Specific Chatrooms'/>
|
||||||
|
* <feature var='http://jabber.org/protocol/disco#info'/>
|
||||||
|
* <feature var='http://jabber.org/protocol/disco#items'/>
|
||||||
|
* <feature var='http://jabber.org/protocol/muc'/>
|
||||||
|
* <feature var='jabber:iq:register'/>
|
||||||
|
* <feature var='jabber:iq:search'/>
|
||||||
|
* <feature var='jabber:iq:time'/>
|
||||||
|
* <feature var='jabber:iq:version'/>
|
||||||
|
* </query>
|
||||||
|
* </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)];
|
||||||
|
stanza = $iq({
|
||||||
|
'type': 'result',
|
||||||
|
'from': 'montague.lit',
|
||||||
|
'to': 'romeo@montague.lit/orchard',
|
||||||
|
'id': info_IQ_id
|
||||||
|
}).c('query', {'xmlns': 'http://jabber.org/protocol/disco#info'})
|
||||||
|
.c('identity', {
|
||||||
|
'category': 'server',
|
||||||
|
'type': 'im'}).up()
|
||||||
|
.c('identity', {
|
||||||
|
'category': 'conference',
|
||||||
|
'type': 'text',
|
||||||
|
'name': 'Play-Specific Chatrooms'}).up()
|
||||||
|
.c('identity', {
|
||||||
|
'category': 'directory',
|
||||||
|
'type': 'chatroom',
|
||||||
|
'name': 'Play-Specific Chatrooms'}).up()
|
||||||
|
.c('feature', {
|
||||||
|
'var': 'http://jabber.org/protocol/disco#info'}).up()
|
||||||
|
.c('feature', {
|
||||||
|
'var': 'http://jabber.org/protocol/disco#items'}).up()
|
||||||
|
.c('feature', {
|
||||||
|
'var': 'jabber:iq:register'}).up()
|
||||||
|
.c('feature', {
|
||||||
|
'var': 'jabber:iq:time'}).up()
|
||||||
|
.c('feature', {
|
||||||
|
'var': 'jabber:iq:version'});
|
||||||
|
_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
|
||||||
|
expect(entities.get(_converse.domain).features.length).toBe(5);
|
||||||
|
expect(entities.get(_converse.domain).identities.length).toBe(3);
|
||||||
|
expect(entities.get('montague.lit').features.where({'var': 'jabber:iq:version'}).length).toBe(1);
|
||||||
|
expect(entities.get('montague.lit').features.where({'var': 'jabber:iq:time'}).length).toBe(1);
|
||||||
|
expect(entities.get('montague.lit').features.where({'var': 'jabber:iq:register'}).length).toBe(1);
|
||||||
|
expect(entities.get('montague.lit').features.where(
|
||||||
|
{'var': 'http://jabber.org/protocol/disco#items'}).length).toBe(1);
|
||||||
|
expect(entities.get('montague.lit').features.where(
|
||||||
|
{'var': 'http://jabber.org/protocol/disco#info'}).length).toBe(1);
|
||||||
|
|
||||||
|
await u.waitUntil(function () {
|
||||||
|
// Converse.js sees that the entity has a disco#items feature,
|
||||||
|
// so it will make a query for it.
|
||||||
|
return IQ_stanzas.filter(iq => iq.querySelector('query[xmlns="http://jabber.org/protocol/disco#items"]')).length > 0;
|
||||||
|
});
|
||||||
|
/* <iq type='result'
|
||||||
|
* from='catalog.shakespeare.lit'
|
||||||
|
* to='romeo@montague.net/orchard'
|
||||||
|
* id='items2'>
|
||||||
|
* <query xmlns='http://jabber.org/protocol/disco#items'>
|
||||||
|
* <item jid='people.shakespeare.lit'
|
||||||
|
* name='Directory of Characters'/>
|
||||||
|
* <item jid='plays.shakespeare.lit'
|
||||||
|
* name='Play-Specific Chatrooms'/>
|
||||||
|
* <item jid='mim.shakespeare.lit'
|
||||||
|
* name='Gateway to Marlowe IM'/>
|
||||||
|
* <item jid='words.shakespeare.lit'
|
||||||
|
* name='Shakespearean Lexicon'/>
|
||||||
|
*
|
||||||
|
* <item jid='catalog.shakespeare.lit'
|
||||||
|
* node='books'
|
||||||
|
* name='Books by and about Shakespeare'/>
|
||||||
|
* <item jid='catalog.shakespeare.lit'
|
||||||
|
* node='clothing'
|
||||||
|
* name='Wear your literary taste with pride'/>
|
||||||
|
* <item jid='catalog.shakespeare.lit'
|
||||||
|
* node='music'
|
||||||
|
* name='Music from the time of Shakespeare'/>
|
||||||
|
* </query>
|
||||||
|
* </iq>
|
||||||
|
*/
|
||||||
|
stanza = IQ_stanzas.find(function (iq) {
|
||||||
|
return iq.querySelector('iq[to="montague.lit"] query[xmlns="http://jabber.org/protocol/disco#items"]');
|
||||||
|
});
|
||||||
|
const items_IQ_id = IQ_ids[IQ_stanzas.indexOf(stanza)];
|
||||||
|
stanza = $iq({
|
||||||
|
'type': 'result',
|
||||||
|
'from': 'montague.lit',
|
||||||
|
'to': 'romeo@montague.lit/orchard',
|
||||||
|
'id': items_IQ_id
|
||||||
|
}).c('query', {'xmlns': 'http://jabber.org/protocol/disco#items'})
|
||||||
|
.c('item', {
|
||||||
|
'jid': 'people.shakespeare.lit',
|
||||||
|
'name': 'Directory of Characters'}).up()
|
||||||
|
.c('item', {
|
||||||
|
'jid': 'plays.shakespeare.lit',
|
||||||
|
'name': 'Play-Specific Chatrooms'}).up()
|
||||||
|
.c('item', {
|
||||||
|
'jid': 'words.shakespeare.lit',
|
||||||
|
'name': 'Gateway to Marlowe IM'}).up()
|
||||||
|
|
||||||
|
.c('item', {
|
||||||
|
'jid': 'montague.lit',
|
||||||
|
'node': 'books',
|
||||||
|
'name': 'Books by and about Shakespeare'}).up()
|
||||||
|
.c('item', {
|
||||||
|
'node': 'montague.lit',
|
||||||
|
'name': 'Wear your literary taste with pride'}).up()
|
||||||
|
.c('item', {
|
||||||
|
'jid': 'montague.lit',
|
||||||
|
'node': 'music',
|
||||||
|
'name': 'Music from the time of Shakespeare'
|
||||||
});
|
});
|
||||||
const info_IQ_id = IQ_ids[IQ_stanzas.indexOf(stanza)];
|
_converse.connection._dataRecv(mock.createRequest(stanza));
|
||||||
stanza = $iq({
|
await u.waitUntil(() => _converse.disco_entities);
|
||||||
'type': 'result',
|
entities = _converse.disco_entities;
|
||||||
'from': 'montague.lit',
|
expect(entities.length).toBe(2); // We have an extra entity, which is the user's JID
|
||||||
'to': 'romeo@montague.lit/orchard',
|
expect(entities.get(_converse.domain).items.length).toBe(3);
|
||||||
'id': info_IQ_id
|
expect(entities.get(_converse.domain).items.pluck('jid').includes('people.shakespeare.lit')).toBeTruthy();
|
||||||
}).c('query', {'xmlns': 'http://jabber.org/protocol/disco#info'})
|
expect(entities.get(_converse.domain).items.pluck('jid').includes('plays.shakespeare.lit')).toBeTruthy();
|
||||||
.c('identity', {
|
expect(entities.get(_converse.domain).items.pluck('jid').includes('words.shakespeare.lit')).toBeTruthy();
|
||||||
'category': 'server',
|
expect(entities.get(_converse.domain).identities.where({'category': 'conference'}).length).toBe(1);
|
||||||
'type': 'im'}).up()
|
expect(entities.get(_converse.domain).identities.where({'category': 'directory'}).length).toBe(1);
|
||||||
.c('identity', {
|
done();
|
||||||
'category': 'conference',
|
}));
|
||||||
'type': 'text',
|
});
|
||||||
'name': 'Play-Specific Chatrooms'}).up()
|
|
||||||
.c('identity', {
|
|
||||||
'category': 'directory',
|
|
||||||
'type': 'chatroom',
|
|
||||||
'name': 'Play-Specific Chatrooms'}).up()
|
|
||||||
.c('feature', {
|
|
||||||
'var': 'http://jabber.org/protocol/disco#info'}).up()
|
|
||||||
.c('feature', {
|
|
||||||
'var': 'http://jabber.org/protocol/disco#items'}).up()
|
|
||||||
.c('feature', {
|
|
||||||
'var': 'jabber:iq:register'}).up()
|
|
||||||
.c('feature', {
|
|
||||||
'var': 'jabber:iq:time'}).up()
|
|
||||||
.c('feature', {
|
|
||||||
'var': 'jabber:iq:version'});
|
|
||||||
_converse.connection._dataRecv(test_utils.createRequest(stanza));
|
|
||||||
|
|
||||||
let entities = await _converse.api.disco.entities.get()
|
describe("Whenever converse.js discovers a new server feature", function () {
|
||||||
expect(entities.length).toBe(2); // We have an extra entity, which is the user's JID
|
it("emits the serviceDiscovered event",
|
||||||
expect(entities.get(_converse.domain).features.length).toBe(5);
|
mock.initConverse(
|
||||||
expect(entities.get(_converse.domain).identities.length).toBe(3);
|
['discoInitialized'], {},
|
||||||
expect(entities.get('montague.lit').features.where({'var': 'jabber:iq:version'}).length).toBe(1);
|
function (done, _converse) {
|
||||||
expect(entities.get('montague.lit').features.where({'var': 'jabber:iq:time'}).length).toBe(1);
|
|
||||||
expect(entities.get('montague.lit').features.where({'var': 'jabber:iq:register'}).length).toBe(1);
|
|
||||||
expect(entities.get('montague.lit').features.where(
|
|
||||||
{'var': 'http://jabber.org/protocol/disco#items'}).length).toBe(1);
|
|
||||||
expect(entities.get('montague.lit').features.where(
|
|
||||||
{'var': 'http://jabber.org/protocol/disco#info'}).length).toBe(1);
|
|
||||||
|
|
||||||
await u.waitUntil(function () {
|
const { Strophe } = converse.env;
|
||||||
// Converse.js sees that the entity has a disco#items feature,
|
sinon.spy(_converse.api, "trigger");
|
||||||
// so it will make a query for it.
|
_converse.disco_entities.get(_converse.domain).features.create({'var': Strophe.NS.MAM});
|
||||||
return _.filter(IQ_stanzas, function (iq) {
|
expect(_converse.api.trigger.called).toBe(true);
|
||||||
return iq.querySelector('query[xmlns="http://jabber.org/protocol/disco#items"]');
|
expect(_converse.api.trigger.args[0][0]).toBe('serviceDiscovered');
|
||||||
}).length > 0;
|
expect(_converse.api.trigger.args[0][1].get('var')).toBe(Strophe.NS.MAM);
|
||||||
});
|
done();
|
||||||
/* <iq type='result'
|
}));
|
||||||
* from='catalog.shakespeare.lit'
|
|
||||||
* to='romeo@montague.net/orchard'
|
|
||||||
* id='items2'>
|
|
||||||
* <query xmlns='http://jabber.org/protocol/disco#items'>
|
|
||||||
* <item jid='people.shakespeare.lit'
|
|
||||||
* name='Directory of Characters'/>
|
|
||||||
* <item jid='plays.shakespeare.lit'
|
|
||||||
* name='Play-Specific Chatrooms'/>
|
|
||||||
* <item jid='mim.shakespeare.lit'
|
|
||||||
* name='Gateway to Marlowe IM'/>
|
|
||||||
* <item jid='words.shakespeare.lit'
|
|
||||||
* name='Shakespearean Lexicon'/>
|
|
||||||
*
|
|
||||||
* <item jid='catalog.shakespeare.lit'
|
|
||||||
* node='books'
|
|
||||||
* name='Books by and about Shakespeare'/>
|
|
||||||
* <item jid='catalog.shakespeare.lit'
|
|
||||||
* node='clothing'
|
|
||||||
* name='Wear your literary taste with pride'/>
|
|
||||||
* <item jid='catalog.shakespeare.lit'
|
|
||||||
* node='music'
|
|
||||||
* name='Music from the time of Shakespeare'/>
|
|
||||||
* </query>
|
|
||||||
* </iq>
|
|
||||||
*/
|
|
||||||
stanza = _.find(IQ_stanzas, 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)];
|
|
||||||
stanza = $iq({
|
|
||||||
'type': 'result',
|
|
||||||
'from': 'montague.lit',
|
|
||||||
'to': 'romeo@montague.lit/orchard',
|
|
||||||
'id': items_IQ_id
|
|
||||||
}).c('query', {'xmlns': 'http://jabber.org/protocol/disco#items'})
|
|
||||||
.c('item', {
|
|
||||||
'jid': 'people.shakespeare.lit',
|
|
||||||
'name': 'Directory of Characters'}).up()
|
|
||||||
.c('item', {
|
|
||||||
'jid': 'plays.shakespeare.lit',
|
|
||||||
'name': 'Play-Specific Chatrooms'}).up()
|
|
||||||
.c('item', {
|
|
||||||
'jid': 'words.shakespeare.lit',
|
|
||||||
'name': 'Gateway to Marlowe IM'}).up()
|
|
||||||
|
|
||||||
.c('item', {
|
|
||||||
'jid': 'montague.lit',
|
|
||||||
'node': 'books',
|
|
||||||
'name': 'Books by and about Shakespeare'}).up()
|
|
||||||
.c('item', {
|
|
||||||
'node': 'montague.lit',
|
|
||||||
'name': 'Wear your literary taste with pride'}).up()
|
|
||||||
.c('item', {
|
|
||||||
'jid': 'montague.lit',
|
|
||||||
'node': 'music',
|
|
||||||
'name': 'Music from the time of Shakespeare'
|
|
||||||
});
|
|
||||||
_converse.connection._dataRecv(test_utils.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).identities.where({'category': 'conference'}).length).toBe(1);
|
|
||||||
expect(entities.get(_converse.domain).identities.where({'category': 'directory'}).length).toBe(1);
|
|
||||||
done();
|
|
||||||
}));
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("Whenever converse.js discovers a new server feature", function () {
|
|
||||||
it("emits the serviceDiscovered event",
|
|
||||||
mock.initConverse(
|
|
||||||
['discoInitialized'], {},
|
|
||||||
function (done, _converse) {
|
|
||||||
|
|
||||||
sinon.spy(_converse.api, "trigger");
|
|
||||||
_converse.disco_entities.get(_converse.domain).features.create({'var': Strophe.NS.MAM});
|
|
||||||
expect(_converse.api.trigger.called).toBe(true);
|
|
||||||
expect(_converse.api.trigger.args[0][0]).toBe('serviceDiscovered');
|
|
||||||
expect(_converse.api.trigger.args[0][1].get('var')).toBe(Strophe.NS.MAM);
|
|
||||||
done();
|
|
||||||
}));
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
418
spec/emojis.js
418
spec/emojis.js
@ -1,238 +1,236 @@
|
|||||||
window.addEventListener('converse-loaded', () => {
|
/*global mock */
|
||||||
const mock = window.mock;
|
|
||||||
const test_utils = window.test_utils;
|
|
||||||
const { Promise, $msg, $pres, sizzle } = converse.env;
|
|
||||||
const u = converse.env.utils;
|
|
||||||
|
|
||||||
describe("Emojis", function () {
|
const { Promise, $msg, $pres, sizzle } = converse.env;
|
||||||
describe("The emoji picker", function () {
|
const u = converse.env.utils;
|
||||||
|
|
||||||
it("can be opened by clicking a button in the chat toolbar",
|
describe("Emojis", function () {
|
||||||
mock.initConverse(
|
describe("The emoji picker", function () {
|
||||||
['rosterGroupsFetched', 'chatBoxesFetched'], {},
|
|
||||||
async function (done, _converse) {
|
|
||||||
|
|
||||||
const contact_jid = mock.cur_names[2].replace(/ /g,'.').toLowerCase() + '@montague.lit';
|
it("can be opened by clicking a button in the chat toolbar",
|
||||||
await test_utils.waitForRoster(_converse, 'current');
|
mock.initConverse(
|
||||||
await test_utils.openControlBox(_converse);
|
['rosterGroupsFetched', 'chatBoxesFetched'], {},
|
||||||
await test_utils.openChatBoxFor(_converse, contact_jid);
|
async function (done, _converse) {
|
||||||
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);
|
|
||||||
toolbar.querySelector('a.toggle-smiley').click();
|
|
||||||
await u.waitUntil(() => u.isVisible(view.el.querySelector('.emoji-picker__lists')), 1000);
|
|
||||||
const picker = await u.waitUntil(() => view.el.querySelector('.emoji-picker__container'), 1000);
|
|
||||||
const item = await u.waitUntil(() => picker.querySelector('.emoji-picker li.insert-emoji a'), 1000);
|
|
||||||
item.click()
|
|
||||||
expect(view.el.querySelector('textarea.chat-textarea').value).toBe(':smiley: ');
|
|
||||||
toolbar.querySelector('a.toggle-smiley').click(); // Close the panel again
|
|
||||||
done();
|
|
||||||
}));
|
|
||||||
|
|
||||||
it("is opened to autocomplete emojis in the textarea",
|
const contact_jid = mock.cur_names[2].replace(/ /g,'.').toLowerCase() + '@montague.lit';
|
||||||
mock.initConverse(
|
await mock.waitForRoster(_converse, 'current');
|
||||||
['rosterGroupsFetched', 'chatBoxesFetched'], {},
|
await mock.openControlBox(_converse);
|
||||||
async function (done, _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);
|
||||||
|
toolbar.querySelector('a.toggle-smiley').click();
|
||||||
|
await u.waitUntil(() => u.isVisible(view.el.querySelector('.emoji-picker__lists')), 1000);
|
||||||
|
const picker = await u.waitUntil(() => view.el.querySelector('.emoji-picker__container'), 1000);
|
||||||
|
const item = await u.waitUntil(() => picker.querySelector('.emoji-picker li.insert-emoji a'), 1000);
|
||||||
|
item.click()
|
||||||
|
expect(view.el.querySelector('textarea.chat-textarea').value).toBe(':smiley: ');
|
||||||
|
toolbar.querySelector('a.toggle-smiley').click(); // Close the panel again
|
||||||
|
done();
|
||||||
|
}));
|
||||||
|
|
||||||
const muc_jid = 'lounge@montague.lit';
|
it("is opened to autocomplete emojis in the textarea",
|
||||||
await test_utils.openAndEnterChatRoom(_converse, muc_jid, 'romeo');
|
mock.initConverse(
|
||||||
const view = _converse.chatboxviews.get(muc_jid);
|
['rosterGroupsFetched', 'chatBoxesFetched'], {},
|
||||||
|
async function (done, _converse) {
|
||||||
|
|
||||||
const textarea = view.el.querySelector('textarea.chat-textarea');
|
const muc_jid = 'lounge@montague.lit';
|
||||||
textarea.value = ':gri';
|
await mock.openAndEnterChatRoom(_converse, muc_jid, 'romeo');
|
||||||
|
const view = _converse.chatboxviews.get(muc_jid);
|
||||||
|
|
||||||
// Press tab
|
const textarea = view.el.querySelector('textarea.chat-textarea');
|
||||||
const tab_event = {
|
textarea.value = ':gri';
|
||||||
'target': textarea,
|
|
||||||
'preventDefault': function preventDefault () {},
|
|
||||||
'stopPropagation': function stopPropagation () {},
|
|
||||||
'keyCode': 9,
|
|
||||||
'key': 'Tab'
|
|
||||||
}
|
|
||||||
view.onKeyDown(tab_event);
|
|
||||||
await u.waitUntil(() => u.isVisible(view.el.querySelector('.emoji-picker__lists')));
|
|
||||||
let picker = await u.waitUntil(() => view.el.querySelector('.emoji-picker__container'));
|
|
||||||
const input = picker.querySelector('.emoji-search');
|
|
||||||
expect(input.value).toBe(':gri');
|
|
||||||
let visible_emojis = sizzle('.emojis-lists__container--search .insert-emoji', picker);
|
|
||||||
expect(visible_emojis.length).toBe(3);
|
|
||||||
expect(visible_emojis[0].getAttribute('data-emoji')).toBe(':grimacing:');
|
|
||||||
expect(visible_emojis[1].getAttribute('data-emoji')).toBe(':grin:');
|
|
||||||
expect(visible_emojis[2].getAttribute('data-emoji')).toBe(':grinning:');
|
|
||||||
|
|
||||||
// Test that TAB autocompletes the to first match
|
// Press tab
|
||||||
view.emoji_picker_view.onKeyDown(tab_event);
|
const tab_event = {
|
||||||
visible_emojis = sizzle('.emojis-lists__container--search .insert-emoji', picker);
|
'target': textarea,
|
||||||
expect(visible_emojis.length).toBe(1);
|
'preventDefault': function preventDefault () {},
|
||||||
expect(visible_emojis[0].getAttribute('data-emoji')).toBe(':grimacing:');
|
'stopPropagation': function stopPropagation () {},
|
||||||
expect(input.value).toBe(':grimacing:');
|
'keyCode': 9,
|
||||||
|
'key': 'Tab'
|
||||||
|
}
|
||||||
|
view.onKeyDown(tab_event);
|
||||||
|
await u.waitUntil(() => u.isVisible(view.el.querySelector('.emoji-picker__lists')));
|
||||||
|
let picker = await u.waitUntil(() => view.el.querySelector('.emoji-picker__container'));
|
||||||
|
const input = picker.querySelector('.emoji-search');
|
||||||
|
expect(input.value).toBe(':gri');
|
||||||
|
let visible_emojis = sizzle('.emojis-lists__container--search .insert-emoji', picker);
|
||||||
|
expect(visible_emojis.length).toBe(3);
|
||||||
|
expect(visible_emojis[0].getAttribute('data-emoji')).toBe(':grimacing:');
|
||||||
|
expect(visible_emojis[1].getAttribute('data-emoji')).toBe(':grin:');
|
||||||
|
expect(visible_emojis[2].getAttribute('data-emoji')).toBe(':grinning:');
|
||||||
|
|
||||||
// Check that ENTER now inserts the match
|
// Test that TAB autocompletes the to first match
|
||||||
const enter_event = Object.assign({}, tab_event, {'keyCode': 13, 'key': 'Enter', 'target': input});
|
view.emoji_picker_view.onKeyDown(tab_event);
|
||||||
view.emoji_picker_view.onKeyDown(enter_event);
|
visible_emojis = sizzle('.emojis-lists__container--search .insert-emoji', picker);
|
||||||
expect(input.value).toBe('');
|
expect(visible_emojis.length).toBe(1);
|
||||||
expect(textarea.value).toBe(':grimacing: ');
|
expect(visible_emojis[0].getAttribute('data-emoji')).toBe(':grimacing:');
|
||||||
|
expect(input.value).toBe(':grimacing:');
|
||||||
|
|
||||||
// Test that username starting with : doesn't cause issues
|
// Check that ENTER now inserts the match
|
||||||
const presence = $pres({
|
const enter_event = Object.assign({}, tab_event, {'keyCode': 13, 'key': 'Enter', 'target': input});
|
||||||
'from': `${muc_jid}/:username`,
|
view.emoji_picker_view.onKeyDown(enter_event);
|
||||||
'id': '27C55F89-1C6A-459A-9EB5-77690145D624',
|
expect(input.value).toBe('');
|
||||||
'to': _converse.jid
|
expect(textarea.value).toBe(':grimacing: ');
|
||||||
})
|
|
||||||
.c('x', { 'xmlns': 'http://jabber.org/protocol/muc#user'})
|
|
||||||
.c('item', {
|
|
||||||
'jid': 'some1@montague.lit',
|
|
||||||
'affiliation': 'member',
|
|
||||||
'role': 'participant'
|
|
||||||
});
|
|
||||||
_converse.connection._dataRecv(test_utils.createRequest(presence));
|
|
||||||
|
|
||||||
textarea.value = ':use';
|
// Test that username starting with : doesn't cause issues
|
||||||
view.onKeyDown(tab_event);
|
const presence = $pres({
|
||||||
await u.waitUntil(() => u.isVisible(view.el.querySelector('.emoji-picker__lists')));
|
'from': `${muc_jid}/:username`,
|
||||||
picker = await u.waitUntil(() => view.el.querySelector('.emoji-picker__container'));
|
'id': '27C55F89-1C6A-459A-9EB5-77690145D624',
|
||||||
expect(input.value).toBe(':use');
|
'to': _converse.jid
|
||||||
visible_emojis = sizzle('.insert-emoji:not(.hidden)', picker);
|
})
|
||||||
expect(visible_emojis.length).toBe(0);
|
.c('x', { 'xmlns': 'http://jabber.org/protocol/muc#user'})
|
||||||
done();
|
.c('item', {
|
||||||
}));
|
'jid': 'some1@montague.lit',
|
||||||
|
'affiliation': 'member',
|
||||||
|
'role': 'participant'
|
||||||
|
});
|
||||||
|
_converse.connection._dataRecv(mock.createRequest(presence));
|
||||||
|
|
||||||
|
textarea.value = ':use';
|
||||||
|
view.onKeyDown(tab_event);
|
||||||
|
await u.waitUntil(() => u.isVisible(view.el.querySelector('.emoji-picker__lists')));
|
||||||
|
picker = await u.waitUntil(() => view.el.querySelector('.emoji-picker__container'));
|
||||||
|
expect(input.value).toBe(':use');
|
||||||
|
visible_emojis = sizzle('.insert-emoji:not(.hidden)', picker);
|
||||||
|
expect(visible_emojis.length).toBe(0);
|
||||||
|
done();
|
||||||
|
}));
|
||||||
|
|
||||||
|
|
||||||
it("allows you to search for particular emojis",
|
it("allows you to search for particular emojis",
|
||||||
mock.initConverse(
|
mock.initConverse(
|
||||||
['rosterGroupsFetched', 'chatBoxesFetched'], {},
|
['rosterGroupsFetched', 'chatBoxesFetched'], {},
|
||||||
async function (done, _converse) {
|
async function (done, _converse) {
|
||||||
|
|
||||||
const muc_jid = 'lounge@montague.lit';
|
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 view = _converse.chatboxviews.get(muc_jid);
|
||||||
const toolbar = view.el.querySelector('ul.chat-toolbar');
|
const toolbar = view.el.querySelector('ul.chat-toolbar');
|
||||||
expect(toolbar.querySelectorAll('.toggle-smiley__container').length).toBe(1);
|
expect(toolbar.querySelectorAll('.toggle-smiley__container').length).toBe(1);
|
||||||
toolbar.querySelector('.toggle-smiley').click();
|
toolbar.querySelector('.toggle-smiley').click();
|
||||||
await u.waitUntil(() => u.isVisible(view.el.querySelector('.emoji-picker__lists')));
|
await u.waitUntil(() => u.isVisible(view.el.querySelector('.emoji-picker__lists')));
|
||||||
const picker = await u.waitUntil(() => view.el.querySelector('.emoji-picker__container'));
|
const picker = await u.waitUntil(() => view.el.querySelector('.emoji-picker__container'));
|
||||||
const input = picker.querySelector('.emoji-search');
|
const input = picker.querySelector('.emoji-search');
|
||||||
expect(sizzle('.insert-emoji:not(.hidden)', picker).length).toBe(1589);
|
expect(sizzle('.insert-emoji:not(.hidden)', picker).length).toBe(1589);
|
||||||
|
|
||||||
expect(view.emoji_picker_view.model.get('query')).toBeUndefined();
|
expect(view.emoji_picker_view.model.get('query')).toBeUndefined();
|
||||||
input.value = 'smiley';
|
input.value = 'smiley';
|
||||||
const event = {
|
const event = {
|
||||||
'target': input,
|
'target': input,
|
||||||
'preventDefault': function preventDefault () {},
|
'preventDefault': function preventDefault () {},
|
||||||
'stopPropagation': function stopPropagation () {}
|
'stopPropagation': function stopPropagation () {}
|
||||||
};
|
};
|
||||||
view.emoji_picker_view.onKeyDown(event);
|
view.emoji_picker_view.onKeyDown(event);
|
||||||
await u.waitUntil(() => view.emoji_picker_view.model.get('query') === 'smiley');
|
await u.waitUntil(() => view.emoji_picker_view.model.get('query') === 'smiley');
|
||||||
let visible_emojis = sizzle('.emojis-lists__container--search .insert-emoji', picker);
|
let visible_emojis = sizzle('.emojis-lists__container--search .insert-emoji', picker);
|
||||||
expect(visible_emojis.length).toBe(2);
|
expect(visible_emojis.length).toBe(2);
|
||||||
expect(visible_emojis[0].getAttribute('data-emoji')).toBe(':smiley:');
|
expect(visible_emojis[0].getAttribute('data-emoji')).toBe(':smiley:');
|
||||||
expect(visible_emojis[1].getAttribute('data-emoji')).toBe(':smiley_cat:');
|
expect(visible_emojis[1].getAttribute('data-emoji')).toBe(':smiley_cat:');
|
||||||
|
|
||||||
// Check that pressing enter without an unambiguous match does nothing
|
// Check that pressing enter without an unambiguous match does nothing
|
||||||
const enter_event = Object.assign({}, event, {'keyCode': 13});
|
const enter_event = Object.assign({}, event, {'keyCode': 13});
|
||||||
view.emoji_picker_view.onKeyDown(enter_event);
|
view.emoji_picker_view.onKeyDown(enter_event);
|
||||||
expect(input.value).toBe('smiley');
|
expect(input.value).toBe('smiley');
|
||||||
|
|
||||||
// Test that TAB autocompletes the to first match
|
// Test that TAB autocompletes the to first match
|
||||||
const tab_event = Object.assign({}, event, {'keyCode': 9, 'key': 'Tab'});
|
const tab_event = Object.assign({}, event, {'keyCode': 9, 'key': 'Tab'});
|
||||||
view.emoji_picker_view.onKeyDown(tab_event);
|
view.emoji_picker_view.onKeyDown(tab_event);
|
||||||
expect(input.value).toBe(':smiley:');
|
expect(input.value).toBe(':smiley:');
|
||||||
visible_emojis = sizzle('.emojis-lists__container--search .insert-emoji', picker);
|
visible_emojis = sizzle('.emojis-lists__container--search .insert-emoji', picker);
|
||||||
expect(visible_emojis.length).toBe(1);
|
expect(visible_emojis.length).toBe(1);
|
||||||
expect(visible_emojis[0].getAttribute('data-emoji')).toBe(':smiley:');
|
expect(visible_emojis[0].getAttribute('data-emoji')).toBe(':smiley:');
|
||||||
|
|
||||||
// Check that ENTER now inserts the match
|
// Check that ENTER now inserts the match
|
||||||
view.emoji_picker_view.onKeyDown(enter_event);
|
view.emoji_picker_view.onKeyDown(enter_event);
|
||||||
expect(input.value).toBe('');
|
expect(input.value).toBe('');
|
||||||
expect(view.el.querySelector('textarea.chat-textarea').value).toBe(':smiley: ');
|
expect(view.el.querySelector('textarea.chat-textarea').value).toBe(':smiley: ');
|
||||||
done();
|
done();
|
||||||
}));
|
}));
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("A Chat Message", function () {
|
describe("A Chat Message", function () {
|
||||||
it("will display larger if it's only emojis",
|
it("will display larger if it's only emojis",
|
||||||
mock.initConverse(
|
mock.initConverse(
|
||||||
['rosterGroupsFetched', 'chatBoxesFetched'], {'use_system_emojis': true},
|
['rosterGroupsFetched', 'chatBoxesFetched'], {'use_system_emojis': true},
|
||||||
async function (done, _converse) {
|
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';
|
const sender_jid = mock.cur_names[1].replace(/ /g,'.').toLowerCase() + '@montague.lit';
|
||||||
_converse.handleMessageStanza($msg({
|
_converse.handleMessageStanza($msg({
|
||||||
'from': sender_jid,
|
'from': sender_jid,
|
||||||
'to': _converse.connection.jid,
|
'to': _converse.connection.jid,
|
||||||
'type': 'chat',
|
'type': 'chat',
|
||||||
'id': _converse.connection.getUniqueId()
|
'id': _converse.connection.getUniqueId()
|
||||||
}).c('body').t('😇').up()
|
}).c('body').t('😇').up()
|
||||||
.c('active', {'xmlns': 'http://jabber.org/protocol/chatstates'}).tree());
|
.c('active', {'xmlns': 'http://jabber.org/protocol/chatstates'}).tree());
|
||||||
await new Promise(resolve => _converse.on('chatBoxViewInitialized', resolve));
|
await new Promise(resolve => _converse.on('chatBoxViewInitialized', resolve));
|
||||||
const view = _converse.api.chatviews.get(sender_jid);
|
const view = _converse.api.chatviews.get(sender_jid);
|
||||||
await new Promise(resolve => view.once('messageInserted', resolve));
|
await new Promise(resolve => view.once('messageInserted', resolve));
|
||||||
let message = view.content.querySelector('.chat-msg__text');
|
let message = view.content.querySelector('.chat-msg__text');
|
||||||
expect(u.hasClass('chat-msg__text--larger', message)).toBe(true);
|
expect(u.hasClass('chat-msg__text--larger', message)).toBe(true);
|
||||||
|
|
||||||
_converse.handleMessageStanza($msg({
|
_converse.handleMessageStanza($msg({
|
||||||
'from': sender_jid,
|
'from': sender_jid,
|
||||||
'to': _converse.connection.jid,
|
'to': _converse.connection.jid,
|
||||||
'type': 'chat',
|
'type': 'chat',
|
||||||
'id': _converse.connection.getUniqueId()
|
'id': _converse.connection.getUniqueId()
|
||||||
}).c('body').t('😇 Hello world! 😇 😇').up()
|
}).c('body').t('😇 Hello world! 😇 😇').up()
|
||||||
.c('active', {'xmlns': 'http://jabber.org/protocol/chatstates'}).tree());
|
.c('active', {'xmlns': 'http://jabber.org/protocol/chatstates'}).tree());
|
||||||
await new Promise(resolve => view.once('messageInserted', resolve));
|
await new Promise(resolve => view.once('messageInserted', resolve));
|
||||||
message = view.content.querySelector('.message:last-child .chat-msg__text');
|
message = view.content.querySelector('.message:last-child .chat-msg__text');
|
||||||
expect(u.hasClass('chat-msg__text--larger', message)).toBe(false);
|
expect(u.hasClass('chat-msg__text--larger', message)).toBe(false);
|
||||||
|
|
||||||
// Test that a modified message that no longer contains only
|
// Test that a modified message that no longer contains only
|
||||||
// emojis now renders normally again.
|
// emojis now renders normally again.
|
||||||
const textarea = view.el.querySelector('textarea.chat-textarea');
|
const textarea = view.el.querySelector('textarea.chat-textarea');
|
||||||
textarea.value = ':poop: :innocent:';
|
textarea.value = ':poop: :innocent:';
|
||||||
view.onKeyDown({
|
view.onKeyDown({
|
||||||
target: textarea,
|
target: textarea,
|
||||||
preventDefault: function preventDefault () {},
|
preventDefault: function preventDefault () {},
|
||||||
keyCode: 13 // Enter
|
keyCode: 13 // Enter
|
||||||
});
|
});
|
||||||
await new Promise(resolve => view.once('messageInserted', resolve));
|
await new Promise(resolve => view.once('messageInserted', resolve));
|
||||||
expect(view.el.querySelectorAll('.chat-msg').length).toBe(3);
|
expect(view.el.querySelectorAll('.chat-msg').length).toBe(3);
|
||||||
expect(view.content.querySelector('.message:last-child .chat-msg__text').textContent).toBe('💩 😇');
|
expect(view.content.querySelector('.message:last-child .chat-msg__text').textContent).toBe('💩 😇');
|
||||||
expect(textarea.value).toBe('');
|
expect(textarea.value).toBe('');
|
||||||
view.onKeyDown({
|
view.onKeyDown({
|
||||||
target: textarea,
|
target: textarea,
|
||||||
keyCode: 38 // Up arrow
|
keyCode: 38 // Up arrow
|
||||||
});
|
});
|
||||||
expect(textarea.value).toBe('💩 😇');
|
expect(textarea.value).toBe('💩 😇');
|
||||||
expect(view.model.messages.at(2).get('correcting')).toBe(true);
|
expect(view.model.messages.at(2).get('correcting')).toBe(true);
|
||||||
await u.waitUntil(() => u.hasClass('correcting', view.el.querySelector('.chat-msg:last-child')), 500);
|
await u.waitUntil(() => u.hasClass('correcting', view.el.querySelector('.chat-msg:last-child')), 500);
|
||||||
textarea.value = textarea.value += 'This is no longer an emoji-only message';
|
textarea.value = textarea.value += 'This is no longer an emoji-only message';
|
||||||
view.onKeyDown({
|
view.onKeyDown({
|
||||||
target: textarea,
|
target: textarea,
|
||||||
preventDefault: function preventDefault () {},
|
preventDefault: function preventDefault () {},
|
||||||
keyCode: 13 // Enter
|
keyCode: 13 // Enter
|
||||||
});
|
});
|
||||||
await new Promise(resolve => view.model.messages.once('rendered', resolve));
|
await new Promise(resolve => view.model.messages.once('rendered', resolve));
|
||||||
expect(view.model.messages.models.length).toBe(3);
|
expect(view.model.messages.models.length).toBe(3);
|
||||||
message = view.content.querySelector('.message:last-child .chat-msg__text');
|
message = view.content.querySelector('.message:last-child .chat-msg__text');
|
||||||
expect(u.hasClass('chat-msg__text--larger', message)).toBe(false);
|
expect(u.hasClass('chat-msg__text--larger', message)).toBe(false);
|
||||||
|
|
||||||
textarea.value = ':smile: Hello world!';
|
textarea.value = ':smile: Hello world!';
|
||||||
view.onKeyDown({
|
view.onKeyDown({
|
||||||
target: textarea,
|
target: textarea,
|
||||||
preventDefault: function preventDefault () {},
|
preventDefault: function preventDefault () {},
|
||||||
keyCode: 13 // Enter
|
keyCode: 13 // Enter
|
||||||
});
|
});
|
||||||
await new Promise(resolve => view.once('messageInserted', resolve));
|
await new Promise(resolve => view.once('messageInserted', resolve));
|
||||||
|
|
||||||
textarea.value = ':smile: :smiley: :imp:';
|
textarea.value = ':smile: :smiley: :imp:';
|
||||||
view.onKeyDown({
|
view.onKeyDown({
|
||||||
target: textarea,
|
target: textarea,
|
||||||
preventDefault: function preventDefault () {},
|
preventDefault: function preventDefault () {},
|
||||||
keyCode: 13 // Enter
|
keyCode: 13 // Enter
|
||||||
});
|
});
|
||||||
await new Promise(resolve => view.once('messageInserted', resolve));
|
await new Promise(resolve => view.once('messageInserted', resolve));
|
||||||
|
|
||||||
message = view.content.querySelector('.message:last-child .chat-msg__text');
|
message = view.content.querySelector('.message:last-child .chat-msg__text');
|
||||||
expect(u.hasClass('chat-msg__text--larger', message)).toBe(true);
|
expect(u.hasClass('chat-msg__text--larger', message)).toBe(true);
|
||||||
done()
|
done()
|
||||||
}));
|
}));
|
||||||
});
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -1,63 +1,61 @@
|
|||||||
window.addEventListener('converse-loaded', () => {
|
/*global mock */
|
||||||
const mock = window.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) => {
|
it("allows you to subscribe to emitted events", mock.initConverse((done, _converse) => {
|
||||||
this.callback = function () {};
|
this.callback = function () {};
|
||||||
spyOn(this, 'callback');
|
spyOn(this, 'callback');
|
||||||
_converse.on('connected', this.callback);
|
_converse.on('connected', this.callback);
|
||||||
_converse.api.trigger('connected');
|
_converse.api.trigger('connected');
|
||||||
expect(this.callback).toHaveBeenCalled();
|
expect(this.callback).toHaveBeenCalled();
|
||||||
_converse.api.trigger('connected');
|
_converse.api.trigger('connected');
|
||||||
expect(this.callback.calls.count(), 2);
|
expect(this.callback.calls.count(), 2);
|
||||||
_converse.api.trigger('connected');
|
_converse.api.trigger('connected');
|
||||||
expect(this.callback.calls.count(), 3);
|
expect(this.callback.calls.count(), 3);
|
||||||
done();
|
done();
|
||||||
}));
|
}));
|
||||||
|
|
||||||
it("allows you to listen once for an emitted event", mock.initConverse((done, _converse) => {
|
it("allows you to listen once for an emitted event", mock.initConverse((done, _converse) => {
|
||||||
this.callback = function () {};
|
this.callback = function () {};
|
||||||
spyOn(this, 'callback');
|
spyOn(this, 'callback');
|
||||||
_converse.once('connected', this.callback);
|
_converse.once('connected', this.callback);
|
||||||
_converse.api.trigger('connected');
|
_converse.api.trigger('connected');
|
||||||
expect(this.callback).toHaveBeenCalled();
|
expect(this.callback).toHaveBeenCalled();
|
||||||
_converse.api.trigger('connected');
|
_converse.api.trigger('connected');
|
||||||
expect(this.callback.calls.count(), 1);
|
expect(this.callback.calls.count(), 1);
|
||||||
_converse.api.trigger('connected');
|
_converse.api.trigger('connected');
|
||||||
expect(this.callback.calls.count(), 1);
|
expect(this.callback.calls.count(), 1);
|
||||||
done();
|
done();
|
||||||
}));
|
}));
|
||||||
|
|
||||||
it("allows you to stop listening or subscribing to an event", mock.initConverse((done, _converse) => {
|
it("allows you to stop listening or subscribing to an event", mock.initConverse((done, _converse) => {
|
||||||
this.callback = function () {};
|
this.callback = function () {};
|
||||||
this.anotherCallback = function () {};
|
this.anotherCallback = function () {};
|
||||||
this.neverCalled = function () {};
|
this.neverCalled = function () {};
|
||||||
|
|
||||||
spyOn(this, 'callback');
|
spyOn(this, 'callback');
|
||||||
spyOn(this, 'anotherCallback');
|
spyOn(this, 'anotherCallback');
|
||||||
spyOn(this, 'neverCalled');
|
spyOn(this, 'neverCalled');
|
||||||
_converse.on('connected', this.callback);
|
_converse.on('connected', this.callback);
|
||||||
_converse.on('connected', this.anotherCallback);
|
_converse.on('connected', this.anotherCallback);
|
||||||
|
|
||||||
_converse.api.trigger('connected');
|
_converse.api.trigger('connected');
|
||||||
expect(this.callback).toHaveBeenCalled();
|
expect(this.callback).toHaveBeenCalled();
|
||||||
expect(this.anotherCallback).toHaveBeenCalled();
|
expect(this.anotherCallback).toHaveBeenCalled();
|
||||||
|
|
||||||
_converse.off('connected', this.callback);
|
_converse.off('connected', this.callback);
|
||||||
|
|
||||||
_converse.api.trigger('connected');
|
_converse.api.trigger('connected');
|
||||||
expect(this.callback.calls.count(), 1);
|
expect(this.callback.calls.count(), 1);
|
||||||
expect(this.anotherCallback.calls.count(), 2);
|
expect(this.anotherCallback.calls.count(), 2);
|
||||||
|
|
||||||
_converse.once('connected', this.neverCalled);
|
_converse.once('connected', this.neverCalled);
|
||||||
_converse.off('connected', this.neverCalled);
|
_converse.off('connected', this.neverCalled);
|
||||||
|
|
||||||
_converse.api.trigger('connected');
|
_converse.api.trigger('connected');
|
||||||
expect(this.callback.calls.count(), 1);
|
expect(this.callback.calls.count(), 1);
|
||||||
expect(this.anotherCallback.calls.count(), 3);
|
expect(this.anotherCallback.calls.count(), 3);
|
||||||
expect(this.neverCalled).not.toHaveBeenCalled();
|
expect(this.neverCalled).not.toHaveBeenCalled();
|
||||||
done();
|
done();
|
||||||
}));
|
}));
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
140
spec/hats.js
140
spec/hats.js
@ -1,80 +1,78 @@
|
|||||||
window.addEventListener('converse-loaded', () => {
|
/*global mock */
|
||||||
const mock = window.mock;
|
|
||||||
const test_utils = window.test_utils;
|
|
||||||
const u = converse.env.utils;
|
|
||||||
|
|
||||||
describe("A XEP-0317 MUC Hat", function () {
|
const u = converse.env.utils;
|
||||||
|
|
||||||
it("can be included in a presence stanza",
|
describe("A XEP-0317 MUC Hat", function () {
|
||||||
mock.initConverse(
|
|
||||||
['rosterGroupsFetched', 'chatBoxesFetched'], {},
|
|
||||||
async function (done, _converse) {
|
|
||||||
|
|
||||||
const muc_jid = 'lounge@montague.lit';
|
it("can be included in a presence stanza",
|
||||||
await test_utils.openAndEnterChatRoom(_converse, muc_jid, 'romeo');
|
mock.initConverse(
|
||||||
const view = _converse.chatboxviews.get(muc_jid);
|
['rosterGroupsFetched', 'chatBoxesFetched'], {},
|
||||||
const hat1_id = u.getUniqueId();
|
async function (done, _converse) {
|
||||||
const hat2_id = u.getUniqueId();
|
|
||||||
_converse.connection._dataRecv(test_utils.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"/>
|
|
||||||
</x>
|
|
||||||
<hats xmlns="xmpp:prosody.im/protocol/hats:1">
|
|
||||||
<hat title="Teacher's Assistant" id="${hat1_id}"/>
|
|
||||||
<hat title="Dark Mage" id="${hat2_id}"/>
|
|
||||||
</hats>
|
|
||||||
</presence>
|
|
||||||
`)));
|
|
||||||
await u.waitUntil(() => view.el.querySelector('.chat-content__notifications').textContent.trim() ===
|
|
||||||
"romeo and Terry have entered the groupchat");
|
|
||||||
|
|
||||||
let hats = view.model.getOccupant("Terry").get('hats');
|
const muc_jid = 'lounge@montague.lit';
|
||||||
expect(hats.length).toBe(2);
|
await mock.openAndEnterChatRoom(_converse, muc_jid, 'romeo');
|
||||||
expect(hats.map(h => h.title).join(' ')).toBe("Teacher's Assistant Dark Mage");
|
const view = _converse.chatboxviews.get(muc_jid);
|
||||||
|
const hat1_id = u.getUniqueId();
|
||||||
|
const hat2_id = u.getUniqueId();
|
||||||
|
_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"/>
|
||||||
|
</x>
|
||||||
|
<hats xmlns="xmpp:prosody.im/protocol/hats:1">
|
||||||
|
<hat title="Teacher's Assistant" id="${hat1_id}"/>
|
||||||
|
<hat title="Dark Mage" id="${hat2_id}"/>
|
||||||
|
</hats>
|
||||||
|
</presence>
|
||||||
|
`)));
|
||||||
|
await u.waitUntil(() => view.el.querySelector('.chat-content__notifications').textContent.trim() ===
|
||||||
|
"romeo and Terry have entered the groupchat");
|
||||||
|
|
||||||
_converse.connection._dataRecv(test_utils.createRequest(u.toStanza(`
|
let hats = view.model.getOccupant("Terry").get('hats');
|
||||||
<message type="groupchat" from="${muc_jid}/Terry" id="${u.getUniqueId()}" to="${_converse.jid}">
|
expect(hats.length).toBe(2);
|
||||||
<body>Hello world</body>
|
expect(hats.map(h => h.title).join(' ')).toBe("Teacher's Assistant Dark Mage");
|
||||||
</message>
|
|
||||||
`)));
|
|
||||||
|
|
||||||
const msg_el = await u.waitUntil(() => view.el.querySelector('.chat-msg'));
|
_converse.connection._dataRecv(mock.createRequest(u.toStanza(`
|
||||||
let badges = Array.from(msg_el.querySelectorAll('.badge'));
|
<message type="groupchat" from="${muc_jid}/Terry" id="${u.getUniqueId()}" to="${_converse.jid}">
|
||||||
expect(badges.length).toBe(2);
|
<body>Hello world</body>
|
||||||
expect(badges.map(b => b.textContent.trim()).join(' ' )).toBe("Teacher's Assistant Dark Mage");
|
</message>
|
||||||
|
`)));
|
||||||
|
|
||||||
const hat3_id = u.getUniqueId();
|
const msg_el = await u.waitUntil(() => view.el.querySelector('.chat-msg'));
|
||||||
_converse.connection._dataRecv(test_utils.createRequest(u.toStanza(`
|
let badges = Array.from(msg_el.querySelectorAll('.badge'));
|
||||||
<presence from="${muc_jid}/Terry" id="${u.getUniqueId()}" to="${_converse.jid}">
|
expect(badges.length).toBe(2);
|
||||||
<x xmlns="http://jabber.org/protocol/muc#user">
|
expect(badges.map(b => b.textContent.trim()).join(' ' )).toBe("Teacher's Assistant Dark Mage");
|
||||||
<item affiliation="member" role="participant"/>
|
|
||||||
</x>
|
|
||||||
<hats xmlns="xmpp:prosody.im/protocol/hats:1">
|
|
||||||
<hat title="Teacher's Assistant" id="${hat1_id}"/>
|
|
||||||
<hat title="Dark Mage" id="${hat2_id}"/>
|
|
||||||
<hat title="Mad hatter" id="${hat3_id}"/>
|
|
||||||
</hats>
|
|
||||||
</presence>
|
|
||||||
`)));
|
|
||||||
|
|
||||||
await u.waitUntil(() => view.model.getOccupant("Terry").get('hats').length === 3);
|
const hat3_id = u.getUniqueId();
|
||||||
hats = view.model.getOccupant("Terry").get('hats');
|
_converse.connection._dataRecv(mock.createRequest(u.toStanza(`
|
||||||
expect(hats.map(h => h.title).join(' ')).toBe("Teacher's Assistant Dark Mage Mad hatter");
|
<presence from="${muc_jid}/Terry" id="${u.getUniqueId()}" to="${_converse.jid}">
|
||||||
await u.waitUntil(() => view.el.querySelectorAll('.chat-msg .badge').length === 3);
|
<x xmlns="http://jabber.org/protocol/muc#user">
|
||||||
badges = Array.from(view.el.querySelectorAll('.chat-msg .badge'));
|
<item affiliation="member" role="participant"/>
|
||||||
expect(badges.map(b => b.textContent.trim()).join(' ' )).toBe("Teacher's Assistant Dark Mage Mad hatter");
|
</x>
|
||||||
|
<hats xmlns="xmpp:prosody.im/protocol/hats:1">
|
||||||
|
<hat title="Teacher's Assistant" id="${hat1_id}"/>
|
||||||
|
<hat title="Dark Mage" id="${hat2_id}"/>
|
||||||
|
<hat title="Mad hatter" id="${hat3_id}"/>
|
||||||
|
</hats>
|
||||||
|
</presence>
|
||||||
|
`)));
|
||||||
|
|
||||||
_converse.connection._dataRecv(test_utils.createRequest(u.toStanza(`
|
await u.waitUntil(() => view.model.getOccupant("Terry").get('hats').length === 3);
|
||||||
<presence from="${muc_jid}/Terry" id="${u.getUniqueId()}" to="${_converse.jid}">
|
hats = view.model.getOccupant("Terry").get('hats');
|
||||||
<x xmlns="http://jabber.org/protocol/muc#user">
|
expect(hats.map(h => h.title).join(' ')).toBe("Teacher's Assistant Dark Mage Mad hatter");
|
||||||
<item affiliation="member" role="participant"/>
|
await u.waitUntil(() => view.el.querySelectorAll('.chat-msg .badge').length === 3);
|
||||||
</x>
|
badges = Array.from(view.el.querySelectorAll('.chat-msg .badge'));
|
||||||
</presence>
|
expect(badges.map(b => b.textContent.trim()).join(' ' )).toBe("Teacher's Assistant Dark Mage Mad hatter");
|
||||||
`)));
|
|
||||||
await u.waitUntil(() => view.model.getOccupant("Terry").get('hats').length === 0);
|
_converse.connection._dataRecv(mock.createRequest(u.toStanza(`
|
||||||
await u.waitUntil(() => view.el.querySelectorAll('.chat-msg .badge').length === 0);
|
<presence from="${muc_jid}/Terry" id="${u.getUniqueId()}" to="${_converse.jid}">
|
||||||
done();
|
<x xmlns="http://jabber.org/protocol/muc#user">
|
||||||
}));
|
<item affiliation="member" role="participant"/>
|
||||||
})
|
</x>
|
||||||
});
|
</presence>
|
||||||
|
`)));
|
||||||
|
await u.waitUntil(() => view.model.getOccupant("Terry").get('hats').length === 0);
|
||||||
|
await u.waitUntil(() => view.el.querySelectorAll('.chat-msg .badge').length === 0);
|
||||||
|
done();
|
||||||
|
}));
|
||||||
|
})
|
||||||
|
327
spec/headline.js
327
spec/headline.js
@ -1,177 +1,176 @@
|
|||||||
window.addEventListener('converse-loaded', () => {
|
/*global mock */
|
||||||
const mock = window.mock;
|
|
||||||
const test_utils = window.test_utils;
|
|
||||||
const $msg = converse.env.$msg,
|
|
||||||
_ = converse.env._,
|
|
||||||
u = converse.env.utils;
|
|
||||||
|
|
||||||
describe("A headlines box", function () {
|
describe("A headlines box", function () {
|
||||||
|
|
||||||
it("will not open nor display non-headline messages",
|
it("will not open nor display non-headline messages",
|
||||||
mock.initConverse(
|
mock.initConverse(
|
||||||
['rosterGroupsFetched', 'chatBoxesFetched'], {}, function (done, _converse) {
|
['rosterGroupsFetched', 'chatBoxesFetched'], {}, function (done, _converse) {
|
||||||
|
|
||||||
/* XMPP spam message:
|
const { u, $msg} = converse.env;
|
||||||
*
|
/* XMPP spam message:
|
||||||
* <message xmlns="jabber:client"
|
*
|
||||||
* to="romeo@montague.lit"
|
* <message xmlns="jabber:client"
|
||||||
* type="chat"
|
* to="romeo@montague.lit"
|
||||||
* from="gapowa20102106@rds-rostov.ru/Adium">
|
* type="chat"
|
||||||
* <nick xmlns="http://jabber.org/protocol/nick">-wwdmz</nick>
|
* from="gapowa20102106@rds-rostov.ru/Adium">
|
||||||
* <body>SORRY FOR THIS ADVERT</body
|
* <nick xmlns="http://jabber.org/protocol/nick">-wwdmz</nick>
|
||||||
* </message
|
* <body>SORRY FOR THIS ADVERT</body
|
||||||
*/
|
* </message
|
||||||
sinon.spy(u, 'isHeadlineMessage');
|
*/
|
||||||
const stanza = $msg({
|
sinon.spy(u, 'isHeadlineMessage');
|
||||||
'xmlns': 'jabber:client',
|
const stanza = $msg({
|
||||||
'to': 'romeo@montague.lit',
|
'xmlns': 'jabber:client',
|
||||||
'type': 'chat',
|
'to': 'romeo@montague.lit',
|
||||||
'from': 'gapowa20102106@rds-rostov.ru/Adium',
|
'type': 'chat',
|
||||||
})
|
'from': 'gapowa20102106@rds-rostov.ru/Adium',
|
||||||
.c('nick', {'xmlns': "http://jabber.org/protocol/nick"}).t("-wwdmz").up()
|
})
|
||||||
.c('body').t('SORRY FOR THIS ADVERT');
|
.c('nick', {'xmlns': "http://jabber.org/protocol/nick"}).t("-wwdmz").up()
|
||||||
_converse.connection._dataRecv(test_utils.createRequest(stanza));
|
.c('body').t('SORRY FOR THIS ADVERT');
|
||||||
expect(u.isHeadlineMessage.called).toBeTruthy();
|
_converse.connection._dataRecv(mock.createRequest(stanza));
|
||||||
expect(u.isHeadlineMessage.returned(false)).toBeTruthy();
|
expect(u.isHeadlineMessage.called).toBeTruthy();
|
||||||
expect(_converse.api.headlines.get().length === 0);
|
expect(u.isHeadlineMessage.returned(false)).toBeTruthy();
|
||||||
u.isHeadlineMessage.restore();
|
expect(_converse.api.headlines.get().length === 0);
|
||||||
done();
|
u.isHeadlineMessage.restore();
|
||||||
}));
|
done();
|
||||||
|
}));
|
||||||
|
|
||||||
it("will open and display headline messages", mock.initConverse(
|
it("will open and display headline messages", mock.initConverse(
|
||||||
['rosterGroupsFetched'], {}, async function (done, _converse) {
|
|
||||||
|
|
||||||
/* <message from='notify.example.com'
|
|
||||||
* to='romeo@im.example.com'
|
|
||||||
* type='headline'
|
|
||||||
* xml:lang='en'>
|
|
||||||
* <subject>SIEVE</subject>
|
|
||||||
* <body><juliet@example.com> You got mail.</body>
|
|
||||||
* <x xmlns='jabber:x:oob'>
|
|
||||||
* <url>
|
|
||||||
* imap://romeo@example.com/INBOX;UIDVALIDITY=385759043/;UID=18
|
|
||||||
* </url>
|
|
||||||
* </x>
|
|
||||||
* </message>
|
|
||||||
*/
|
|
||||||
sinon.spy(u, 'isHeadlineMessage');
|
|
||||||
const stanza = $msg({
|
|
||||||
'type': 'headline',
|
|
||||||
'from': 'notify.example.com',
|
|
||||||
'to': 'romeo@montague.lit',
|
|
||||||
'xml:lang': 'en'
|
|
||||||
})
|
|
||||||
.c('subject').t('SIEVE').up()
|
|
||||||
.c('body').t('<juliet@example.com> 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));
|
|
||||||
await u.waitUntil(() => _converse.chatboxviews.keys().includes('notify.example.com'));
|
|
||||||
expect(u.isHeadlineMessage.called).toBeTruthy();
|
|
||||||
expect(u.isHeadlineMessage.returned(true)).toBeTruthy();
|
|
||||||
u.isHeadlineMessage.restore(); // unwraps
|
|
||||||
const view = _converse.chatboxviews.get('notify.example.com');
|
|
||||||
expect(view.model.get('show_avatar')).toBeFalsy();
|
|
||||||
expect(view.el.querySelector('img.avatar')).toBe(null);
|
|
||||||
done();
|
|
||||||
}));
|
|
||||||
|
|
||||||
it("will show headline messages in the controlbox", mock.initConverse(
|
|
||||||
['rosterGroupsFetched'], {}, async function (done, _converse) {
|
['rosterGroupsFetched'], {}, async function (done, _converse) {
|
||||||
|
|
||||||
/* <message from='notify.example.com'
|
const { u, $msg} = converse.env;
|
||||||
* to='romeo@im.example.com'
|
/* <message from='notify.example.com'
|
||||||
* type='headline'
|
* to='romeo@im.example.com'
|
||||||
* xml:lang='en'>
|
* type='headline'
|
||||||
* <subject>SIEVE</subject>
|
* xml:lang='en'>
|
||||||
* <body><juliet@example.com> You got mail.</body>
|
* <subject>SIEVE</subject>
|
||||||
* <x xmlns='jabber:x:oob'>
|
* <body><juliet@example.com> You got mail.</body>
|
||||||
* <url>
|
* <x xmlns='jabber:x:oob'>
|
||||||
* imap://romeo@example.com/INBOX;UIDVALIDITY=385759043/;UID=18
|
* <url>
|
||||||
* </url>
|
* imap://romeo@example.com/INBOX;UIDVALIDITY=385759043/;UID=18
|
||||||
* </x>
|
* </url>
|
||||||
* </message>
|
* </x>
|
||||||
*/
|
* </message>
|
||||||
const stanza = $msg({
|
*/
|
||||||
'type': 'headline',
|
sinon.spy(u, 'isHeadlineMessage');
|
||||||
'from': 'notify.example.com',
|
const stanza = $msg({
|
||||||
'to': 'romeo@montague.lit',
|
'type': 'headline',
|
||||||
'xml:lang': 'en'
|
'from': 'notify.example.com',
|
||||||
})
|
'to': 'romeo@montague.lit',
|
||||||
.c('subject').t('SIEVE').up()
|
'xml:lang': 'en'
|
||||||
.c('body').t('<juliet@example.com> You got mail.').up()
|
})
|
||||||
.c('x', {'xmlns': 'jabber:x:oob'})
|
.c('subject').t('SIEVE').up()
|
||||||
.c('url').t('imap://romeo@example.com/INBOX;UIDVALIDITY=385759043/;UID=18');
|
.c('body').t('<juliet@example.com> 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));
|
||||||
const view = _converse.chatboxviews.get('controlbox');
|
await u.waitUntil(() => _converse.chatboxviews.keys().includes('notify.example.com'));
|
||||||
await u.waitUntil(() => view.el.querySelectorAll(".open-headline").length);
|
expect(u.isHeadlineMessage.called).toBeTruthy();
|
||||||
expect(view.el.querySelectorAll('.open-headline').length).toBe(1);
|
expect(u.isHeadlineMessage.returned(true)).toBeTruthy();
|
||||||
expect(view.el.querySelector('.open-headline').text).toBe('notify.example.com');
|
u.isHeadlineMessage.restore(); // unwraps
|
||||||
done();
|
const view = _converse.chatboxviews.get('notify.example.com');
|
||||||
}));
|
expect(view.model.get('show_avatar')).toBeFalsy();
|
||||||
|
expect(view.el.querySelector('img.avatar')).toBe(null);
|
||||||
|
done();
|
||||||
|
}));
|
||||||
|
|
||||||
it("will remove headline messages from the controlbox if closed", mock.initConverse(
|
it("will show headline messages in the controlbox", mock.initConverse(
|
||||||
['rosterGroupsFetched'], {}, async function (done, _converse) {
|
['rosterGroupsFetched'], {}, async function (done, _converse) {
|
||||||
|
|
||||||
await test_utils.openControlBox(_converse);
|
const { u, $msg} = converse.env;
|
||||||
/* <message from='notify.example.com'
|
/* <message from='notify.example.com'
|
||||||
* to='romeo@im.example.com'
|
* to='romeo@im.example.com'
|
||||||
* type='headline'
|
* type='headline'
|
||||||
* xml:lang='en'>
|
* xml:lang='en'>
|
||||||
* <subject>SIEVE</subject>
|
* <subject>SIEVE</subject>
|
||||||
* <body><juliet@example.com> You got mail.</body>
|
* <body><juliet@example.com> You got mail.</body>
|
||||||
* <x xmlns='jabber:x:oob'>
|
* <x xmlns='jabber:x:oob'>
|
||||||
* <url>
|
* <url>
|
||||||
* imap://romeo@example.com/INBOX;UIDVALIDITY=385759043/;UID=18
|
* imap://romeo@example.com/INBOX;UIDVALIDITY=385759043/;UID=18
|
||||||
* </url>
|
* </url>
|
||||||
* </x>
|
* </x>
|
||||||
* </message>
|
* </message>
|
||||||
*/
|
*/
|
||||||
const stanza = $msg({
|
const stanza = $msg({
|
||||||
'type': 'headline',
|
'type': 'headline',
|
||||||
'from': 'notify.example.com',
|
'from': 'notify.example.com',
|
||||||
'to': 'romeo@montague.lit',
|
'to': 'romeo@montague.lit',
|
||||||
'xml:lang': 'en'
|
'xml:lang': 'en'
|
||||||
})
|
})
|
||||||
.c('subject').t('SIEVE').up()
|
.c('subject').t('SIEVE').up()
|
||||||
.c('body').t('<juliet@example.com> You got mail.').up()
|
.c('body').t('<juliet@example.com> You got mail.').up()
|
||||||
.c('x', {'xmlns': 'jabber:x:oob'})
|
.c('x', {'xmlns': 'jabber:x:oob'})
|
||||||
.c('url').t('imap://romeo@example.com/INBOX;UIDVALIDITY=385759043/;UID=18');
|
.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');
|
const view = _converse.chatboxviews.get('controlbox');
|
||||||
await u.waitUntil(() => cbview.el.querySelectorAll(".open-headline").length);
|
await u.waitUntil(() => view.el.querySelectorAll(".open-headline").length);
|
||||||
const hlview = _converse.chatboxviews.get('notify.example.com');
|
expect(view.el.querySelectorAll('.open-headline').length).toBe(1);
|
||||||
await u.isVisible(hlview.el);
|
expect(view.el.querySelector('.open-headline').text).toBe('notify.example.com');
|
||||||
const close_el = await u.waitUntil(() => hlview.el.querySelector('.close-chatbox-button'));
|
done();
|
||||||
close_el.click();
|
}));
|
||||||
await u.waitUntil(() => cbview.el.querySelectorAll(".open-headline").length === 0);
|
|
||||||
expect(cbview.el.querySelectorAll('.open-headline').length).toBe(0);
|
|
||||||
done();
|
|
||||||
}));
|
|
||||||
|
|
||||||
it("will not show a headline messages from a full JID if allow_non_roster_messaging is false",
|
it("will remove headline messages from the controlbox if closed", mock.initConverse(
|
||||||
mock.initConverse(
|
['rosterGroupsFetched'], {}, async function (done, _converse) {
|
||||||
['rosterGroupsFetched', 'chatBoxesFetched'], {}, function (done, _converse) {
|
|
||||||
|
|
||||||
_converse.allow_non_roster_messaging = false;
|
const { u, $msg} = converse.env;
|
||||||
sinon.spy(u, 'isHeadlineMessage');
|
await mock.openControlBox(_converse);
|
||||||
const stanza = $msg({
|
/* <message from='notify.example.com'
|
||||||
'type': 'headline',
|
* to='romeo@im.example.com'
|
||||||
'from': 'andre5114@jabber.snc.ru/Spark',
|
* type='headline'
|
||||||
'to': 'romeo@montague.lit',
|
* xml:lang='en'>
|
||||||
'xml:lang': 'en'
|
* <subject>SIEVE</subject>
|
||||||
})
|
* <body><juliet@example.com> You got mail.</body>
|
||||||
.c('nick').t('gpocy').up()
|
* <x xmlns='jabber:x:oob'>
|
||||||
.c('body').t('Здравствуйте друзья');
|
* <url>
|
||||||
_converse.connection._dataRecv(test_utils.createRequest(stanza));
|
* imap://romeo@example.com/INBOX;UIDVALIDITY=385759043/;UID=18
|
||||||
expect(_.without('controlbox', _converse.chatboxviews.keys()).length).toBe(0);
|
* </url>
|
||||||
expect(u.isHeadlineMessage.called).toBeTruthy();
|
* </x>
|
||||||
expect(u.isHeadlineMessage.returned(true)).toBeTruthy();
|
* </message>
|
||||||
u.isHeadlineMessage.restore(); // unwraps
|
*/
|
||||||
done();
|
const stanza = $msg({
|
||||||
}));
|
'type': 'headline',
|
||||||
});
|
'from': 'notify.example.com',
|
||||||
|
'to': 'romeo@montague.lit',
|
||||||
|
'xml:lang': 'en'
|
||||||
|
})
|
||||||
|
.c('subject').t('SIEVE').up()
|
||||||
|
.c('body').t('<juliet@example.com> 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(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');
|
||||||
|
await u.isVisible(hlview.el);
|
||||||
|
const close_el = await u.waitUntil(() => hlview.el.querySelector('.close-chatbox-button'));
|
||||||
|
close_el.click();
|
||||||
|
await u.waitUntil(() => cbview.el.querySelectorAll(".open-headline").length === 0);
|
||||||
|
expect(cbview.el.querySelectorAll('.open-headline').length).toBe(0);
|
||||||
|
done();
|
||||||
|
}));
|
||||||
|
|
||||||
|
it("will not show a headline messages from a full JID if allow_non_roster_messaging is false",
|
||||||
|
mock.initConverse(
|
||||||
|
['rosterGroupsFetched', 'chatBoxesFetched'], {}, function (done, _converse) {
|
||||||
|
|
||||||
|
const { u, $msg, _ } = converse.env;
|
||||||
|
_converse.allow_non_roster_messaging = false;
|
||||||
|
sinon.spy(u, 'isHeadlineMessage');
|
||||||
|
const stanza = $msg({
|
||||||
|
'type': 'headline',
|
||||||
|
'from': 'andre5114@jabber.snc.ru/Spark',
|
||||||
|
'to': 'romeo@montague.lit',
|
||||||
|
'xml:lang': 'en'
|
||||||
|
})
|
||||||
|
.c('nick').t('gpocy').up()
|
||||||
|
.c('body').t('Здравствуйте друзья');
|
||||||
|
_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();
|
||||||
|
}));
|
||||||
});
|
});
|
||||||
|
File diff suppressed because it is too large
Load Diff
112
spec/login.js
112
spec/login.js
@ -1,79 +1,77 @@
|
|||||||
window.addEventListener('converse-loaded', () => {
|
/*global mock */
|
||||||
const mock = window.mock;
|
|
||||||
const test_utils = window.test_utils;
|
|
||||||
const u = converse.env.utils;
|
|
||||||
|
|
||||||
describe("The Login Form", function () {
|
const u = converse.env.utils;
|
||||||
|
|
||||||
it("contains a checkbox to indicate whether the computer is trusted or not",
|
describe("The Login Form", function () {
|
||||||
mock.initConverse(
|
|
||||||
['chatBoxesInitialized'],
|
|
||||||
{ auto_login: false,
|
|
||||||
allow_registration: false },
|
|
||||||
async function (done, _converse) {
|
|
||||||
|
|
||||||
test_utils.openControlBox(_converse);
|
it("contains a checkbox to indicate whether the computer is trusted or not",
|
||||||
const cbview = await u.waitUntil(() => _converse.chatboxviews.get('controlbox'));
|
mock.initConverse(
|
||||||
|
['chatBoxesInitialized'],
|
||||||
|
{ auto_login: false,
|
||||||
|
allow_registration: false },
|
||||||
|
async function (done, _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);
|
||||||
|
|
||||||
|
const checkbox = checkboxes[0];
|
||||||
|
const label = cbview.el.querySelector(`label[for="${checkbox.getAttribute('id')}"]`);
|
||||||
|
expect(label.textContent).toBe('This is a trusted device');
|
||||||
|
expect(checkbox.checked).toBe(true);
|
||||||
|
|
||||||
|
cbview.el.querySelector('input[name="jid"]').value = 'romeo@montague.lit';
|
||||||
|
cbview.el.querySelector('input[name="password"]').value = 'secret';
|
||||||
|
|
||||||
|
spyOn(cbview.loginpanel, 'connect');
|
||||||
|
cbview.delegateEvents();
|
||||||
|
|
||||||
|
expect(_converse.config.get('storage')).toBe('persistent');
|
||||||
|
cbview.el.querySelector('input[type="submit"]').click();
|
||||||
|
expect(_converse.config.get('storage')).toBe('persistent');
|
||||||
|
expect(cbview.loginpanel.connect).toHaveBeenCalled();
|
||||||
|
|
||||||
|
checkbox.click();
|
||||||
|
cbview.el.querySelector('input[type="submit"]').click();
|
||||||
|
expect(_converse.config.get('storage')).toBe('session');
|
||||||
|
done();
|
||||||
|
}));
|
||||||
|
|
||||||
|
it("checkbox can be set to false by default",
|
||||||
|
mock.initConverse(
|
||||||
|
['chatBoxesInitialized'],
|
||||||
|
{ auto_login: false,
|
||||||
|
trusted: false,
|
||||||
|
allow_registration: false },
|
||||||
|
function (done, _converse) {
|
||||||
|
|
||||||
|
u.waitUntil(() => _converse.chatboxviews.get('controlbox'))
|
||||||
|
.then(() => {
|
||||||
|
var cbview = _converse.chatboxviews.get('controlbox');
|
||||||
|
mock.openControlBox(_converse);
|
||||||
const checkboxes = cbview.el.querySelectorAll('input[type="checkbox"]');
|
const checkboxes = cbview.el.querySelectorAll('input[type="checkbox"]');
|
||||||
expect(checkboxes.length).toBe(1);
|
expect(checkboxes.length).toBe(1);
|
||||||
|
|
||||||
const checkbox = checkboxes[0];
|
const checkbox = checkboxes[0];
|
||||||
const label = cbview.el.querySelector(`label[for="${checkbox.getAttribute('id')}"]`);
|
const label = cbview.el.querySelector(`label[for="${checkbox.getAttribute('id')}"]`);
|
||||||
expect(label.textContent).toBe('This is a trusted device');
|
expect(label.textContent).toBe('This is a trusted device');
|
||||||
expect(checkbox.checked).toBe(true);
|
expect(checkbox.checked).toBe(false);
|
||||||
|
|
||||||
cbview.el.querySelector('input[name="jid"]').value = 'romeo@montague.lit';
|
cbview.el.querySelector('input[name="jid"]').value = 'romeo@montague.lit';
|
||||||
cbview.el.querySelector('input[name="password"]').value = 'secret';
|
cbview.el.querySelector('input[name="password"]').value = 'secret';
|
||||||
|
|
||||||
spyOn(cbview.loginpanel, 'connect');
|
spyOn(cbview.loginpanel, 'connect');
|
||||||
cbview.delegateEvents();
|
|
||||||
|
|
||||||
expect(_converse.config.get('storage')).toBe('persistent');
|
expect(_converse.config.get('storage')).toBe('session');
|
||||||
cbview.el.querySelector('input[type="submit"]').click();
|
cbview.el.querySelector('input[type="submit"]').click();
|
||||||
expect(_converse.config.get('storage')).toBe('persistent');
|
expect(_converse.config.get('storage')).toBe('session');
|
||||||
expect(cbview.loginpanel.connect).toHaveBeenCalled();
|
expect(cbview.loginpanel.connect).toHaveBeenCalled();
|
||||||
|
|
||||||
checkbox.click();
|
checkbox.click();
|
||||||
cbview.el.querySelector('input[type="submit"]').click();
|
cbview.el.querySelector('input[type="submit"]').click();
|
||||||
expect(_converse.config.get('storage')).toBe('session');
|
expect(_converse.config.get('storage')).toBe('persistent');
|
||||||
done();
|
done();
|
||||||
}));
|
});
|
||||||
|
}));
|
||||||
it("checkbox can be set to false by default",
|
|
||||||
mock.initConverse(
|
|
||||||
['chatBoxesInitialized'],
|
|
||||||
{ auto_login: false,
|
|
||||||
trusted: false,
|
|
||||||
allow_registration: false },
|
|
||||||
function (done, _converse) {
|
|
||||||
|
|
||||||
u.waitUntil(() => _converse.chatboxviews.get('controlbox'))
|
|
||||||
.then(() => {
|
|
||||||
var cbview = _converse.chatboxviews.get('controlbox');
|
|
||||||
test_utils.openControlBox(_converse);
|
|
||||||
const checkboxes = cbview.el.querySelectorAll('input[type="checkbox"]');
|
|
||||||
expect(checkboxes.length).toBe(1);
|
|
||||||
|
|
||||||
const checkbox = checkboxes[0];
|
|
||||||
const label = cbview.el.querySelector(`label[for="${checkbox.getAttribute('id')}"]`);
|
|
||||||
expect(label.textContent).toBe('This is a trusted device');
|
|
||||||
expect(checkbox.checked).toBe(false);
|
|
||||||
|
|
||||||
cbview.el.querySelector('input[name="jid"]').value = 'romeo@montague.lit';
|
|
||||||
cbview.el.querySelector('input[name="password"]').value = 'secret';
|
|
||||||
|
|
||||||
spyOn(cbview.loginpanel, 'connect');
|
|
||||||
|
|
||||||
expect(_converse.config.get('storage')).toBe('session');
|
|
||||||
cbview.el.querySelector('input[type="submit"]').click();
|
|
||||||
expect(_converse.config.get('storage')).toBe('session');
|
|
||||||
expect(cbview.loginpanel.connect).toHaveBeenCalled();
|
|
||||||
|
|
||||||
checkbox.click();
|
|
||||||
cbview.el.querySelector('input[type="submit"]').click();
|
|
||||||
expect(_converse.config.get('storage')).toBe('persistent');
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
}));
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
2088
spec/mam.js
2088
spec/mam.js
File diff suppressed because it is too large
Load Diff
3764
spec/messages.js
3764
spec/messages.js
File diff suppressed because it is too large
Load Diff
282
spec/minchats.js
282
spec/minchats.js
@ -1,167 +1,165 @@
|
|||||||
window.addEventListener('converse-loaded', () => {
|
/*global mock */
|
||||||
const mock = window.mock;
|
|
||||||
const test_utils = window.test_utils;
|
|
||||||
const _ = converse.env._;
|
|
||||||
const $msg = converse.env.$msg;
|
|
||||||
const u = converse.env.utils;
|
|
||||||
|
|
||||||
describe("The Minimized Chats Widget", function () {
|
const _ = converse.env._;
|
||||||
|
const $msg = converse.env.$msg;
|
||||||
|
const u = converse.env.utils;
|
||||||
|
|
||||||
it("shows chats that have been minimized",
|
describe("The Minimized Chats Widget", function () {
|
||||||
mock.initConverse(
|
|
||||||
['rosterGroupsFetched'], {},
|
|
||||||
async function (done, _converse) {
|
|
||||||
|
|
||||||
await test_utils.waitForRoster(_converse, 'current');
|
it("shows chats that have been minimized",
|
||||||
await test_utils.openControlBox(_converse);
|
mock.initConverse(
|
||||||
_converse.minimized_chats.initToggle();
|
['rosterGroupsFetched'], {},
|
||||||
|
async function (done, _converse) {
|
||||||
|
|
||||||
let contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit';
|
await mock.waitForRoster(_converse, 'current');
|
||||||
await test_utils.openChatBoxFor(_converse, contact_jid)
|
await mock.openControlBox(_converse);
|
||||||
let chatview = _converse.chatboxviews.get(contact_jid);
|
_converse.minimized_chats.initToggle();
|
||||||
expect(chatview.model.get('minimized')).toBeFalsy();
|
|
||||||
expect(u.isVisible(_converse.minimized_chats.el)).toBe(false);
|
|
||||||
chatview.el.querySelector('.toggle-chatbox-button').click();
|
|
||||||
expect(chatview.model.get('minimized')).toBeTruthy();
|
|
||||||
expect(u.isVisible(_converse.minimized_chats.el)).toBe(true);
|
|
||||||
expect(_converse.minimized_chats.keys().length).toBe(1);
|
|
||||||
expect(_converse.minimized_chats.keys()[0]).toBe(contact_jid);
|
|
||||||
|
|
||||||
contact_jid = mock.cur_names[1].replace(/ /g,'.').toLowerCase() + '@montague.lit';
|
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)
|
||||||
chatview = _converse.chatboxviews.get(contact_jid);
|
let chatview = _converse.chatboxviews.get(contact_jid);
|
||||||
expect(chatview.model.get('minimized')).toBeFalsy();
|
expect(chatview.model.get('minimized')).toBeFalsy();
|
||||||
chatview.el.querySelector('.toggle-chatbox-button').click();
|
expect(u.isVisible(_converse.minimized_chats.el)).toBe(false);
|
||||||
expect(chatview.model.get('minimized')).toBeTruthy();
|
chatview.el.querySelector('.toggle-chatbox-button').click();
|
||||||
expect(u.isVisible(_converse.minimized_chats.el)).toBe(true);
|
expect(chatview.model.get('minimized')).toBeTruthy();
|
||||||
expect(_converse.minimized_chats.keys().length).toBe(2);
|
expect(u.isVisible(_converse.minimized_chats.el)).toBe(true);
|
||||||
expect(_.includes(_converse.minimized_chats.keys(), contact_jid)).toBeTruthy();
|
expect(_converse.minimized_chats.keys().length).toBe(1);
|
||||||
done();
|
expect(_converse.minimized_chats.keys()[0]).toBe(contact_jid);
|
||||||
}));
|
|
||||||
|
|
||||||
it("can be toggled to hide or show minimized chats",
|
contact_jid = mock.cur_names[1].replace(/ /g,'.').toLowerCase() + '@montague.lit';
|
||||||
mock.initConverse(
|
await mock.openChatBoxFor(_converse, contact_jid);
|
||||||
['rosterGroupsFetched'], {},
|
chatview = _converse.chatboxviews.get(contact_jid);
|
||||||
async function (done, _converse) {
|
expect(chatview.model.get('minimized')).toBeFalsy();
|
||||||
|
chatview.el.querySelector('.toggle-chatbox-button').click();
|
||||||
|
expect(chatview.model.get('minimized')).toBeTruthy();
|
||||||
|
expect(u.isVisible(_converse.minimized_chats.el)).toBe(true);
|
||||||
|
expect(_converse.minimized_chats.keys().length).toBe(2);
|
||||||
|
expect(_.includes(_converse.minimized_chats.keys(), contact_jid)).toBeTruthy();
|
||||||
|
done();
|
||||||
|
}));
|
||||||
|
|
||||||
await test_utils.waitForRoster(_converse, 'current');
|
it("can be toggled to hide or show minimized chats",
|
||||||
await test_utils.openControlBox(_converse);
|
mock.initConverse(
|
||||||
_converse.minimized_chats.initToggle();
|
['rosterGroupsFetched'], {},
|
||||||
|
async function (done, _converse) {
|
||||||
|
|
||||||
const contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit';
|
await mock.waitForRoster(_converse, 'current');
|
||||||
await test_utils.openChatBoxFor(_converse, contact_jid);
|
await mock.openControlBox(_converse);
|
||||||
const chatview = _converse.chatboxviews.get(contact_jid);
|
_converse.minimized_chats.initToggle();
|
||||||
expect(u.isVisible(_converse.minimized_chats.el)).toBeFalsy();
|
|
||||||
chatview.model.set({'minimized': true});
|
|
||||||
expect(u.isVisible(_converse.minimized_chats.el)).toBeTruthy();
|
|
||||||
expect(_converse.minimized_chats.keys().length).toBe(1);
|
|
||||||
expect(_converse.minimized_chats.keys()[0]).toBe(contact_jid);
|
|
||||||
expect(u.isVisible(_converse.minimized_chats.el.querySelector('.minimized-chats-flyout'))).toBeTruthy();
|
|
||||||
expect(_converse.minimized_chats.toggleview.model.get('collapsed')).toBeFalsy();
|
|
||||||
_converse.minimized_chats.el.querySelector('#toggle-minimized-chats').click();
|
|
||||||
await u.waitUntil(() => u.isVisible(_converse.minimized_chats.el.querySelector('.minimized-chats-flyout')));
|
|
||||||
expect(_converse.minimized_chats.toggleview.model.get('collapsed')).toBeTruthy();
|
|
||||||
done();
|
|
||||||
}));
|
|
||||||
|
|
||||||
it("shows the number messages received to minimized chats",
|
const contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit';
|
||||||
mock.initConverse(
|
await mock.openChatBoxFor(_converse, contact_jid);
|
||||||
['rosterGroupsFetched', 'chatBoxesFetched'], {},
|
const chatview = _converse.chatboxviews.get(contact_jid);
|
||||||
async function (done, _converse) {
|
expect(u.isVisible(_converse.minimized_chats.el)).toBeFalsy();
|
||||||
|
chatview.model.set({'minimized': true});
|
||||||
|
expect(u.isVisible(_converse.minimized_chats.el)).toBeTruthy();
|
||||||
|
expect(_converse.minimized_chats.keys().length).toBe(1);
|
||||||
|
expect(_converse.minimized_chats.keys()[0]).toBe(contact_jid);
|
||||||
|
expect(u.isVisible(_converse.minimized_chats.el.querySelector('.minimized-chats-flyout'))).toBeTruthy();
|
||||||
|
expect(_converse.minimized_chats.toggleview.model.get('collapsed')).toBeFalsy();
|
||||||
|
_converse.minimized_chats.el.querySelector('#toggle-minimized-chats').click();
|
||||||
|
await u.waitUntil(() => u.isVisible(_converse.minimized_chats.el.querySelector('.minimized-chats-flyout')));
|
||||||
|
expect(_converse.minimized_chats.toggleview.model.get('collapsed')).toBeTruthy();
|
||||||
|
done();
|
||||||
|
}));
|
||||||
|
|
||||||
await test_utils.waitForRoster(_converse, 'current', 4);
|
it("shows the number messages received to minimized chats",
|
||||||
await test_utils.openControlBox(_converse);
|
mock.initConverse(
|
||||||
_converse.minimized_chats.initToggle();
|
['rosterGroupsFetched', 'chatBoxesFetched'], {},
|
||||||
|
async function (done, _converse) {
|
||||||
|
|
||||||
var i, contact_jid, chatview, msg;
|
await mock.waitForRoster(_converse, 'current', 4);
|
||||||
_converse.minimized_chats.toggleview.model.set({'collapsed': true});
|
await mock.openControlBox(_converse);
|
||||||
|
_converse.minimized_chats.initToggle();
|
||||||
|
|
||||||
const unread_el = _converse.minimized_chats.toggleview.el.querySelector('.unread-message-count');
|
var i, contact_jid, chatview, msg;
|
||||||
expect(unread_el === null).toBe(true);
|
_converse.minimized_chats.toggleview.model.set({'collapsed': true});
|
||||||
|
|
||||||
for (i=0; i<3; i++) {
|
const unread_el = _converse.minimized_chats.toggleview.el.querySelector('.unread-message-count');
|
||||||
contact_jid = mock.cur_names[i].replace(/ /g,'.').toLowerCase() + '@montague.lit';
|
expect(unread_el === null).toBe(true);
|
||||||
test_utils.openChatBoxFor(_converse, contact_jid);
|
|
||||||
}
|
|
||||||
await u.waitUntil(() => _converse.chatboxes.length == 4);
|
|
||||||
|
|
||||||
chatview = _converse.chatboxviews.get(contact_jid);
|
for (i=0; i<3; i++) {
|
||||||
chatview.model.set({'minimized': true});
|
contact_jid = mock.cur_names[i].replace(/ /g,'.').toLowerCase() + '@montague.lit';
|
||||||
for (i=0; i<3; i++) {
|
mock.openChatBoxFor(_converse, contact_jid);
|
||||||
msg = $msg({
|
}
|
||||||
from: contact_jid,
|
await u.waitUntil(() => _converse.chatboxes.length == 4);
|
||||||
to: _converse.connection.jid,
|
|
||||||
type: 'chat',
|
|
||||||
id: u.getUniqueId()
|
|
||||||
}).c('body').t('This message is sent to a minimized chatbox').up()
|
|
||||||
.c('active', {'xmlns': 'http://jabber.org/protocol/chatstates'}).tree();
|
|
||||||
_converse.handleMessageStanza(msg);
|
|
||||||
}
|
|
||||||
await u.waitUntil(() => chatview.model.messages.length === 3, 500);
|
|
||||||
|
|
||||||
expect(u.isVisible(_converse.minimized_chats.toggleview.el.querySelector('.unread-message-count'))).toBeTruthy();
|
chatview = _converse.chatboxviews.get(contact_jid);
|
||||||
expect(_converse.minimized_chats.toggleview.el.querySelector('.unread-message-count').textContent).toBe((3).toString());
|
chatview.model.set({'minimized': true});
|
||||||
// Chat state notifications don't increment the unread messages counter
|
for (i=0; i<3; i++) {
|
||||||
// <composing> state
|
msg = $msg({
|
||||||
_converse.handleMessageStanza($msg({
|
|
||||||
from: contact_jid,
|
from: contact_jid,
|
||||||
to: _converse.connection.jid,
|
to: _converse.connection.jid,
|
||||||
type: 'chat',
|
type: 'chat',
|
||||||
id: u.getUniqueId()
|
id: u.getUniqueId()
|
||||||
}).c('composing', {'xmlns': 'http://jabber.org/protocol/chatstates'}).tree());
|
}).c('body').t('This message is sent to a minimized chatbox').up()
|
||||||
expect(_converse.minimized_chats.toggleview.el.querySelector('.unread-message-count').textContent).toBe((i).toString());
|
.c('active', {'xmlns': 'http://jabber.org/protocol/chatstates'}).tree();
|
||||||
|
_converse.handleMessageStanza(msg);
|
||||||
|
}
|
||||||
|
await u.waitUntil(() => chatview.model.messages.length === 3, 500);
|
||||||
|
|
||||||
// <paused> state
|
expect(u.isVisible(_converse.minimized_chats.toggleview.el.querySelector('.unread-message-count'))).toBeTruthy();
|
||||||
_converse.handleMessageStanza($msg({
|
expect(_converse.minimized_chats.toggleview.el.querySelector('.unread-message-count').textContent).toBe((3).toString());
|
||||||
from: contact_jid,
|
// Chat state notifications don't increment the unread messages counter
|
||||||
to: _converse.connection.jid,
|
// <composing> state
|
||||||
type: 'chat',
|
_converse.handleMessageStanza($msg({
|
||||||
id: u.getUniqueId()
|
from: contact_jid,
|
||||||
}).c('paused', {'xmlns': 'http://jabber.org/protocol/chatstates'}).tree());
|
to: _converse.connection.jid,
|
||||||
expect(_converse.minimized_chats.toggleview.el.querySelector('.unread-message-count').textContent).toBe((i).toString());
|
type: 'chat',
|
||||||
|
id: u.getUniqueId()
|
||||||
|
}).c('composing', {'xmlns': 'http://jabber.org/protocol/chatstates'}).tree());
|
||||||
|
expect(_converse.minimized_chats.toggleview.el.querySelector('.unread-message-count').textContent).toBe((i).toString());
|
||||||
|
|
||||||
// <gone> state
|
// <paused> state
|
||||||
_converse.handleMessageStanza($msg({
|
_converse.handleMessageStanza($msg({
|
||||||
from: contact_jid,
|
from: contact_jid,
|
||||||
to: _converse.connection.jid,
|
to: _converse.connection.jid,
|
||||||
type: 'chat',
|
type: 'chat',
|
||||||
id: u.getUniqueId()
|
id: u.getUniqueId()
|
||||||
}).c('gone', {'xmlns': 'http://jabber.org/protocol/chatstates'}).tree());
|
}).c('paused', {'xmlns': 'http://jabber.org/protocol/chatstates'}).tree());
|
||||||
expect(_converse.minimized_chats.toggleview.el.querySelector('.unread-message-count').textContent).toBe((i).toString());
|
expect(_converse.minimized_chats.toggleview.el.querySelector('.unread-message-count').textContent).toBe((i).toString());
|
||||||
|
|
||||||
// <inactive> state
|
// <gone> state
|
||||||
_converse.handleMessageStanza($msg({
|
_converse.handleMessageStanza($msg({
|
||||||
from: contact_jid,
|
from: contact_jid,
|
||||||
to: _converse.connection.jid,
|
to: _converse.connection.jid,
|
||||||
type: 'chat',
|
type: 'chat',
|
||||||
id: u.getUniqueId()
|
id: u.getUniqueId()
|
||||||
}).c('inactive', {'xmlns': 'http://jabber.org/protocol/chatstates'}).tree());
|
}).c('gone', {'xmlns': 'http://jabber.org/protocol/chatstates'}).tree());
|
||||||
expect(_converse.minimized_chats.toggleview.el.querySelector('.unread-message-count').textContent).toBe((i).toString());
|
expect(_converse.minimized_chats.toggleview.el.querySelector('.unread-message-count').textContent).toBe((i).toString());
|
||||||
done();
|
|
||||||
}));
|
|
||||||
|
|
||||||
it("shows the number messages received to minimized groupchats",
|
// <inactive> state
|
||||||
mock.initConverse(
|
_converse.handleMessageStanza($msg({
|
||||||
['rosterGroupsFetched'], {},
|
from: contact_jid,
|
||||||
async function (done, _converse) {
|
to: _converse.connection.jid,
|
||||||
|
type: 'chat',
|
||||||
|
id: u.getUniqueId()
|
||||||
|
}).c('inactive', {'xmlns': 'http://jabber.org/protocol/chatstates'}).tree());
|
||||||
|
expect(_converse.minimized_chats.toggleview.el.querySelector('.unread-message-count').textContent).toBe((i).toString());
|
||||||
|
done();
|
||||||
|
}));
|
||||||
|
|
||||||
const muc_jid = 'kitchen@conference.shakespeare.lit';
|
it("shows the number messages received to minimized groupchats",
|
||||||
await test_utils.openAndEnterChatRoom(_converse, 'kitchen@conference.shakespeare.lit', 'fires');
|
mock.initConverse(
|
||||||
const view = _converse.chatboxviews.get(muc_jid);
|
['rosterGroupsFetched'], {},
|
||||||
view.model.set({'minimized': true});
|
async function (done, _converse) {
|
||||||
const message = 'fires: Your attention is required';
|
|
||||||
const nick = mock.chatroom_names[0];
|
const muc_jid = 'kitchen@conference.shakespeare.lit';
|
||||||
const msg = $msg({
|
await mock.openAndEnterChatRoom(_converse, 'kitchen@conference.shakespeare.lit', 'fires');
|
||||||
from: muc_jid+'/'+nick,
|
const view = _converse.chatboxviews.get(muc_jid);
|
||||||
id: u.getUniqueId(),
|
view.model.set({'minimized': true});
|
||||||
to: 'romeo@montague.lit',
|
const message = 'fires: Your attention is required';
|
||||||
type: 'groupchat'
|
const nick = mock.chatroom_names[0];
|
||||||
}).c('body').t(message).tree();
|
const msg = $msg({
|
||||||
view.model.queueMessage(msg);
|
from: muc_jid+'/'+nick,
|
||||||
await u.waitUntil(() => view.model.messages.length);
|
id: u.getUniqueId(),
|
||||||
expect(u.isVisible(_converse.minimized_chats.toggleview.el.querySelector('.unread-message-count'))).toBeTruthy();
|
to: 'romeo@montague.lit',
|
||||||
expect(_converse.minimized_chats.toggleview.el.querySelector('.unread-message-count').textContent).toBe('1');
|
type: 'groupchat'
|
||||||
done();
|
}).c('body').t(message).tree();
|
||||||
}));
|
view.model.queueMessage(msg);
|
||||||
});
|
await u.waitUntil(() => view.model.messages.length);
|
||||||
|
expect(u.isVisible(_converse.minimized_chats.toggleview.el.querySelector('.unread-message-count'))).toBeTruthy();
|
||||||
|
expect(_converse.minimized_chats.toggleview.el.querySelector('.unread-message-count').textContent).toBe('1');
|
||||||
|
done();
|
||||||
|
}));
|
||||||
});
|
});
|
||||||
|
710
spec/modtools.js
710
spec/modtools.js
@ -1,370 +1,368 @@
|
|||||||
window.addEventListener('converse-loaded', () => {
|
/*global mock */
|
||||||
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;
|
|
||||||
|
|
||||||
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;
|
||||||
|
|
||||||
it("allows you to set affiliations and roles",
|
describe("The groupchat moderator tool", function () {
|
||||||
mock.initConverse(
|
|
||||||
['rosterGroupsFetched'], {},
|
|
||||||
async function (done, _converse) {
|
|
||||||
|
|
||||||
spyOn(_converse.ChatRoomView.prototype, 'showModeratorToolsModal').and.callThrough();
|
it("allows you to set affiliations and roles",
|
||||||
const muc_jid = 'lounge@montague.lit';
|
|
||||||
|
|
||||||
let members = [
|
|
||||||
{'jid': 'hag66@shakespeare.lit', 'nick': 'witch', 'affiliation': 'member'},
|
|
||||||
{'jid': 'gower@shakespeare.lit', 'nick': 'gower', 'affiliation': 'member'},
|
|
||||||
{'jid': 'wiccarocks@shakespeare.lit', 'nick': 'wiccan', 'affiliation': 'admin'},
|
|
||||||
{'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);
|
|
||||||
const view = _converse.chatboxviews.get(muc_jid);
|
|
||||||
await u.waitUntil(() => (view.model.occupants.length === 5), 1000);
|
|
||||||
|
|
||||||
const textarea = view.el.querySelector('.chat-textarea');
|
|
||||||
textarea.value = '/modtools';
|
|
||||||
const enter = { 'target': textarea, 'preventDefault': function preventDefault () {}, 'keyCode': 13 };
|
|
||||||
view.onKeyDown(enter);
|
|
||||||
await u.waitUntil(() => view.showModeratorToolsModal.calls.count());
|
|
||||||
|
|
||||||
const modal = view.modtools_modal;
|
|
||||||
await u.waitUntil(() => u.isVisible(modal.el), 1000);
|
|
||||||
let tab = modal.el.querySelector('#affiliations-tab');
|
|
||||||
// Clear so that we don't match older stanzas
|
|
||||||
_converse.connection.IQ_stanzas = [];
|
|
||||||
tab.click();
|
|
||||||
let select = modal.el.querySelector('.select-affiliation');
|
|
||||||
expect(select.value).toBe('owner');
|
|
||||||
select.value = 'admin';
|
|
||||||
let button = modal.el.querySelector('.btn-primary[name="users_with_affiliation"]');
|
|
||||||
button.click();
|
|
||||||
await u.waitUntil(() => !modal.loading_users_with_affiliation);
|
|
||||||
let user_els = modal.el.querySelectorAll('.list-group--users > li');
|
|
||||||
expect(user_els.length).toBe(1);
|
|
||||||
expect(user_els[0].querySelector('.list-group-item.active').textContent.trim()).toBe('JID: wiccarocks@shakespeare.lit');
|
|
||||||
expect(user_els[0].querySelector('.list-group-item:nth-child(2n)').textContent.trim()).toBe('Nickname: wiccan');
|
|
||||||
expect(user_els[0].querySelector('.list-group-item:nth-child(3n) div').textContent.trim()).toBe('Affiliation: admin');
|
|
||||||
|
|
||||||
_converse.connection.IQ_stanzas = [];
|
|
||||||
select.value = 'owner';
|
|
||||||
button.click();
|
|
||||||
await u.waitUntil(() => !modal.loading_users_with_affiliation);
|
|
||||||
user_els = modal.el.querySelectorAll('.list-group--users > li');
|
|
||||||
expect(user_els.length).toBe(2);
|
|
||||||
expect(user_els[0].querySelector('.list-group-item.active').textContent.trim()).toBe('JID: romeo@montague.lit');
|
|
||||||
expect(user_els[0].querySelector('.list-group-item:nth-child(2n)').textContent.trim()).toBe('Nickname: romeo');
|
|
||||||
expect(user_els[0].querySelector('.list-group-item:nth-child(3n) div').textContent.trim()).toBe('Affiliation: owner');
|
|
||||||
|
|
||||||
expect(user_els[1].querySelector('.list-group-item.active').textContent.trim()).toBe('JID: crone1@shakespeare.lit');
|
|
||||||
expect(user_els[1].querySelector('.list-group-item:nth-child(2n)').textContent.trim()).toBe('Nickname: thirdwitch');
|
|
||||||
expect(user_els[1].querySelector('.list-group-item:nth-child(3n) div').textContent.trim()).toBe('Affiliation: owner');
|
|
||||||
|
|
||||||
const toggle = user_els[1].querySelector('.list-group-item:nth-child(3n) .toggle-form');
|
|
||||||
const form = user_els[1].querySelector('.list-group-item:nth-child(3n) .affiliation-form');
|
|
||||||
expect(u.hasClass('hidden', form)).toBeTruthy();
|
|
||||||
toggle.click();
|
|
||||||
expect(u.hasClass('hidden', form)).toBeFalsy();
|
|
||||||
select = form.querySelector('.select-affiliation');
|
|
||||||
expect(select.value).toBe('owner');
|
|
||||||
select.value = 'admin';
|
|
||||||
const input = form.querySelector('input[name="reason"]');
|
|
||||||
input.value = "You're an admin now";
|
|
||||||
const submit = form.querySelector('.btn-primary');
|
|
||||||
submit.click();
|
|
||||||
|
|
||||||
spyOn(_converse.ChatRoomOccupants.prototype, 'fetchMembers').and.callThrough();
|
|
||||||
const sent_IQ = _converse.connection.IQ_stanzas.pop();
|
|
||||||
expect(Strophe.serialize(sent_IQ)).toBe(
|
|
||||||
`<iq id="${sent_IQ.getAttribute('id')}" to="lounge@montague.lit" type="set" xmlns="jabber:client">`+
|
|
||||||
`<query xmlns="http://jabber.org/protocol/muc#admin">`+
|
|
||||||
`<item affiliation="admin" jid="crone1@shakespeare.lit">`+
|
|
||||||
`<reason>You're an admin now</reason>`+
|
|
||||||
`</item>`+
|
|
||||||
`</query>`+
|
|
||||||
`</iq>`);
|
|
||||||
|
|
||||||
_converse.connection.IQ_stanzas = [];
|
|
||||||
const stanza = $iq({
|
|
||||||
'type': 'result',
|
|
||||||
'id': sent_IQ.getAttribute('id'),
|
|
||||||
'from': view.model.get('jid'),
|
|
||||||
'to': _converse.connection.jid
|
|
||||||
});
|
|
||||||
_converse.connection._dataRecv(test_utils.createRequest(stanza));
|
|
||||||
await u.waitUntil(() => view.model.occupants.fetchMembers.calls.count());
|
|
||||||
|
|
||||||
members = [
|
|
||||||
{'jid': 'hag66@shakespeare.lit', 'nick': 'witch', 'affiliation': 'member'},
|
|
||||||
{'jid': 'gower@shakespeare.lit', 'nick': 'gower', 'affiliation': 'member'},
|
|
||||||
{'jid': 'wiccarocks@shakespeare.lit', 'nick': 'wiccan', 'affiliation': 'admin'},
|
|
||||||
{'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 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');
|
|
||||||
|
|
||||||
user_els = modal.el.querySelectorAll('.list-group--users > li');
|
|
||||||
expect(user_els.length).toBe(1);
|
|
||||||
expect(user_els[0].querySelector('.list-group-item.active').textContent.trim()).toBe('JID: romeo@montague.lit');
|
|
||||||
expect(user_els[0].querySelector('.list-group-item:nth-child(2n)').textContent.trim()).toBe('Nickname: romeo');
|
|
||||||
expect(user_els[0].querySelector('.list-group-item:nth-child(3n) div').textContent.trim()).toBe('Affiliation: owner');
|
|
||||||
|
|
||||||
tab = modal.el.querySelector('#roles-tab');
|
|
||||||
tab.click();
|
|
||||||
select = modal.el.querySelector('.select-role');
|
|
||||||
expect(u.isVisible(select)).toBe(true);
|
|
||||||
expect(select.value).toBe('moderator');
|
|
||||||
button = modal.el.querySelector('.btn-primary[name="users_with_role"]');
|
|
||||||
button.click();
|
|
||||||
|
|
||||||
const roles_panel = modal.el.querySelector('#roles-tabpanel');
|
|
||||||
await u.waitUntil(() => roles_panel.querySelectorAll('.list-group--users > li').length === 1);
|
|
||||||
select.value = 'participant';
|
|
||||||
button.click();
|
|
||||||
await u.waitUntil(() => !modal.loading_users_with_affiliation);
|
|
||||||
user_els = roles_panel.querySelectorAll('.list-group--users > li')
|
|
||||||
expect(user_els.length).toBe(1);
|
|
||||||
expect(user_els[0].textContent.trim()).toBe('No users with that role found.');
|
|
||||||
done();
|
|
||||||
}));
|
|
||||||
|
|
||||||
it("allows you to filter affiliation search results",
|
|
||||||
mock.initConverse(
|
|
||||||
['rosterGroupsFetched'], {},
|
|
||||||
async function (done, _converse) {
|
|
||||||
|
|
||||||
spyOn(_converse.ChatRoomView.prototype, 'showModeratorToolsModal').and.callThrough();
|
|
||||||
const muc_jid = 'lounge@montague.lit';
|
|
||||||
const members = [
|
|
||||||
{'jid': 'hag66@shakespeare.lit', 'nick': 'witch', 'affiliation': 'member'},
|
|
||||||
{'jid': 'gower@shakespeare.lit', 'nick': 'gower', 'affiliation': 'member'},
|
|
||||||
{'jid': 'wiccarocks@shakespeare.lit', 'nick': 'wiccan', 'affiliation': 'member'},
|
|
||||||
{'jid': 'crone1@shakespeare.lit', 'nick': 'thirdwitch', 'affiliation': 'member'},
|
|
||||||
{'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);
|
|
||||||
const view = _converse.chatboxviews.get(muc_jid);
|
|
||||||
await u.waitUntil(() => (view.model.occupants.length === 6), 1000);
|
|
||||||
|
|
||||||
const textarea = view.el.querySelector('.chat-textarea');
|
|
||||||
textarea.value = '/modtools';
|
|
||||||
const enter = { 'target': textarea, 'preventDefault': function preventDefault () {}, 'keyCode': 13 };
|
|
||||||
view.onKeyDown(enter);
|
|
||||||
await u.waitUntil(() => view.showModeratorToolsModal.calls.count());
|
|
||||||
|
|
||||||
const modal = view.modtools_modal;
|
|
||||||
await u.waitUntil(() => u.isVisible(modal.el), 1000);
|
|
||||||
// Clear so that we don't match older stanzas
|
|
||||||
_converse.connection.IQ_stanzas = [];
|
|
||||||
const select = modal.el.querySelector('.select-affiliation');
|
|
||||||
expect(select.value).toBe('owner');
|
|
||||||
select.value = 'member';
|
|
||||||
const button = modal.el.querySelector('.btn-primary[name="users_with_affiliation"]');
|
|
||||||
button.click();
|
|
||||||
await u.waitUntil(() => !modal.loading_users_with_affiliation);
|
|
||||||
const user_els = modal.el.querySelectorAll('.list-group--users > li');
|
|
||||||
expect(user_els.length).toBe(6);
|
|
||||||
|
|
||||||
const nicks = Array.from(modal.el.querySelectorAll('.list-group--users > li')).map(el => el.getAttribute('data-nick'));
|
|
||||||
expect(nicks.join(' ')).toBe('gower juliet romeo thirdwitch wiccan witch');
|
|
||||||
|
|
||||||
const filter = modal.el.querySelector('[name="filter"]');
|
|
||||||
expect(filter).not.toBe(null);
|
|
||||||
|
|
||||||
filter.value = 'romeo';
|
|
||||||
u.triggerEvent(filter, "keyup", "KeyboardEvent");
|
|
||||||
await u.waitUntil(() => ( modal.el.querySelectorAll('.list-group--users > li').length === 1));
|
|
||||||
|
|
||||||
filter.value = 'r';
|
|
||||||
u.triggerEvent(filter, "keyup", "KeyboardEvent");
|
|
||||||
await u.waitUntil(() => ( modal.el.querySelectorAll('.list-group--users > li').length === 3));
|
|
||||||
|
|
||||||
filter.value = 'gower';
|
|
||||||
u.triggerEvent(filter, "keyup", "KeyboardEvent");
|
|
||||||
await u.waitUntil(() => ( modal.el.querySelectorAll('.list-group--users > li').length === 1));
|
|
||||||
done();
|
|
||||||
}));
|
|
||||||
|
|
||||||
it("allows you to filter role search results",
|
|
||||||
mock.initConverse(
|
|
||||||
['rosterGroupsFetched'], {},
|
|
||||||
async function (done, _converse) {
|
|
||||||
|
|
||||||
spyOn(_converse.ChatRoomView.prototype, 'showModeratorToolsModal').and.callThrough();
|
|
||||||
const muc_jid = 'lounge@montague.lit';
|
|
||||||
await test_utils.openAndEnterChatRoom(_converse, muc_jid, 'romeo', []);
|
|
||||||
const view = _converse.chatboxviews.get(muc_jid);
|
|
||||||
|
|
||||||
_converse.connection._dataRecv(test_utils.createRequest(
|
|
||||||
$pres({to: _converse.jid, from: `${muc_jid}/nomorenicks`})
|
|
||||||
.c('x', {xmlns: Strophe.NS.MUC_USER})
|
|
||||||
.c('item', {
|
|
||||||
'affiliation': 'none',
|
|
||||||
'jid': `nomorenicks@montague.lit`,
|
|
||||||
'role': 'participant'
|
|
||||||
})
|
|
||||||
));
|
|
||||||
_converse.connection._dataRecv(test_utils.createRequest(
|
|
||||||
$pres({to: _converse.jid, from: `${muc_jid}/newb`})
|
|
||||||
.c('x', {xmlns: Strophe.NS.MUC_USER})
|
|
||||||
.c('item', {
|
|
||||||
'affiliation': 'none',
|
|
||||||
'jid': `newb@montague.lit`,
|
|
||||||
'role': 'participant'
|
|
||||||
})
|
|
||||||
));
|
|
||||||
_converse.connection._dataRecv(test_utils.createRequest(
|
|
||||||
$pres({to: _converse.jid, from: `${muc_jid}/some1`})
|
|
||||||
.c('x', {xmlns: Strophe.NS.MUC_USER})
|
|
||||||
.c('item', {
|
|
||||||
'affiliation': 'none',
|
|
||||||
'jid': `some1@montague.lit`,
|
|
||||||
'role': 'participant'
|
|
||||||
})
|
|
||||||
));
|
|
||||||
_converse.connection._dataRecv(test_utils.createRequest(
|
|
||||||
$pres({to: _converse.jid, from: `${muc_jid}/oldhag`})
|
|
||||||
.c('x', {xmlns: Strophe.NS.MUC_USER})
|
|
||||||
.c('item', {
|
|
||||||
'affiliation': 'none',
|
|
||||||
'jid': `oldhag@montague.lit`,
|
|
||||||
'role': 'participant'
|
|
||||||
})
|
|
||||||
));
|
|
||||||
_converse.connection._dataRecv(test_utils.createRequest(
|
|
||||||
$pres({to: _converse.jid, from: `${muc_jid}/crone`})
|
|
||||||
.c('x', {xmlns: Strophe.NS.MUC_USER})
|
|
||||||
.c('item', {
|
|
||||||
'affiliation': 'none',
|
|
||||||
'jid': `crone@montague.lit`,
|
|
||||||
'role': 'participant'
|
|
||||||
})
|
|
||||||
));
|
|
||||||
_converse.connection._dataRecv(test_utils.createRequest(
|
|
||||||
$pres({to: _converse.jid, from: `${muc_jid}/tux`})
|
|
||||||
.c('x', {xmlns: Strophe.NS.MUC_USER})
|
|
||||||
.c('item', {
|
|
||||||
'affiliation': 'none',
|
|
||||||
'jid': `tux@montague.lit`,
|
|
||||||
'role': 'participant'
|
|
||||||
})
|
|
||||||
));
|
|
||||||
await u.waitUntil(() => (view.model.occupants.length === 7), 1000);
|
|
||||||
|
|
||||||
const textarea = view.el.querySelector('.chat-textarea');
|
|
||||||
textarea.value = '/modtools';
|
|
||||||
const enter = { 'target': textarea, 'preventDefault': function preventDefault () {}, 'keyCode': 13 };
|
|
||||||
view.onKeyDown(enter);
|
|
||||||
await u.waitUntil(() => view.showModeratorToolsModal.calls.count());
|
|
||||||
|
|
||||||
const modal = view.modtools_modal;
|
|
||||||
await u.waitUntil(() => u.isVisible(modal.el), 1000);
|
|
||||||
|
|
||||||
const tab = modal.el.querySelector('#roles-tab');
|
|
||||||
tab.click();
|
|
||||||
|
|
||||||
// Clear so that we don't match older stanzas
|
|
||||||
_converse.connection.IQ_stanzas = [];
|
|
||||||
|
|
||||||
const select = modal.el.querySelector('.select-role');
|
|
||||||
expect(select.value).toBe('moderator');
|
|
||||||
select.value = 'participant';
|
|
||||||
|
|
||||||
const button = modal.el.querySelector('.btn-primary[name="users_with_role"]');
|
|
||||||
button.click();
|
|
||||||
await u.waitUntil(() => !modal.loading_users_with_role);
|
|
||||||
const user_els = modal.el.querySelectorAll('.list-group--users > li');
|
|
||||||
expect(user_els.length).toBe(6);
|
|
||||||
|
|
||||||
const nicks = Array.from(modal.el.querySelectorAll('.list-group--users > li')).map(el => el.getAttribute('data-nick'));
|
|
||||||
expect(nicks.join(' ')).toBe('crone newb nomorenicks oldhag some1 tux');
|
|
||||||
|
|
||||||
const filter = modal.el.querySelector('[name="filter"]');
|
|
||||||
expect(filter).not.toBe(null);
|
|
||||||
|
|
||||||
filter.value = 'tux';
|
|
||||||
u.triggerEvent(filter, "keyup", "KeyboardEvent");
|
|
||||||
await u.waitUntil(() => ( modal.el.querySelectorAll('.list-group--users > li').length === 1));
|
|
||||||
|
|
||||||
filter.value = 'r';
|
|
||||||
u.triggerEvent(filter, "keyup", "KeyboardEvent");
|
|
||||||
await u.waitUntil(() => ( modal.el.querySelectorAll('.list-group--users > li').length === 2));
|
|
||||||
|
|
||||||
filter.value = 'crone';
|
|
||||||
u.triggerEvent(filter, "keyup", "KeyboardEvent");
|
|
||||||
await u.waitUntil(() => ( modal.el.querySelectorAll('.list-group--users > li').length === 1));
|
|
||||||
done();
|
|
||||||
}));
|
|
||||||
|
|
||||||
it("shows an error message if a particular affiliation list may not be retrieved",
|
|
||||||
mock.initConverse(
|
mock.initConverse(
|
||||||
['rosterGroupsFetched'], {},
|
['rosterGroupsFetched'], {},
|
||||||
async function (done, _converse) {
|
async function (done, _converse) {
|
||||||
|
|
||||||
spyOn(_converse.ChatRoomView.prototype, 'showModeratorToolsModal').and.callThrough();
|
spyOn(_converse.ChatRoomView.prototype, 'showModeratorToolsModal').and.callThrough();
|
||||||
const muc_jid = 'lounge@montague.lit';
|
const muc_jid = 'lounge@montague.lit';
|
||||||
const members = [
|
|
||||||
{'jid': 'hag66@shakespeare.lit', 'nick': 'witch', 'affiliation': 'member'},
|
|
||||||
{'jid': 'gower@shakespeare.lit', 'nick': 'gower', 'affiliation': 'member'},
|
|
||||||
{'jid': 'wiccarocks@shakespeare.lit', 'nick': 'wiccan', 'affiliation': 'admin'},
|
|
||||||
{'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);
|
|
||||||
const view = _converse.chatboxviews.get(muc_jid);
|
|
||||||
await u.waitUntil(() => (view.model.occupants.length === 5));
|
|
||||||
|
|
||||||
const textarea = view.el.querySelector('.chat-textarea');
|
let members = [
|
||||||
textarea.value = '/modtools';
|
{'jid': 'hag66@shakespeare.lit', 'nick': 'witch', 'affiliation': 'member'},
|
||||||
const enter = { 'target': textarea, 'preventDefault': function preventDefault () {}, 'keyCode': 13 };
|
{'jid': 'gower@shakespeare.lit', 'nick': 'gower', 'affiliation': 'member'},
|
||||||
view.onKeyDown(enter);
|
{'jid': 'wiccarocks@shakespeare.lit', 'nick': 'wiccan', 'affiliation': 'admin'},
|
||||||
await u.waitUntil(() => view.showModeratorToolsModal.calls.count());
|
{'jid': 'crone1@shakespeare.lit', 'nick': 'thirdwitch', 'affiliation': 'owner'},
|
||||||
|
{'jid': 'romeo@montague.lit', 'nick': 'romeo', 'affiliation': 'owner'},
|
||||||
|
];
|
||||||
|
await mock.openAndEnterChatRoom(_converse, muc_jid, 'romeo', [], members);
|
||||||
|
const view = _converse.chatboxviews.get(muc_jid);
|
||||||
|
await u.waitUntil(() => (view.model.occupants.length === 5), 1000);
|
||||||
|
|
||||||
const modal = view.modtools_modal;
|
const textarea = view.el.querySelector('.chat-textarea');
|
||||||
await u.waitUntil(() => u.isVisible(modal.el), 1000);
|
textarea.value = '/modtools';
|
||||||
const tab = modal.el.querySelector('#affiliations-tab');
|
const enter = { 'target': textarea, 'preventDefault': function preventDefault () {}, 'keyCode': 13 };
|
||||||
// Clear so that we don't match older stanzas
|
view.onKeyDown(enter);
|
||||||
_converse.connection.IQ_stanzas = [];
|
await u.waitUntil(() => view.showModeratorToolsModal.calls.count());
|
||||||
const IQ_stanzas = _converse.connection.IQ_stanzas;
|
|
||||||
tab.click();
|
|
||||||
const select = modal.el.querySelector('.select-affiliation');
|
|
||||||
select.value = 'outcast';
|
|
||||||
const button = modal.el.querySelector('.btn-primary[name="users_with_affiliation"]');
|
|
||||||
button.click();
|
|
||||||
|
|
||||||
const iq_query = await u.waitUntil(() => _.filter(
|
const modal = view.modtools_modal;
|
||||||
IQ_stanzas,
|
await u.waitUntil(() => u.isVisible(modal.el), 1000);
|
||||||
s => sizzle(`iq[to="${muc_jid}"] query[xmlns="${Strophe.NS.MUC_ADMIN}"] item[affiliation="outcast"]`, s).length
|
let tab = modal.el.querySelector('#affiliations-tab');
|
||||||
).pop());
|
// Clear so that we don't match older stanzas
|
||||||
|
_converse.connection.IQ_stanzas = [];
|
||||||
|
tab.click();
|
||||||
|
let select = modal.el.querySelector('.select-affiliation');
|
||||||
|
expect(select.value).toBe('owner');
|
||||||
|
select.value = 'admin';
|
||||||
|
let button = modal.el.querySelector('.btn-primary[name="users_with_affiliation"]');
|
||||||
|
button.click();
|
||||||
|
await u.waitUntil(() => !modal.loading_users_with_affiliation);
|
||||||
|
let user_els = modal.el.querySelectorAll('.list-group--users > li');
|
||||||
|
expect(user_els.length).toBe(1);
|
||||||
|
expect(user_els[0].querySelector('.list-group-item.active').textContent.trim()).toBe('JID: wiccarocks@shakespeare.lit');
|
||||||
|
expect(user_els[0].querySelector('.list-group-item:nth-child(2n)').textContent.trim()).toBe('Nickname: wiccan');
|
||||||
|
expect(user_els[0].querySelector('.list-group-item:nth-child(3n) div').textContent.trim()).toBe('Affiliation: admin');
|
||||||
|
|
||||||
const error = u.toStanza(
|
_converse.connection.IQ_stanzas = [];
|
||||||
`<iq from="${muc_jid}"
|
select.value = 'owner';
|
||||||
id="${iq_query.getAttribute('id')}"
|
button.click();
|
||||||
type="error"
|
await u.waitUntil(() => !modal.loading_users_with_affiliation);
|
||||||
to="${_converse.jid}">
|
user_els = modal.el.querySelectorAll('.list-group--users > li');
|
||||||
|
expect(user_els.length).toBe(2);
|
||||||
|
expect(user_els[0].querySelector('.list-group-item.active').textContent.trim()).toBe('JID: romeo@montague.lit');
|
||||||
|
expect(user_els[0].querySelector('.list-group-item:nth-child(2n)').textContent.trim()).toBe('Nickname: romeo');
|
||||||
|
expect(user_els[0].querySelector('.list-group-item:nth-child(3n) div').textContent.trim()).toBe('Affiliation: owner');
|
||||||
|
|
||||||
<error type="auth">
|
expect(user_els[1].querySelector('.list-group-item.active').textContent.trim()).toBe('JID: crone1@shakespeare.lit');
|
||||||
<forbidden xmlns="${Strophe.NS.STANZAS}"/>
|
expect(user_els[1].querySelector('.list-group-item:nth-child(2n)').textContent.trim()).toBe('Nickname: thirdwitch');
|
||||||
</error>
|
expect(user_els[1].querySelector('.list-group-item:nth-child(3n) div').textContent.trim()).toBe('Affiliation: owner');
|
||||||
</iq>`);
|
|
||||||
_converse.connection._dataRecv(test_utils.createRequest(error));
|
|
||||||
await u.waitUntil(() => !modal.loading_users_with_affiliation);
|
|
||||||
|
|
||||||
const user_els = modal.el.querySelectorAll('.list-group--users > li');
|
const toggle = user_els[1].querySelector('.list-group-item:nth-child(3n) .toggle-form');
|
||||||
expect(user_els.length).toBe(1);
|
const form = user_els[1].querySelector('.list-group-item:nth-child(3n) .affiliation-form');
|
||||||
expect(user_els[0].textContent.trim()).toBe('Error: not allowed to fetch outcast list for MUC lounge@montague.lit');
|
expect(u.hasClass('hidden', form)).toBeTruthy();
|
||||||
done();
|
toggle.click();
|
||||||
}));
|
expect(u.hasClass('hidden', form)).toBeFalsy();
|
||||||
});
|
select = form.querySelector('.select-affiliation');
|
||||||
|
expect(select.value).toBe('owner');
|
||||||
|
select.value = 'admin';
|
||||||
|
const input = form.querySelector('input[name="reason"]');
|
||||||
|
input.value = "You're an admin now";
|
||||||
|
const submit = form.querySelector('.btn-primary');
|
||||||
|
submit.click();
|
||||||
|
|
||||||
|
spyOn(_converse.ChatRoomOccupants.prototype, 'fetchMembers').and.callThrough();
|
||||||
|
const sent_IQ = _converse.connection.IQ_stanzas.pop();
|
||||||
|
expect(Strophe.serialize(sent_IQ)).toBe(
|
||||||
|
`<iq id="${sent_IQ.getAttribute('id')}" to="lounge@montague.lit" type="set" xmlns="jabber:client">`+
|
||||||
|
`<query xmlns="http://jabber.org/protocol/muc#admin">`+
|
||||||
|
`<item affiliation="admin" jid="crone1@shakespeare.lit">`+
|
||||||
|
`<reason>You're an admin now</reason>`+
|
||||||
|
`</item>`+
|
||||||
|
`</query>`+
|
||||||
|
`</iq>`);
|
||||||
|
|
||||||
|
_converse.connection.IQ_stanzas = [];
|
||||||
|
const stanza = $iq({
|
||||||
|
'type': 'result',
|
||||||
|
'id': sent_IQ.getAttribute('id'),
|
||||||
|
'from': view.model.get('jid'),
|
||||||
|
'to': _converse.connection.jid
|
||||||
|
});
|
||||||
|
_converse.connection._dataRecv(mock.createRequest(stanza));
|
||||||
|
await u.waitUntil(() => view.model.occupants.fetchMembers.calls.count());
|
||||||
|
|
||||||
|
members = [
|
||||||
|
{'jid': 'hag66@shakespeare.lit', 'nick': 'witch', 'affiliation': 'member'},
|
||||||
|
{'jid': 'gower@shakespeare.lit', 'nick': 'gower', 'affiliation': 'member'},
|
||||||
|
{'jid': 'wiccarocks@shakespeare.lit', 'nick': 'wiccan', 'affiliation': 'admin'},
|
||||||
|
{'jid': 'crone1@shakespeare.lit', 'nick': 'thirdwitch', 'affiliation': 'admin'},
|
||||||
|
{'jid': 'romeo@montague.lit', 'nick': 'romeo', 'affiliation': 'owner'},
|
||||||
|
];
|
||||||
|
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');
|
||||||
|
|
||||||
|
user_els = modal.el.querySelectorAll('.list-group--users > li');
|
||||||
|
expect(user_els.length).toBe(1);
|
||||||
|
expect(user_els[0].querySelector('.list-group-item.active').textContent.trim()).toBe('JID: romeo@montague.lit');
|
||||||
|
expect(user_els[0].querySelector('.list-group-item:nth-child(2n)').textContent.trim()).toBe('Nickname: romeo');
|
||||||
|
expect(user_els[0].querySelector('.list-group-item:nth-child(3n) div').textContent.trim()).toBe('Affiliation: owner');
|
||||||
|
|
||||||
|
tab = modal.el.querySelector('#roles-tab');
|
||||||
|
tab.click();
|
||||||
|
select = modal.el.querySelector('.select-role');
|
||||||
|
expect(u.isVisible(select)).toBe(true);
|
||||||
|
expect(select.value).toBe('moderator');
|
||||||
|
button = modal.el.querySelector('.btn-primary[name="users_with_role"]');
|
||||||
|
button.click();
|
||||||
|
|
||||||
|
const roles_panel = modal.el.querySelector('#roles-tabpanel');
|
||||||
|
await u.waitUntil(() => roles_panel.querySelectorAll('.list-group--users > li').length === 1);
|
||||||
|
select.value = 'participant';
|
||||||
|
button.click();
|
||||||
|
await u.waitUntil(() => !modal.loading_users_with_affiliation);
|
||||||
|
user_els = roles_panel.querySelectorAll('.list-group--users > li')
|
||||||
|
expect(user_els.length).toBe(1);
|
||||||
|
expect(user_els[0].textContent.trim()).toBe('No users with that role found.');
|
||||||
|
done();
|
||||||
|
}));
|
||||||
|
|
||||||
|
it("allows you to filter affiliation search results",
|
||||||
|
mock.initConverse(
|
||||||
|
['rosterGroupsFetched'], {},
|
||||||
|
async function (done, _converse) {
|
||||||
|
|
||||||
|
spyOn(_converse.ChatRoomView.prototype, 'showModeratorToolsModal').and.callThrough();
|
||||||
|
const muc_jid = 'lounge@montague.lit';
|
||||||
|
const members = [
|
||||||
|
{'jid': 'hag66@shakespeare.lit', 'nick': 'witch', 'affiliation': 'member'},
|
||||||
|
{'jid': 'gower@shakespeare.lit', 'nick': 'gower', 'affiliation': 'member'},
|
||||||
|
{'jid': 'wiccarocks@shakespeare.lit', 'nick': 'wiccan', 'affiliation': 'member'},
|
||||||
|
{'jid': 'crone1@shakespeare.lit', 'nick': 'thirdwitch', 'affiliation': 'member'},
|
||||||
|
{'jid': 'romeo@montague.lit', 'nick': 'romeo', 'affiliation': 'member'},
|
||||||
|
{'jid': 'juliet@capulet.lit', 'nick': 'juliet', 'affiliation': 'member'},
|
||||||
|
];
|
||||||
|
await mock.openAndEnterChatRoom(_converse, muc_jid, 'romeo', [], members);
|
||||||
|
const view = _converse.chatboxviews.get(muc_jid);
|
||||||
|
await u.waitUntil(() => (view.model.occupants.length === 6), 1000);
|
||||||
|
|
||||||
|
const textarea = view.el.querySelector('.chat-textarea');
|
||||||
|
textarea.value = '/modtools';
|
||||||
|
const enter = { 'target': textarea, 'preventDefault': function preventDefault () {}, 'keyCode': 13 };
|
||||||
|
view.onKeyDown(enter);
|
||||||
|
await u.waitUntil(() => view.showModeratorToolsModal.calls.count());
|
||||||
|
|
||||||
|
const modal = view.modtools_modal;
|
||||||
|
await u.waitUntil(() => u.isVisible(modal.el), 1000);
|
||||||
|
// Clear so that we don't match older stanzas
|
||||||
|
_converse.connection.IQ_stanzas = [];
|
||||||
|
const select = modal.el.querySelector('.select-affiliation');
|
||||||
|
expect(select.value).toBe('owner');
|
||||||
|
select.value = 'member';
|
||||||
|
const button = modal.el.querySelector('.btn-primary[name="users_with_affiliation"]');
|
||||||
|
button.click();
|
||||||
|
await u.waitUntil(() => !modal.loading_users_with_affiliation);
|
||||||
|
const user_els = modal.el.querySelectorAll('.list-group--users > li');
|
||||||
|
expect(user_els.length).toBe(6);
|
||||||
|
|
||||||
|
const nicks = Array.from(modal.el.querySelectorAll('.list-group--users > li')).map(el => el.getAttribute('data-nick'));
|
||||||
|
expect(nicks.join(' ')).toBe('gower juliet romeo thirdwitch wiccan witch');
|
||||||
|
|
||||||
|
const filter = modal.el.querySelector('[name="filter"]');
|
||||||
|
expect(filter).not.toBe(null);
|
||||||
|
|
||||||
|
filter.value = 'romeo';
|
||||||
|
u.triggerEvent(filter, "keyup", "KeyboardEvent");
|
||||||
|
await u.waitUntil(() => ( modal.el.querySelectorAll('.list-group--users > li').length === 1));
|
||||||
|
|
||||||
|
filter.value = 'r';
|
||||||
|
u.triggerEvent(filter, "keyup", "KeyboardEvent");
|
||||||
|
await u.waitUntil(() => ( modal.el.querySelectorAll('.list-group--users > li').length === 3));
|
||||||
|
|
||||||
|
filter.value = 'gower';
|
||||||
|
u.triggerEvent(filter, "keyup", "KeyboardEvent");
|
||||||
|
await u.waitUntil(() => ( modal.el.querySelectorAll('.list-group--users > li').length === 1));
|
||||||
|
done();
|
||||||
|
}));
|
||||||
|
|
||||||
|
it("allows you to filter role search results",
|
||||||
|
mock.initConverse(
|
||||||
|
['rosterGroupsFetched'], {},
|
||||||
|
async function (done, _converse) {
|
||||||
|
|
||||||
|
spyOn(_converse.ChatRoomView.prototype, 'showModeratorToolsModal').and.callThrough();
|
||||||
|
const muc_jid = 'lounge@montague.lit';
|
||||||
|
await mock.openAndEnterChatRoom(_converse, muc_jid, 'romeo', []);
|
||||||
|
const view = _converse.chatboxviews.get(muc_jid);
|
||||||
|
|
||||||
|
_converse.connection._dataRecv(mock.createRequest(
|
||||||
|
$pres({to: _converse.jid, from: `${muc_jid}/nomorenicks`})
|
||||||
|
.c('x', {xmlns: Strophe.NS.MUC_USER})
|
||||||
|
.c('item', {
|
||||||
|
'affiliation': 'none',
|
||||||
|
'jid': `nomorenicks@montague.lit`,
|
||||||
|
'role': 'participant'
|
||||||
|
})
|
||||||
|
));
|
||||||
|
_converse.connection._dataRecv(mock.createRequest(
|
||||||
|
$pres({to: _converse.jid, from: `${muc_jid}/newb`})
|
||||||
|
.c('x', {xmlns: Strophe.NS.MUC_USER})
|
||||||
|
.c('item', {
|
||||||
|
'affiliation': 'none',
|
||||||
|
'jid': `newb@montague.lit`,
|
||||||
|
'role': 'participant'
|
||||||
|
})
|
||||||
|
));
|
||||||
|
_converse.connection._dataRecv(mock.createRequest(
|
||||||
|
$pres({to: _converse.jid, from: `${muc_jid}/some1`})
|
||||||
|
.c('x', {xmlns: Strophe.NS.MUC_USER})
|
||||||
|
.c('item', {
|
||||||
|
'affiliation': 'none',
|
||||||
|
'jid': `some1@montague.lit`,
|
||||||
|
'role': 'participant'
|
||||||
|
})
|
||||||
|
));
|
||||||
|
_converse.connection._dataRecv(mock.createRequest(
|
||||||
|
$pres({to: _converse.jid, from: `${muc_jid}/oldhag`})
|
||||||
|
.c('x', {xmlns: Strophe.NS.MUC_USER})
|
||||||
|
.c('item', {
|
||||||
|
'affiliation': 'none',
|
||||||
|
'jid': `oldhag@montague.lit`,
|
||||||
|
'role': 'participant'
|
||||||
|
})
|
||||||
|
));
|
||||||
|
_converse.connection._dataRecv(mock.createRequest(
|
||||||
|
$pres({to: _converse.jid, from: `${muc_jid}/crone`})
|
||||||
|
.c('x', {xmlns: Strophe.NS.MUC_USER})
|
||||||
|
.c('item', {
|
||||||
|
'affiliation': 'none',
|
||||||
|
'jid': `crone@montague.lit`,
|
||||||
|
'role': 'participant'
|
||||||
|
})
|
||||||
|
));
|
||||||
|
_converse.connection._dataRecv(mock.createRequest(
|
||||||
|
$pres({to: _converse.jid, from: `${muc_jid}/tux`})
|
||||||
|
.c('x', {xmlns: Strophe.NS.MUC_USER})
|
||||||
|
.c('item', {
|
||||||
|
'affiliation': 'none',
|
||||||
|
'jid': `tux@montague.lit`,
|
||||||
|
'role': 'participant'
|
||||||
|
})
|
||||||
|
));
|
||||||
|
await u.waitUntil(() => (view.model.occupants.length === 7), 1000);
|
||||||
|
|
||||||
|
const textarea = view.el.querySelector('.chat-textarea');
|
||||||
|
textarea.value = '/modtools';
|
||||||
|
const enter = { 'target': textarea, 'preventDefault': function preventDefault () {}, 'keyCode': 13 };
|
||||||
|
view.onKeyDown(enter);
|
||||||
|
await u.waitUntil(() => view.showModeratorToolsModal.calls.count());
|
||||||
|
|
||||||
|
const modal = view.modtools_modal;
|
||||||
|
await u.waitUntil(() => u.isVisible(modal.el), 1000);
|
||||||
|
|
||||||
|
const tab = modal.el.querySelector('#roles-tab');
|
||||||
|
tab.click();
|
||||||
|
|
||||||
|
// Clear so that we don't match older stanzas
|
||||||
|
_converse.connection.IQ_stanzas = [];
|
||||||
|
|
||||||
|
const select = modal.el.querySelector('.select-role');
|
||||||
|
expect(select.value).toBe('moderator');
|
||||||
|
select.value = 'participant';
|
||||||
|
|
||||||
|
const button = modal.el.querySelector('.btn-primary[name="users_with_role"]');
|
||||||
|
button.click();
|
||||||
|
await u.waitUntil(() => !modal.loading_users_with_role);
|
||||||
|
const user_els = modal.el.querySelectorAll('.list-group--users > li');
|
||||||
|
expect(user_els.length).toBe(6);
|
||||||
|
|
||||||
|
const nicks = Array.from(modal.el.querySelectorAll('.list-group--users > li')).map(el => el.getAttribute('data-nick'));
|
||||||
|
expect(nicks.join(' ')).toBe('crone newb nomorenicks oldhag some1 tux');
|
||||||
|
|
||||||
|
const filter = modal.el.querySelector('[name="filter"]');
|
||||||
|
expect(filter).not.toBe(null);
|
||||||
|
|
||||||
|
filter.value = 'tux';
|
||||||
|
u.triggerEvent(filter, "keyup", "KeyboardEvent");
|
||||||
|
await u.waitUntil(() => ( modal.el.querySelectorAll('.list-group--users > li').length === 1));
|
||||||
|
|
||||||
|
filter.value = 'r';
|
||||||
|
u.triggerEvent(filter, "keyup", "KeyboardEvent");
|
||||||
|
await u.waitUntil(() => ( modal.el.querySelectorAll('.list-group--users > li').length === 2));
|
||||||
|
|
||||||
|
filter.value = 'crone';
|
||||||
|
u.triggerEvent(filter, "keyup", "KeyboardEvent");
|
||||||
|
await u.waitUntil(() => ( modal.el.querySelectorAll('.list-group--users > li').length === 1));
|
||||||
|
done();
|
||||||
|
}));
|
||||||
|
|
||||||
|
it("shows an error message if a particular affiliation list may not be retrieved",
|
||||||
|
mock.initConverse(
|
||||||
|
['rosterGroupsFetched'], {},
|
||||||
|
async function (done, _converse) {
|
||||||
|
|
||||||
|
spyOn(_converse.ChatRoomView.prototype, 'showModeratorToolsModal').and.callThrough();
|
||||||
|
const muc_jid = 'lounge@montague.lit';
|
||||||
|
const members = [
|
||||||
|
{'jid': 'hag66@shakespeare.lit', 'nick': 'witch', 'affiliation': 'member'},
|
||||||
|
{'jid': 'gower@shakespeare.lit', 'nick': 'gower', 'affiliation': 'member'},
|
||||||
|
{'jid': 'wiccarocks@shakespeare.lit', 'nick': 'wiccan', 'affiliation': 'admin'},
|
||||||
|
{'jid': 'crone1@shakespeare.lit', 'nick': 'thirdwitch', 'affiliation': 'owner'},
|
||||||
|
{'jid': 'romeo@montague.lit', 'nick': 'romeo', 'affiliation': 'owner'},
|
||||||
|
];
|
||||||
|
await mock.openAndEnterChatRoom(_converse, muc_jid, 'romeo', [], members);
|
||||||
|
const view = _converse.chatboxviews.get(muc_jid);
|
||||||
|
await u.waitUntil(() => (view.model.occupants.length === 5));
|
||||||
|
|
||||||
|
const textarea = view.el.querySelector('.chat-textarea');
|
||||||
|
textarea.value = '/modtools';
|
||||||
|
const enter = { 'target': textarea, 'preventDefault': function preventDefault () {}, 'keyCode': 13 };
|
||||||
|
view.onKeyDown(enter);
|
||||||
|
await u.waitUntil(() => view.showModeratorToolsModal.calls.count());
|
||||||
|
|
||||||
|
const modal = view.modtools_modal;
|
||||||
|
await u.waitUntil(() => u.isVisible(modal.el), 1000);
|
||||||
|
const tab = modal.el.querySelector('#affiliations-tab');
|
||||||
|
// Clear so that we don't match older stanzas
|
||||||
|
_converse.connection.IQ_stanzas = [];
|
||||||
|
const IQ_stanzas = _converse.connection.IQ_stanzas;
|
||||||
|
tab.click();
|
||||||
|
const select = modal.el.querySelector('.select-affiliation');
|
||||||
|
select.value = 'outcast';
|
||||||
|
const button = modal.el.querySelector('.btn-primary[name="users_with_affiliation"]');
|
||||||
|
button.click();
|
||||||
|
|
||||||
|
const iq_query = await u.waitUntil(() => _.filter(
|
||||||
|
IQ_stanzas,
|
||||||
|
s => sizzle(`iq[to="${muc_jid}"] query[xmlns="${Strophe.NS.MUC_ADMIN}"] item[affiliation="outcast"]`, s).length
|
||||||
|
).pop());
|
||||||
|
|
||||||
|
const error = u.toStanza(
|
||||||
|
`<iq from="${muc_jid}"
|
||||||
|
id="${iq_query.getAttribute('id')}"
|
||||||
|
type="error"
|
||||||
|
to="${_converse.jid}">
|
||||||
|
|
||||||
|
<error type="auth">
|
||||||
|
<forbidden xmlns="${Strophe.NS.STANZAS}"/>
|
||||||
|
</error>
|
||||||
|
</iq>`);
|
||||||
|
_converse.connection._dataRecv(mock.createRequest(error));
|
||||||
|
await u.waitUntil(() => !modal.loading_users_with_affiliation);
|
||||||
|
|
||||||
|
const user_els = modal.el.querySelectorAll('.list-group--users > li');
|
||||||
|
expect(user_els.length).toBe(1);
|
||||||
|
expect(user_els[0].textContent.trim()).toBe('Error: not allowed to fetch outcast list for MUC lounge@montague.lit');
|
||||||
|
done();
|
||||||
|
}));
|
||||||
});
|
});
|
||||||
|
9884
spec/muc.js
9884
spec/muc.js
File diff suppressed because it is too large
Load Diff
2368
spec/muc_messages.js
2368
spec/muc_messages.js
File diff suppressed because it is too large
Load Diff
@ -1,209 +1,207 @@
|
|||||||
window.addEventListener('converse-loaded', () => {
|
/*global mock */
|
||||||
const mock = window.mock;
|
|
||||||
const test_utils = window.test_utils;
|
|
||||||
const _ = converse.env._;
|
|
||||||
const $msg = converse.env.$msg;
|
|
||||||
const u = converse.env.utils;
|
|
||||||
|
|
||||||
describe("Notifications", function () {
|
const _ = converse.env._;
|
||||||
// Implement the protocol defined in https://xmpp.org/extensions/xep-0313.html#config
|
const $msg = converse.env.$msg;
|
||||||
|
const u = converse.env.utils;
|
||||||
|
|
||||||
describe("When show_desktop_notifications is set to true", function () {
|
describe("Notifications", function () {
|
||||||
describe("And the desktop is not focused", function () {
|
// Implement the protocol defined in https://xmpp.org/extensions/xep-0313.html#config
|
||||||
describe("an HTML5 Notification", function () {
|
|
||||||
|
|
||||||
it("is shown when a new private message is received",
|
describe("When show_desktop_notifications is set to true", function () {
|
||||||
mock.initConverse(['rosterGroupsFetched'], {}, async (done, _converse) => {
|
describe("And the desktop is not focused", function () {
|
||||||
|
describe("an HTML5 Notification", function () {
|
||||||
|
|
||||||
await test_utils.waitForRoster(_converse, 'current');
|
it("is shown when a new private message is received",
|
||||||
spyOn(_converse, 'showMessageNotification').and.callThrough();
|
|
||||||
spyOn(_converse, 'areDesktopNotificationsEnabled').and.returnValue(true);
|
|
||||||
spyOn(_converse, 'isMessageToHiddenChat').and.returnValue(true);
|
|
||||||
|
|
||||||
const message = 'This message will show a desktop notification';
|
|
||||||
const sender_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit',
|
|
||||||
msg = $msg({
|
|
||||||
from: sender_jid,
|
|
||||||
to: _converse.connection.jid,
|
|
||||||
type: 'chat',
|
|
||||||
id: u.getUniqueId()
|
|
||||||
}).c('body').t(message).up()
|
|
||||||
.c('active', {'xmlns': 'http://jabber.org/protocol/chatstates'}).tree();
|
|
||||||
await _converse.handleMessageStanza(msg); // This will emit 'message'
|
|
||||||
await u.waitUntil(() => _converse.api.chatviews.get(sender_jid));
|
|
||||||
expect(_converse.areDesktopNotificationsEnabled).toHaveBeenCalled();
|
|
||||||
expect(_converse.showMessageNotification).toHaveBeenCalled();
|
|
||||||
done();
|
|
||||||
}));
|
|
||||||
|
|
||||||
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');
|
|
||||||
const view = _converse.api.chatviews.get('lounge@montague.lit');
|
|
||||||
if (!view.el.querySelectorAll('.chat-area').length) {
|
|
||||||
view.renderChatArea();
|
|
||||||
}
|
|
||||||
let no_notification = false;
|
|
||||||
if (typeof window.Notification === 'undefined') {
|
|
||||||
no_notification = true;
|
|
||||||
window.Notification = function () {
|
|
||||||
return {
|
|
||||||
'close': function () {}
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
|
||||||
spyOn(_converse, 'showMessageNotification').and.callThrough();
|
|
||||||
spyOn(_converse, 'areDesktopNotificationsEnabled').and.returnValue(true);
|
|
||||||
|
|
||||||
const message = 'romeo: This message will show a desktop notification';
|
|
||||||
const nick = mock.chatroom_names[0],
|
|
||||||
msg = $msg({
|
|
||||||
from: 'lounge@montague.lit/'+nick,
|
|
||||||
id: u.getUniqueId(),
|
|
||||||
to: 'romeo@montague.lit',
|
|
||||||
type: 'groupchat'
|
|
||||||
}).c('body').t(message).tree();
|
|
||||||
_converse.connection._dataRecv(test_utils.createRequest(msg));
|
|
||||||
await new Promise(resolve => view.once('messageInserted', resolve));
|
|
||||||
|
|
||||||
await u.waitUntil(() => _converse.areDesktopNotificationsEnabled.calls.count() === 1);
|
|
||||||
expect(_converse.showMessageNotification).toHaveBeenCalled();
|
|
||||||
if (no_notification) {
|
|
||||||
delete window.Notification;
|
|
||||||
}
|
|
||||||
done();
|
|
||||||
}));
|
|
||||||
|
|
||||||
it("is shown for headline messages",
|
|
||||||
mock.initConverse(['rosterGroupsFetched'], {}, async (done, _converse) => {
|
|
||||||
|
|
||||||
spyOn(_converse, 'showMessageNotification').and.callThrough();
|
|
||||||
spyOn(_converse, 'isMessageToHiddenChat').and.returnValue(true);
|
|
||||||
spyOn(_converse, 'areDesktopNotificationsEnabled').and.returnValue(true);
|
|
||||||
const stanza = $msg({
|
|
||||||
'type': 'headline',
|
|
||||||
'from': 'notify.example.com',
|
|
||||||
'to': 'romeo@montague.lit',
|
|
||||||
'xml:lang': 'en'
|
|
||||||
})
|
|
||||||
.c('subject').t('SIEVE').up()
|
|
||||||
.c('body').t('<juliet@example.com> 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));
|
|
||||||
await u.waitUntil(() => _converse.chatboxviews.keys().length);
|
|
||||||
const view = _converse.chatboxviews.get('notify.example.com');
|
|
||||||
await new Promise(resolve => view.once('messageInserted', resolve));
|
|
||||||
expect(
|
|
||||||
_.includes(_converse.chatboxviews.keys(),
|
|
||||||
'notify.example.com')
|
|
||||||
).toBeTruthy();
|
|
||||||
expect(_converse.showMessageNotification).toHaveBeenCalled();
|
|
||||||
done();
|
|
||||||
}));
|
|
||||||
|
|
||||||
it("is not shown for full JID headline messages if allow_non_roster_messaging is false", mock.initConverse((done, _converse) => {
|
|
||||||
_converse.allow_non_roster_messaging = false;
|
|
||||||
spyOn(_converse, 'showMessageNotification').and.callThrough();
|
|
||||||
spyOn(_converse, 'areDesktopNotificationsEnabled').and.returnValue(true);
|
|
||||||
const stanza = $msg({
|
|
||||||
'type': 'headline',
|
|
||||||
'from': 'someone@notify.example.com',
|
|
||||||
'to': 'romeo@montague.lit',
|
|
||||||
'xml:lang': 'en'
|
|
||||||
})
|
|
||||||
.c('subject').t('SIEVE').up()
|
|
||||||
.c('body').t('<juliet@example.com> 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));
|
|
||||||
expect(
|
|
||||||
_.includes(_converse.chatboxviews.keys(),
|
|
||||||
'someone@notify.example.com')
|
|
||||||
).toBeFalsy();
|
|
||||||
expect(_converse.showMessageNotification).not.toHaveBeenCalled();
|
|
||||||
done();
|
|
||||||
}));
|
|
||||||
|
|
||||||
it("is shown when a user changes their chat state (if show_chat_state_notifications is true)",
|
|
||||||
mock.initConverse(['rosterGroupsFetched'], {show_chat_state_notifications: true},
|
|
||||||
async (done, _converse) => {
|
|
||||||
|
|
||||||
await test_utils.waitForRoster(_converse, 'current', 3);
|
|
||||||
spyOn(_converse, 'areDesktopNotificationsEnabled').and.returnValue(true);
|
|
||||||
spyOn(_converse, 'showChatStateNotification');
|
|
||||||
const jid = mock.cur_names[2].replace(/ /g,'.').toLowerCase() + '@montague.lit';
|
|
||||||
_converse.roster.get(jid).presence.set('show', 'busy'); // This will emit 'contactStatusChanged'
|
|
||||||
await u.waitUntil(() => _converse.areDesktopNotificationsEnabled.calls.count() === 1);
|
|
||||||
expect(_converse.showChatStateNotification).toHaveBeenCalled();
|
|
||||||
done()
|
|
||||||
}));
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("When a new contact request is received", function () {
|
|
||||||
it("an HTML5 Notification is received", mock.initConverse((done, _converse) => {
|
|
||||||
spyOn(_converse, 'areDesktopNotificationsEnabled').and.returnValue(true);
|
|
||||||
spyOn(_converse, 'showContactRequestNotification');
|
|
||||||
_converse.api.trigger('contactRequest', {'fullname': 'Peter Parker', 'jid': 'peter@parker.com'});
|
|
||||||
expect(_converse.areDesktopNotificationsEnabled).toHaveBeenCalled();
|
|
||||||
expect(_converse.showContactRequestNotification).toHaveBeenCalled();
|
|
||||||
done();
|
|
||||||
}));
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("When play_sounds is set to true", function () {
|
|
||||||
describe("A notification sound", function () {
|
|
||||||
|
|
||||||
it("is played when the current user is mentioned in a groupchat",
|
|
||||||
mock.initConverse(['rosterGroupsFetched'], {}, async (done, _converse) => {
|
mock.initConverse(['rosterGroupsFetched'], {}, async (done, _converse) => {
|
||||||
|
|
||||||
test_utils.createContacts(_converse, 'current');
|
await mock.waitForRoster(_converse, 'current');
|
||||||
await test_utils.openAndEnterChatRoom(_converse, 'lounge@montague.lit', 'romeo');
|
spyOn(_converse, 'showMessageNotification').and.callThrough();
|
||||||
_converse.play_sounds = true;
|
spyOn(_converse, 'areDesktopNotificationsEnabled').and.returnValue(true);
|
||||||
spyOn(_converse, 'playSoundNotification');
|
spyOn(_converse, 'isMessageToHiddenChat').and.returnValue(true);
|
||||||
const view = _converse.chatboxviews.get('lounge@montague.lit');
|
|
||||||
|
const message = 'This message will show a desktop notification';
|
||||||
|
const sender_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit',
|
||||||
|
msg = $msg({
|
||||||
|
from: sender_jid,
|
||||||
|
to: _converse.connection.jid,
|
||||||
|
type: 'chat',
|
||||||
|
id: u.getUniqueId()
|
||||||
|
}).c('body').t(message).up()
|
||||||
|
.c('active', {'xmlns': 'http://jabber.org/protocol/chatstates'}).tree();
|
||||||
|
await _converse.handleMessageStanza(msg); // This will emit 'message'
|
||||||
|
await u.waitUntil(() => _converse.api.chatviews.get(sender_jid));
|
||||||
|
expect(_converse.areDesktopNotificationsEnabled).toHaveBeenCalled();
|
||||||
|
expect(_converse.showMessageNotification).toHaveBeenCalled();
|
||||||
|
done();
|
||||||
|
}));
|
||||||
|
|
||||||
|
it("is shown when you are mentioned in a groupchat",
|
||||||
|
mock.initConverse(['rosterGroupsFetched'], {}, async (done, _converse) => {
|
||||||
|
|
||||||
|
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) {
|
if (!view.el.querySelectorAll('.chat-area').length) {
|
||||||
view.renderChatArea();
|
view.renderChatArea();
|
||||||
}
|
}
|
||||||
let text = 'This message will play a sound because it mentions romeo';
|
let no_notification = false;
|
||||||
let message = $msg({
|
if (typeof window.Notification === 'undefined') {
|
||||||
from: 'lounge@montague.lit/otheruser',
|
no_notification = true;
|
||||||
id: '1',
|
window.Notification = function () {
|
||||||
to: 'romeo@montague.lit',
|
return {
|
||||||
type: 'groupchat'
|
'close': function () {}
|
||||||
}).c('body').t(text);
|
};
|
||||||
await view.model.queueMessage(message.nodeTree);
|
};
|
||||||
await u.waitUntil(() => _converse.playSoundNotification.calls.count());
|
}
|
||||||
expect(_converse.playSoundNotification).toHaveBeenCalled();
|
spyOn(_converse, 'showMessageNotification').and.callThrough();
|
||||||
|
spyOn(_converse, 'areDesktopNotificationsEnabled').and.returnValue(true);
|
||||||
|
|
||||||
text = "This message won't play a sound";
|
const message = 'romeo: This message will show a desktop notification';
|
||||||
message = $msg({
|
const nick = mock.chatroom_names[0],
|
||||||
from: 'lounge@montague.lit/otheruser',
|
msg = $msg({
|
||||||
id: '2',
|
from: 'lounge@montague.lit/'+nick,
|
||||||
to: 'romeo@montague.lit',
|
id: u.getUniqueId(),
|
||||||
type: 'groupchat'
|
to: 'romeo@montague.lit',
|
||||||
}).c('body').t(text);
|
type: 'groupchat'
|
||||||
await view.model.queueMessage(message.nodeTree);
|
}).c('body').t(message).tree();
|
||||||
expect(_converse.playSoundNotification, 1);
|
_converse.connection._dataRecv(mock.createRequest(msg));
|
||||||
_converse.play_sounds = false;
|
await new Promise(resolve => view.once('messageInserted', resolve));
|
||||||
|
|
||||||
text = "This message won't play a sound because it is sent by romeo";
|
await u.waitUntil(() => _converse.areDesktopNotificationsEnabled.calls.count() === 1);
|
||||||
message = $msg({
|
expect(_converse.showMessageNotification).toHaveBeenCalled();
|
||||||
from: 'lounge@montague.lit/romeo',
|
if (no_notification) {
|
||||||
id: '3',
|
delete window.Notification;
|
||||||
to: 'romeo@montague.lit',
|
}
|
||||||
type: 'groupchat'
|
|
||||||
}).c('body').t(text);
|
|
||||||
await view.model.queueMessage(message.nodeTree);
|
|
||||||
expect(_converse.playSoundNotification, 1);
|
|
||||||
_converse.play_sounds = false;
|
|
||||||
done();
|
done();
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
it("is shown for headline messages",
|
||||||
|
mock.initConverse(['rosterGroupsFetched'], {}, async (done, _converse) => {
|
||||||
|
|
||||||
|
spyOn(_converse, 'showMessageNotification').and.callThrough();
|
||||||
|
spyOn(_converse, 'isMessageToHiddenChat').and.returnValue(true);
|
||||||
|
spyOn(_converse, 'areDesktopNotificationsEnabled').and.returnValue(true);
|
||||||
|
const stanza = $msg({
|
||||||
|
'type': 'headline',
|
||||||
|
'from': 'notify.example.com',
|
||||||
|
'to': 'romeo@montague.lit',
|
||||||
|
'xml:lang': 'en'
|
||||||
|
})
|
||||||
|
.c('subject').t('SIEVE').up()
|
||||||
|
.c('body').t('<juliet@example.com> 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(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));
|
||||||
|
expect(
|
||||||
|
_.includes(_converse.chatboxviews.keys(),
|
||||||
|
'notify.example.com')
|
||||||
|
).toBeTruthy();
|
||||||
|
expect(_converse.showMessageNotification).toHaveBeenCalled();
|
||||||
|
done();
|
||||||
|
}));
|
||||||
|
|
||||||
|
it("is not shown for full JID headline messages if allow_non_roster_messaging is false", mock.initConverse((done, _converse) => {
|
||||||
|
_converse.allow_non_roster_messaging = false;
|
||||||
|
spyOn(_converse, 'showMessageNotification').and.callThrough();
|
||||||
|
spyOn(_converse, 'areDesktopNotificationsEnabled').and.returnValue(true);
|
||||||
|
const stanza = $msg({
|
||||||
|
'type': 'headline',
|
||||||
|
'from': 'someone@notify.example.com',
|
||||||
|
'to': 'romeo@montague.lit',
|
||||||
|
'xml:lang': 'en'
|
||||||
|
})
|
||||||
|
.c('subject').t('SIEVE').up()
|
||||||
|
.c('body').t('<juliet@example.com> 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(mock.createRequest(stanza));
|
||||||
|
expect(
|
||||||
|
_.includes(_converse.chatboxviews.keys(),
|
||||||
|
'someone@notify.example.com')
|
||||||
|
).toBeFalsy();
|
||||||
|
expect(_converse.showMessageNotification).not.toHaveBeenCalled();
|
||||||
|
done();
|
||||||
|
}));
|
||||||
|
|
||||||
|
it("is shown when a user changes their chat state (if show_chat_state_notifications is true)",
|
||||||
|
mock.initConverse(['rosterGroupsFetched'], {show_chat_state_notifications: true},
|
||||||
|
async (done, _converse) => {
|
||||||
|
|
||||||
|
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';
|
||||||
|
_converse.roster.get(jid).presence.set('show', 'busy'); // This will emit 'contactStatusChanged'
|
||||||
|
await u.waitUntil(() => _converse.areDesktopNotificationsEnabled.calls.count() === 1);
|
||||||
|
expect(_converse.showChatStateNotification).toHaveBeenCalled();
|
||||||
|
done()
|
||||||
|
}));
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe("When a new contact request is received", function () {
|
||||||
|
it("an HTML5 Notification is received", mock.initConverse((done, _converse) => {
|
||||||
|
spyOn(_converse, 'areDesktopNotificationsEnabled').and.returnValue(true);
|
||||||
|
spyOn(_converse, 'showContactRequestNotification');
|
||||||
|
_converse.api.trigger('contactRequest', {'fullname': 'Peter Parker', 'jid': 'peter@parker.com'});
|
||||||
|
expect(_converse.areDesktopNotificationsEnabled).toHaveBeenCalled();
|
||||||
|
expect(_converse.showContactRequestNotification).toHaveBeenCalled();
|
||||||
|
done();
|
||||||
|
}));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("When play_sounds is set to true", function () {
|
||||||
|
describe("A notification sound", function () {
|
||||||
|
|
||||||
|
it("is played when the current user is mentioned in a groupchat",
|
||||||
|
mock.initConverse(['rosterGroupsFetched'], {}, async (done, _converse) => {
|
||||||
|
|
||||||
|
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');
|
||||||
|
if (!view.el.querySelectorAll('.chat-area').length) {
|
||||||
|
view.renderChatArea();
|
||||||
|
}
|
||||||
|
let text = 'This message will play a sound because it mentions romeo';
|
||||||
|
let message = $msg({
|
||||||
|
from: 'lounge@montague.lit/otheruser',
|
||||||
|
id: '1',
|
||||||
|
to: 'romeo@montague.lit',
|
||||||
|
type: 'groupchat'
|
||||||
|
}).c('body').t(text);
|
||||||
|
await view.model.queueMessage(message.nodeTree);
|
||||||
|
await u.waitUntil(() => _converse.playSoundNotification.calls.count());
|
||||||
|
expect(_converse.playSoundNotification).toHaveBeenCalled();
|
||||||
|
|
||||||
|
text = "This message won't play a sound";
|
||||||
|
message = $msg({
|
||||||
|
from: 'lounge@montague.lit/otheruser',
|
||||||
|
id: '2',
|
||||||
|
to: 'romeo@montague.lit',
|
||||||
|
type: 'groupchat'
|
||||||
|
}).c('body').t(text);
|
||||||
|
await view.model.queueMessage(message.nodeTree);
|
||||||
|
expect(_converse.playSoundNotification, 1);
|
||||||
|
_converse.play_sounds = false;
|
||||||
|
|
||||||
|
text = "This message won't play a sound because it is sent by romeo";
|
||||||
|
message = $msg({
|
||||||
|
from: 'lounge@montague.lit/romeo',
|
||||||
|
id: '3',
|
||||||
|
to: 'romeo@montague.lit',
|
||||||
|
type: 'groupchat'
|
||||||
|
}).c('body').t(text);
|
||||||
|
await view.model.queueMessage(message.nodeTree);
|
||||||
|
expect(_converse.playSoundNotification, 1);
|
||||||
|
_converse.play_sounds = false;
|
||||||
|
done();
|
||||||
|
}));
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
3010
spec/omemo.js
3010
spec/omemo.js
File diff suppressed because it is too large
Load Diff
56
spec/ping.js
56
spec/ping.js
@ -1,36 +1,34 @@
|
|||||||
window.addEventListener('converse-loaded', () => {
|
/*global mock */
|
||||||
const mock = window.mock;
|
|
||||||
const test_utils = window.test_utils;
|
const Strophe = converse.env.Strophe;
|
||||||
const Strophe = converse.env.Strophe;
|
const u = converse.env.utils;
|
||||||
const u = converse.env.utils;
|
|
||||||
|
|
||||||
|
|
||||||
describe("XMPP Ping", function () {
|
describe("XMPP Ping", function () {
|
||||||
|
|
||||||
describe("An IQ stanza", function () {
|
describe("An IQ stanza", function () {
|
||||||
|
|
||||||
it("is returned when converse.js gets pinged", mock.initConverse((done, _converse) => {
|
it("is returned when converse.js gets pinged", mock.initConverse((done, _converse) => {
|
||||||
const ping = u.toStanza(`
|
const ping = u.toStanza(`
|
||||||
<iq from="${_converse.domain}"
|
<iq from="${_converse.domain}"
|
||||||
to="${_converse.jid}" id="s2c1" type="get">
|
to="${_converse.jid}" id="s2c1" type="get">
|
||||||
<ping xmlns="urn:xmpp:ping"/>
|
<ping xmlns="urn:xmpp:ping"/>
|
||||||
</iq>`);
|
</iq>`);
|
||||||
_converse.connection._dataRecv(test_utils.createRequest(ping));
|
_converse.connection._dataRecv(mock.createRequest(ping));
|
||||||
const sent_stanza = _converse.connection.IQ_stanzas.pop();
|
const sent_stanza = _converse.connection.IQ_stanzas.pop();
|
||||||
expect(Strophe.serialize(sent_stanza)).toBe(
|
expect(Strophe.serialize(sent_stanza)).toBe(
|
||||||
`<iq id="s2c1" to="${_converse.domain}" type="result" xmlns="jabber:client"/>`);
|
`<iq id="s2c1" to="${_converse.domain}" type="result" xmlns="jabber:client"/>`);
|
||||||
done();
|
done();
|
||||||
}));
|
}));
|
||||||
|
|
||||||
it("is sent out when converse.js pings a server", mock.initConverse((done, _converse) => {
|
it("is sent out when converse.js pings a server", mock.initConverse((done, _converse) => {
|
||||||
_converse.api.ping();
|
_converse.api.ping();
|
||||||
const sent_stanza = _converse.connection.IQ_stanzas.pop();
|
const sent_stanza = _converse.connection.IQ_stanzas.pop();
|
||||||
expect(Strophe.serialize(sent_stanza)).toBe(
|
expect(Strophe.serialize(sent_stanza)).toBe(
|
||||||
`<iq id="${sent_stanza.getAttribute('id')}" to="montague.lit" type="get" xmlns="jabber:client">`+
|
`<iq id="${sent_stanza.getAttribute('id')}" to="montague.lit" type="get" xmlns="jabber:client">`+
|
||||||
`<ping xmlns="urn:xmpp:ping"/>`+
|
`<ping xmlns="urn:xmpp:ping"/>`+
|
||||||
`</iq>`);
|
`</iq>`);
|
||||||
done();
|
done();
|
||||||
}));
|
}));
|
||||||
});
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
549
spec/presence.js
549
spec/presence.js
@ -1,290 +1,287 @@
|
|||||||
window.addEventListener('converse-loaded', () => {
|
/*global mock */
|
||||||
const mock = window.mock;
|
// See: https://xmpp.org/rfcs/rfc3921.html
|
||||||
const test_utils = window.test_utils;
|
|
||||||
const Strophe = converse.env.Strophe;
|
|
||||||
const u = converse.env.utils;
|
|
||||||
// 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",
|
it("includes a entity capabilities node",
|
||||||
mock.initConverse(
|
mock.initConverse(
|
||||||
['rosterGroupsFetched'], {},
|
['rosterGroupsFetched'], {},
|
||||||
(done, _converse) => {
|
(done, _converse) => {
|
||||||
|
|
||||||
_converse.api.disco.own.identities.clear();
|
_converse.api.disco.own.identities.clear();
|
||||||
_converse.api.disco.own.features.clear();
|
_converse.api.disco.own.features.clear();
|
||||||
|
|
||||||
_converse.api.disco.own.identities.add("client", "pc", "Exodus 0.9.1");
|
_converse.api.disco.own.identities.add("client", "pc", "Exodus 0.9.1");
|
||||||
_converse.api.disco.own.features.add("http://jabber.org/protocol/caps");
|
_converse.api.disco.own.features.add("http://jabber.org/protocol/caps");
|
||||||
_converse.api.disco.own.features.add("http://jabber.org/protocol/disco#info");
|
_converse.api.disco.own.features.add("http://jabber.org/protocol/disco#info");
|
||||||
_converse.api.disco.own.features.add("http://jabber.org/protocol/disco#items");
|
_converse.api.disco.own.features.add("http://jabber.org/protocol/disco#items");
|
||||||
_converse.api.disco.own.features.add("http://jabber.org/protocol/muc");
|
_converse.api.disco.own.features.add("http://jabber.org/protocol/muc");
|
||||||
|
|
||||||
const presence = _converse.xmppstatus.constructPresence();
|
const presence = _converse.xmppstatus.constructPresence();
|
||||||
expect(presence.toLocaleString()).toBe(
|
expect(presence.toLocaleString()).toBe(
|
||||||
`<presence xmlns="jabber:client">`+
|
`<presence xmlns="jabber:client">`+
|
||||||
`<priority>0</priority>`+
|
`<priority>0</priority>`+
|
||||||
`<c hash="sha-1" node="https://conversejs.org" ver="QgayPKawpkPSDYmwT/WM94uAlu0=" xmlns="http://jabber.org/protocol/caps"/>`+
|
`<c hash="sha-1" node="https://conversejs.org" ver="QgayPKawpkPSDYmwT/WM94uAlu0=" xmlns="http://jabber.org/protocol/caps"/>`+
|
||||||
`</presence>`)
|
`</presence>`)
|
||||||
done();
|
done();
|
||||||
}));
|
}));
|
||||||
|
|
||||||
it("has a given priority", mock.initConverse((done, _converse) => {
|
it("has a given priority", mock.initConverse((done, _converse) => {
|
||||||
let pres = _converse.xmppstatus.constructPresence('online', null, 'Hello world');
|
let pres = _converse.xmppstatus.constructPresence('online', null, 'Hello world');
|
||||||
expect(pres.toLocaleString()).toBe(
|
expect(pres.toLocaleString()).toBe(
|
||||||
`<presence xmlns="jabber:client">`+
|
`<presence xmlns="jabber:client">`+
|
||||||
`<status>Hello world</status>`+
|
`<status>Hello world</status>`+
|
||||||
|
`<priority>0</priority>`+
|
||||||
|
`<c hash="sha-1" node="https://conversejs.org" ver="Hxbsr5fazs62i+O0GxIXf2OEDNs=" xmlns="http://jabber.org/protocol/caps"/>`+
|
||||||
|
`</presence>`
|
||||||
|
);
|
||||||
|
_converse.priority = 2;
|
||||||
|
pres = _converse.xmppstatus.constructPresence('away', null, 'Going jogging');
|
||||||
|
expect(pres.toLocaleString()).toBe(
|
||||||
|
`<presence xmlns="jabber:client">`+
|
||||||
|
`<show>away</show>`+
|
||||||
|
`<status>Going jogging</status>`+
|
||||||
|
`<priority>2</priority>`+
|
||||||
|
`<c hash="sha-1" node="https://conversejs.org" ver="Hxbsr5fazs62i+O0GxIXf2OEDNs=" xmlns="http://jabber.org/protocol/caps"/>`+
|
||||||
|
`</presence>`
|
||||||
|
);
|
||||||
|
|
||||||
|
delete _converse.priority;
|
||||||
|
pres = _converse.xmppstatus.constructPresence('dnd', null, 'Doing taxes');
|
||||||
|
expect(pres.toLocaleString()).toBe(
|
||||||
|
`<presence xmlns="jabber:client">`+
|
||||||
|
`<show>dnd</show>`+
|
||||||
|
`<status>Doing taxes</status>`+
|
||||||
|
`<priority>0</priority>`+
|
||||||
|
`<c hash="sha-1" node="https://conversejs.org" ver="Hxbsr5fazs62i+O0GxIXf2OEDNs=" xmlns="http://jabber.org/protocol/caps"/>`+
|
||||||
|
`</presence>`
|
||||||
|
);
|
||||||
|
done();
|
||||||
|
}));
|
||||||
|
|
||||||
|
it("includes the saved status message",
|
||||||
|
mock.initConverse(
|
||||||
|
['rosterGroupsFetched'], {},
|
||||||
|
async (done, _converse) => {
|
||||||
|
|
||||||
|
const { u, Strophe } = converse.env;
|
||||||
|
mock.openControlBox(_converse);
|
||||||
|
spyOn(_converse.connection, 'send').and.callThrough();
|
||||||
|
|
||||||
|
const cbview = _converse.chatboxviews.get('controlbox');
|
||||||
|
cbview.el.querySelector('.change-status').click()
|
||||||
|
const modal = _converse.xmppstatusview.status_modal;
|
||||||
|
await u.waitUntil(() => u.isVisible(modal.el), 1000);
|
||||||
|
const msg = 'My custom status';
|
||||||
|
modal.el.querySelector('input[name="status_message"]').value = msg;
|
||||||
|
modal.el.querySelector('[type="submit"]').click();
|
||||||
|
|
||||||
|
const sent_stanzas = _converse.connection.sent_stanzas;
|
||||||
|
let sent_presence = await u.waitUntil(() => sent_stanzas.filter(s => Strophe.serialize(s).match('presence')).pop());
|
||||||
|
expect(Strophe.serialize(sent_presence))
|
||||||
|
.toBe(`<presence xmlns="jabber:client">`+
|
||||||
|
`<status>My custom status</status>`+
|
||||||
`<priority>0</priority>`+
|
`<priority>0</priority>`+
|
||||||
`<c hash="sha-1" node="https://conversejs.org" ver="Hxbsr5fazs62i+O0GxIXf2OEDNs=" xmlns="http://jabber.org/protocol/caps"/>`+
|
`<c hash="sha-1" node="https://conversejs.org" ver="Hxbsr5fazs62i+O0GxIXf2OEDNs=" xmlns="http://jabber.org/protocol/caps"/>`+
|
||||||
`</presence>`
|
`</presence>`)
|
||||||
);
|
|
||||||
_converse.priority = 2;
|
|
||||||
pres = _converse.xmppstatus.constructPresence('away', null, 'Going jogging');
|
|
||||||
expect(pres.toLocaleString()).toBe(
|
|
||||||
`<presence xmlns="jabber:client">`+
|
|
||||||
`<show>away</show>`+
|
|
||||||
`<status>Going jogging</status>`+
|
|
||||||
`<priority>2</priority>`+
|
|
||||||
`<c hash="sha-1" node="https://conversejs.org" ver="Hxbsr5fazs62i+O0GxIXf2OEDNs=" xmlns="http://jabber.org/protocol/caps"/>`+
|
|
||||||
`</presence>`
|
|
||||||
);
|
|
||||||
|
|
||||||
delete _converse.priority;
|
await u.waitUntil(() => modal.el.getAttribute('aria-hidden') === "true");
|
||||||
pres = _converse.xmppstatus.constructPresence('dnd', null, 'Doing taxes');
|
await u.waitUntil(() => !u.isVisible(modal.el));
|
||||||
expect(pres.toLocaleString()).toBe(
|
cbview.el.querySelector('.change-status').click()
|
||||||
|
await u.waitUntil(() => modal.el.getAttribute('aria-hidden') === "false", 1000);
|
||||||
|
modal.el.querySelector('label[for="radio-busy"]').click(); // Change status to "dnd"
|
||||||
|
modal.el.querySelector('[type="submit"]').click();
|
||||||
|
await u.waitUntil(() => sent_stanzas.filter(s => Strophe.serialize(s).match('presence')).length === 2);
|
||||||
|
sent_presence = sent_stanzas.filter(s => Strophe.serialize(s).match('presence')).pop();
|
||||||
|
expect(Strophe.serialize(sent_presence))
|
||||||
|
.toBe(
|
||||||
`<presence xmlns="jabber:client">`+
|
`<presence xmlns="jabber:client">`+
|
||||||
`<show>dnd</show>`+
|
`<show>dnd</show>`+
|
||||||
`<status>Doing taxes</status>`+
|
`<status>My custom status</status>`+
|
||||||
`<priority>0</priority>`+
|
`<priority>0</priority>`+
|
||||||
`<c hash="sha-1" node="https://conversejs.org" ver="Hxbsr5fazs62i+O0GxIXf2OEDNs=" xmlns="http://jabber.org/protocol/caps"/>`+
|
`<c hash="sha-1" node="https://conversejs.org" ver="Hxbsr5fazs62i+O0GxIXf2OEDNs=" xmlns="http://jabber.org/protocol/caps"/>`+
|
||||||
`</presence>`
|
`</presence>`)
|
||||||
);
|
done();
|
||||||
done();
|
}));
|
||||||
}));
|
});
|
||||||
|
|
||||||
it("includes the saved status message",
|
describe("A received presence stanza", function () {
|
||||||
mock.initConverse(
|
|
||||||
['rosterGroupsFetched'], {},
|
it("has its priority taken into account",
|
||||||
async (done, _converse) => {
|
mock.initConverse(
|
||||||
|
['rosterGroupsFetched'], {},
|
||||||
test_utils.openControlBox(_converse);
|
async (done, _converse) => {
|
||||||
spyOn(_converse.connection, 'send').and.callThrough();
|
|
||||||
|
const u = converse.env.utils;
|
||||||
const cbview = _converse.chatboxviews.get('controlbox');
|
mock.openControlBox(_converse);
|
||||||
cbview.el.querySelector('.change-status').click()
|
await mock.waitForRoster(_converse, 'current');
|
||||||
const modal = _converse.xmppstatusview.status_modal;
|
const contact_jid = mock.cur_names[8].replace(/ /g,'.').toLowerCase() + '@montague.lit';
|
||||||
await u.waitUntil(() => u.isVisible(modal.el), 1000);
|
const contact = await _converse.api.contacts.get(contact_jid);
|
||||||
const msg = 'My custom status';
|
let stanza = u.toStanza(`
|
||||||
modal.el.querySelector('input[name="status_message"]').value = msg;
|
<presence xmlns="jabber:client"
|
||||||
modal.el.querySelector('[type="submit"]').click();
|
to="romeo@montague.lit/converse.js-21770972"
|
||||||
|
from="${contact_jid}/priority-1-resource">
|
||||||
const sent_stanzas = _converse.connection.sent_stanzas;
|
<priority>1</priority>
|
||||||
let sent_presence = await u.waitUntil(() => sent_stanzas.filter(s => Strophe.serialize(s).match('presence')).pop());
|
<c xmlns="http://jabber.org/protocol/caps" hash="sha-1" ext="voice-v1 camera-v1 video-v1"
|
||||||
expect(Strophe.serialize(sent_presence))
|
ver="AcN1/PEN8nq7AHD+9jpxMV4U6YM=" node="http://pidgin.im/"/>
|
||||||
.toBe(`<presence xmlns="jabber:client">`+
|
<x xmlns="vcard-temp:x:update">
|
||||||
`<status>My custom status</status>`+
|
<photo>ce51d94f7f22b87a21274abb93710b9eb7cc1c65</photo>
|
||||||
`<priority>0</priority>`+
|
</x>
|
||||||
`<c hash="sha-1" node="https://conversejs.org" ver="Hxbsr5fazs62i+O0GxIXf2OEDNs=" xmlns="http://jabber.org/protocol/caps"/>`+
|
<delay xmlns="urn:xmpp:delay" stamp="2017-02-15T20:26:05Z" from="${contact_jid}/priority-1-resource"/>
|
||||||
`</presence>`)
|
</presence>`);
|
||||||
|
_converse.connection._dataRecv(mock.createRequest(stanza));
|
||||||
await u.waitUntil(() => modal.el.getAttribute('aria-hidden') === "true");
|
expect(contact.presence.get('show')).toBe('online');
|
||||||
await u.waitUntil(() => !u.isVisible(modal.el));
|
expect(contact.presence.resources.length).toBe(1);
|
||||||
cbview.el.querySelector('.change-status').click()
|
expect(contact.presence.resources.get('priority-1-resource').get('priority')).toBe(1);
|
||||||
await u.waitUntil(() => modal.el.getAttribute('aria-hidden') === "false", 1000);
|
expect(contact.presence.resources.get('priority-1-resource').get('show')).toBe('online');
|
||||||
modal.el.querySelector('label[for="radio-busy"]').click(); // Change status to "dnd"
|
|
||||||
modal.el.querySelector('[type="submit"]').click();
|
stanza = u.toStanza(
|
||||||
await u.waitUntil(() => sent_stanzas.filter(s => Strophe.serialize(s).match('presence')).length === 2);
|
'<presence xmlns="jabber:client"'+
|
||||||
sent_presence = sent_stanzas.filter(s => Strophe.serialize(s).match('presence')).pop();
|
' to="romeo@montague.lit/converse.js-21770972"'+
|
||||||
expect(Strophe.serialize(sent_presence))
|
' from="'+contact_jid+'/priority-0-resource">'+
|
||||||
.toBe(
|
' <status/>'+
|
||||||
`<presence xmlns="jabber:client">`+
|
' <priority>0</priority>'+
|
||||||
`<show>dnd</show>`+
|
' <show>xa</show>'+
|
||||||
`<status>My custom status</status>`+
|
' <c xmlns="http://jabber.org/protocol/caps" ver="GyIX/Kpa4ScVmsZCxRBboJlLAYU=" hash="sha-1"'+
|
||||||
`<priority>0</priority>`+
|
' node="http://www.igniterealtime.org/projects/smack/"/>'+
|
||||||
`<c hash="sha-1" node="https://conversejs.org" ver="Hxbsr5fazs62i+O0GxIXf2OEDNs=" xmlns="http://jabber.org/protocol/caps"/>`+
|
' <delay xmlns="urn:xmpp:delay" stamp="2017-02-15T17:02:24Z" from="'+contact_jid+'/priority-0-resource"/>'+
|
||||||
`</presence>`)
|
'</presence>');
|
||||||
done();
|
_converse.connection._dataRecv(mock.createRequest(stanza));
|
||||||
}));
|
expect(contact.presence.get('show')).toBe('online');
|
||||||
});
|
|
||||||
|
expect(contact.presence.resources.length).toBe(2);
|
||||||
describe("A received presence stanza", function () {
|
expect(contact.presence.resources.get('priority-0-resource').get('priority')).toBe(0);
|
||||||
|
expect(contact.presence.resources.get('priority-0-resource').get('show')).toBe('xa');
|
||||||
it("has its priority taken into account",
|
expect(contact.presence.resources.get('priority-1-resource').get('priority')).toBe(1);
|
||||||
mock.initConverse(
|
expect(contact.presence.resources.get('priority-1-resource').get('show')).toBe('online');
|
||||||
['rosterGroupsFetched'], {},
|
|
||||||
async (done, _converse) => {
|
stanza = u.toStanza(
|
||||||
|
'<presence xmlns="jabber:client"'+
|
||||||
test_utils.openControlBox(_converse);
|
' to="romeo@montague.lit/converse.js-21770972"'+
|
||||||
await test_utils.waitForRoster(_converse, 'current');
|
' from="'+contact_jid+'/priority-2-resource">'+
|
||||||
const contact_jid = mock.cur_names[8].replace(/ /g,'.').toLowerCase() + '@montague.lit';
|
' <priority>2</priority>'+
|
||||||
const contact = await _converse.api.contacts.get(contact_jid);
|
' <show>dnd</show>'+
|
||||||
let stanza = u.toStanza(`
|
'</presence>');
|
||||||
<presence xmlns="jabber:client"
|
_converse.connection._dataRecv(mock.createRequest(stanza));
|
||||||
to="romeo@montague.lit/converse.js-21770972"
|
expect(contact.presence.get('show')).toBe('dnd');
|
||||||
from="${contact_jid}/priority-1-resource">
|
expect(contact.presence.resources.length).toBe(3);
|
||||||
<priority>1</priority>
|
expect(contact.presence.resources.get('priority-0-resource').get('priority')).toBe(0);
|
||||||
<c xmlns="http://jabber.org/protocol/caps" hash="sha-1" ext="voice-v1 camera-v1 video-v1"
|
expect(contact.presence.resources.get('priority-0-resource').get('show')).toBe('xa');
|
||||||
ver="AcN1/PEN8nq7AHD+9jpxMV4U6YM=" node="http://pidgin.im/"/>
|
expect(contact.presence.resources.get('priority-1-resource').get('priority')).toBe(1);
|
||||||
<x xmlns="vcard-temp:x:update">
|
expect(contact.presence.resources.get('priority-1-resource').get('show')).toBe('online');
|
||||||
<photo>ce51d94f7f22b87a21274abb93710b9eb7cc1c65</photo>
|
expect(contact.presence.resources.get('priority-2-resource').get('priority')).toBe(2);
|
||||||
</x>
|
expect(contact.presence.resources.get('priority-2-resource').get('show')).toBe('dnd');
|
||||||
<delay xmlns="urn:xmpp:delay" stamp="2017-02-15T20:26:05Z" from="${contact_jid}/priority-1-resource"/>
|
|
||||||
</presence>`);
|
stanza = u.toStanza(
|
||||||
_converse.connection._dataRecv(test_utils.createRequest(stanza));
|
'<presence xmlns="jabber:client"'+
|
||||||
expect(contact.presence.get('show')).toBe('online');
|
' to="romeo@montague.lit/converse.js-21770972"'+
|
||||||
expect(contact.presence.resources.length).toBe(1);
|
' from="'+contact_jid+'/priority-3-resource">'+
|
||||||
expect(contact.presence.resources.get('priority-1-resource').get('priority')).toBe(1);
|
' <priority>3</priority>'+
|
||||||
expect(contact.presence.resources.get('priority-1-resource').get('show')).toBe('online');
|
' <show>away</show>'+
|
||||||
|
'</presence>');
|
||||||
stanza = u.toStanza(
|
_converse.connection._dataRecv(mock.createRequest(stanza));
|
||||||
'<presence xmlns="jabber:client"'+
|
expect(_converse.roster.get(contact_jid).presence.get('show')).toBe('away');
|
||||||
' to="romeo@montague.lit/converse.js-21770972"'+
|
expect(contact.presence.resources.length).toBe(4);
|
||||||
' from="'+contact_jid+'/priority-0-resource">'+
|
expect(contact.presence.resources.get('priority-0-resource').get('priority')).toBe(0);
|
||||||
' <status/>'+
|
expect(contact.presence.resources.get('priority-0-resource').get('show')).toBe('xa');
|
||||||
' <priority>0</priority>'+
|
expect(contact.presence.resources.get('priority-1-resource').get('priority')).toBe(1);
|
||||||
' <show>xa</show>'+
|
expect(contact.presence.resources.get('priority-1-resource').get('show')).toBe('online');
|
||||||
' <c xmlns="http://jabber.org/protocol/caps" ver="GyIX/Kpa4ScVmsZCxRBboJlLAYU=" hash="sha-1"'+
|
expect(contact.presence.resources.get('priority-2-resource').get('priority')).toBe(2);
|
||||||
' node="http://www.igniterealtime.org/projects/smack/"/>'+
|
expect(contact.presence.resources.get('priority-2-resource').get('show')).toBe('dnd');
|
||||||
' <delay xmlns="urn:xmpp:delay" stamp="2017-02-15T17:02:24Z" from="'+contact_jid+'/priority-0-resource"/>'+
|
expect(contact.presence.resources.get('priority-3-resource').get('priority')).toBe(3);
|
||||||
'</presence>');
|
expect(contact.presence.resources.get('priority-3-resource').get('show')).toBe('away');
|
||||||
_converse.connection._dataRecv(test_utils.createRequest(stanza));
|
|
||||||
expect(contact.presence.get('show')).toBe('online');
|
stanza = u.toStanza(
|
||||||
|
'<presence xmlns="jabber:client"'+
|
||||||
expect(contact.presence.resources.length).toBe(2);
|
' to="romeo@montague.lit/converse.js-21770972"'+
|
||||||
expect(contact.presence.resources.get('priority-0-resource').get('priority')).toBe(0);
|
' from="'+contact_jid+'/older-priority-1-resource">'+
|
||||||
expect(contact.presence.resources.get('priority-0-resource').get('show')).toBe('xa');
|
' <priority>1</priority>'+
|
||||||
expect(contact.presence.resources.get('priority-1-resource').get('priority')).toBe(1);
|
' <show>dnd</show>'+
|
||||||
expect(contact.presence.resources.get('priority-1-resource').get('show')).toBe('online');
|
' <delay xmlns="urn:xmpp:delay" stamp="2017-02-15T15:02:24Z" from="'+contact_jid+'/older-priority-1-resource"/>'+
|
||||||
|
'</presence>');
|
||||||
stanza = u.toStanza(
|
_converse.connection._dataRecv(mock.createRequest(stanza));
|
||||||
'<presence xmlns="jabber:client"'+
|
expect(_converse.roster.get(contact_jid).presence.get('show')).toBe('away');
|
||||||
' to="romeo@montague.lit/converse.js-21770972"'+
|
expect(contact.presence.resources.length).toBe(5);
|
||||||
' from="'+contact_jid+'/priority-2-resource">'+
|
expect(contact.presence.resources.get('older-priority-1-resource').get('priority')).toBe(1);
|
||||||
' <priority>2</priority>'+
|
expect(contact.presence.resources.get('older-priority-1-resource').get('show')).toBe('dnd');
|
||||||
' <show>dnd</show>'+
|
expect(contact.presence.resources.get('priority-0-resource').get('priority')).toBe(0);
|
||||||
'</presence>');
|
expect(contact.presence.resources.get('priority-0-resource').get('show')).toBe('xa');
|
||||||
_converse.connection._dataRecv(test_utils.createRequest(stanza));
|
expect(contact.presence.resources.get('priority-1-resource').get('priority')).toBe(1);
|
||||||
expect(contact.presence.get('show')).toBe('dnd');
|
expect(contact.presence.resources.get('priority-1-resource').get('show')).toBe('online');
|
||||||
expect(contact.presence.resources.length).toBe(3);
|
expect(contact.presence.resources.get('priority-2-resource').get('priority')).toBe(2);
|
||||||
expect(contact.presence.resources.get('priority-0-resource').get('priority')).toBe(0);
|
expect(contact.presence.resources.get('priority-2-resource').get('show')).toBe('dnd');
|
||||||
expect(contact.presence.resources.get('priority-0-resource').get('show')).toBe('xa');
|
expect(contact.presence.resources.get('priority-3-resource').get('priority')).toBe(3);
|
||||||
expect(contact.presence.resources.get('priority-1-resource').get('priority')).toBe(1);
|
expect(contact.presence.resources.get('priority-3-resource').get('show')).toBe('away');
|
||||||
expect(contact.presence.resources.get('priority-1-resource').get('show')).toBe('online');
|
|
||||||
expect(contact.presence.resources.get('priority-2-resource').get('priority')).toBe(2);
|
stanza = u.toStanza(
|
||||||
expect(contact.presence.resources.get('priority-2-resource').get('show')).toBe('dnd');
|
'<presence xmlns="jabber:client"'+
|
||||||
|
' to="romeo@montague.lit/converse.js-21770972"'+
|
||||||
stanza = u.toStanza(
|
' type="unavailable"'+
|
||||||
'<presence xmlns="jabber:client"'+
|
' from="'+contact_jid+'/priority-3-resource">'+
|
||||||
' to="romeo@montague.lit/converse.js-21770972"'+
|
'</presence>');
|
||||||
' from="'+contact_jid+'/priority-3-resource">'+
|
_converse.connection._dataRecv(mock.createRequest(stanza));
|
||||||
' <priority>3</priority>'+
|
expect(_converse.roster.get(contact_jid).presence.get('show')).toBe('dnd');
|
||||||
' <show>away</show>'+
|
expect(contact.presence.resources.length).toBe(4);
|
||||||
'</presence>');
|
expect(contact.presence.resources.get('priority-0-resource').get('priority')).toBe(0);
|
||||||
_converse.connection._dataRecv(test_utils.createRequest(stanza));
|
expect(contact.presence.resources.get('priority-0-resource').get('show')).toBe('xa');
|
||||||
expect(_converse.roster.get(contact_jid).presence.get('show')).toBe('away');
|
expect(contact.presence.resources.get('priority-1-resource').get('priority')).toBe(1);
|
||||||
expect(contact.presence.resources.length).toBe(4);
|
expect(contact.presence.resources.get('priority-1-resource').get('show')).toBe('online');
|
||||||
expect(contact.presence.resources.get('priority-0-resource').get('priority')).toBe(0);
|
expect(contact.presence.resources.get('priority-2-resource').get('priority')).toBe(2);
|
||||||
expect(contact.presence.resources.get('priority-0-resource').get('show')).toBe('xa');
|
expect(contact.presence.resources.get('priority-2-resource').get('show')).toBe('dnd');
|
||||||
expect(contact.presence.resources.get('priority-1-resource').get('priority')).toBe(1);
|
expect(contact.presence.resources.get('older-priority-1-resource').get('priority')).toBe(1);
|
||||||
expect(contact.presence.resources.get('priority-1-resource').get('show')).toBe('online');
|
expect(contact.presence.resources.get('older-priority-1-resource').get('show')).toBe('dnd');
|
||||||
expect(contact.presence.resources.get('priority-2-resource').get('priority')).toBe(2);
|
|
||||||
expect(contact.presence.resources.get('priority-2-resource').get('show')).toBe('dnd');
|
stanza = u.toStanza(
|
||||||
expect(contact.presence.resources.get('priority-3-resource').get('priority')).toBe(3);
|
'<presence xmlns="jabber:client"'+
|
||||||
expect(contact.presence.resources.get('priority-3-resource').get('show')).toBe('away');
|
' to="romeo@montague.lit/converse.js-21770972"'+
|
||||||
|
' type="unavailable"'+
|
||||||
stanza = u.toStanza(
|
' from="'+contact_jid+'/priority-2-resource">'+
|
||||||
'<presence xmlns="jabber:client"'+
|
'</presence>');
|
||||||
' to="romeo@montague.lit/converse.js-21770972"'+
|
_converse.connection._dataRecv(mock.createRequest(stanza));
|
||||||
' from="'+contact_jid+'/older-priority-1-resource">'+
|
expect(_converse.roster.get(contact_jid).presence.get('show')).toBe('online');
|
||||||
' <priority>1</priority>'+
|
expect(contact.presence.resources.length).toBe(3);
|
||||||
' <show>dnd</show>'+
|
expect(contact.presence.resources.get('priority-0-resource').get('priority')).toBe(0);
|
||||||
' <delay xmlns="urn:xmpp:delay" stamp="2017-02-15T15:02:24Z" from="'+contact_jid+'/older-priority-1-resource"/>'+
|
expect(contact.presence.resources.get('priority-0-resource').get('show')).toBe('xa');
|
||||||
'</presence>');
|
expect(contact.presence.resources.get('priority-1-resource').get('priority')).toBe(1);
|
||||||
_converse.connection._dataRecv(test_utils.createRequest(stanza));
|
expect(contact.presence.resources.get('priority-1-resource').get('show')).toBe('online');
|
||||||
expect(_converse.roster.get(contact_jid).presence.get('show')).toBe('away');
|
expect(contact.presence.resources.get('older-priority-1-resource').get('priority')).toBe(1);
|
||||||
expect(contact.presence.resources.length).toBe(5);
|
expect(contact.presence.resources.get('older-priority-1-resource').get('show')).toBe('dnd');
|
||||||
expect(contact.presence.resources.get('older-priority-1-resource').get('priority')).toBe(1);
|
|
||||||
expect(contact.presence.resources.get('older-priority-1-resource').get('show')).toBe('dnd');
|
stanza = u.toStanza(
|
||||||
expect(contact.presence.resources.get('priority-0-resource').get('priority')).toBe(0);
|
'<presence xmlns="jabber:client"'+
|
||||||
expect(contact.presence.resources.get('priority-0-resource').get('show')).toBe('xa');
|
' to="romeo@montague.lit/converse.js-21770972"'+
|
||||||
expect(contact.presence.resources.get('priority-1-resource').get('priority')).toBe(1);
|
' type="unavailable"'+
|
||||||
expect(contact.presence.resources.get('priority-1-resource').get('show')).toBe('online');
|
' from="'+contact_jid+'/priority-1-resource">'+
|
||||||
expect(contact.presence.resources.get('priority-2-resource').get('priority')).toBe(2);
|
'</presence>');
|
||||||
expect(contact.presence.resources.get('priority-2-resource').get('show')).toBe('dnd');
|
_converse.connection._dataRecv(mock.createRequest(stanza));
|
||||||
expect(contact.presence.resources.get('priority-3-resource').get('priority')).toBe(3);
|
expect(_converse.roster.get(contact_jid).presence.get('show')).toBe('dnd');
|
||||||
expect(contact.presence.resources.get('priority-3-resource').get('show')).toBe('away');
|
expect(contact.presence.resources.length).toBe(2);
|
||||||
|
expect(contact.presence.resources.get('priority-0-resource').get('priority')).toBe(0);
|
||||||
stanza = u.toStanza(
|
expect(contact.presence.resources.get('priority-0-resource').get('show')).toBe('xa');
|
||||||
'<presence xmlns="jabber:client"'+
|
expect(contact.presence.resources.get('older-priority-1-resource').get('priority')).toBe(1);
|
||||||
' to="romeo@montague.lit/converse.js-21770972"'+
|
expect(contact.presence.resources.get('older-priority-1-resource').get('show')).toBe('dnd');
|
||||||
' type="unavailable"'+
|
|
||||||
' from="'+contact_jid+'/priority-3-resource">'+
|
stanza = u.toStanza(
|
||||||
'</presence>');
|
'<presence xmlns="jabber:client"'+
|
||||||
_converse.connection._dataRecv(test_utils.createRequest(stanza));
|
' to="romeo@montague.lit/converse.js-21770972"'+
|
||||||
expect(_converse.roster.get(contact_jid).presence.get('show')).toBe('dnd');
|
' type="unavailable"'+
|
||||||
expect(contact.presence.resources.length).toBe(4);
|
' from="'+contact_jid+'/older-priority-1-resource">'+
|
||||||
expect(contact.presence.resources.get('priority-0-resource').get('priority')).toBe(0);
|
'</presence>');
|
||||||
expect(contact.presence.resources.get('priority-0-resource').get('show')).toBe('xa');
|
_converse.connection._dataRecv(mock.createRequest(stanza));
|
||||||
expect(contact.presence.resources.get('priority-1-resource').get('priority')).toBe(1);
|
expect(_converse.roster.get(contact_jid).presence.get('show')).toBe('xa');
|
||||||
expect(contact.presence.resources.get('priority-1-resource').get('show')).toBe('online');
|
expect(contact.presence.resources.length).toBe(1);
|
||||||
expect(contact.presence.resources.get('priority-2-resource').get('priority')).toBe(2);
|
expect(contact.presence.resources.get('priority-0-resource').get('priority')).toBe(0);
|
||||||
expect(contact.presence.resources.get('priority-2-resource').get('show')).toBe('dnd');
|
expect(contact.presence.resources.get('priority-0-resource').get('show')).toBe('xa');
|
||||||
expect(contact.presence.resources.get('older-priority-1-resource').get('priority')).toBe(1);
|
|
||||||
expect(contact.presence.resources.get('older-priority-1-resource').get('show')).toBe('dnd');
|
stanza = u.toStanza(
|
||||||
|
'<presence xmlns="jabber:client"'+
|
||||||
stanza = u.toStanza(
|
' to="romeo@montague.lit/converse.js-21770972"'+
|
||||||
'<presence xmlns="jabber:client"'+
|
' type="unavailable"'+
|
||||||
' to="romeo@montague.lit/converse.js-21770972"'+
|
' from="'+contact_jid+'/priority-0-resource">'+
|
||||||
' type="unavailable"'+
|
'</presence>');
|
||||||
' from="'+contact_jid+'/priority-2-resource">'+
|
_converse.connection._dataRecv(mock.createRequest(stanza));
|
||||||
'</presence>');
|
expect(_converse.roster.get(contact_jid).presence.get('show')).toBe('offline');
|
||||||
_converse.connection._dataRecv(test_utils.createRequest(stanza));
|
expect(contact.presence.resources.length).toBe(0);
|
||||||
expect(_converse.roster.get(contact_jid).presence.get('show')).toBe('online');
|
done();
|
||||||
expect(contact.presence.resources.length).toBe(3);
|
}));
|
||||||
expect(contact.presence.resources.get('priority-0-resource').get('priority')).toBe(0);
|
|
||||||
expect(contact.presence.resources.get('priority-0-resource').get('show')).toBe('xa');
|
|
||||||
expect(contact.presence.resources.get('priority-1-resource').get('priority')).toBe(1);
|
|
||||||
expect(contact.presence.resources.get('priority-1-resource').get('show')).toBe('online');
|
|
||||||
expect(contact.presence.resources.get('older-priority-1-resource').get('priority')).toBe(1);
|
|
||||||
expect(contact.presence.resources.get('older-priority-1-resource').get('show')).toBe('dnd');
|
|
||||||
|
|
||||||
stanza = u.toStanza(
|
|
||||||
'<presence xmlns="jabber:client"'+
|
|
||||||
' to="romeo@montague.lit/converse.js-21770972"'+
|
|
||||||
' type="unavailable"'+
|
|
||||||
' from="'+contact_jid+'/priority-1-resource">'+
|
|
||||||
'</presence>');
|
|
||||||
_converse.connection._dataRecv(test_utils.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);
|
|
||||||
expect(contact.presence.resources.get('priority-0-resource').get('show')).toBe('xa');
|
|
||||||
expect(contact.presence.resources.get('older-priority-1-resource').get('priority')).toBe(1);
|
|
||||||
expect(contact.presence.resources.get('older-priority-1-resource').get('show')).toBe('dnd');
|
|
||||||
|
|
||||||
stanza = u.toStanza(
|
|
||||||
'<presence xmlns="jabber:client"'+
|
|
||||||
' to="romeo@montague.lit/converse.js-21770972"'+
|
|
||||||
' type="unavailable"'+
|
|
||||||
' from="'+contact_jid+'/older-priority-1-resource">'+
|
|
||||||
'</presence>');
|
|
||||||
_converse.connection._dataRecv(test_utils.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);
|
|
||||||
expect(contact.presence.resources.get('priority-0-resource').get('show')).toBe('xa');
|
|
||||||
|
|
||||||
stanza = u.toStanza(
|
|
||||||
'<presence xmlns="jabber:client"'+
|
|
||||||
' to="romeo@montague.lit/converse.js-21770972"'+
|
|
||||||
' type="unavailable"'+
|
|
||||||
' from="'+contact_jid+'/priority-0-resource">'+
|
|
||||||
'</presence>');
|
|
||||||
_converse.connection._dataRecv(test_utils.createRequest(stanza));
|
|
||||||
expect(_converse.roster.get(contact_jid).presence.get('show')).toBe('offline');
|
|
||||||
expect(contact.presence.resources.length).toBe(0);
|
|
||||||
done();
|
|
||||||
}));
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
@ -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);
|
|
||||||
}));
|
|
||||||
});
|
|
||||||
}));
|
|
1055
spec/protocol.js
1055
spec/protocol.js
File diff suppressed because it is too large
Load Diff
348
spec/push.js
348
spec/push.js
@ -1,191 +1,189 @@
|
|||||||
window.addEventListener('converse-loaded', () => {
|
/*global mock */
|
||||||
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;
|
|
||||||
|
|
||||||
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;
|
||||||
|
|
||||||
it("can be enabled",
|
describe("XEP-0357 Push Notifications", function () {
|
||||||
mock.initConverse(
|
|
||||||
['rosterGroupsFetched'], {
|
|
||||||
'push_app_servers': [{
|
|
||||||
'jid': 'push-5@client.example',
|
|
||||||
'node': 'yxs32uqsflafdk3iuqo'
|
|
||||||
}]
|
|
||||||
}, async function (done, _converse) {
|
|
||||||
|
|
||||||
const IQ_stanzas = _converse.connection.IQ_stanzas;
|
it("can be enabled",
|
||||||
expect(_converse.session.get('push_enabled')).toBeFalsy();
|
mock.initConverse(
|
||||||
|
['rosterGroupsFetched'], {
|
||||||
|
'push_app_servers': [{
|
||||||
|
'jid': 'push-5@client.example',
|
||||||
|
'node': 'yxs32uqsflafdk3iuqo'
|
||||||
|
}]
|
||||||
|
}, async function (done, _converse) {
|
||||||
|
|
||||||
await test_utils.waitUntilDiscoConfirmed(
|
const IQ_stanzas = _converse.connection.IQ_stanzas;
|
||||||
_converse, _converse.push_app_servers[0].jid,
|
expect(_converse.session.get('push_enabled')).toBeFalsy();
|
||||||
[{'category': 'pubsub', 'type':'push'}],
|
|
||||||
['urn:xmpp:push:0'], [], 'info');
|
|
||||||
await test_utils.waitUntilDiscoConfirmed(
|
|
||||||
_converse,
|
|
||||||
_converse.bare_jid,
|
|
||||||
[{'category': 'account', 'type':'registered'}],
|
|
||||||
['urn:xmpp:push:0'], [], 'info');
|
|
||||||
const stanza = await u.waitUntil(() =>
|
|
||||||
_.filter(IQ_stanzas, iq => iq.querySelector('iq[type="set"] enable[xmlns="urn:xmpp:push:0"]')).pop()
|
|
||||||
);
|
|
||||||
expect(Strophe.serialize(stanza)).toEqual(
|
|
||||||
`<iq id="${stanza.getAttribute('id')}" type="set" xmlns="jabber:client">`+
|
|
||||||
'<enable jid="push-5@client.example" node="yxs32uqsflafdk3iuqo" xmlns="urn:xmpp:push:0"/>'+
|
|
||||||
'</iq>'
|
|
||||||
)
|
|
||||||
_converse.connection._dataRecv(test_utils.createRequest($iq({
|
|
||||||
'to': _converse.connection.jid,
|
|
||||||
'type': 'result',
|
|
||||||
'id': stanza.getAttribute('id')
|
|
||||||
})));
|
|
||||||
await u.waitUntil(() => _converse.session.get('push_enabled'));
|
|
||||||
done();
|
|
||||||
}));
|
|
||||||
|
|
||||||
it("can be enabled for a MUC domain",
|
await mock.waitUntilDiscoConfirmed(
|
||||||
mock.initConverse(
|
_converse, _converse.push_app_servers[0].jid,
|
||||||
['rosterGroupsFetched'], {
|
[{'category': 'pubsub', 'type':'push'}],
|
||||||
'enable_muc_push': true,
|
['urn:xmpp:push:0'], [], 'info');
|
||||||
'push_app_servers': [{
|
await mock.waitUntilDiscoConfirmed(
|
||||||
'jid': 'push-5@client.example',
|
|
||||||
'node': 'yxs32uqsflafdk3iuqo'
|
|
||||||
}]
|
|
||||||
}, async function (done, _converse) {
|
|
||||||
|
|
||||||
const IQ_stanzas = _converse.connection.IQ_stanzas;
|
|
||||||
await test_utils.waitUntilDiscoConfirmed(
|
|
||||||
_converse, _converse.push_app_servers[0].jid,
|
|
||||||
[{'category': 'pubsub', 'type':'push'}],
|
|
||||||
['urn:xmpp:push:0'], [], 'info');
|
|
||||||
await test_utils.waitUntilDiscoConfirmed(
|
|
||||||
_converse, _converse.bare_jid, [],
|
|
||||||
['urn:xmpp:push:0']);
|
|
||||||
|
|
||||||
let iq = await u.waitUntil(() => _.filter(
|
|
||||||
IQ_stanzas,
|
|
||||||
iq => sizzle(`iq[type="set"] enable[xmlns="${Strophe.NS.PUSH}"]`, iq).length
|
|
||||||
).pop());
|
|
||||||
|
|
||||||
expect(Strophe.serialize(iq)).toBe(
|
|
||||||
`<iq id="${iq.getAttribute('id')}" type="set" xmlns="jabber:client">`+
|
|
||||||
`<enable jid="push-5@client.example" node="yxs32uqsflafdk3iuqo" xmlns="urn:xmpp:push:0"/>`+
|
|
||||||
`</iq>`
|
|
||||||
);
|
|
||||||
const result = u.toStanza(`<iq type="result" id="${iq.getAttribute('id')}" to="romeo@montague.lit" />`);
|
|
||||||
_converse.connection._dataRecv(test_utils.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(
|
|
||||||
_converse, 'chat.shakespeare.lit',
|
|
||||||
[{'category': 'account', 'type':'registered'}],
|
|
||||||
['urn:xmpp:push:0'], [], 'info');
|
|
||||||
iq = await u.waitUntil(() => _.filter(
|
|
||||||
IQ_stanzas,
|
|
||||||
iq => sizzle(`iq[type="set"][to="chat.shakespeare.lit"] enable[xmlns="${Strophe.NS.PUSH}"]`, iq).length
|
|
||||||
).pop());
|
|
||||||
|
|
||||||
expect(Strophe.serialize(iq)).toEqual(
|
|
||||||
`<iq id="${iq.getAttribute('id')}" to="chat.shakespeare.lit" type="set" xmlns="jabber:client">`+
|
|
||||||
'<enable jid="push-5@client.example" node="yxs32uqsflafdk3iuqo" xmlns="urn:xmpp:push:0"/>'+
|
|
||||||
'</iq>'
|
|
||||||
);
|
|
||||||
_converse.connection._dataRecv(test_utils.createRequest($iq({
|
|
||||||
'to': _converse.connection.jid,
|
|
||||||
'type': 'result',
|
|
||||||
'id': iq.getAttribute('id')
|
|
||||||
})));
|
|
||||||
await u.waitUntil(() => _.includes(_converse.session.get('push_enabled'), 'chat.shakespeare.lit'));
|
|
||||||
done();
|
|
||||||
}));
|
|
||||||
|
|
||||||
it("can be disabled",
|
|
||||||
mock.initConverse(
|
|
||||||
['rosterGroupsFetched'], {
|
|
||||||
'push_app_servers': [{
|
|
||||||
'jid': 'push-5@client.example',
|
|
||||||
'node': 'yxs32uqsflafdk3iuqo',
|
|
||||||
'disable': true
|
|
||||||
}]
|
|
||||||
}, async function (done, _converse) {
|
|
||||||
|
|
||||||
const IQ_stanzas = _converse.connection.IQ_stanzas;
|
|
||||||
expect(_converse.session.get('push_enabled')).toBeFalsy();
|
|
||||||
|
|
||||||
await test_utils.waitUntilDiscoConfirmed(
|
|
||||||
_converse,
|
_converse,
|
||||||
_converse.bare_jid,
|
_converse.bare_jid,
|
||||||
[{'category': 'account', 'type':'registered'}],
|
[{'category': 'account', 'type':'registered'}],
|
||||||
['urn:xmpp:push:0'], [], 'info');
|
['urn:xmpp:push:0'], [], 'info');
|
||||||
const stanza = await u.waitUntil(
|
const stanza = await u.waitUntil(() =>
|
||||||
() => _.filter(IQ_stanzas, iq => iq.querySelector('iq[type="set"] disable[xmlns="urn:xmpp:push:0"]')).pop()
|
_.filter(IQ_stanzas, iq => iq.querySelector('iq[type="set"] enable[xmlns="urn:xmpp:push:0"]')).pop()
|
||||||
);
|
);
|
||||||
expect(Strophe.serialize(stanza)).toEqual(
|
expect(Strophe.serialize(stanza)).toEqual(
|
||||||
`<iq id="${stanza.getAttribute('id')}" type="set" xmlns="jabber:client">`+
|
`<iq id="${stanza.getAttribute('id')}" type="set" xmlns="jabber:client">`+
|
||||||
'<disable jid="push-5@client.example" node="yxs32uqsflafdk3iuqo" xmlns="urn:xmpp:push:0"/>'+
|
'<enable jid="push-5@client.example" node="yxs32uqsflafdk3iuqo" xmlns="urn:xmpp:push:0"/>'+
|
||||||
'</iq>'
|
'</iq>'
|
||||||
);
|
)
|
||||||
_converse.connection._dataRecv(test_utils.createRequest($iq({
|
_converse.connection._dataRecv(mock.createRequest($iq({
|
||||||
'to': _converse.connection.jid,
|
'to': _converse.connection.jid,
|
||||||
'type': 'result',
|
'type': 'result',
|
||||||
'id': stanza.getAttribute('id')
|
'id': stanza.getAttribute('id')
|
||||||
})));
|
})));
|
||||||
await u.waitUntil(() => _converse.session.get('push_enabled'))
|
await u.waitUntil(() => _converse.session.get('push_enabled'));
|
||||||
done();
|
done();
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
it("can be enabled for a MUC domain",
|
||||||
|
mock.initConverse(
|
||||||
|
['rosterGroupsFetched'], {
|
||||||
|
'enable_muc_push': true,
|
||||||
|
'push_app_servers': [{
|
||||||
|
'jid': 'push-5@client.example',
|
||||||
|
'node': 'yxs32uqsflafdk3iuqo'
|
||||||
|
}]
|
||||||
|
}, async function (done, _converse) {
|
||||||
|
|
||||||
|
const IQ_stanzas = _converse.connection.IQ_stanzas;
|
||||||
|
await mock.waitUntilDiscoConfirmed(
|
||||||
|
_converse, _converse.push_app_servers[0].jid,
|
||||||
|
[{'category': 'pubsub', 'type':'push'}],
|
||||||
|
['urn:xmpp:push:0'], [], 'info');
|
||||||
|
await mock.waitUntilDiscoConfirmed(
|
||||||
|
_converse, _converse.bare_jid, [],
|
||||||
|
['urn:xmpp:push:0']);
|
||||||
|
|
||||||
|
let iq = await u.waitUntil(() => _.filter(
|
||||||
|
IQ_stanzas,
|
||||||
|
iq => sizzle(`iq[type="set"] enable[xmlns="${Strophe.NS.PUSH}"]`, iq).length
|
||||||
|
).pop());
|
||||||
|
|
||||||
|
expect(Strophe.serialize(iq)).toBe(
|
||||||
|
`<iq id="${iq.getAttribute('id')}" type="set" xmlns="jabber:client">`+
|
||||||
|
`<enable jid="push-5@client.example" node="yxs32uqsflafdk3iuqo" xmlns="urn:xmpp:push:0"/>`+
|
||||||
|
`</iq>`
|
||||||
|
);
|
||||||
|
const result = u.toStanza(`<iq type="result" id="${iq.getAttribute('id')}" to="romeo@montague.lit" />`);
|
||||||
|
_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);
|
||||||
|
|
||||||
|
mock.openAndEnterChatRoom(_converse, 'coven@chat.shakespeare.lit', 'oldhag');
|
||||||
|
await mock.waitUntilDiscoConfirmed(
|
||||||
|
_converse, 'chat.shakespeare.lit',
|
||||||
|
[{'category': 'account', 'type':'registered'}],
|
||||||
|
['urn:xmpp:push:0'], [], 'info');
|
||||||
|
iq = await u.waitUntil(() => _.filter(
|
||||||
|
IQ_stanzas,
|
||||||
|
iq => sizzle(`iq[type="set"][to="chat.shakespeare.lit"] enable[xmlns="${Strophe.NS.PUSH}"]`, iq).length
|
||||||
|
).pop());
|
||||||
|
|
||||||
|
expect(Strophe.serialize(iq)).toEqual(
|
||||||
|
`<iq id="${iq.getAttribute('id')}" to="chat.shakespeare.lit" type="set" xmlns="jabber:client">`+
|
||||||
|
'<enable jid="push-5@client.example" node="yxs32uqsflafdk3iuqo" xmlns="urn:xmpp:push:0"/>'+
|
||||||
|
'</iq>'
|
||||||
|
);
|
||||||
|
_converse.connection._dataRecv(mock.createRequest($iq({
|
||||||
|
'to': _converse.connection.jid,
|
||||||
|
'type': 'result',
|
||||||
|
'id': iq.getAttribute('id')
|
||||||
|
})));
|
||||||
|
await u.waitUntil(() => _.includes(_converse.session.get('push_enabled'), 'chat.shakespeare.lit'));
|
||||||
|
done();
|
||||||
|
}));
|
||||||
|
|
||||||
|
it("can be disabled",
|
||||||
|
mock.initConverse(
|
||||||
|
['rosterGroupsFetched'], {
|
||||||
|
'push_app_servers': [{
|
||||||
|
'jid': 'push-5@client.example',
|
||||||
|
'node': 'yxs32uqsflafdk3iuqo',
|
||||||
|
'disable': true
|
||||||
|
}]
|
||||||
|
}, async function (done, _converse) {
|
||||||
|
|
||||||
|
const IQ_stanzas = _converse.connection.IQ_stanzas;
|
||||||
|
expect(_converse.session.get('push_enabled')).toBeFalsy();
|
||||||
|
|
||||||
|
await mock.waitUntilDiscoConfirmed(
|
||||||
|
_converse,
|
||||||
|
_converse.bare_jid,
|
||||||
|
[{'category': 'account', 'type':'registered'}],
|
||||||
|
['urn:xmpp:push:0'], [], 'info');
|
||||||
|
const stanza = await u.waitUntil(
|
||||||
|
() => _.filter(IQ_stanzas, iq => iq.querySelector('iq[type="set"] disable[xmlns="urn:xmpp:push:0"]')).pop()
|
||||||
|
);
|
||||||
|
expect(Strophe.serialize(stanza)).toEqual(
|
||||||
|
`<iq id="${stanza.getAttribute('id')}" type="set" xmlns="jabber:client">`+
|
||||||
|
'<disable jid="push-5@client.example" node="yxs32uqsflafdk3iuqo" xmlns="urn:xmpp:push:0"/>'+
|
||||||
|
'</iq>'
|
||||||
|
);
|
||||||
|
_converse.connection._dataRecv(mock.createRequest($iq({
|
||||||
|
'to': _converse.connection.jid,
|
||||||
|
'type': 'result',
|
||||||
|
'id': stanza.getAttribute('id')
|
||||||
|
})));
|
||||||
|
await u.waitUntil(() => _converse.session.get('push_enabled'))
|
||||||
|
done();
|
||||||
|
}));
|
||||||
|
|
||||||
|
|
||||||
it("can require a secret token to be included",
|
it("can require a secret token to be included",
|
||||||
mock.initConverse(
|
mock.initConverse(
|
||||||
['rosterGroupsFetched'], {
|
['rosterGroupsFetched'], {
|
||||||
'push_app_servers': [{
|
'push_app_servers': [{
|
||||||
'jid': 'push-5@client.example',
|
'jid': 'push-5@client.example',
|
||||||
'node': 'yxs32uqsflafdk3iuqo',
|
'node': 'yxs32uqsflafdk3iuqo',
|
||||||
'secret': 'eruio234vzxc2kla-91'
|
'secret': 'eruio234vzxc2kla-91'
|
||||||
}]
|
}]
|
||||||
}, async function (done, _converse) {
|
}, async function (done, _converse) {
|
||||||
|
|
||||||
const IQ_stanzas = _converse.connection.IQ_stanzas;
|
const IQ_stanzas = _converse.connection.IQ_stanzas;
|
||||||
expect(_converse.session.get('push_enabled')).toBeFalsy();
|
expect(_converse.session.get('push_enabled')).toBeFalsy();
|
||||||
|
|
||||||
await test_utils.waitUntilDiscoConfirmed(
|
await mock.waitUntilDiscoConfirmed(
|
||||||
_converse, _converse.push_app_servers[0].jid,
|
_converse, _converse.push_app_servers[0].jid,
|
||||||
[{'category': 'pubsub', 'type':'push'}],
|
[{'category': 'pubsub', 'type':'push'}],
|
||||||
|
['urn:xmpp:push:0'], [], 'info');
|
||||||
|
await mock.waitUntilDiscoConfirmed(
|
||||||
|
_converse,
|
||||||
|
_converse.bare_jid,
|
||||||
|
[{'category': 'account', 'type':'registered'}],
|
||||||
['urn:xmpp:push:0'], [], 'info');
|
['urn:xmpp:push:0'], [], 'info');
|
||||||
await test_utils.waitUntilDiscoConfirmed(
|
|
||||||
_converse,
|
|
||||||
_converse.bare_jid,
|
|
||||||
[{'category': 'account', 'type':'registered'}],
|
|
||||||
['urn:xmpp:push:0'], [], 'info');
|
|
||||||
|
|
||||||
const stanza = await u.waitUntil(
|
const stanza = await u.waitUntil(
|
||||||
() => _.filter(IQ_stanzas, iq => iq.querySelector('iq[type="set"] enable[xmlns="urn:xmpp:push:0"]')).pop()
|
() => _.filter(IQ_stanzas, iq => iq.querySelector('iq[type="set"] enable[xmlns="urn:xmpp:push:0"]')).pop()
|
||||||
);
|
);
|
||||||
expect(Strophe.serialize(stanza)).toEqual(
|
expect(Strophe.serialize(stanza)).toEqual(
|
||||||
`<iq id="${stanza.getAttribute('id')}" type="set" xmlns="jabber:client">`+
|
`<iq id="${stanza.getAttribute('id')}" type="set" xmlns="jabber:client">`+
|
||||||
'<enable jid="push-5@client.example" node="yxs32uqsflafdk3iuqo" xmlns="urn:xmpp:push:0">'+
|
'<enable jid="push-5@client.example" node="yxs32uqsflafdk3iuqo" xmlns="urn:xmpp:push:0">'+
|
||||||
'<x type="submit" xmlns="jabber:x:data">'+
|
'<x type="submit" xmlns="jabber:x:data">'+
|
||||||
'<field var="FORM_TYPE"><value>http://jabber.org/protocol/pubsub#publish-options</value></field>'+
|
'<field var="FORM_TYPE"><value>http://jabber.org/protocol/pubsub#publish-options</value></field>'+
|
||||||
'<field var="secret"><value>eruio234vzxc2kla-91</value></field>'+
|
'<field var="secret"><value>eruio234vzxc2kla-91</value></field>'+
|
||||||
'</x>'+
|
'</x>'+
|
||||||
'</enable>'+
|
'</enable>'+
|
||||||
'</iq>'
|
'</iq>'
|
||||||
)
|
)
|
||||||
_converse.connection._dataRecv(test_utils.createRequest($iq({
|
_converse.connection._dataRecv(mock.createRequest($iq({
|
||||||
'to': _converse.connection.jid,
|
'to': _converse.connection.jid,
|
||||||
'type': 'result',
|
'type': 'result',
|
||||||
'id': stanza.getAttribute('id')
|
'id': stanza.getAttribute('id')
|
||||||
})));
|
})));
|
||||||
await u.waitUntil(() => _converse.session.get('push_enabled'))
|
await u.waitUntil(() => _converse.session.get('push_enabled'))
|
||||||
done();
|
done();
|
||||||
}));
|
}));
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
638
spec/register.js
638
spec/register.js
@ -1,365 +1,363 @@
|
|||||||
window.addEventListener('converse-loaded', () => {
|
/*global mock */
|
||||||
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;
|
|
||||||
|
|
||||||
describe("The Registration Panel", function () {
|
const Strophe = converse.env.Strophe;
|
||||||
|
const $iq = converse.env.$iq;
|
||||||
|
const { _, sizzle} = converse.env;
|
||||||
|
const u = converse.env.utils;
|
||||||
|
|
||||||
it("is not available unless allow_registration=true",
|
describe("The Registration Panel", function () {
|
||||||
mock.initConverse(
|
|
||||||
['chatBoxesInitialized'],
|
|
||||||
{ auto_login: false,
|
|
||||||
allow_registration: false },
|
|
||||||
async function (done, _converse) {
|
|
||||||
|
|
||||||
await u.waitUntil(() => _converse.chatboxviews.get('controlbox'));
|
it("is not available unless allow_registration=true",
|
||||||
const cbview = _converse.api.controlbox.get();
|
mock.initConverse(
|
||||||
expect(cbview.el.querySelectorAll('a.register-account').length).toBe(0);
|
['chatBoxesInitialized'],
|
||||||
done();
|
{ auto_login: false,
|
||||||
}));
|
allow_registration: false },
|
||||||
|
async function (done, _converse) {
|
||||||
|
|
||||||
it("can be opened by clicking on the registration tab",
|
await u.waitUntil(() => _converse.chatboxviews.get('controlbox'));
|
||||||
mock.initConverse(
|
const cbview = _converse.api.controlbox.get();
|
||||||
['chatBoxesInitialized'],
|
expect(cbview.el.querySelectorAll('a.register-account').length).toBe(0);
|
||||||
{ auto_login: false,
|
done();
|
||||||
allow_registration: true },
|
}));
|
||||||
async function (done, _converse) {
|
|
||||||
|
|
||||||
const toggle = document.querySelector(".toggle-controlbox");
|
it("can be opened by clicking on the registration tab",
|
||||||
if (!u.isVisible(document.querySelector("#controlbox"))) {
|
mock.initConverse(
|
||||||
if (!u.isVisible(toggle)) {
|
['chatBoxesInitialized'],
|
||||||
u.removeClass('hidden', toggle);
|
{ auto_login: false,
|
||||||
}
|
allow_registration: true },
|
||||||
toggle.click();
|
async function (done, _converse) {
|
||||||
|
|
||||||
|
const toggle = document.querySelector(".toggle-controlbox");
|
||||||
|
if (!u.isVisible(document.querySelector("#controlbox"))) {
|
||||||
|
if (!u.isVisible(toggle)) {
|
||||||
|
u.removeClass('hidden', toggle);
|
||||||
}
|
}
|
||||||
await u.waitUntil(() => _.get(_converse.chatboxviews.get('controlbox'), 'registerpanel'), 300);
|
|
||||||
const cbview = _converse.chatboxviews.get('controlbox');
|
|
||||||
const panels = cbview.el.querySelector('.controlbox-panes');
|
|
||||||
const login = panels.firstElementChild;
|
|
||||||
const registration = panels.childNodes[1];
|
|
||||||
const register_link = cbview.el.querySelector('a.register-account');
|
|
||||||
expect(register_link.textContent).toBe("Create an account");
|
|
||||||
register_link.click();
|
|
||||||
|
|
||||||
await u.waitUntil(() => u.isVisible(registration));
|
|
||||||
expect(u.isVisible(login)).toBe(false);
|
|
||||||
done();
|
|
||||||
}));
|
|
||||||
|
|
||||||
it("allows the user to choose an XMPP provider's domain",
|
|
||||||
mock.initConverse(
|
|
||||||
['chatBoxesInitialized'],
|
|
||||||
{ auto_login: false,
|
|
||||||
discover_connection_methods: false,
|
|
||||||
allow_registration: true },
|
|
||||||
async function (done, _converse) {
|
|
||||||
|
|
||||||
spyOn(Strophe.Connection.prototype, 'connect');
|
|
||||||
|
|
||||||
await u.waitUntil(() => _.get(_converse.chatboxviews.get('controlbox'), 'registerpanel'));
|
|
||||||
const toggle = document.querySelector(".toggle-controlbox");
|
|
||||||
toggle.click();
|
toggle.click();
|
||||||
|
}
|
||||||
|
await u.waitUntil(() => _.get(_converse.chatboxviews.get('controlbox'), 'registerpanel'), 300);
|
||||||
|
const cbview = _converse.chatboxviews.get('controlbox');
|
||||||
|
const panels = cbview.el.querySelector('.controlbox-panes');
|
||||||
|
const login = panels.firstElementChild;
|
||||||
|
const registration = panels.childNodes[1];
|
||||||
|
const register_link = cbview.el.querySelector('a.register-account');
|
||||||
|
expect(register_link.textContent).toBe("Create an account");
|
||||||
|
register_link.click();
|
||||||
|
|
||||||
const cbview = _converse.api.controlbox.get();
|
await u.waitUntil(() => u.isVisible(registration));
|
||||||
await u.waitUntil(() => u.isVisible(cbview.el));
|
expect(u.isVisible(login)).toBe(false);
|
||||||
const registerview = cbview.registerpanel;
|
done();
|
||||||
spyOn(registerview, 'onProviderChosen').and.callThrough();
|
}));
|
||||||
registerview.delegateEvents(); // We need to rebind all events otherwise our spy won't be called
|
|
||||||
|
|
||||||
// Open the register panel
|
it("allows the user to choose an XMPP provider's domain",
|
||||||
cbview.el.querySelector('.toggle-register-login').click();
|
mock.initConverse(
|
||||||
|
['chatBoxesInitialized'],
|
||||||
|
{ auto_login: false,
|
||||||
|
discover_connection_methods: false,
|
||||||
|
allow_registration: true },
|
||||||
|
async function (done, _converse) {
|
||||||
|
|
||||||
// Check the form layout
|
spyOn(Strophe.Connection.prototype, 'connect');
|
||||||
const form = cbview.el.querySelector('#converse-register');
|
|
||||||
expect(form.querySelectorAll('input').length).toEqual(2);
|
|
||||||
expect(form.querySelectorAll('input')[0].getAttribute('name')).toEqual('domain');
|
|
||||||
expect(sizzle('input:last', form).pop().getAttribute('type')).toEqual('submit');
|
|
||||||
// Check that the input[type=domain] input is required
|
|
||||||
const submit_button = form.querySelector('input[type=submit]');
|
|
||||||
submit_button.click();
|
|
||||||
expect(registerview.onProviderChosen).not.toHaveBeenCalled();
|
|
||||||
|
|
||||||
// Check that the form is accepted if input[type=domain] has a value
|
await u.waitUntil(() => _.get(_converse.chatboxviews.get('controlbox'), 'registerpanel'));
|
||||||
form.querySelector('input[name=domain]').value = 'conversejs.org';
|
const toggle = document.querySelector(".toggle-controlbox");
|
||||||
submit_button.click();
|
toggle.click();
|
||||||
expect(registerview.onProviderChosen).toHaveBeenCalled();
|
|
||||||
await u.waitUntil(() => _converse.connection.connect.calls.count());
|
|
||||||
done();
|
|
||||||
}));
|
|
||||||
|
|
||||||
it("will render a registration form as received from the XMPP provider",
|
const cbview = _converse.api.controlbox.get();
|
||||||
mock.initConverse(
|
await u.waitUntil(() => u.isVisible(cbview.el));
|
||||||
['chatBoxesInitialized'],
|
const registerview = cbview.registerpanel;
|
||||||
{ auto_login: false,
|
spyOn(registerview, 'onProviderChosen').and.callThrough();
|
||||||
discover_connection_methods: false,
|
registerview.delegateEvents(); // We need to rebind all events otherwise our spy won't be called
|
||||||
allow_registration: true },
|
|
||||||
async function (done, _converse) {
|
|
||||||
|
|
||||||
spyOn(Strophe.Connection.prototype, 'connect');
|
// Open the register panel
|
||||||
await u.waitUntil(() => _.get(_converse.chatboxviews.get('controlbox'), 'registerpanel'));
|
cbview.el.querySelector('.toggle-register-login').click();
|
||||||
const cbview = _converse.api.controlbox.get();
|
|
||||||
cbview.el.querySelector('.toggle-register-login').click();
|
|
||||||
|
|
||||||
const registerview = _converse.chatboxviews.get('controlbox').registerpanel;
|
// Check the form layout
|
||||||
spyOn(registerview, 'onProviderChosen').and.callThrough();
|
const form = cbview.el.querySelector('#converse-register');
|
||||||
spyOn(registerview, 'getRegistrationFields').and.callThrough();
|
expect(form.querySelectorAll('input').length).toEqual(2);
|
||||||
spyOn(registerview, 'onRegistrationFields').and.callThrough();
|
expect(form.querySelectorAll('input')[0].getAttribute('name')).toEqual('domain');
|
||||||
spyOn(registerview, 'renderRegistrationForm').and.callThrough();
|
expect(sizzle('input:last', form).pop().getAttribute('type')).toEqual('submit');
|
||||||
registerview.delegateEvents(); // We need to rebind all events otherwise our spy won't be called
|
// Check that the input[type=domain] input is required
|
||||||
|
const submit_button = form.querySelector('input[type=submit]');
|
||||||
|
submit_button.click();
|
||||||
|
expect(registerview.onProviderChosen).not.toHaveBeenCalled();
|
||||||
|
|
||||||
expect(registerview._registering).toBeFalsy();
|
// Check that the form is accepted if input[type=domain] has a value
|
||||||
expect(_converse.api.connection.connected()).toBeFalsy();
|
form.querySelector('input[name=domain]').value = 'conversejs.org';
|
||||||
registerview.el.querySelector('input[name=domain]').value = 'conversejs.org';
|
submit_button.click();
|
||||||
registerview.el.querySelector('input[type=submit]').click();
|
expect(registerview.onProviderChosen).toHaveBeenCalled();
|
||||||
expect(registerview.onProviderChosen).toHaveBeenCalled();
|
await u.waitUntil(() => _converse.connection.connect.calls.count());
|
||||||
expect(registerview._registering).toBeTruthy();
|
done();
|
||||||
await u.waitUntil(() => _converse.connection.connect.calls.count());
|
}));
|
||||||
|
|
||||||
let stanza = new Strophe.Builder("stream:features", {
|
it("will render a registration form as received from the XMPP provider",
|
||||||
'xmlns:stream': "http://etherx.jabber.org/streams",
|
mock.initConverse(
|
||||||
'xmlns': "jabber:client"
|
['chatBoxesInitialized'],
|
||||||
})
|
{ auto_login: false,
|
||||||
.c('register', {xmlns: "http://jabber.org/features/iq-register"}).up()
|
discover_connection_methods: false,
|
||||||
.c('mechanisms', {xmlns: "urn:ietf:params:xml:ns:xmpp-sasl"});
|
allow_registration: true },
|
||||||
_converse.connection._connect_cb(test_utils.createRequest(stanza));
|
async function (done, _converse) {
|
||||||
|
|
||||||
expect(registerview.getRegistrationFields).toHaveBeenCalled();
|
spyOn(Strophe.Connection.prototype, 'connect');
|
||||||
|
await u.waitUntil(() => _.get(_converse.chatboxviews.get('controlbox'), 'registerpanel'));
|
||||||
|
const cbview = _converse.api.controlbox.get();
|
||||||
|
cbview.el.querySelector('.toggle-register-login').click();
|
||||||
|
|
||||||
stanza = $iq({
|
const registerview = _converse.chatboxviews.get('controlbox').registerpanel;
|
||||||
'type': 'result',
|
spyOn(registerview, 'onProviderChosen').and.callThrough();
|
||||||
'id': 'reg1'
|
spyOn(registerview, 'getRegistrationFields').and.callThrough();
|
||||||
}).c('query', {'xmlns': 'jabber:iq:register'})
|
spyOn(registerview, 'onRegistrationFields').and.callThrough();
|
||||||
.c('instructions')
|
spyOn(registerview, 'renderRegistrationForm').and.callThrough();
|
||||||
.t('Please choose a username, password and provide your email address').up()
|
registerview.delegateEvents(); // We need to rebind all events otherwise our spy won't be called
|
||||||
.c('username').up()
|
|
||||||
.c('password').up()
|
|
||||||
.c('email');
|
|
||||||
_converse.connection._dataRecv(test_utils.createRequest(stanza));
|
|
||||||
expect(registerview.onRegistrationFields).toHaveBeenCalled();
|
|
||||||
expect(registerview.renderRegistrationForm).toHaveBeenCalled();
|
|
||||||
expect(registerview.el.querySelectorAll('input').length).toBe(5);
|
|
||||||
expect(registerview.el.querySelectorAll('input[type=submit]').length).toBe(1);
|
|
||||||
expect(registerview.el.querySelectorAll('input[type=button]').length).toBe(1);
|
|
||||||
done();
|
|
||||||
}));
|
|
||||||
|
|
||||||
it("will set form_type to legacy and submit it as legacy",
|
expect(registerview._registering).toBeFalsy();
|
||||||
mock.initConverse(
|
expect(_converse.api.connection.connected()).toBeFalsy();
|
||||||
['chatBoxesInitialized'],
|
registerview.el.querySelector('input[name=domain]').value = 'conversejs.org';
|
||||||
{ auto_login: false,
|
registerview.el.querySelector('input[type=submit]').click();
|
||||||
discover_connection_methods: false,
|
expect(registerview.onProviderChosen).toHaveBeenCalled();
|
||||||
allow_registration: true },
|
expect(registerview._registering).toBeTruthy();
|
||||||
async function (done, _converse) {
|
await u.waitUntil(() => _converse.connection.connect.calls.count());
|
||||||
|
|
||||||
await u.waitUntil(() => _.get(_converse.chatboxviews.get('controlbox'), 'registerpanel'));
|
let stanza = new Strophe.Builder("stream:features", {
|
||||||
const toggle = document.querySelector(".toggle-controlbox");
|
'xmlns:stream': "http://etherx.jabber.org/streams",
|
||||||
if (!u.isVisible(document.querySelector("#controlbox"))) {
|
'xmlns': "jabber:client"
|
||||||
if (!u.isVisible(toggle)) {
|
})
|
||||||
u.removeClass('hidden', toggle);
|
.c('register', {xmlns: "http://jabber.org/features/iq-register"}).up()
|
||||||
}
|
.c('mechanisms', {xmlns: "urn:ietf:params:xml:ns:xmpp-sasl"});
|
||||||
toggle.click();
|
_converse.connection._connect_cb(mock.createRequest(stanza));
|
||||||
|
|
||||||
|
expect(registerview.getRegistrationFields).toHaveBeenCalled();
|
||||||
|
|
||||||
|
stanza = $iq({
|
||||||
|
'type': 'result',
|
||||||
|
'id': 'reg1'
|
||||||
|
}).c('query', {'xmlns': 'jabber:iq:register'})
|
||||||
|
.c('instructions')
|
||||||
|
.t('Please choose a username, password and provide your email address').up()
|
||||||
|
.c('username').up()
|
||||||
|
.c('password').up()
|
||||||
|
.c('email');
|
||||||
|
_converse.connection._dataRecv(mock.createRequest(stanza));
|
||||||
|
expect(registerview.onRegistrationFields).toHaveBeenCalled();
|
||||||
|
expect(registerview.renderRegistrationForm).toHaveBeenCalled();
|
||||||
|
expect(registerview.el.querySelectorAll('input').length).toBe(5);
|
||||||
|
expect(registerview.el.querySelectorAll('input[type=submit]').length).toBe(1);
|
||||||
|
expect(registerview.el.querySelectorAll('input[type=button]').length).toBe(1);
|
||||||
|
done();
|
||||||
|
}));
|
||||||
|
|
||||||
|
it("will set form_type to legacy and submit it as legacy",
|
||||||
|
mock.initConverse(
|
||||||
|
['chatBoxesInitialized'],
|
||||||
|
{ auto_login: false,
|
||||||
|
discover_connection_methods: false,
|
||||||
|
allow_registration: true },
|
||||||
|
async function (done, _converse) {
|
||||||
|
|
||||||
|
await u.waitUntil(() => _.get(_converse.chatboxviews.get('controlbox'), 'registerpanel'));
|
||||||
|
const toggle = document.querySelector(".toggle-controlbox");
|
||||||
|
if (!u.isVisible(document.querySelector("#controlbox"))) {
|
||||||
|
if (!u.isVisible(toggle)) {
|
||||||
|
u.removeClass('hidden', toggle);
|
||||||
}
|
}
|
||||||
const cbview = _converse.api.controlbox.get();
|
toggle.click();
|
||||||
cbview.el.querySelector('.toggle-register-login').click();
|
}
|
||||||
|
const cbview = _converse.api.controlbox.get();
|
||||||
|
cbview.el.querySelector('.toggle-register-login').click();
|
||||||
|
|
||||||
const registerview = cbview.registerpanel;
|
const registerview = cbview.registerpanel;
|
||||||
spyOn(registerview, 'onProviderChosen').and.callThrough();
|
spyOn(registerview, 'onProviderChosen').and.callThrough();
|
||||||
spyOn(registerview, 'getRegistrationFields').and.callThrough();
|
spyOn(registerview, 'getRegistrationFields').and.callThrough();
|
||||||
spyOn(registerview, 'onRegistrationFields').and.callThrough();
|
spyOn(registerview, 'onRegistrationFields').and.callThrough();
|
||||||
spyOn(registerview, 'renderRegistrationForm').and.callThrough();
|
spyOn(registerview, 'renderRegistrationForm').and.callThrough();
|
||||||
registerview.delegateEvents(); // We need to rebind all events otherwise our spy won't be called
|
registerview.delegateEvents(); // We need to rebind all events otherwise our spy won't be called
|
||||||
|
|
||||||
registerview.el.querySelector('input[name=domain]').value = 'conversejs.org';
|
registerview.el.querySelector('input[name=domain]').value = 'conversejs.org';
|
||||||
registerview.el.querySelector('input[type=submit]').click();
|
registerview.el.querySelector('input[type=submit]').click();
|
||||||
|
|
||||||
let stanza = new Strophe.Builder("stream:features", {
|
let stanza = new Strophe.Builder("stream:features", {
|
||||||
'xmlns:stream': "http://etherx.jabber.org/streams",
|
'xmlns:stream': "http://etherx.jabber.org/streams",
|
||||||
'xmlns': "jabber:client"
|
'xmlns': "jabber:client"
|
||||||
})
|
})
|
||||||
.c('register', {xmlns: "http://jabber.org/features/iq-register"}).up()
|
.c('register', {xmlns: "http://jabber.org/features/iq-register"}).up()
|
||||||
.c('mechanisms', {xmlns: "urn:ietf:params:xml:ns:xmpp-sasl"});
|
.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({
|
stanza = $iq({
|
||||||
'type': 'result',
|
'type': 'result',
|
||||||
'id': 'reg1'
|
'id': 'reg1'
|
||||||
}).c('query', {'xmlns': 'jabber:iq:register'})
|
}).c('query', {'xmlns': 'jabber:iq:register'})
|
||||||
.c('instructions')
|
.c('instructions')
|
||||||
.t('Please choose a username, password and provide your email address').up()
|
.t('Please choose a username, password and provide your email address').up()
|
||||||
.c('username').up()
|
.c('username').up()
|
||||||
.c('password').up()
|
.c('password').up()
|
||||||
.c('email');
|
.c('email');
|
||||||
_converse.connection._dataRecv(test_utils.createRequest(stanza));
|
_converse.connection._dataRecv(mock.createRequest(stanza));
|
||||||
expect(registerview.form_type).toBe('legacy');
|
expect(registerview.form_type).toBe('legacy');
|
||||||
|
|
||||||
registerview.el.querySelector('input[name=username]').value = 'testusername';
|
registerview.el.querySelector('input[name=username]').value = 'testusername';
|
||||||
registerview.el.querySelector('input[name=password]').value = 'testpassword';
|
registerview.el.querySelector('input[name=password]').value = 'testpassword';
|
||||||
registerview.el.querySelector('input[name=email]').value = 'test@email.local';
|
registerview.el.querySelector('input[name=email]').value = 'test@email.local';
|
||||||
|
|
||||||
spyOn(_converse.connection, 'send');
|
spyOn(_converse.connection, 'send');
|
||||||
registerview.el.querySelector('input[type=submit]').click();
|
registerview.el.querySelector('input[type=submit]').click();
|
||||||
|
|
||||||
expect(_converse.connection.send).toHaveBeenCalled();
|
expect(_converse.connection.send).toHaveBeenCalled();
|
||||||
stanza = _converse.connection.send.calls.argsFor(0)[0].tree();
|
stanza = _converse.connection.send.calls.argsFor(0)[0].tree();
|
||||||
expect(stanza.querySelector('query').childNodes.length).toBe(3);
|
expect(stanza.querySelector('query').childNodes.length).toBe(3);
|
||||||
expect(stanza.querySelector('query').firstElementChild.tagName).toBe('username');
|
expect(stanza.querySelector('query').firstElementChild.tagName).toBe('username');
|
||||||
|
|
||||||
delete _converse.connection;
|
delete _converse.connection;
|
||||||
done();
|
done();
|
||||||
}));
|
}));
|
||||||
|
|
||||||
it("will set form_type to xform and submit it as xform",
|
it("will set form_type to xform and submit it as xform",
|
||||||
mock.initConverse(
|
mock.initConverse(
|
||||||
['chatBoxesInitialized'],
|
['chatBoxesInitialized'],
|
||||||
{ auto_login: false,
|
{ auto_login: false,
|
||||||
discover_connection_methods: false,
|
discover_connection_methods: false,
|
||||||
allow_registration: true },
|
allow_registration: true },
|
||||||
async function (done, _converse) {
|
async function (done, _converse) {
|
||||||
|
|
||||||
await u.waitUntil(() => _.get(_converse.chatboxviews.get('controlbox'), 'registerpanel'));
|
await u.waitUntil(() => _.get(_converse.chatboxviews.get('controlbox'), 'registerpanel'));
|
||||||
const toggle = document.querySelector(".toggle-controlbox");
|
const toggle = document.querySelector(".toggle-controlbox");
|
||||||
if (!u.isVisible(document.querySelector("#controlbox"))) {
|
if (!u.isVisible(document.querySelector("#controlbox"))) {
|
||||||
if (!u.isVisible(toggle)) {
|
if (!u.isVisible(toggle)) {
|
||||||
u.removeClass('hidden', toggle);
|
u.removeClass('hidden', toggle);
|
||||||
}
|
|
||||||
toggle.click();
|
|
||||||
}
|
}
|
||||||
const cbview = _converse.api.controlbox.get();
|
toggle.click();
|
||||||
cbview.el.querySelector('.toggle-register-login').click();
|
}
|
||||||
const registerview = _converse.chatboxviews.get('controlbox').registerpanel;
|
const cbview = _converse.api.controlbox.get();
|
||||||
spyOn(registerview, 'onProviderChosen').and.callThrough();
|
cbview.el.querySelector('.toggle-register-login').click();
|
||||||
spyOn(registerview, 'getRegistrationFields').and.callThrough();
|
const registerview = _converse.chatboxviews.get('controlbox').registerpanel;
|
||||||
spyOn(registerview, 'onRegistrationFields').and.callThrough();
|
spyOn(registerview, 'onProviderChosen').and.callThrough();
|
||||||
spyOn(registerview, 'renderRegistrationForm').and.callThrough();
|
spyOn(registerview, 'getRegistrationFields').and.callThrough();
|
||||||
registerview.delegateEvents(); // We need to rebind all events otherwise our spy won't be called
|
spyOn(registerview, 'onRegistrationFields').and.callThrough();
|
||||||
|
spyOn(registerview, 'renderRegistrationForm').and.callThrough();
|
||||||
|
registerview.delegateEvents(); // We need to rebind all events otherwise our spy won't be called
|
||||||
|
|
||||||
registerview.el.querySelector('input[name=domain]').value = 'conversejs.org';
|
registerview.el.querySelector('input[name=domain]').value = 'conversejs.org';
|
||||||
registerview.el.querySelector('input[type=submit]').click();
|
registerview.el.querySelector('input[type=submit]').click();
|
||||||
|
|
||||||
let stanza = new Strophe.Builder("stream:features", {
|
let stanza = new Strophe.Builder("stream:features", {
|
||||||
'xmlns:stream': "http://etherx.jabber.org/streams",
|
'xmlns:stream': "http://etherx.jabber.org/streams",
|
||||||
'xmlns': "jabber:client"
|
'xmlns': "jabber:client"
|
||||||
})
|
})
|
||||||
.c('register', {xmlns: "http://jabber.org/features/iq-register"}).up()
|
.c('register', {xmlns: "http://jabber.org/features/iq-register"}).up()
|
||||||
.c('mechanisms', {xmlns: "urn:ietf:params:xml:ns:xmpp-sasl"});
|
.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({
|
stanza = $iq({
|
||||||
'type': 'result',
|
'type': 'result',
|
||||||
'id': 'reg1'
|
'id': 'reg1'
|
||||||
}).c('query', {'xmlns': 'jabber:iq:register'})
|
}).c('query', {'xmlns': 'jabber:iq:register'})
|
||||||
.c('instructions')
|
.c('instructions')
|
||||||
.t('Using xform data').up()
|
.t('Using xform data').up()
|
||||||
.c('x', { 'xmlns': 'jabber:x:data', 'type': 'form' })
|
.c('x', { 'xmlns': 'jabber:x:data', 'type': 'form' })
|
||||||
.c('instructions').t('xform instructions').up()
|
.c('instructions').t('xform instructions').up()
|
||||||
.c('field', {'type': 'text-single', 'var': 'username'}).c('required').up().up()
|
.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-private', 'var': 'password'}).c('required').up().up()
|
||||||
.c('field', {'type': 'text-single', 'var': 'email'}).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');
|
expect(registerview.form_type).toBe('xform');
|
||||||
|
|
||||||
registerview.el.querySelector('input[name=username]').value = 'testusername';
|
registerview.el.querySelector('input[name=username]').value = 'testusername';
|
||||||
registerview.el.querySelector('input[name=password]').value = 'testpassword';
|
registerview.el.querySelector('input[name=password]').value = 'testpassword';
|
||||||
registerview.el.querySelector('input[name=email]').value = 'test@email.local';
|
registerview.el.querySelector('input[name=email]').value = 'test@email.local';
|
||||||
|
|
||||||
spyOn(_converse.connection, 'send');
|
spyOn(_converse.connection, 'send');
|
||||||
|
|
||||||
registerview.el.querySelector('input[type=submit]').click();
|
registerview.el.querySelector('input[type=submit]').click();
|
||||||
|
|
||||||
expect(_converse.connection.send).toHaveBeenCalled();
|
expect(_converse.connection.send).toHaveBeenCalled();
|
||||||
stanza = _converse.connection.send.calls.argsFor(0)[0].tree();
|
stanza = _converse.connection.send.calls.argsFor(0)[0].tree();
|
||||||
expect(Strophe.serialize(stanza).toLocaleString().trim().replace(/(\n|\s{2,})/g, '')).toEqual(
|
expect(Strophe.serialize(stanza).toLocaleString().trim().replace(/(\n|\s{2,})/g, '')).toEqual(
|
||||||
'<iq id="'+stanza.getAttribute('id')+'" type="set" xmlns="jabber:client">'+
|
'<iq id="'+stanza.getAttribute('id')+'" type="set" xmlns="jabber:client">'+
|
||||||
'<query xmlns="jabber:iq:register">'+
|
'<query xmlns="jabber:iq:register">'+
|
||||||
'<x type="submit" xmlns="jabber:x:data">'+
|
'<x type="submit" xmlns="jabber:x:data">'+
|
||||||
'<field var="username">'+
|
'<field var="username">'+
|
||||||
'<value>testusername</value>'+
|
'<value>testusername</value>'+
|
||||||
'</field>'+
|
'</field>'+
|
||||||
'<field var="password">'+
|
'<field var="password">'+
|
||||||
'<value>testpassword</value>'+
|
'<value>testpassword</value>'+
|
||||||
'</field>'+
|
'</field>'+
|
||||||
'<field var="email">'+
|
'<field var="email">'+
|
||||||
'<value>test@email.local</value>'+
|
'<value>test@email.local</value>'+
|
||||||
'</field>'+
|
'</field>'+
|
||||||
'</x>'+
|
'</x>'+
|
||||||
'</query>'+
|
'</query>'+
|
||||||
'</iq>'
|
'</iq>'
|
||||||
);
|
);
|
||||||
|
|
||||||
delete _converse.connection;
|
delete _converse.connection;
|
||||||
done();
|
done();
|
||||||
}));
|
}));
|
||||||
|
|
||||||
it("renders the account registration form",
|
it("renders the account registration form",
|
||||||
mock.initConverse(
|
mock.initConverse(
|
||||||
['chatBoxesInitialized'],
|
['chatBoxesInitialized'],
|
||||||
{ auto_login: false,
|
{ auto_login: false,
|
||||||
view_mode: 'fullscreen',
|
view_mode: 'fullscreen',
|
||||||
discover_connection_methods: false,
|
discover_connection_methods: false,
|
||||||
allow_registration: true },
|
allow_registration: true },
|
||||||
async function (done, _converse) {
|
async function (done, _converse) {
|
||||||
|
|
||||||
await u.waitUntil(() => _.get(_converse.chatboxviews.get('controlbox'), 'registerpanel'));
|
await u.waitUntil(() => _.get(_converse.chatboxviews.get('controlbox'), 'registerpanel'));
|
||||||
const toggle = document.querySelector(".toggle-controlbox");
|
const toggle = document.querySelector(".toggle-controlbox");
|
||||||
if (!u.isVisible(document.querySelector("#controlbox"))) {
|
if (!u.isVisible(document.querySelector("#controlbox"))) {
|
||||||
if (!u.isVisible(toggle)) {
|
if (!u.isVisible(toggle)) {
|
||||||
u.removeClass('hidden', toggle);
|
u.removeClass('hidden', toggle);
|
||||||
}
|
|
||||||
toggle.click();
|
|
||||||
}
|
}
|
||||||
const cbview = _converse.chatboxviews.get('controlbox');
|
toggle.click();
|
||||||
cbview.el.querySelector('.toggle-register-login').click();
|
}
|
||||||
const registerview = _converse.chatboxviews.get('controlbox').registerpanel;
|
const cbview = _converse.chatboxviews.get('controlbox');
|
||||||
spyOn(registerview, 'onProviderChosen').and.callThrough();
|
cbview.el.querySelector('.toggle-register-login').click();
|
||||||
spyOn(registerview, 'getRegistrationFields').and.callThrough();
|
const registerview = _converse.chatboxviews.get('controlbox').registerpanel;
|
||||||
spyOn(registerview, 'onRegistrationFields').and.callThrough();
|
spyOn(registerview, 'onProviderChosen').and.callThrough();
|
||||||
spyOn(registerview, 'renderRegistrationForm').and.callThrough();
|
spyOn(registerview, 'getRegistrationFields').and.callThrough();
|
||||||
registerview.delegateEvents(); // We need to rebind all events otherwise our spy won't be called
|
spyOn(registerview, 'onRegistrationFields').and.callThrough();
|
||||||
|
spyOn(registerview, 'renderRegistrationForm').and.callThrough();
|
||||||
|
registerview.delegateEvents(); // We need to rebind all events otherwise our spy won't be called
|
||||||
|
|
||||||
registerview.el.querySelector('input[name=domain]').value = 'conversejs.org';
|
registerview.el.querySelector('input[name=domain]').value = 'conversejs.org';
|
||||||
registerview.el.querySelector('input[type=submit]').click();
|
registerview.el.querySelector('input[type=submit]').click();
|
||||||
|
|
||||||
let stanza = new Strophe.Builder("stream:features", {
|
let stanza = new Strophe.Builder("stream:features", {
|
||||||
'xmlns:stream': "http://etherx.jabber.org/streams",
|
'xmlns:stream': "http://etherx.jabber.org/streams",
|
||||||
'xmlns': "jabber:client"
|
'xmlns': "jabber:client"
|
||||||
})
|
})
|
||||||
.c('register', {xmlns: "http://jabber.org/features/iq-register"}).up()
|
.c('register', {xmlns: "http://jabber.org/features/iq-register"}).up()
|
||||||
.c('mechanisms', {xmlns: "urn:ietf:params:xml:ns:xmpp-sasl"});
|
.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(`
|
stanza = u.toStanza(`
|
||||||
<iq xmlns="jabber:client" type="result" from="conversations.im" id="ad1e0d50-5adb-4397-a997-5feab56fe418:sendIQ" xml:lang="en">
|
<iq xmlns="jabber:client" type="result" from="conversations.im" id="ad1e0d50-5adb-4397-a997-5feab56fe418:sendIQ" xml:lang="en">
|
||||||
<query xmlns="jabber:iq:register">
|
<query xmlns="jabber:iq:register">
|
||||||
<x xmlns="jabber:x:data" type="form">
|
<x xmlns="jabber:x:data" type="form">
|
||||||
<instructions>Choose a username and password to register with this server</instructions>
|
<instructions>Choose a username and password to register with this server</instructions>
|
||||||
<field var="FORM_TYPE" type="hidden"><value>urn:xmpp:captcha</value></field>
|
<field var="FORM_TYPE" type="hidden"><value>urn:xmpp:captcha</value></field>
|
||||||
<field var="username" type="text-single" label="User"><required/></field>
|
<field var="username" type="text-single" label="User"><required/></field>
|
||||||
<field var="password" type="text-private" label="Password"><required/></field>
|
<field var="password" type="text-private" label="Password"><required/></field>
|
||||||
<field var="from" type="hidden"><value>conversations.im</value></field>
|
<field var="from" type="hidden"><value>conversations.im</value></field>
|
||||||
<field var="challenge" type="hidden"><value>15376320046808160053</value></field>
|
<field var="challenge" type="hidden"><value>15376320046808160053</value></field>
|
||||||
<field var="sid" type="hidden"><value>ad1e0d50-5adb-4397-a997-5feab56fe418:sendIQ</value></field>
|
<field var="sid" type="hidden"><value>ad1e0d50-5adb-4397-a997-5feab56fe418:sendIQ</value></field>
|
||||||
<field var="ocr" type="text-single" label="Enter the text you see">
|
<field var="ocr" type="text-single" label="Enter the text you see">
|
||||||
<media xmlns="urn:xmpp:media-element">
|
<media xmlns="urn:xmpp:media-element">
|
||||||
<uri type="image/png">cid:sha1+2df8c1b366f1e90ce60354f97d1fe75237290b8a@bob.xmpp.org</uri>
|
<uri type="image/png">cid:sha1+2df8c1b366f1e90ce60354f97d1fe75237290b8a@bob.xmpp.org</uri>
|
||||||
</media>
|
</media>
|
||||||
<required/>
|
<required/>
|
||||||
</field>
|
</field>
|
||||||
</x>
|
</x>
|
||||||
<data xmlns="urn:xmpp:bob" cid="sha1+2df8c1b366f1e90ce60354f97d1fe75237290b8a@bob.xmpp.org"
|
<data xmlns="urn:xmpp:bob" cid="sha1+2df8c1b366f1e90ce60354f97d1fe75237290b8a@bob.xmpp.org"
|
||||||
type="image/png"
|
type="image/png"
|
||||||
max-age="0">iVBORw0KGgoAAAANSUhEUgAAALQAAAA8BAMAAAA9AI20AAAAMFBMVEX///8AAADf39+fn59fX19/f3+/v78fHx8/Pz9PT08bGxsvLy9jY2NTU1MXFxcnJyc84bkWAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAERUlEQVRYhe1WTXMaRxDdDxY4JWpYvDinpVyxdATLin0MiRLlCHEi+7hYUcVHTSI7urhK6yr5//gn5N/4Z7inX89+CQkTcFUO6gOwS8/r7tdvesbzvoT5ROR5JJ9bB97xAK22XWAY1WznlnUr7QaAzSOsWufXQ6wH/FmO60b4D936LJr8TWRwW4SNgOsodZr8m4vZUoRt2xZ3xHXgna1FCE5+f5aWwPU//bXgg8eHjyqPp4aXJeOlwLUIt0O39zOvPWW3WfHmCCkli816FxlK0rnFGKZ484dN+eIXsw1R+G+JfjwgOpMnm+r5SxA63gS2Q8MchO1RLN8jSn4W4F5OPed2evhTthKLG3bsfjLL874XGBpWHLrU0953i/ev7JsfViHbhsWSQTunJDOppeAe0hVGokJUHBOphmjrbBlgabviJKXbIP0B//gKSBHZh2rvJnQp3wsapMFz+VsTPNhPr0Hn9N57YOjywaxFSU6S79fUF39KBDgnt6yjZOeSffk+4IXDZovbQl9E96m34EzQKMepQcbzijAGiBmDsO+LaqzqG3m3kEf+DQ2mY+vdk5c2n2Iaj5QGi6n59FHDmcuP4t8MGlRaF39P6ENyIaB2EXdpjLnQq9IgdVxfax3ilBc10u4gowX9K6BaKiZNmCC7CF/WpkJvWxN00OjuoqGYLqAnpILLE68Ymrt9M0S9hcznUJ8RykdlLalUfFaDjvA8pT2kxmsl5fuMaM6mSWUpUhDoudSucdhiZFDwphEHwsMwhEpH0jsm+/UBK2wCzFIiitalN7YjWkyIBgTNPgpDXX4rjk4UH+yPPgfK4HNZQCP/KZ0fGnrnKl8+pXl3X7FwZuwNUdwDGO+BjPUn6XaKtbkm+MJ6vtaXSnIz6wBT/m+VvZNIhz7ayabQLSeRQDmYkjt0KlmHDa555v9DzFxx+CCvCG4K3dbx6mTYtfPs1Dgdh0i3W+cl4lnnhblMKKBBA23X1Ezc3E5ZoPS5KHjPiU1rKTviYe1fTsa6e3UwXGWI4ykB8uiGqkmA6Cbf3K4JTH3LOBlbX+yPWll57LKVeH8CTEvyVPV2TXL8kPnPqtA51CaFYxOH2rJoZunSnvsSj48WiaDccl6KEgiMSarITsa+rWWBnqFloYlT1qWW2GKw9nPSbEvoVHFst967XgNQjxdA66Q6VFEUh488xfaSo7cHB52XYzA4eRlVteeT8ostWfuPea0oF6MwzlwgZE9gQI+uUV0gzK+WlpUrNI8juhhX/OyNwZnRrsDfxOqS1aDR+gC6NUPvJpvQeVZ9eiNr9aDUuddY3bLnA4tH4r/49UboznH1ia8PV/uP3WUB3dxtzj1uxfDZgbEbZx17Itwrf0Jyc8N4en+5dhivtKeYjGJ8yXgUzKvSU/uWJZmsuAYtseDku+K3zMHi4lC1h0suPmtZaEp2tm3hEV2lXwb6zu7szv6f9glF5rPGT5xR7AAAAABJRU5ErkJggg==</data>
|
max-age="0">iVBORw0KGgoAAAANSUhEUgAAALQAAAA8BAMAAAA9AI20AAAAMFBMVEX///8AAADf39+fn59fX19/f3+/v78fHx8/Pz9PT08bGxsvLy9jY2NTU1MXFxcnJyc84bkWAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAERUlEQVRYhe1WTXMaRxDdDxY4JWpYvDinpVyxdATLin0MiRLlCHEi+7hYUcVHTSI7urhK6yr5//gn5N/4Z7inX89+CQkTcFUO6gOwS8/r7tdvesbzvoT5ROR5JJ9bB97xAK22XWAY1WznlnUr7QaAzSOsWufXQ6wH/FmO60b4D936LJr8TWRwW4SNgOsodZr8m4vZUoRt2xZ3xHXgna1FCE5+f5aWwPU//bXgg8eHjyqPp4aXJeOlwLUIt0O39zOvPWW3WfHmCCkli816FxlK0rnFGKZ484dN+eIXsw1R+G+JfjwgOpMnm+r5SxA63gS2Q8MchO1RLN8jSn4W4F5OPed2evhTthKLG3bsfjLL874XGBpWHLrU0953i/ev7JsfViHbhsWSQTunJDOppeAe0hVGokJUHBOphmjrbBlgabviJKXbIP0B//gKSBHZh2rvJnQp3wsapMFz+VsTPNhPr0Hn9N57YOjywaxFSU6S79fUF39KBDgnt6yjZOeSffk+4IXDZovbQl9E96m34EzQKMepQcbzijAGiBmDsO+LaqzqG3m3kEf+DQ2mY+vdk5c2n2Iaj5QGi6n59FHDmcuP4t8MGlRaF39P6ENyIaB2EXdpjLnQq9IgdVxfax3ilBc10u4gowX9K6BaKiZNmCC7CF/WpkJvWxN00OjuoqGYLqAnpILLE68Ymrt9M0S9hcznUJ8RykdlLalUfFaDjvA8pT2kxmsl5fuMaM6mSWUpUhDoudSucdhiZFDwphEHwsMwhEpH0jsm+/UBK2wCzFIiitalN7YjWkyIBgTNPgpDXX4rjk4UH+yPPgfK4HNZQCP/KZ0fGnrnKl8+pXl3X7FwZuwNUdwDGO+BjPUn6XaKtbkm+MJ6vtaXSnIz6wBT/m+VvZNIhz7ayabQLSeRQDmYkjt0KlmHDa555v9DzFxx+CCvCG4K3dbx6mTYtfPs1Dgdh0i3W+cl4lnnhblMKKBBA23X1Ezc3E5ZoPS5KHjPiU1rKTviYe1fTsa6e3UwXGWI4ykB8uiGqkmA6Cbf3K4JTH3LOBlbX+yPWll57LKVeH8CTEvyVPV2TXL8kPnPqtA51CaFYxOH2rJoZunSnvsSj48WiaDccl6KEgiMSarITsa+rWWBnqFloYlT1qWW2GKw9nPSbEvoVHFst967XgNQjxdA66Q6VFEUh488xfaSo7cHB52XYzA4eRlVteeT8ostWfuPea0oF6MwzlwgZE9gQI+uUV0gzK+WlpUrNI8juhhX/OyNwZnRrsDfxOqS1aDR+gC6NUPvJpvQeVZ9eiNr9aDUuddY3bLnA4tH4r/49UboznH1ia8PV/uP3WUB3dxtzj1uxfDZgbEbZx17Itwrf0Jyc8N4en+5dhivtKeYjGJ8yXgUzKvSU/uWJZmsuAYtseDku+K3zMHi4lC1h0suPmtZaEp2tm3hEV2lXwb6zu7szv6f9glF5rPGT5xR7AAAAABJRU5ErkJggg==</data>
|
||||||
<instructions>You need a client that supports x:data and CAPTCHA to register</instructions>
|
<instructions>You need a client that supports x:data and CAPTCHA to register</instructions>
|
||||||
</query>
|
</query>
|
||||||
</iq>`);
|
</iq>`);
|
||||||
_converse.connection._dataRecv(test_utils.createRequest(stanza));
|
_converse.connection._dataRecv(mock.createRequest(stanza));
|
||||||
expect(registerview.form_type).toBe('xform');
|
expect(registerview.form_type).toBe('xform');
|
||||||
expect(registerview.el.querySelectorAll('#converse-register input[required="required"]').length).toBe(3);
|
expect(registerview.el.querySelectorAll('#converse-register input[required="required"]').length).toBe(3);
|
||||||
// Hide the controlbox so that we can see whether the test
|
// Hide the controlbox so that we can see whether the test
|
||||||
// passed or failed
|
// passed or failed
|
||||||
u.addClass('hidden', _converse.chatboxviews.get('controlbox').el);
|
u.addClass('hidden', _converse.chatboxviews.get('controlbox').el);
|
||||||
delete _converse.connection;
|
delete _converse.connection;
|
||||||
done();
|
done();
|
||||||
}));
|
}));
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
2106
spec/retractions.js
2106
spec/retractions.js
File diff suppressed because it is too large
Load Diff
@ -1,121 +1,119 @@
|
|||||||
window.addEventListener('converse-loaded', () => {
|
/*global mock */
|
||||||
const mock = window.mock;
|
|
||||||
const test_utils = window.test_utils;
|
|
||||||
const _ = converse.env._,
|
|
||||||
$iq = converse.env.$iq,
|
|
||||||
Strophe = converse.env.Strophe,
|
|
||||||
sizzle = converse.env.sizzle,
|
|
||||||
u = converse.env.utils;
|
|
||||||
|
|
||||||
describe("Chatrooms", function () {
|
const _ = converse.env._,
|
||||||
|
$iq = converse.env.$iq,
|
||||||
|
Strophe = converse.env.Strophe,
|
||||||
|
sizzle = converse.env.sizzle,
|
||||||
|
u = converse.env.utils;
|
||||||
|
|
||||||
|
describe("Chatrooms", function () {
|
||||||
|
|
||||||
|
|
||||||
describe("The /register commmand", function () {
|
describe("The /register commmand", function () {
|
||||||
|
|
||||||
it("allows you to register your nickname in a room",
|
it("allows you to register your nickname in a room",
|
||||||
mock.initConverse(
|
mock.initConverse(
|
||||||
['rosterGroupsFetched', 'chatBoxesFetched'], {'auto_register_muc_nickname': true},
|
['rosterGroupsFetched', 'chatBoxesFetched'], {'auto_register_muc_nickname': true},
|
||||||
async function (done, _converse) {
|
async function (done, _converse) {
|
||||||
|
|
||||||
const muc_jid = 'coven@chat.shakespeare.lit';
|
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 view = _converse.chatboxviews.get(muc_jid);
|
||||||
const textarea = view.el.querySelector('.chat-textarea')
|
const textarea = view.el.querySelector('.chat-textarea')
|
||||||
textarea.value = '/register';
|
textarea.value = '/register';
|
||||||
view.onKeyDown({
|
view.onKeyDown({
|
||||||
target: textarea,
|
target: textarea,
|
||||||
preventDefault: function preventDefault () {},
|
preventDefault: function preventDefault () {},
|
||||||
keyCode: 13
|
keyCode: 13
|
||||||
});
|
});
|
||||||
let stanza = await u.waitUntil(() => _.filter(
|
let stanza = await u.waitUntil(() => _.filter(
|
||||||
_converse.connection.IQ_stanzas,
|
_converse.connection.IQ_stanzas,
|
||||||
iq => sizzle(`iq[to="${muc_jid}"][type="get"] query[xmlns="jabber:iq:register"]`, iq).length
|
iq => sizzle(`iq[to="${muc_jid}"][type="get"] query[xmlns="jabber:iq:register"]`, iq).length
|
||||||
).pop());
|
).pop());
|
||||||
expect(Strophe.serialize(stanza))
|
expect(Strophe.serialize(stanza))
|
||||||
.toBe(`<iq from="romeo@montague.lit/orchard" id="${stanza.getAttribute('id')}" to="coven@chat.shakespeare.lit" `+
|
|
||||||
`type="get" xmlns="jabber:client">`+
|
|
||||||
`<query xmlns="jabber:iq:register"/></iq>`);
|
|
||||||
const result = $iq({
|
|
||||||
'from': view.model.get('jid'),
|
|
||||||
'id': stanza.getAttribute('id'),
|
|
||||||
'to': _converse.bare_jid,
|
|
||||||
'type': 'result',
|
|
||||||
}).c('query', {'type': 'jabber:iq:register'})
|
|
||||||
.c('x', {'xmlns': 'jabber:x:data', 'type': 'form'})
|
|
||||||
.c('field', {
|
|
||||||
'label': 'Desired Nickname',
|
|
||||||
'type': 'text-single',
|
|
||||||
'var': 'muc#register_roomnick'
|
|
||||||
}).c('required');
|
|
||||||
_converse.connection._dataRecv(test_utils.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
|
|
||||||
).pop());
|
|
||||||
|
|
||||||
expect(Strophe.serialize(stanza)).toBe(
|
|
||||||
`<iq from="romeo@montague.lit/orchard" id="${stanza.getAttribute('id')}" to="coven@chat.shakespeare.lit" type="set" xmlns="jabber:client">`+
|
|
||||||
`<query xmlns="jabber:iq:register">`+
|
|
||||||
`<x type="submit" xmlns="jabber:x:data">`+
|
|
||||||
`<field var="FORM_TYPE"><value>http://jabber.org/protocol/muc#register</value></field>`+
|
|
||||||
`<field var="muc#register_roomnick"><value>romeo</value></field>`+
|
|
||||||
`</x>`+
|
|
||||||
`</query>`+
|
|
||||||
`</iq>`);
|
|
||||||
done();
|
|
||||||
}));
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("The auto_register_muc_nickname option", function () {
|
|
||||||
|
|
||||||
it("allows you to automatically register your nickname when joining a room",
|
|
||||||
mock.initConverse(
|
|
||||||
['rosterGroupsFetched', 'chatBoxesFetched'], {'auto_register_muc_nickname': true},
|
|
||||||
async function (done, _converse) {
|
|
||||||
|
|
||||||
const muc_jid = 'coven@chat.shakespeare.lit';
|
|
||||||
await test_utils.openAndEnterChatRoom(_converse, muc_jid, 'romeo');
|
|
||||||
const view = _converse.chatboxviews.get(muc_jid);
|
|
||||||
|
|
||||||
let stanza = await u.waitUntil(() => _.filter(
|
|
||||||
_converse.connection.IQ_stanzas,
|
|
||||||
iq => sizzle(`iq[to="coven@chat.shakespeare.lit"][type="get"] query[xmlns="jabber:iq:register"]`, iq).length
|
|
||||||
).pop());
|
|
||||||
|
|
||||||
expect(Strophe.serialize(stanza))
|
|
||||||
.toBe(`<iq from="romeo@montague.lit/orchard" id="${stanza.getAttribute('id')}" to="coven@chat.shakespeare.lit" `+
|
.toBe(`<iq from="romeo@montague.lit/orchard" id="${stanza.getAttribute('id')}" to="coven@chat.shakespeare.lit" `+
|
||||||
`type="get" xmlns="jabber:client">`+
|
`type="get" xmlns="jabber:client">`+
|
||||||
`<query xmlns="jabber:iq:register"/></iq>`);
|
`<query xmlns="jabber:iq:register"/></iq>`);
|
||||||
const result = $iq({
|
const result = $iq({
|
||||||
'from': view.model.get('jid'),
|
'from': view.model.get('jid'),
|
||||||
'id': stanza.getAttribute('id'),
|
'id': stanza.getAttribute('id'),
|
||||||
'to': _converse.bare_jid,
|
'to': _converse.bare_jid,
|
||||||
'type': 'result',
|
'type': 'result',
|
||||||
}).c('query', {'type': 'jabber:iq:register'})
|
}).c('query', {'type': 'jabber:iq:register'})
|
||||||
.c('x', {'xmlns': 'jabber:x:data', 'type': 'form'})
|
.c('x', {'xmlns': 'jabber:x:data', 'type': 'form'})
|
||||||
.c('field', {
|
.c('field', {
|
||||||
'label': 'Desired Nickname',
|
'label': 'Desired Nickname',
|
||||||
'type': 'text-single',
|
'type': 'text-single',
|
||||||
'var': 'muc#register_roomnick'
|
'var': 'muc#register_roomnick'
|
||||||
}).c('required');
|
}).c('required');
|
||||||
_converse.connection._dataRecv(test_utils.createRequest(result));
|
_converse.connection._dataRecv(mock.createRequest(result));
|
||||||
stanza = await u.waitUntil(() => _.filter(
|
stanza = await u.waitUntil(() => _.filter(
|
||||||
_converse.connection.IQ_stanzas,
|
_converse.connection.IQ_stanzas,
|
||||||
iq => sizzle(`iq[to="coven@chat.shakespeare.lit"][type="set"] query[xmlns="jabber:iq:register"]`, iq).length
|
iq => sizzle(`iq[to="${muc_jid}"][type="set"] query[xmlns="jabber:iq:register"]`, iq).length
|
||||||
).pop());
|
).pop());
|
||||||
|
|
||||||
expect(Strophe.serialize(stanza)).toBe(
|
expect(Strophe.serialize(stanza)).toBe(
|
||||||
`<iq from="romeo@montague.lit/orchard" id="${stanza.getAttribute('id')}" to="coven@chat.shakespeare.lit" type="set" xmlns="jabber:client">`+
|
`<iq from="romeo@montague.lit/orchard" id="${stanza.getAttribute('id')}" to="coven@chat.shakespeare.lit" type="set" xmlns="jabber:client">`+
|
||||||
`<query xmlns="jabber:iq:register">`+
|
`<query xmlns="jabber:iq:register">`+
|
||||||
`<x type="submit" xmlns="jabber:x:data">`+
|
`<x type="submit" xmlns="jabber:x:data">`+
|
||||||
`<field var="FORM_TYPE"><value>http://jabber.org/protocol/muc#register</value></field>`+
|
`<field var="FORM_TYPE"><value>http://jabber.org/protocol/muc#register</value></field>`+
|
||||||
`<field var="muc#register_roomnick"><value>romeo</value></field>`+
|
`<field var="muc#register_roomnick"><value>romeo</value></field>`+
|
||||||
`</x>`+
|
`</x>`+
|
||||||
`</query>`+
|
`</query>`+
|
||||||
`</iq>`);
|
`</iq>`);
|
||||||
done();
|
done();
|
||||||
}));
|
}));
|
||||||
});
|
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("The auto_register_muc_nickname option", function () {
|
||||||
|
|
||||||
|
it("allows you to automatically register your nickname when joining a room",
|
||||||
|
mock.initConverse(
|
||||||
|
['rosterGroupsFetched', 'chatBoxesFetched'], {'auto_register_muc_nickname': true},
|
||||||
|
async function (done, _converse) {
|
||||||
|
|
||||||
|
const muc_jid = 'coven@chat.shakespeare.lit';
|
||||||
|
await mock.openAndEnterChatRoom(_converse, muc_jid, 'romeo');
|
||||||
|
const view = _converse.chatboxviews.get(muc_jid);
|
||||||
|
|
||||||
|
let stanza = await u.waitUntil(() => _.filter(
|
||||||
|
_converse.connection.IQ_stanzas,
|
||||||
|
iq => sizzle(`iq[to="coven@chat.shakespeare.lit"][type="get"] query[xmlns="jabber:iq:register"]`, iq).length
|
||||||
|
).pop());
|
||||||
|
|
||||||
|
expect(Strophe.serialize(stanza))
|
||||||
|
.toBe(`<iq from="romeo@montague.lit/orchard" id="${stanza.getAttribute('id')}" to="coven@chat.shakespeare.lit" `+
|
||||||
|
`type="get" xmlns="jabber:client">`+
|
||||||
|
`<query xmlns="jabber:iq:register"/></iq>`);
|
||||||
|
const result = $iq({
|
||||||
|
'from': view.model.get('jid'),
|
||||||
|
'id': stanza.getAttribute('id'),
|
||||||
|
'to': _converse.bare_jid,
|
||||||
|
'type': 'result',
|
||||||
|
}).c('query', {'type': 'jabber:iq:register'})
|
||||||
|
.c('x', {'xmlns': 'jabber:x:data', 'type': 'form'})
|
||||||
|
.c('field', {
|
||||||
|
'label': 'Desired Nickname',
|
||||||
|
'type': 'text-single',
|
||||||
|
'var': 'muc#register_roomnick'
|
||||||
|
}).c('required');
|
||||||
|
_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
|
||||||
|
).pop());
|
||||||
|
|
||||||
|
expect(Strophe.serialize(stanza)).toBe(
|
||||||
|
`<iq from="romeo@montague.lit/orchard" id="${stanza.getAttribute('id')}" to="coven@chat.shakespeare.lit" type="set" xmlns="jabber:client">`+
|
||||||
|
`<query xmlns="jabber:iq:register">`+
|
||||||
|
`<x type="submit" xmlns="jabber:x:data">`+
|
||||||
|
`<field var="FORM_TYPE"><value>http://jabber.org/protocol/muc#register</value></field>`+
|
||||||
|
`<field var="muc#register_roomnick"><value>romeo</value></field>`+
|
||||||
|
`</x>`+
|
||||||
|
`</query>`+
|
||||||
|
`</iq>`);
|
||||||
|
done();
|
||||||
|
}));
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -1,333 +1,338 @@
|
|||||||
window.addEventListener('converse-loaded', () => {
|
/* global mock */
|
||||||
const mock = window.mock;
|
|
||||||
const test_utils = window.test_utils;
|
|
||||||
const { Strophe, $iq, $msg, $pres, sizzle, _ } = converse.env;
|
|
||||||
const u = converse.env.utils;
|
|
||||||
|
|
||||||
|
describe("A list of open groupchats", function () {
|
||||||
|
|
||||||
describe("A list of open groupchats", function () {
|
it("is shown in controlbox", mock.initConverse(
|
||||||
|
['rosterGroupsFetched', 'chatBoxesFetched'],
|
||||||
it("is shown in controlbox", mock.initConverse(
|
{ allow_bookmarks: false // Makes testing easier, otherwise we
|
||||||
['rosterGroupsFetched', 'chatBoxesFetched'],
|
|
||||||
{ allow_bookmarks: false // Makes testing easier, otherwise we
|
|
||||||
// have to mock stanza traffic.
|
|
||||||
}, async function (done, _converse) {
|
|
||||||
|
|
||||||
await test_utils.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');
|
|
||||||
|
|
||||||
const lview = _converse.rooms_list_view
|
|
||||||
await u.waitUntil(() => lview.el.querySelectorAll(".open-room").length);
|
|
||||||
let room_els = lview.el.querySelectorAll(".open-room");
|
|
||||||
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 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);
|
|
||||||
|
|
||||||
let view = _converse.chatboxviews.get('room@conference.shakespeare.lit');
|
|
||||||
await view.close();
|
|
||||||
room_els = _converse.rooms_list_view.el.querySelectorAll(".open-room");
|
|
||||||
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'));
|
|
||||||
|
|
||||||
view = _converse.chatboxviews.get('lounge@montague.lit');
|
|
||||||
await view.close();
|
|
||||||
room_els = _converse.rooms_list_view.el.querySelectorAll(".open-room");
|
|
||||||
expect(room_els.length).toBe(0);
|
|
||||||
|
|
||||||
list = controlbox.el.querySelector('.list-container--openrooms');
|
|
||||||
expect(_.includes(list.classList, 'hidden')).toBeTruthy();
|
|
||||||
done();
|
|
||||||
}));
|
|
||||||
|
|
||||||
it("uses bookmarks to determine groupchat names",
|
|
||||||
mock.initConverse(
|
|
||||||
['rosterGroupsFetched', 'chatBoxesFetched'],
|
|
||||||
{'view_mode': 'fullscreen'},
|
|
||||||
async function (done, _converse) {
|
|
||||||
|
|
||||||
await test_utils.openAndEnterChatRoom(_converse, 'lounge@montague.lit', 'romeo');
|
|
||||||
let stanza = $pres({
|
|
||||||
to: 'romeo@montague.lit/orchard',
|
|
||||||
from: 'lounge@montague.lit/newguy'
|
|
||||||
})
|
|
||||||
.c('x', {xmlns: Strophe.NS.MUC_USER})
|
|
||||||
.c('item', {
|
|
||||||
'affiliation': 'none',
|
|
||||||
'jid': 'newguy@montague.lit/_converse.js-290929789',
|
|
||||||
'role': 'participant'
|
|
||||||
}).tree();
|
|
||||||
_converse.connection._dataRecv(test_utils.createRequest(stanza));
|
|
||||||
|
|
||||||
spyOn(_converse.Bookmarks.prototype, 'fetchBookmarks').and.callThrough();
|
|
||||||
|
|
||||||
await test_utils.waitUntilDiscoConfirmed(
|
|
||||||
_converse, _converse.bare_jid,
|
|
||||||
[{'category': 'pubsub', 'type':'pep'}],
|
|
||||||
[`${Strophe.NS.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());
|
|
||||||
expect(Strophe.serialize(sent_stanza)).toBe(
|
|
||||||
`<iq from="romeo@montague.lit/orchard" id="${sent_stanza.getAttribute('id')}" type="get" xmlns="jabber:client">`+
|
|
||||||
'<pubsub xmlns="http://jabber.org/protocol/pubsub">'+
|
|
||||||
'<items node="storage:bookmarks"/>'+
|
|
||||||
'</pubsub>'+
|
|
||||||
'</iq>');
|
|
||||||
|
|
||||||
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'})
|
|
||||||
.c('conference', {
|
|
||||||
'name': 'Bookmarked Lounge',
|
|
||||||
'jid': 'lounge@montague.lit'
|
|
||||||
});
|
|
||||||
_converse.connection._dataRecv(test_utils.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();
|
|
||||||
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 () {
|
|
||||||
|
|
||||||
it("is highlighted if it's currently open", mock.initConverse(
|
|
||||||
['rosterGroupsFetched', 'chatBoxesFetched'],
|
|
||||||
{ view_mode: 'fullscreen',
|
|
||||||
allow_bookmarks: false // Makes testing easier, otherwise we have to mock stanza traffic.
|
|
||||||
}, async function (done, _converse) {
|
|
||||||
|
|
||||||
const muc_jid = 'coven@chat.shakespeare.lit';
|
|
||||||
await _converse.api.rooms.open(muc_jid, {'nick': 'some1'}, true);
|
|
||||||
const lview = _converse.rooms_list_view
|
|
||||||
await u.waitUntil(() => lview.el.querySelectorAll(".open-room").length);
|
|
||||||
let room_els = lview.el.querySelectorAll(".available-chatroom");
|
|
||||||
expect(room_els.length).toBe(1);
|
|
||||||
|
|
||||||
let item = room_els[0];
|
|
||||||
await u.waitUntil(() => lview.model.get(muc_jid).get('hidden') === false);
|
|
||||||
await u.waitUntil(() => u.hasClass('open', item), 1000);
|
|
||||||
expect(item.textContent.trim()).toBe('coven@chat.shakespeare.lit');
|
|
||||||
await _converse.api.rooms.open('balcony@chat.shakespeare.lit', {'nick': 'some1'}, true);
|
|
||||||
await u.waitUntil(() => lview.el.querySelectorAll(".open-room").length > 1);
|
|
||||||
room_els = lview.el.querySelectorAll(".open-room");
|
|
||||||
expect(room_els.length).toBe(2);
|
|
||||||
|
|
||||||
room_els = lview.el.querySelectorAll(".available-chatroom.open");
|
|
||||||
expect(room_els.length).toBe(1);
|
|
||||||
item = room_els[0];
|
|
||||||
expect(item.textContent.trim()).toBe('balcony@chat.shakespeare.lit');
|
|
||||||
done();
|
|
||||||
}));
|
|
||||||
|
|
||||||
it("has an info icon which opens a details modal when clicked", mock.initConverse(
|
|
||||||
['rosterGroupsFetched', 'chatBoxesFetched'],
|
|
||||||
{ whitelisted_plugins: ['converse-roomslist'],
|
|
||||||
allow_bookmarks: false // Makes testing easier, otherwise we
|
|
||||||
// have to mock stanza traffic.
|
// have to mock stanza traffic.
|
||||||
}, async function (done, _converse) {
|
}, async function (done, _converse) {
|
||||||
|
|
||||||
const IQ_stanzas = _converse.connection.IQ_stanzas;
|
const u = converse.env.utils;
|
||||||
const room_jid = 'coven@chat.shakespeare.lit';
|
|
||||||
await test_utils.openControlBox(_converse);
|
|
||||||
await _converse.api.rooms.open(room_jid, {'nick': 'some1'});
|
|
||||||
const view = _converse.chatboxviews.get(room_jid);
|
|
||||||
|
|
||||||
const selector = `iq[to="${room_jid}"] query[xmlns="http://jabber.org/protocol/disco#info"]`;
|
await mock.openControlBox(_converse);
|
||||||
const features_query = await u.waitUntil(() => IQ_stanzas.filter(iq => iq.querySelector(selector)).pop());
|
const controlbox = _converse.chatboxviews.get('controlbox');
|
||||||
const features_stanza = $iq({
|
let list = controlbox.el.querySelector('.list-container--openrooms');
|
||||||
'from': 'coven@chat.shakespeare.lit',
|
expect(u.hasClass('hidden', list)).toBeTruthy();
|
||||||
'id': features_query.getAttribute('id'),
|
await mock.openChatRoom(_converse, 'room', 'conference.shakespeare.lit', 'JC');
|
||||||
'to': 'romeo@montague.lit/desktop',
|
|
||||||
'type': 'result'
|
|
||||||
})
|
|
||||||
.c('query', { 'xmlns': 'http://jabber.org/protocol/disco#info'})
|
|
||||||
.c('identity', {
|
|
||||||
'category': 'conference',
|
|
||||||
'name': 'A Dark Cave',
|
|
||||||
'type': 'text'
|
|
||||||
}).up()
|
|
||||||
.c('feature', {'var': 'http://jabber.org/protocol/muc'}).up()
|
|
||||||
.c('feature', {'var': 'muc_passwordprotected'}).up()
|
|
||||||
.c('feature', {'var': 'muc_hidden'}).up()
|
|
||||||
.c('feature', {'var': 'muc_temporary'}).up()
|
|
||||||
.c('feature', {'var': 'muc_open'}).up()
|
|
||||||
.c('feature', {'var': 'muc_unmoderated'}).up()
|
|
||||||
.c('feature', {'var': 'muc_nonanonymous'}).up()
|
|
||||||
.c('feature', {'var': 'urn:xmpp:mam:0'}).up()
|
|
||||||
.c('x', { 'xmlns':'jabber:x:data', 'type':'result'})
|
|
||||||
.c('field', {'var':'FORM_TYPE', 'type':'hidden'})
|
|
||||||
.c('value').t('http://jabber.org/protocol/muc#roominfo').up().up()
|
|
||||||
.c('field', {'type':'text-single', 'var':'muc#roominfo_description', 'label':'Description'})
|
|
||||||
.c('value').t('This is the description').up().up()
|
|
||||||
.c('field', {'type':'text-single', 'var':'muc#roominfo_occupants', 'label':'Number of occupants'})
|
|
||||||
.c('value').t(0);
|
|
||||||
_converse.connection._dataRecv(test_utils.createRequest(features_stanza));
|
|
||||||
await u.waitUntil(() => view.model.session.get('connection_status') === converse.ROOMSTATUS.CONNECTING)
|
|
||||||
let presence = $pres({
|
|
||||||
to: _converse.connection.jid,
|
|
||||||
from: 'coven@chat.shakespeare.lit/some1',
|
|
||||||
id: 'DC352437-C019-40EC-B590-AF29E879AF97'
|
|
||||||
}).c('x').attrs({xmlns:'http://jabber.org/protocol/muc#user'})
|
|
||||||
.c('item').attrs({
|
|
||||||
affiliation: 'member',
|
|
||||||
jid: _converse.bare_jid,
|
|
||||||
role: 'participant'
|
|
||||||
}).up()
|
|
||||||
.c('status').attrs({code:'110'});
|
|
||||||
_converse.connection._dataRecv(test_utils.createRequest(presence));
|
|
||||||
|
|
||||||
await u.waitUntil(() => _converse.rooms_list_view.el.querySelectorAll(".open-room").length, 500);
|
const lview = _converse.rooms_list_view
|
||||||
const room_els = _converse.rooms_list_view.el.querySelectorAll(".open-room");
|
await u.waitUntil(() => lview.el.querySelectorAll(".open-room").length);
|
||||||
expect(room_els.length).toBe(1);
|
let room_els = lview.el.querySelectorAll(".open-room");
|
||||||
const info_el = _converse.rooms_list_view.el.querySelector(".room-info");
|
expect(room_els.length).toBe(1);
|
||||||
info_el.click();
|
expect(room_els[0].innerText).toBe('room@conference.shakespeare.lit');
|
||||||
|
|
||||||
const modal = view.model.room_details_modal;
|
await mock.openChatRoom(_converse, 'lounge', 'montague.lit', 'romeo');
|
||||||
await u.waitUntil(() => u.isVisible(modal.el), 1000);
|
await u.waitUntil(() => lview.el.querySelectorAll(".open-room").length > 1);
|
||||||
let els = modal.el.querySelectorAll('p.room-info');
|
room_els = _converse.rooms_list_view.el.querySelectorAll(".open-room");
|
||||||
expect(els[0].textContent).toBe("Name: A Dark Cave")
|
expect(room_els.length).toBe(2);
|
||||||
expect(els[1].textContent).toBe("Groupchat address (JID): coven@chat.shakespeare.lit")
|
|
||||||
expect(els[2].textContent).toBe("Description: This is the description")
|
|
||||||
expect(els[3].textContent).toBe("Online users: 1")
|
|
||||||
const features_list = modal.el.querySelector('.features-list');
|
|
||||||
expect(features_list.textContent.replace(/(\n|\s{2,})/g, '')).toBe(
|
|
||||||
'Password protected - This groupchat requires a password before entry'+
|
|
||||||
'Hidden - This groupchat is not publicly searchable'+
|
|
||||||
'Open - Anyone can join this groupchat'+
|
|
||||||
'Temporary - This groupchat will disappear once the last person leaves'+
|
|
||||||
'Not anonymous - All other groupchat participants can see your XMPP address'+
|
|
||||||
'Not moderated - Participants entering this groupchat can write right away'
|
|
||||||
);
|
|
||||||
presence = $pres({
|
|
||||||
to: 'romeo@montague.lit/_converse.js-29092160',
|
|
||||||
from: 'coven@chat.shakespeare.lit/newguy'
|
|
||||||
})
|
|
||||||
.c('x', {xmlns: Strophe.NS.MUC_USER})
|
|
||||||
.c('item', {
|
|
||||||
'affiliation': 'none',
|
|
||||||
'jid': 'newguy@montague.lit/_converse.js-290929789',
|
|
||||||
'role': 'participant'
|
|
||||||
});
|
|
||||||
_converse.connection._dataRecv(test_utils.createRequest(presence));
|
|
||||||
|
|
||||||
els = modal.el.querySelectorAll('p.room-info');
|
let view = _converse.chatboxviews.get('room@conference.shakespeare.lit');
|
||||||
expect(els[3].textContent).toBe("Online users: 2")
|
await view.close();
|
||||||
|
room_els = _converse.rooms_list_view.el.querySelectorAll(".open-room");
|
||||||
|
expect(room_els.length).toBe(1);
|
||||||
|
expect(room_els[0].innerText).toBe('lounge@montague.lit');
|
||||||
|
list = controlbox.el.querySelector('.list-container--openrooms');
|
||||||
|
u.waitUntil(() => Array.from(list.classList).includes('hidden'));
|
||||||
|
|
||||||
view.model.set({'subject': {'author': 'someone', 'text': 'Hatching dark plots'}});
|
view = _converse.chatboxviews.get('lounge@montague.lit');
|
||||||
els = modal.el.querySelectorAll('p.room-info');
|
await view.close();
|
||||||
expect(els[0].textContent).toBe("Name: A Dark Cave")
|
room_els = _converse.rooms_list_view.el.querySelectorAll(".open-room");
|
||||||
expect(els[1].textContent).toBe("Groupchat address (JID): coven@chat.shakespeare.lit")
|
expect(room_els.length).toBe(0);
|
||||||
expect(els[2].textContent).toBe("Description: This is the description")
|
|
||||||
expect(els[3].textContent).toBe("Topic: Hatching dark plots")
|
|
||||||
expect(els[4].textContent).toBe("Topic author: someone")
|
|
||||||
expect(els[5].textContent).toBe("Online users: 2")
|
|
||||||
done();
|
|
||||||
}));
|
|
||||||
|
|
||||||
it("can be closed", mock.initConverse(
|
list = controlbox.el.querySelector('.list-container--openrooms');
|
||||||
['rosterGroupsFetched'],
|
expect(Array.from(list.classList).includes('hidden')).toBeTruthy();
|
||||||
{ whitelisted_plugins: ['converse-roomslist'],
|
done();
|
||||||
allow_bookmarks: false // Makes testing easier, otherwise we have to mock stanza traffic.
|
}));
|
||||||
},
|
|
||||||
async function (done, _converse) {
|
|
||||||
|
|
||||||
spyOn(window, 'confirm').and.callFake(() => true);
|
it("uses bookmarks to determine groupchat names",
|
||||||
expect(_converse.chatboxes.length).toBe(1);
|
mock.initConverse(
|
||||||
await test_utils.openChatRoom(_converse, 'lounge', 'conference.shakespeare.lit', 'JC');
|
['rosterGroupsFetched', 'chatBoxesFetched'],
|
||||||
expect(_converse.chatboxes.length).toBe(2);
|
{'view_mode': 'fullscreen'},
|
||||||
const lview = _converse.rooms_list_view
|
async function (done, _converse) {
|
||||||
await u.waitUntil(() => lview.el.querySelectorAll(".open-room").length);
|
|
||||||
let room_els = lview.el.querySelectorAll(".open-room");
|
|
||||||
expect(room_els.length).toBe(1);
|
|
||||||
const close_el = _converse.rooms_list_view.el.querySelector(".close-room");
|
|
||||||
close_el.click();
|
|
||||||
expect(window.confirm).toHaveBeenCalledWith(
|
|
||||||
'Are you sure you want to leave the groupchat lounge@conference.shakespeare.lit?');
|
|
||||||
|
|
||||||
await new Promise(resolve => _converse.api.listen.once('chatBoxClosed', resolve));
|
const { Strophe, $iq, $pres, sizzle } = converse.env;
|
||||||
room_els = _converse.rooms_list_view.el.querySelectorAll(".open-room");
|
const u = converse.env.utils;
|
||||||
expect(room_els.length).toBe(0);
|
|
||||||
expect(_converse.chatboxes.length).toBe(1);
|
|
||||||
done();
|
|
||||||
}));
|
|
||||||
|
|
||||||
it("shows unread messages directed at the user", mock.initConverse(
|
await mock.openAndEnterChatRoom(_converse, 'lounge@montague.lit', 'romeo');
|
||||||
null,
|
let stanza = $pres({
|
||||||
{ whitelisted_plugins: ['converse-roomslist'],
|
to: 'romeo@montague.lit/orchard',
|
||||||
allow_bookmarks: false // Makes testing easier, otherwise we have to mock stanza traffic.
|
from: 'lounge@montague.lit/newguy'
|
||||||
}, async (done, _converse) => {
|
})
|
||||||
|
.c('x', {xmlns: Strophe.NS.MUC_USER})
|
||||||
|
.c('item', {
|
||||||
|
'affiliation': 'none',
|
||||||
|
'jid': 'newguy@montague.lit/_converse.js-290929789',
|
||||||
|
'role': 'participant'
|
||||||
|
}).tree();
|
||||||
|
_converse.connection._dataRecv(mock.createRequest(stanza));
|
||||||
|
|
||||||
await test_utils.openControlBox(_converse);
|
spyOn(_converse.Bookmarks.prototype, 'fetchBookmarks').and.callThrough();
|
||||||
const room_jid = 'kitchen@conference.shakespeare.lit';
|
|
||||||
await u.waitUntil(() => _converse.rooms_list_view !== undefined, 500);
|
|
||||||
await test_utils.openAndEnterChatRoom(_converse, room_jid, 'romeo');
|
|
||||||
const view = _converse.chatboxviews.get(room_jid);
|
|
||||||
view.model.set({'minimized': true});
|
|
||||||
const nick = mock.chatroom_names[0];
|
|
||||||
await view.model.queueMessage(
|
|
||||||
$msg({
|
|
||||||
from: room_jid+'/'+nick,
|
|
||||||
id: u.getUniqueId(),
|
|
||||||
to: 'romeo@montague.lit',
|
|
||||||
type: 'groupchat'
|
|
||||||
}).c('body').t('foo').tree());
|
|
||||||
|
|
||||||
// If the user isn't mentioned, the counter doesn't get incremented, but the text of the groupchat is bold
|
await mock.waitUntilDiscoConfirmed(
|
||||||
const lview = _converse.rooms_list_view
|
_converse, _converse.bare_jid,
|
||||||
let room_el = await u.waitUntil(() => lview.el.querySelector(".available-chatroom"));
|
[{'category': 'pubsub', 'type':'pep'}],
|
||||||
expect(Array.from(room_el.classList).includes('unread-msgs')).toBeTruthy();
|
[`${Strophe.NS.PUBSUB}#publish-options`]
|
||||||
|
);
|
||||||
|
|
||||||
// If the user is mentioned, the counter also gets updated
|
const IQ_stanzas = _converse.connection.IQ_stanzas;
|
||||||
await view.model.queueMessage(
|
const sent_stanza = await u.waitUntil(() => IQ_stanzas.filter(s => sizzle('items[node="storage:bookmarks"]', s).length).pop());
|
||||||
$msg({
|
expect(Strophe.serialize(sent_stanza)).toBe(
|
||||||
from: room_jid+'/'+nick,
|
`<iq from="romeo@montague.lit/orchard" id="${sent_stanza.getAttribute('id')}" type="get" xmlns="jabber:client">`+
|
||||||
id: u.getUniqueId(),
|
'<pubsub xmlns="http://jabber.org/protocol/pubsub">'+
|
||||||
to: 'romeo@montague.lit',
|
'<items node="storage:bookmarks"/>'+
|
||||||
type: 'groupchat'
|
'</pubsub>'+
|
||||||
}).c('body').t('romeo: Your attention is required').tree()
|
'</iq>');
|
||||||
);
|
|
||||||
|
|
||||||
let indicator_el = await u.waitUntil(() => lview.el.querySelector(".msgs-indicator"));
|
stanza = $iq({'to': _converse.connection.jid, 'type':'result', 'id':sent_stanza.getAttribute('id')})
|
||||||
expect(indicator_el.textContent).toBe('1');
|
.c('pubsub', {'xmlns': Strophe.NS.PUBSUB})
|
||||||
|
.c('items', {'node': 'storage:bookmarks'})
|
||||||
|
.c('item', {'id': 'current'})
|
||||||
|
.c('storage', {'xmlns': 'storage:bookmarks'})
|
||||||
|
.c('conference', {
|
||||||
|
'name': 'Bookmarked Lounge',
|
||||||
|
'jid': 'lounge@montague.lit'
|
||||||
|
});
|
||||||
|
_converse.connection._dataRecv(mock.createRequest(stanza));
|
||||||
|
|
||||||
spyOn(view.model, 'incrementUnreadMsgCounter').and.callThrough();
|
await _converse.api.waitUntil('roomsListInitialized');
|
||||||
await view.model.queueMessage(
|
const controlbox = _converse.chatboxviews.get('controlbox');
|
||||||
$msg({
|
const list = controlbox.el.querySelector('.list-container--openrooms');
|
||||||
from: room_jid+'/'+nick,
|
expect(Array.from(list.classList).includes('hidden')).toBeFalsy();
|
||||||
id: u.getUniqueId(),
|
const items = list.querySelectorAll('.list-item');
|
||||||
to: 'romeo@montague.lit',
|
expect(items.length).toBe(1);
|
||||||
type: 'groupchat'
|
expect(items[0].textContent.trim()).toBe('Bookmarked Lounge');
|
||||||
}).c('body').t('romeo: and another thing...').tree()
|
expect(_converse.bookmarks.fetchBookmarks).toHaveBeenCalled();
|
||||||
);
|
done();
|
||||||
await u.waitUntil(() => view.model.incrementUnreadMsgCounter.calls.count());
|
}));
|
||||||
await u.waitUntil(() => lview.el.querySelector(".msgs-indicator").textContent === '2', 1000);
|
});
|
||||||
|
|
||||||
// When the chat gets maximized again, the unread indicators are removed
|
describe("A groupchat shown in the groupchats list", function () {
|
||||||
view.model.set({'minimized': false});
|
|
||||||
indicator_el = lview.el.querySelector(".msgs-indicator");
|
it("is highlighted if it's currently open", mock.initConverse(
|
||||||
expect(indicator_el === null);
|
['rosterGroupsFetched', 'chatBoxesFetched'],
|
||||||
room_el = lview.el.querySelector(".available-chatroom");
|
{ view_mode: 'fullscreen',
|
||||||
expect(_.includes(room_el.classList, 'unread-msgs')).toBeFalsy();
|
allow_bookmarks: false // Makes testing easier, otherwise we have to mock stanza traffic.
|
||||||
done();
|
}, 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
|
||||||
|
await u.waitUntil(() => lview.el.querySelectorAll(".open-room").length);
|
||||||
|
let room_els = lview.el.querySelectorAll(".available-chatroom");
|
||||||
|
expect(room_els.length).toBe(1);
|
||||||
|
|
||||||
|
let item = room_els[0];
|
||||||
|
await u.waitUntil(() => lview.model.get(muc_jid).get('hidden') === false);
|
||||||
|
await u.waitUntil(() => u.hasClass('open', item), 1000);
|
||||||
|
expect(item.textContent.trim()).toBe('coven@chat.shakespeare.lit');
|
||||||
|
await _converse.api.rooms.open('balcony@chat.shakespeare.lit', {'nick': 'some1'}, true);
|
||||||
|
await u.waitUntil(() => lview.el.querySelectorAll(".open-room").length > 1);
|
||||||
|
room_els = lview.el.querySelectorAll(".open-room");
|
||||||
|
expect(room_els.length).toBe(2);
|
||||||
|
|
||||||
|
room_els = lview.el.querySelectorAll(".available-chatroom.open");
|
||||||
|
expect(room_els.length).toBe(1);
|
||||||
|
item = room_els[0];
|
||||||
|
expect(item.textContent.trim()).toBe('balcony@chat.shakespeare.lit');
|
||||||
|
done();
|
||||||
|
}));
|
||||||
|
|
||||||
|
it("has an info icon which opens a details modal when clicked", mock.initConverse(
|
||||||
|
['rosterGroupsFetched', 'chatBoxesFetched'],
|
||||||
|
{ whitelisted_plugins: ['converse-roomslist'],
|
||||||
|
allow_bookmarks: false // Makes testing easier, otherwise we
|
||||||
|
// 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 mock.openControlBox(_converse);
|
||||||
|
await _converse.api.rooms.open(room_jid, {'nick': 'some1'});
|
||||||
|
const view = _converse.chatboxviews.get(room_jid);
|
||||||
|
|
||||||
|
const selector = `iq[to="${room_jid}"] query[xmlns="http://jabber.org/protocol/disco#info"]`;
|
||||||
|
const features_query = await u.waitUntil(() => IQ_stanzas.filter(iq => iq.querySelector(selector)).pop());
|
||||||
|
const features_stanza = $iq({
|
||||||
|
'from': 'coven@chat.shakespeare.lit',
|
||||||
|
'id': features_query.getAttribute('id'),
|
||||||
|
'to': 'romeo@montague.lit/desktop',
|
||||||
|
'type': 'result'
|
||||||
|
})
|
||||||
|
.c('query', { 'xmlns': 'http://jabber.org/protocol/disco#info'})
|
||||||
|
.c('identity', {
|
||||||
|
'category': 'conference',
|
||||||
|
'name': 'A Dark Cave',
|
||||||
|
'type': 'text'
|
||||||
|
}).up()
|
||||||
|
.c('feature', {'var': 'http://jabber.org/protocol/muc'}).up()
|
||||||
|
.c('feature', {'var': 'muc_passwordprotected'}).up()
|
||||||
|
.c('feature', {'var': 'muc_hidden'}).up()
|
||||||
|
.c('feature', {'var': 'muc_temporary'}).up()
|
||||||
|
.c('feature', {'var': 'muc_open'}).up()
|
||||||
|
.c('feature', {'var': 'muc_unmoderated'}).up()
|
||||||
|
.c('feature', {'var': 'muc_nonanonymous'}).up()
|
||||||
|
.c('feature', {'var': 'urn:xmpp:mam:0'}).up()
|
||||||
|
.c('x', { 'xmlns':'jabber:x:data', 'type':'result'})
|
||||||
|
.c('field', {'var':'FORM_TYPE', 'type':'hidden'})
|
||||||
|
.c('value').t('http://jabber.org/protocol/muc#roominfo').up().up()
|
||||||
|
.c('field', {'type':'text-single', 'var':'muc#roominfo_description', 'label':'Description'})
|
||||||
|
.c('value').t('This is the description').up().up()
|
||||||
|
.c('field', {'type':'text-single', 'var':'muc#roominfo_occupants', 'label':'Number of occupants'})
|
||||||
|
.c('value').t(0);
|
||||||
|
_converse.connection._dataRecv(mock.createRequest(features_stanza));
|
||||||
|
await u.waitUntil(() => view.model.session.get('connection_status') === converse.ROOMSTATUS.CONNECTING)
|
||||||
|
let presence = $pres({
|
||||||
|
to: _converse.connection.jid,
|
||||||
|
from: 'coven@chat.shakespeare.lit/some1',
|
||||||
|
id: 'DC352437-C019-40EC-B590-AF29E879AF97'
|
||||||
|
}).c('x').attrs({xmlns:'http://jabber.org/protocol/muc#user'})
|
||||||
|
.c('item').attrs({
|
||||||
|
affiliation: 'member',
|
||||||
|
jid: _converse.bare_jid,
|
||||||
|
role: 'participant'
|
||||||
|
}).up()
|
||||||
|
.c('status').attrs({code:'110'});
|
||||||
|
_converse.connection._dataRecv(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");
|
||||||
|
expect(room_els.length).toBe(1);
|
||||||
|
const info_el = _converse.rooms_list_view.el.querySelector(".room-info");
|
||||||
|
info_el.click();
|
||||||
|
|
||||||
|
const modal = view.model.room_details_modal;
|
||||||
|
await u.waitUntil(() => u.isVisible(modal.el), 1000);
|
||||||
|
let els = modal.el.querySelectorAll('p.room-info');
|
||||||
|
expect(els[0].textContent).toBe("Name: A Dark Cave")
|
||||||
|
expect(els[1].textContent).toBe("Groupchat address (JID): coven@chat.shakespeare.lit")
|
||||||
|
expect(els[2].textContent).toBe("Description: This is the description")
|
||||||
|
expect(els[3].textContent).toBe("Online users: 1")
|
||||||
|
const features_list = modal.el.querySelector('.features-list');
|
||||||
|
expect(features_list.textContent.replace(/(\n|\s{2,})/g, '')).toBe(
|
||||||
|
'Password protected - This groupchat requires a password before entry'+
|
||||||
|
'Hidden - This groupchat is not publicly searchable'+
|
||||||
|
'Open - Anyone can join this groupchat'+
|
||||||
|
'Temporary - This groupchat will disappear once the last person leaves'+
|
||||||
|
'Not anonymous - All other groupchat participants can see your XMPP address'+
|
||||||
|
'Not moderated - Participants entering this groupchat can write right away'
|
||||||
|
);
|
||||||
|
presence = $pres({
|
||||||
|
to: 'romeo@montague.lit/_converse.js-29092160',
|
||||||
|
from: 'coven@chat.shakespeare.lit/newguy'
|
||||||
|
})
|
||||||
|
.c('x', {xmlns: Strophe.NS.MUC_USER})
|
||||||
|
.c('item', {
|
||||||
|
'affiliation': 'none',
|
||||||
|
'jid': 'newguy@montague.lit/_converse.js-290929789',
|
||||||
|
'role': 'participant'
|
||||||
|
});
|
||||||
|
_converse.connection._dataRecv(mock.createRequest(presence));
|
||||||
|
|
||||||
|
els = modal.el.querySelectorAll('p.room-info');
|
||||||
|
expect(els[3].textContent).toBe("Online users: 2")
|
||||||
|
|
||||||
|
view.model.set({'subject': {'author': 'someone', 'text': 'Hatching dark plots'}});
|
||||||
|
els = modal.el.querySelectorAll('p.room-info');
|
||||||
|
expect(els[0].textContent).toBe("Name: A Dark Cave")
|
||||||
|
expect(els[1].textContent).toBe("Groupchat address (JID): coven@chat.shakespeare.lit")
|
||||||
|
expect(els[2].textContent).toBe("Description: This is the description")
|
||||||
|
expect(els[3].textContent).toBe("Topic: Hatching dark plots")
|
||||||
|
expect(els[4].textContent).toBe("Topic author: someone")
|
||||||
|
expect(els[5].textContent).toBe("Online users: 2")
|
||||||
|
done();
|
||||||
|
}));
|
||||||
|
|
||||||
|
it("can be closed", mock.initConverse(
|
||||||
|
['rosterGroupsFetched'],
|
||||||
|
{ whitelisted_plugins: ['converse-roomslist'],
|
||||||
|
allow_bookmarks: false // Makes testing easier, otherwise we have to mock stanza traffic.
|
||||||
|
},
|
||||||
|
async function (done, _converse) {
|
||||||
|
|
||||||
|
const u = converse.env.utils;
|
||||||
|
spyOn(window, 'confirm').and.callFake(() => true);
|
||||||
|
expect(_converse.chatboxes.length).toBe(1);
|
||||||
|
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);
|
||||||
|
let room_els = lview.el.querySelectorAll(".open-room");
|
||||||
|
expect(room_els.length).toBe(1);
|
||||||
|
const close_el = _converse.rooms_list_view.el.querySelector(".close-room");
|
||||||
|
close_el.click();
|
||||||
|
expect(window.confirm).toHaveBeenCalledWith(
|
||||||
|
'Are you sure you want to leave the groupchat lounge@conference.shakespeare.lit?');
|
||||||
|
|
||||||
|
await new Promise(resolve => _converse.api.listen.once('chatBoxClosed', resolve));
|
||||||
|
room_els = _converse.rooms_list_view.el.querySelectorAll(".open-room");
|
||||||
|
expect(room_els.length).toBe(0);
|
||||||
|
expect(_converse.chatboxes.length).toBe(1);
|
||||||
|
done();
|
||||||
|
}));
|
||||||
|
|
||||||
|
it("shows unread messages directed at the user", mock.initConverse(
|
||||||
|
null,
|
||||||
|
{ whitelisted_plugins: ['converse-roomslist'],
|
||||||
|
allow_bookmarks: false // Makes testing easier, otherwise we have to mock stanza traffic.
|
||||||
|
}, async (done, _converse) => {
|
||||||
|
|
||||||
|
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 mock.openAndEnterChatRoom(_converse, room_jid, 'romeo');
|
||||||
|
const view = _converse.chatboxviews.get(room_jid);
|
||||||
|
view.model.set({'minimized': true});
|
||||||
|
const nick = mock.chatroom_names[0];
|
||||||
|
await view.model.queueMessage(
|
||||||
|
$msg({
|
||||||
|
from: room_jid+'/'+nick,
|
||||||
|
id: u.getUniqueId(),
|
||||||
|
to: 'romeo@montague.lit',
|
||||||
|
type: 'groupchat'
|
||||||
|
}).c('body').t('foo').tree());
|
||||||
|
|
||||||
|
// If the user isn't mentioned, the counter doesn't get incremented, but the text of the groupchat is bold
|
||||||
|
const lview = _converse.rooms_list_view
|
||||||
|
let room_el = await u.waitUntil(() => lview.el.querySelector(".available-chatroom"));
|
||||||
|
expect(Array.from(room_el.classList).includes('unread-msgs')).toBeTruthy();
|
||||||
|
|
||||||
|
// If the user is mentioned, the counter also gets updated
|
||||||
|
await view.model.queueMessage(
|
||||||
|
$msg({
|
||||||
|
from: room_jid+'/'+nick,
|
||||||
|
id: u.getUniqueId(),
|
||||||
|
to: 'romeo@montague.lit',
|
||||||
|
type: 'groupchat'
|
||||||
|
}).c('body').t('romeo: Your attention is required').tree()
|
||||||
|
);
|
||||||
|
|
||||||
|
let indicator_el = await u.waitUntil(() => lview.el.querySelector(".msgs-indicator"));
|
||||||
|
expect(indicator_el.textContent).toBe('1');
|
||||||
|
|
||||||
|
spyOn(view.model, 'incrementUnreadMsgCounter').and.callThrough();
|
||||||
|
await view.model.queueMessage(
|
||||||
|
$msg({
|
||||||
|
from: room_jid+'/'+nick,
|
||||||
|
id: u.getUniqueId(),
|
||||||
|
to: 'romeo@montague.lit',
|
||||||
|
type: 'groupchat'
|
||||||
|
}).c('body').t('romeo: and another thing...').tree()
|
||||||
|
);
|
||||||
|
await u.waitUntil(() => view.model.incrementUnreadMsgCounter.calls.count());
|
||||||
|
await u.waitUntil(() => lview.el.querySelector(".msgs-indicator").textContent === '2', 1000);
|
||||||
|
|
||||||
|
// When the chat gets maximized again, the unread indicators are removed
|
||||||
|
view.model.set({'minimized': false});
|
||||||
|
indicator_el = lview.el.querySelector(".msgs-indicator");
|
||||||
|
expect(indicator_el === null);
|
||||||
|
room_el = lview.el.querySelector(".available-chatroom");
|
||||||
|
expect(Array.from(room_el.classList).includes('unread-msgs')).toBeFalsy();
|
||||||
|
done();
|
||||||
|
}));
|
||||||
});
|
});
|
||||||
|
2442
spec/roster.js
2442
spec/roster.js
File diff suppressed because it is too large
Load Diff
456
spec/smacks.js
456
spec/smacks.js
@ -1,282 +1,280 @@
|
|||||||
window.addEventListener('converse-loaded', () => {
|
/*global mock */
|
||||||
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;
|
|
||||||
|
|
||||||
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;
|
||||||
|
|
||||||
it("gets enabled with an <enable> stanza and resumed with a <resume> stanza",
|
describe("XEP-0198 Stream Management", function () {
|
||||||
mock.initConverse(
|
|
||||||
['chatBoxesInitialized'],
|
|
||||||
{ 'auto_login': false,
|
|
||||||
'enable_smacks': true,
|
|
||||||
'show_controlbox_by_default': true,
|
|
||||||
'smacks_max_unacked_stanzas': 2
|
|
||||||
},
|
|
||||||
async function (done, _converse) {
|
|
||||||
|
|
||||||
const view = _converse.chatboxviews.get('controlbox');
|
it("gets enabled with an <enable> stanza and resumed with a <resume> stanza",
|
||||||
spyOn(view, 'renderControlBoxPane').and.callThrough();
|
mock.initConverse(
|
||||||
|
['chatBoxesInitialized'],
|
||||||
|
{ 'auto_login': false,
|
||||||
|
'enable_smacks': true,
|
||||||
|
'show_controlbox_by_default': true,
|
||||||
|
'smacks_max_unacked_stanzas': 2
|
||||||
|
},
|
||||||
|
async function (done, _converse) {
|
||||||
|
|
||||||
await _converse.api.user.login('romeo@montague.lit/orchard', 'secret');
|
const view = _converse.chatboxviews.get('controlbox');
|
||||||
const sent_stanzas = _converse.connection.sent_stanzas;
|
spyOn(view, 'renderControlBoxPane').and.callThrough();
|
||||||
let stanza = await u.waitUntil(() =>
|
|
||||||
sent_stanzas.filter(s => (s.tagName === 'enable')).pop());
|
|
||||||
|
|
||||||
expect(_converse.session.get('smacks_enabled')).toBe(false);
|
await _converse.api.user.login('romeo@montague.lit/orchard', 'secret');
|
||||||
expect(Strophe.serialize(stanza)).toEqual('<enable resume="true" xmlns="urn:xmpp:sm:3"/>');
|
const sent_stanzas = _converse.connection.sent_stanzas;
|
||||||
|
let stanza = await u.waitUntil(() =>
|
||||||
|
sent_stanzas.filter(s => (s.tagName === 'enable')).pop());
|
||||||
|
|
||||||
let result = u.toStanza(`<enabled xmlns="urn:xmpp:sm:3" id="some-long-sm-id" resume="true"/>`);
|
expect(_converse.session.get('smacks_enabled')).toBe(false);
|
||||||
_converse.connection._dataRecv(test_utils.createRequest(result));
|
expect(Strophe.serialize(stanza)).toEqual('<enable resume="true" xmlns="urn:xmpp:sm:3"/>');
|
||||||
expect(_converse.session.get('smacks_enabled')).toBe(true);
|
|
||||||
|
|
||||||
await u.waitUntil(() => view.renderControlBoxPane.calls.count());
|
let result = u.toStanza(`<enabled xmlns="urn:xmpp:sm:3" id="some-long-sm-id" resume="true"/>`);
|
||||||
|
_converse.connection._dataRecv(mock.createRequest(result));
|
||||||
|
expect(_converse.session.get('smacks_enabled')).toBe(true);
|
||||||
|
|
||||||
let IQ_stanzas = _converse.connection.IQ_stanzas;
|
await u.waitUntil(() => view.renderControlBoxPane.calls.count());
|
||||||
await u.waitUntil(() => IQ_stanzas.length === 4);
|
|
||||||
|
|
||||||
let iq = IQ_stanzas[IQ_stanzas.length-1];
|
let IQ_stanzas = _converse.connection.IQ_stanzas;
|
||||||
expect(Strophe.serialize(iq)).toBe(
|
await u.waitUntil(() => IQ_stanzas.length === 4);
|
||||||
`<iq id="${iq.getAttribute('id')}" type="get" xmlns="jabber:client"><query xmlns="jabber:iq:roster"/></iq>`);
|
|
||||||
await test_utils.waitForRoster(_converse, 'current', 1);
|
|
||||||
IQ_stanzas.pop();
|
|
||||||
|
|
||||||
const expected_IQs = disco_iq => ([
|
let iq = IQ_stanzas[IQ_stanzas.length-1];
|
||||||
`<iq from="romeo@montague.lit" id="${disco_iq.getAttribute('id')}" to="romeo@montague.lit" type="get" xmlns="jabber:client">`+
|
expect(Strophe.serialize(iq)).toBe(
|
||||||
`<pubsub xmlns="http://jabber.org/protocol/pubsub"><items node="eu.siacs.conversations.axolotl.devicelist"/></pubsub></iq>`,
|
`<iq id="${iq.getAttribute('id')}" type="get" xmlns="jabber:client"><query xmlns="jabber:iq:roster"/></iq>`);
|
||||||
|
await mock.waitForRoster(_converse, 'current', 1);
|
||||||
|
IQ_stanzas.pop();
|
||||||
|
|
||||||
`<iq from="romeo@montague.lit/orchard" id="${iq.getAttribute('id')}" to="romeo@montague.lit" type="get" xmlns="jabber:client">`+
|
const expected_IQs = disco_iq => ([
|
||||||
`<query xmlns="http://jabber.org/protocol/disco#info"/></iq>`,
|
`<iq from="romeo@montague.lit" id="${disco_iq.getAttribute('id')}" to="romeo@montague.lit" type="get" xmlns="jabber:client">`+
|
||||||
|
`<pubsub xmlns="http://jabber.org/protocol/pubsub"><items node="eu.siacs.conversations.axolotl.devicelist"/></pubsub></iq>`,
|
||||||
|
|
||||||
`<iq from="romeo@montague.lit/orchard" id="${iq.getAttribute('id')}" to="montague.lit" type="get" xmlns="jabber:client">`+
|
`<iq from="romeo@montague.lit/orchard" id="${iq.getAttribute('id')}" to="romeo@montague.lit" type="get" xmlns="jabber:client">`+
|
||||||
`<query xmlns="http://jabber.org/protocol/disco#info"/></iq>`]);
|
`<query xmlns="http://jabber.org/protocol/disco#info"/></iq>`,
|
||||||
|
|
||||||
const disco_iq = IQ_stanzas.pop();
|
`<iq from="romeo@montague.lit/orchard" id="${iq.getAttribute('id')}" to="montague.lit" type="get" xmlns="jabber:client">`+
|
||||||
expect(expected_IQs(disco_iq).includes(Strophe.serialize(disco_iq))).toBe(true);
|
`<query xmlns="http://jabber.org/protocol/disco#info"/></iq>`]);
|
||||||
iq = IQ_stanzas.pop();
|
|
||||||
expect(expected_IQs(disco_iq).includes(Strophe.serialize(disco_iq))).toBe(true);
|
|
||||||
iq = IQ_stanzas.pop();
|
|
||||||
expect(expected_IQs(disco_iq).includes(Strophe.serialize(disco_iq))).toBe(true);
|
|
||||||
|
|
||||||
expect(sent_stanzas.filter(s => (s.nodeName === 'r')).length).toBe(2);
|
const disco_iq = IQ_stanzas.pop();
|
||||||
expect(_converse.session.get('unacked_stanzas').length).toBe(5);
|
expect(expected_IQs(disco_iq).includes(Strophe.serialize(disco_iq))).toBe(true);
|
||||||
|
iq = IQ_stanzas.pop();
|
||||||
|
expect(expected_IQs(disco_iq).includes(Strophe.serialize(disco_iq))).toBe(true);
|
||||||
|
iq = IQ_stanzas.pop();
|
||||||
|
expect(expected_IQs(disco_iq).includes(Strophe.serialize(disco_iq))).toBe(true);
|
||||||
|
|
||||||
// test handling of acks
|
expect(sent_stanzas.filter(s => (s.nodeName === 'r')).length).toBe(2);
|
||||||
let ack = u.toStanza(`<a xmlns="urn:xmpp:sm:3" h="2"/>`);
|
expect(_converse.session.get('unacked_stanzas').length).toBe(5);
|
||||||
_converse.connection._dataRecv(test_utils.createRequest(ack));
|
|
||||||
expect(_converse.session.get('unacked_stanzas').length).toBe(3);
|
|
||||||
|
|
||||||
// test handling of ack requests
|
// test handling of acks
|
||||||
let r = u.toStanza(`<r xmlns="urn:xmpp:sm:3"/>`);
|
let ack = u.toStanza(`<a xmlns="urn:xmpp:sm:3" h="2"/>`);
|
||||||
_converse.connection._dataRecv(test_utils.createRequest(r));
|
_converse.connection._dataRecv(mock.createRequest(ack));
|
||||||
|
expect(_converse.session.get('unacked_stanzas').length).toBe(3);
|
||||||
|
|
||||||
ack = await u.waitUntil(() => sent_stanzas.filter(s => (s.nodeName === 'a')).pop());
|
// test handling of ack requests
|
||||||
expect(Strophe.serialize(ack)).toBe('<a h="1" xmlns="urn:xmpp:sm:3"/>');
|
let r = u.toStanza(`<r xmlns="urn:xmpp:sm:3"/>`);
|
||||||
|
_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"/>');
|
||||||
|
|
||||||
|
|
||||||
const disco_result = $iq({
|
const disco_result = $iq({
|
||||||
'type': 'result',
|
'type': 'result',
|
||||||
'from': 'montague.lit',
|
'from': 'montague.lit',
|
||||||
'to': 'romeo@montague.lit/orchard',
|
'to': 'romeo@montague.lit/orchard',
|
||||||
'id': disco_iq.getAttribute('id'),
|
'id': disco_iq.getAttribute('id'),
|
||||||
}).c('query', {'xmlns': 'http://jabber.org/protocol/disco#info'})
|
}).c('query', {'xmlns': 'http://jabber.org/protocol/disco#info'})
|
||||||
.c('identity', {
|
.c('identity', {
|
||||||
'category': 'server',
|
'category': 'server',
|
||||||
'type': 'im'
|
'type': 'im'
|
||||||
}).up()
|
}).up()
|
||||||
.c('feature', {'var': 'http://jabber.org/protocol/disco#info'}).up()
|
.c('feature', {'var': 'http://jabber.org/protocol/disco#info'}).up()
|
||||||
.c('feature', {'var': 'http://jabber.org/protocol/disco#items'});
|
.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"/>`);
|
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);
|
expect(_converse.session.get('unacked_stanzas').length).toBe(2);
|
||||||
|
|
||||||
r = u.toStanza(`<r xmlns="urn:xmpp:sm:3"/>`);
|
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());
|
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"/>');
|
expect(Strophe.serialize(ack)).toBe('<a h="1" xmlns="urn:xmpp:sm:3"/>');
|
||||||
await _converse.api.waitUntil('rosterInitialized');
|
await _converse.api.waitUntil('rosterInitialized');
|
||||||
|
|
||||||
// test session resumption
|
// test session resumption
|
||||||
_converse.connection.IQ_stanzas = [];
|
_converse.connection.IQ_stanzas = [];
|
||||||
IQ_stanzas = _converse.connection.IQ_stanzas;
|
IQ_stanzas = _converse.connection.IQ_stanzas;
|
||||||
await _converse.api.connection.reconnect();
|
await _converse.api.connection.reconnect();
|
||||||
stanza = await u.waitUntil(() => sent_stanzas.filter(s => (s.tagName === 'resume')).pop());
|
stanza = await u.waitUntil(() => sent_stanzas.filter(s => (s.tagName === 'resume')).pop());
|
||||||
expect(Strophe.serialize(stanza)).toEqual('<resume h="2" previd="some-long-sm-id" xmlns="urn:xmpp:sm:3"/>');
|
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"/>`);
|
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
|
// Another <enable> stanza doesn't get sent out
|
||||||
expect(sent_stanzas.filter(s => (s.tagName === 'enable')).length).toBe(1);
|
expect(sent_stanzas.filter(s => (s.tagName === 'enable')).length).toBe(1);
|
||||||
expect(_converse.session.get('smacks_enabled')).toBe(true);
|
expect(_converse.session.get('smacks_enabled')).toBe(true);
|
||||||
|
|
||||||
await new Promise(resolve => _converse.api.listen.once('reconnected', resolve));
|
await new Promise(resolve => _converse.api.listen.once('reconnected', resolve));
|
||||||
await u.waitUntil(() => IQ_stanzas.length === 1);
|
await u.waitUntil(() => IQ_stanzas.length === 1);
|
||||||
|
|
||||||
// Test that unacked stanzas get resent out
|
// Test that unacked stanzas get resent out
|
||||||
iq = IQ_stanzas.pop();
|
iq = IQ_stanzas.pop();
|
||||||
expect(Strophe.serialize(iq)).toBe(`<iq id="${iq.getAttribute('id')}" type="get" xmlns="jabber:client"><query xmlns="jabber:iq:roster"/></iq>`);
|
expect(Strophe.serialize(iq)).toBe(`<iq id="${iq.getAttribute('id')}" type="get" xmlns="jabber:client"><query xmlns="jabber:iq:roster"/></iq>`);
|
||||||
|
|
||||||
expect(IQ_stanzas.filter(iq => sizzle('query[xmlns="jabber:iq:roster"]', iq).pop()).length).toBe(0);
|
expect(IQ_stanzas.filter(iq => sizzle('query[xmlns="jabber:iq:roster"]', iq).pop()).length).toBe(0);
|
||||||
done();
|
done();
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
|
||||||
it("might not resume and the session will then be reset",
|
it("might not resume and the session will then be reset",
|
||||||
mock.initConverse(
|
mock.initConverse(
|
||||||
['chatBoxesInitialized'],
|
['chatBoxesInitialized'],
|
||||||
{ 'auto_login': false,
|
{ 'auto_login': false,
|
||||||
'enable_smacks': true,
|
'enable_smacks': true,
|
||||||
'show_controlbox_by_default': true,
|
'show_controlbox_by_default': true,
|
||||||
'smacks_max_unacked_stanzas': 2
|
'smacks_max_unacked_stanzas': 2
|
||||||
},
|
},
|
||||||
async function (done, _converse) {
|
async function (done, _converse) {
|
||||||
|
|
||||||
await _converse.api.user.login('romeo@montague.lit/orchard', 'secret');
|
await _converse.api.user.login('romeo@montague.lit/orchard', 'secret');
|
||||||
const sent_stanzas = _converse.connection.sent_stanzas;
|
const sent_stanzas = _converse.connection.sent_stanzas;
|
||||||
let stanza = await u.waitUntil(() => sent_stanzas.filter(s => (s.tagName === 'enable')).pop());
|
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"/>');
|
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"/>`);
|
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
|
// test session resumption
|
||||||
await _converse.api.connection.reconnect();
|
await _converse.api.connection.reconnect();
|
||||||
stanza = await u.waitUntil(() => sent_stanzas.filter(s => (s.tagName === 'resume')).pop());
|
stanza = await u.waitUntil(() => sent_stanzas.filter(s => (s.tagName === 'resume')).pop());
|
||||||
expect(Strophe.serialize(stanza)).toEqual('<resume h="1" previd="some-long-sm-id" xmlns="urn:xmpp:sm:3"/>');
|
expect(Strophe.serialize(stanza)).toEqual('<resume h="1" previd="some-long-sm-id" xmlns="urn:xmpp:sm:3"/>');
|
||||||
|
|
||||||
result = u.toStanza(
|
result = u.toStanza(
|
||||||
`<failed xmlns="urn:xmpp:sm:3" h="another-sequence-number">`+
|
`<failed xmlns="urn:xmpp:sm:3" h="another-sequence-number">`+
|
||||||
`<item-not-found xmlns="urn:ietf:params:xml:ns:xmpp-stanzas"/>`+
|
`<item-not-found xmlns="urn:ietf:params:xml:ns:xmpp-stanzas"/>`+
|
||||||
`</failed>`);
|
`</failed>`);
|
||||||
_converse.connection._dataRecv(test_utils.createRequest(result));
|
_converse.connection._dataRecv(mock.createRequest(result));
|
||||||
|
|
||||||
// Session data gets reset
|
// Session data gets reset
|
||||||
expect(_converse.session.get('smacks_enabled')).toBe(false);
|
expect(_converse.session.get('smacks_enabled')).toBe(false);
|
||||||
expect(_converse.session.get('num_stanzas_handled')).toBe(0);
|
expect(_converse.session.get('num_stanzas_handled')).toBe(0);
|
||||||
expect(_converse.session.get('num_stanzas_handled_by_server')).toBe(0);
|
expect(_converse.session.get('num_stanzas_handled_by_server')).toBe(0);
|
||||||
expect(_converse.session.get('num_stanzas_since_last_ack')).toBe(0);
|
expect(_converse.session.get('num_stanzas_since_last_ack')).toBe(0);
|
||||||
expect(_converse.session.get('unacked_stanzas').length).toBe(0);
|
expect(_converse.session.get('unacked_stanzas').length).toBe(0);
|
||||||
expect(_converse.session.get('roster_cached')).toBeFalsy();
|
expect(_converse.session.get('roster_cached')).toBeFalsy();
|
||||||
|
|
||||||
|
|
||||||
await u.waitUntil(() => sent_stanzas.filter(s => (s.tagName === 'enable')).length === 2);
|
await u.waitUntil(() => sent_stanzas.filter(s => (s.tagName === 'enable')).length === 2);
|
||||||
stanza = sent_stanzas.filter(s => (s.tagName === 'enable')).pop();
|
stanza = sent_stanzas.filter(s => (s.tagName === 'enable')).pop();
|
||||||
expect(Strophe.serialize(stanza)).toEqual('<enable resume="true" xmlns="urn:xmpp:sm:3"/>');
|
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"/>`);
|
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);
|
expect(_converse.session.get('smacks_enabled')).toBe(true);
|
||||||
|
|
||||||
// Check that the roster gets fetched
|
// 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));
|
await new Promise(resolve => _converse.api.listen.once('reconnected', resolve));
|
||||||
done();
|
done();
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
|
||||||
it("can cause MUC messages to be received before chatboxes are initialized",
|
it("can cause MUC messages to be received before chatboxes are initialized",
|
||||||
mock.initConverse(
|
mock.initConverse(
|
||||||
['chatBoxesInitialized'],
|
['chatBoxesInitialized'],
|
||||||
{ 'auto_login': false,
|
{ 'auto_login': false,
|
||||||
'blacklisted_plugins': 'converse-mam',
|
'blacklisted_plugins': 'converse-mam',
|
||||||
'enable_smacks': true,
|
'enable_smacks': true,
|
||||||
'muc_fetch_members': false,
|
'muc_fetch_members': false,
|
||||||
'show_controlbox_by_default': true,
|
'show_controlbox_by_default': true,
|
||||||
'smacks_max_unacked_stanzas': 2
|
'smacks_max_unacked_stanzas': 2
|
||||||
},
|
},
|
||||||
async function (done, _converse) {
|
async function (done, _converse) {
|
||||||
|
|
||||||
const key = "converse-test-session/converse.session-romeo@montague.lit-converse.session-romeo@montague.lit";
|
const key = "converse-test-session/converse.session-romeo@montague.lit-converse.session-romeo@montague.lit";
|
||||||
sessionStorage.setItem(
|
sessionStorage.setItem(
|
||||||
key,
|
key,
|
||||||
JSON.stringify({
|
JSON.stringify({
|
||||||
"id": "converse.session-romeo@montague.lit",
|
"id": "converse.session-romeo@montague.lit",
|
||||||
"jid": "romeo@montague.lit/converse.js-100020907",
|
"jid": "romeo@montague.lit/converse.js-100020907",
|
||||||
"bare_jid": "romeo@montague.lit",
|
"bare_jid": "romeo@montague.lit",
|
||||||
"resource": "converse.js-100020907",
|
"resource": "converse.js-100020907",
|
||||||
"domain": "montague.lit",
|
"domain": "montague.lit",
|
||||||
"active": false,
|
"active": false,
|
||||||
"smacks_enabled": true,
|
"smacks_enabled": true,
|
||||||
"num_stanzas_handled": 580,
|
"num_stanzas_handled": 580,
|
||||||
"num_stanzas_handled_by_server": 525,
|
"num_stanzas_handled_by_server": 525,
|
||||||
"num_stanzas_since_last_ack": 0,
|
"num_stanzas_since_last_ack": 0,
|
||||||
"unacked_stanzas": [],
|
"unacked_stanzas": [],
|
||||||
"smacks_stream_id": "some-long-sm-id",
|
"smacks_stream_id": "some-long-sm-id",
|
||||||
"push_enabled": ["romeo@montague.lit"],
|
"push_enabled": ["romeo@montague.lit"],
|
||||||
"carbons_enabled": true,
|
"carbons_enabled": true,
|
||||||
"roster_cached": true
|
"roster_cached": true
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
const muc_jid = 'lounge@montague.lit';
|
const muc_jid = 'lounge@montague.lit';
|
||||||
const chatkey = `converse.chatboxes-romeo@montague.lit-${muc_jid}`;
|
const chatkey = `converse.chatboxes-romeo@montague.lit-${muc_jid}`;
|
||||||
sessionStorage.setItem('converse.chatboxes-romeo@montague.lit', JSON.stringify([chatkey]));
|
sessionStorage.setItem('converse.chatboxes-romeo@montague.lit', JSON.stringify([chatkey]));
|
||||||
sessionStorage.setItem(chatkey,
|
sessionStorage.setItem(chatkey,
|
||||||
JSON.stringify({
|
JSON.stringify({
|
||||||
hidden: false,
|
hidden: false,
|
||||||
message_type: "groupchat",
|
message_type: "groupchat",
|
||||||
name: "lounge",
|
name: "lounge",
|
||||||
num_unread: 0,
|
num_unread: 0,
|
||||||
type: "chatroom",
|
type: "chatroom",
|
||||||
jid: muc_jid,
|
jid: muc_jid,
|
||||||
id: muc_jid,
|
id: muc_jid,
|
||||||
box_id: "box-YXJnQGNvbmZlcmVuY2UuY2hhdC5leGFtcGxlLm9yZw==",
|
box_id: "box-YXJnQGNvbmZlcmVuY2UuY2hhdC5leGFtcGxlLm9yZw==",
|
||||||
nick: "romeo"
|
nick: "romeo"
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
_converse.no_connection_on_bind = true; // XXX Don't trigger CONNECTED in tests/mock.js
|
_converse.no_connection_on_bind = true; // XXX Don't trigger CONNECTED in tests/mock.js
|
||||||
await _converse.api.user.login('romeo@montague.lit', 'secret');
|
await _converse.api.user.login('romeo@montague.lit', 'secret');
|
||||||
delete _converse.no_connection_on_bind;
|
delete _converse.no_connection_on_bind;
|
||||||
|
|
||||||
const sent_stanzas = _converse.connection.sent_stanzas;
|
const sent_stanzas = _converse.connection.sent_stanzas;
|
||||||
const stanza = await u.waitUntil(() => sent_stanzas.filter(s => (s.tagName === 'resume')).pop());
|
const stanza = await u.waitUntil(() => sent_stanzas.filter(s => (s.tagName === 'resume')).pop());
|
||||||
expect(Strophe.serialize(stanza)).toEqual('<resume h="580" previd="some-long-sm-id" xmlns="urn:xmpp:sm:3"/>');
|
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"/>`);
|
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);
|
expect(_converse.session.get('smacks_enabled')).toBe(true);
|
||||||
|
|
||||||
|
|
||||||
const nick = 'romeo';
|
const nick = 'romeo';
|
||||||
const func = _converse.chatboxes.onChatBoxesFetched;
|
const func = _converse.chatboxes.onChatBoxesFetched;
|
||||||
spyOn(_converse.chatboxes, 'onChatBoxesFetched').and.callFake(collection => {
|
spyOn(_converse.chatboxes, 'onChatBoxesFetched').and.callFake(collection => {
|
||||||
const muc = new _converse.ChatRoom({'jid': muc_jid, 'id': muc_jid, nick}, {'collection': _converse.chatboxes});
|
const muc = new _converse.ChatRoom({'jid': muc_jid, 'id': muc_jid, nick}, {'collection': _converse.chatboxes});
|
||||||
_converse.chatboxes.add(muc);
|
_converse.chatboxes.add(muc);
|
||||||
func.call(_converse.chatboxes, collection);
|
func.call(_converse.chatboxes, collection);
|
||||||
});
|
});
|
||||||
|
|
||||||
// A MUC message gets received
|
// A MUC message gets received
|
||||||
const msg = $msg({
|
const msg = $msg({
|
||||||
from: `${muc_jid}/juliet`,
|
from: `${muc_jid}/juliet`,
|
||||||
id: u.getUniqueId(),
|
id: u.getUniqueId(),
|
||||||
to: 'romeo@montague.lit',
|
to: 'romeo@montague.lit',
|
||||||
type: 'groupchat'
|
type: 'groupchat'
|
||||||
}).c('body').t('First message').tree();
|
}).c('body').t('First message').tree();
|
||||||
|
|
||||||
_converse.connection._dataRecv(test_utils.createRequest(msg));
|
_converse.connection._dataRecv(mock.createRequest(msg));
|
||||||
|
|
||||||
await _converse.api.waitUntil('chatBoxesFetched');
|
await _converse.api.waitUntil('chatBoxesFetched');
|
||||||
const muc = _converse.chatboxes.get(muc_jid);
|
const muc = _converse.chatboxes.get(muc_jid);
|
||||||
await u.waitUntil(() => muc.message_queue.length === 1);
|
await u.waitUntil(() => muc.message_queue.length === 1);
|
||||||
|
|
||||||
const view = _converse.chatboxviews.get(muc_jid);
|
const view = _converse.chatboxviews.get(muc_jid);
|
||||||
await test_utils.getRoomFeatures(_converse, muc_jid);
|
await mock.getRoomFeatures(_converse, muc_jid);
|
||||||
await test_utils.receiveOwnMUCPresence(_converse, muc_jid, nick);
|
await mock.receiveOwnMUCPresence(_converse, muc_jid, nick);
|
||||||
await u.waitUntil(() => (view.model.session.get('connection_status') === converse.ROOMSTATUS.ENTERED));
|
await u.waitUntil(() => (view.model.session.get('connection_status') === converse.ROOMSTATUS.ENTERED));
|
||||||
await view.model.messages.fetched;
|
await view.model.messages.fetched;
|
||||||
|
|
||||||
await u.waitUntil(() => muc.messages.length);
|
await u.waitUntil(() => muc.messages.length);
|
||||||
expect(muc.messages.at(0).get('message')).toBe('First message')
|
expect(muc.messages.at(0).get('message')).toBe('First message')
|
||||||
done();
|
done();
|
||||||
}));
|
}));
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
416
spec/spoilers.js
416
spec/spoilers.js
@ -1,237 +1,239 @@
|
|||||||
window.addEventListener('converse-loaded', () => {
|
/* global mock */
|
||||||
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;
|
|
||||||
|
|
||||||
describe("A spoiler message", function () {
|
describe("A spoiler message", function () {
|
||||||
|
|
||||||
it("can be received with a hint",
|
it("can be received with a hint",
|
||||||
mock.initConverse(
|
mock.initConverse(
|
||||||
['rosterGroupsFetched', 'chatBoxesFetched'], {},
|
['rosterGroupsFetched', 'chatBoxesFetched'], {},
|
||||||
async (done, _converse) => {
|
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';
|
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'>
|
/* <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>
|
* <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>
|
* <spoiler xmlns='urn:xmpp:spoiler:0'>Love story end</spoiler>
|
||||||
* </message>
|
* </message>
|
||||||
*/
|
*/
|
||||||
const spoiler_hint = "Love story end"
|
const spoiler_hint = "Love story end"
|
||||||
const spoiler = "And at the end of the story, both of them die! It is so tragic!";
|
const spoiler = "And at the end of the story, both of them die! It is so tragic!";
|
||||||
const msg = $msg({
|
const $msg = converse.env.$msg;
|
||||||
'xmlns': 'jabber:client',
|
const u = converse.env.utils;
|
||||||
'to': _converse.bare_jid,
|
const msg = $msg({
|
||||||
'from': sender_jid,
|
'xmlns': 'jabber:client',
|
||||||
'type': 'chat'
|
'to': _converse.bare_jid,
|
||||||
}).c('body').t(spoiler).up()
|
'from': sender_jid,
|
||||||
.c('spoiler', {
|
'type': 'chat'
|
||||||
'xmlns': 'urn:xmpp:spoiler:0',
|
}).c('body').t(spoiler).up()
|
||||||
}).t(spoiler_hint)
|
.c('spoiler', {
|
||||||
.tree();
|
'xmlns': 'urn:xmpp:spoiler:0',
|
||||||
_converse.connection._dataRecv(test_utils.createRequest(msg));
|
}).t(spoiler_hint)
|
||||||
await new Promise(resolve => _converse.api.listen.once('chatBoxViewInitialized', resolve));
|
.tree();
|
||||||
const view = _converse.chatboxviews.get(sender_jid);
|
_converse.connection._dataRecv(mock.createRequest(msg));
|
||||||
await new Promise(resolve => view.once('messageInserted', resolve));
|
await new Promise(resolve => _converse.api.listen.once('chatBoxViewInitialized', resolve));
|
||||||
await u.waitUntil(() => view.model.vcard.get('fullname') === 'Mercutio')
|
const view = _converse.chatboxviews.get(sender_jid);
|
||||||
expect(view.el.querySelector('.chat-msg__author').textContent.trim()).toBe('Mercutio');
|
await new Promise(resolve => view.once('messageInserted', resolve));
|
||||||
const message_content = view.el.querySelector('.chat-msg__text');
|
await u.waitUntil(() => view.model.vcard.get('fullname') === 'Mercutio')
|
||||||
expect(message_content.textContent).toBe(spoiler);
|
expect(view.el.querySelector('.chat-msg__author').textContent.trim()).toBe('Mercutio');
|
||||||
const spoiler_hint_el = view.el.querySelector('.spoiler-hint');
|
const message_content = view.el.querySelector('.chat-msg__text');
|
||||||
expect(spoiler_hint_el.textContent).toBe(spoiler_hint);
|
expect(message_content.textContent).toBe(spoiler);
|
||||||
done();
|
const spoiler_hint_el = view.el.querySelector('.spoiler-hint');
|
||||||
}));
|
expect(spoiler_hint_el.textContent).toBe(spoiler_hint);
|
||||||
|
done();
|
||||||
|
}));
|
||||||
|
|
||||||
it("can be received without a hint",
|
it("can be received without a hint",
|
||||||
mock.initConverse(
|
mock.initConverse(
|
||||||
['rosterGroupsFetched', 'chatBoxesFetched'], {},
|
['rosterGroupsFetched', 'chatBoxesFetched'], {},
|
||||||
async (done, _converse) => {
|
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';
|
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'>
|
/* <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>
|
* <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>
|
* <spoiler xmlns='urn:xmpp:spoiler:0'>Love story end</spoiler>
|
||||||
* </message>
|
* </message>
|
||||||
*/
|
*/
|
||||||
const spoiler = "And at the end of the story, both of them die! It is so tragic!";
|
const $msg = converse.env.$msg;
|
||||||
const msg = $msg({
|
const u = converse.env.utils;
|
||||||
'xmlns': 'jabber:client',
|
const spoiler = "And at the end of the story, both of them die! It is so tragic!";
|
||||||
'to': _converse.bare_jid,
|
const msg = $msg({
|
||||||
'from': sender_jid,
|
'xmlns': 'jabber:client',
|
||||||
'type': 'chat'
|
'to': _converse.bare_jid,
|
||||||
}).c('body').t(spoiler).up()
|
'from': sender_jid,
|
||||||
.c('spoiler', {
|
'type': 'chat'
|
||||||
'xmlns': 'urn:xmpp:spoiler:0',
|
}).c('body').t(spoiler).up()
|
||||||
}).tree();
|
.c('spoiler', {
|
||||||
_converse.connection._dataRecv(test_utils.createRequest(msg));
|
'xmlns': 'urn:xmpp:spoiler:0',
|
||||||
await new Promise(resolve => _converse.api.listen.once('chatBoxViewInitialized', resolve));
|
}).tree();
|
||||||
const view = _converse.chatboxviews.get(sender_jid);
|
_converse.connection._dataRecv(mock.createRequest(msg));
|
||||||
await new Promise(resolve => view.model.messages.once('rendered', resolve));
|
await new Promise(resolve => _converse.api.listen.once('chatBoxViewInitialized', resolve));
|
||||||
await u.waitUntil(() => u.isVisible(view.el));
|
const view = _converse.chatboxviews.get(sender_jid);
|
||||||
await u.waitUntil(() => view.model.vcard.get('fullname') === 'Mercutio')
|
await new Promise(resolve => view.model.messages.once('rendered', resolve));
|
||||||
expect(view.el.querySelector('.chat-msg__author').textContent.includes('Mercutio')).toBeTruthy();
|
await u.waitUntil(() => u.isVisible(view.el));
|
||||||
const message_content = view.el.querySelector('.chat-msg__text');
|
await u.waitUntil(() => view.model.vcard.get('fullname') === 'Mercutio')
|
||||||
expect(message_content.textContent).toBe(spoiler);
|
expect(view.el.querySelector('.chat-msg__author').textContent.includes('Mercutio')).toBeTruthy();
|
||||||
const spoiler_hint_el = view.el.querySelector('.spoiler-hint');
|
const message_content = view.el.querySelector('.chat-msg__text');
|
||||||
expect(spoiler_hint_el.textContent).toBe('');
|
expect(message_content.textContent).toBe(spoiler);
|
||||||
done();
|
const spoiler_hint_el = view.el.querySelector('.spoiler-hint');
|
||||||
}));
|
expect(spoiler_hint_el.textContent).toBe('');
|
||||||
|
done();
|
||||||
|
}));
|
||||||
|
|
||||||
it("can be sent without a hint",
|
it("can be sent without a hint",
|
||||||
mock.initConverse(
|
mock.initConverse(
|
||||||
['rosterGroupsFetched', 'chatBoxesFetched'], {},
|
['rosterGroupsFetched', 'chatBoxesFetched'], {},
|
||||||
async (done, _converse) => {
|
async (done, _converse) => {
|
||||||
|
|
||||||
await test_utils.waitForRoster(_converse, 'current', 1);
|
await mock.waitForRoster(_converse, 'current', 1);
|
||||||
test_utils.openControlBox(_converse);
|
mock.openControlBox(_converse);
|
||||||
const contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit';
|
const contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit';
|
||||||
|
|
||||||
// XXX: We need to send a presence from the contact, so that we
|
const { $pres, Strophe} = converse.env;
|
||||||
// have a resource, that resource is then queried to see
|
const u = converse.env.utils;
|
||||||
// whether Strophe.NS.SPOILER is supported, in which case
|
|
||||||
// the spoiler button will appear.
|
|
||||||
const presence = $pres({
|
|
||||||
'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]);
|
|
||||||
const view = _converse.api.chatviews.get(contact_jid);
|
|
||||||
spyOn(_converse.connection, 'send');
|
|
||||||
|
|
||||||
await u.waitUntil(() => view.el.querySelector('.toggle-compose-spoiler'));
|
// XXX: We need to send a presence from the contact, so that we
|
||||||
let spoiler_toggle = view.el.querySelector('.toggle-compose-spoiler');
|
// have a resource, that resource is then queried to see
|
||||||
spoiler_toggle.click();
|
// whether Strophe.NS.SPOILER is supported, in which case
|
||||||
|
// the spoiler button will appear.
|
||||||
|
const presence = $pres({
|
||||||
|
'from': contact_jid+'/phone',
|
||||||
|
'to': 'romeo@montague.lit'
|
||||||
|
});
|
||||||
|
_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');
|
||||||
|
|
||||||
const textarea = view.el.querySelector('.chat-textarea');
|
await u.waitUntil(() => view.el.querySelector('.toggle-compose-spoiler'));
|
||||||
textarea.value = 'This is the spoiler';
|
let spoiler_toggle = view.el.querySelector('.toggle-compose-spoiler');
|
||||||
view.onKeyDown({
|
spoiler_toggle.click();
|
||||||
target: textarea,
|
|
||||||
preventDefault: function preventDefault () {},
|
|
||||||
keyCode: 13
|
|
||||||
});
|
|
||||||
await new Promise(resolve => view.once('messageInserted', resolve));
|
|
||||||
|
|
||||||
/* Test the XML stanza
|
const textarea = view.el.querySelector('.chat-textarea');
|
||||||
*
|
textarea.value = 'This is the spoiler';
|
||||||
* <message from="romeo@montague.lit/orchard"
|
view.onKeyDown({
|
||||||
* to="max.frankfurter@montague.lit"
|
target: textarea,
|
||||||
* type="chat"
|
preventDefault: function preventDefault () {},
|
||||||
* id="4547c38b-d98b-45a5-8f44-b4004dbc335e"
|
keyCode: 13
|
||||||
* xmlns="jabber:client">
|
});
|
||||||
* <body>This is the spoiler</body>
|
await new Promise(resolve => view.once('messageInserted', resolve));
|
||||||
* <active xmlns="http://jabber.org/protocol/chatstates"/>
|
|
||||||
* <spoiler xmlns="urn:xmpp:spoiler:0"/>
|
|
||||||
* </message>"
|
|
||||||
*/
|
|
||||||
const stanza = _converse.connection.send.calls.argsFor(0)[0].tree();
|
|
||||||
const spoiler_el = stanza.querySelector('spoiler[xmlns="urn:xmpp:spoiler:0"]');
|
|
||||||
expect(spoiler_el === null).toBeFalsy();
|
|
||||||
expect(spoiler_el.textContent).toBe('');
|
|
||||||
|
|
||||||
const body_el = stanza.querySelector('body');
|
/* Test the XML stanza
|
||||||
expect(body_el.textContent).toBe('This is the spoiler');
|
*
|
||||||
|
* <message from="romeo@montague.lit/orchard"
|
||||||
|
* to="max.frankfurter@montague.lit"
|
||||||
|
* type="chat"
|
||||||
|
* id="4547c38b-d98b-45a5-8f44-b4004dbc335e"
|
||||||
|
* xmlns="jabber:client">
|
||||||
|
* <body>This is the spoiler</body>
|
||||||
|
* <active xmlns="http://jabber.org/protocol/chatstates"/>
|
||||||
|
* <spoiler xmlns="urn:xmpp:spoiler:0"/>
|
||||||
|
* </message>"
|
||||||
|
*/
|
||||||
|
const stanza = _converse.connection.send.calls.argsFor(0)[0].tree();
|
||||||
|
const spoiler_el = stanza.querySelector('spoiler[xmlns="urn:xmpp:spoiler:0"]');
|
||||||
|
expect(spoiler_el === null).toBeFalsy();
|
||||||
|
expect(spoiler_el.textContent).toBe('');
|
||||||
|
|
||||||
/* Test the HTML spoiler message */
|
const body_el = stanza.querySelector('body');
|
||||||
expect(view.el.querySelector('.chat-msg__author').textContent.trim()).toBe('Romeo Montague');
|
expect(body_el.textContent).toBe('This is the spoiler');
|
||||||
|
|
||||||
const spoiler_msg_el = view.el.querySelector('.chat-msg__text.spoiler');
|
/* Test the HTML spoiler message */
|
||||||
expect(spoiler_msg_el.textContent).toBe('This is the spoiler');
|
expect(view.el.querySelector('.chat-msg__author').textContent.trim()).toBe('Romeo Montague');
|
||||||
expect(_.includes(spoiler_msg_el.classList, 'collapsed')).toBeTruthy();
|
|
||||||
|
|
||||||
spoiler_toggle = view.el.querySelector('.spoiler-toggle');
|
const spoiler_msg_el = view.el.querySelector('.chat-msg__text.spoiler');
|
||||||
expect(spoiler_toggle.textContent).toBe('Show more');
|
expect(spoiler_msg_el.textContent).toBe('This is the spoiler');
|
||||||
spoiler_toggle.click();
|
expect(Array.from(spoiler_msg_el.classList).includes('collapsed')).toBeTruthy();
|
||||||
expect(_.includes(spoiler_msg_el.classList, 'collapsed')).toBeFalsy();
|
|
||||||
expect(spoiler_toggle.textContent).toBe('Show less');
|
|
||||||
spoiler_toggle.click();
|
|
||||||
expect(_.includes(spoiler_msg_el.classList, 'collapsed')).toBeTruthy();
|
|
||||||
done();
|
|
||||||
}));
|
|
||||||
|
|
||||||
it("can be sent with a hint",
|
spoiler_toggle = view.el.querySelector('.spoiler-toggle');
|
||||||
mock.initConverse(
|
expect(spoiler_toggle.textContent).toBe('Show more');
|
||||||
['rosterGroupsFetched', 'chatBoxesFetched'], {},
|
spoiler_toggle.click();
|
||||||
async (done, _converse) => {
|
expect(Array.from(spoiler_msg_el.classList).includes('collapsed')).toBeFalsy();
|
||||||
|
expect(spoiler_toggle.textContent).toBe('Show less');
|
||||||
|
spoiler_toggle.click();
|
||||||
|
expect(Array.from(spoiler_msg_el.classList).includes('collapsed')).toBeTruthy();
|
||||||
|
done();
|
||||||
|
}));
|
||||||
|
|
||||||
await test_utils.waitForRoster(_converse, 'current', 1);
|
it("can be sent with a hint",
|
||||||
test_utils.openControlBox(_converse);
|
mock.initConverse(
|
||||||
const contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit';
|
['rosterGroupsFetched', 'chatBoxesFetched'], {},
|
||||||
|
async (done, _converse) => {
|
||||||
|
|
||||||
// XXX: We need to send a presence from the contact, so that we
|
await mock.waitForRoster(_converse, 'current', 1);
|
||||||
// have a resource, that resource is then queried to see
|
mock.openControlBox(_converse);
|
||||||
// whether Strophe.NS.SPOILER is supported, in which case
|
const contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit';
|
||||||
// the spoiler button will appear.
|
|
||||||
const presence = $pres({
|
|
||||||
'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]);
|
|
||||||
const view = _converse.api.chatviews.get(contact_jid);
|
|
||||||
|
|
||||||
await u.waitUntil(() => view.el.querySelector('.toggle-compose-spoiler'));
|
const { $pres, Strophe} = converse.env;
|
||||||
let spoiler_toggle = view.el.querySelector('.toggle-compose-spoiler');
|
const u = converse.env.utils;
|
||||||
spoiler_toggle.click();
|
|
||||||
|
|
||||||
spyOn(_converse.connection, 'send');
|
// XXX: We need to send a presence from the contact, so that we
|
||||||
|
// have a resource, that resource is then queried to see
|
||||||
|
// whether Strophe.NS.SPOILER is supported, in which case
|
||||||
|
// the spoiler button will appear.
|
||||||
|
const presence = $pres({
|
||||||
|
'from': contact_jid+'/phone',
|
||||||
|
'to': 'romeo@montague.lit'
|
||||||
|
});
|
||||||
|
_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);
|
||||||
|
|
||||||
const textarea = view.el.querySelector('.chat-textarea');
|
await u.waitUntil(() => view.el.querySelector('.toggle-compose-spoiler'));
|
||||||
textarea.value = 'This is the spoiler';
|
let spoiler_toggle = view.el.querySelector('.toggle-compose-spoiler');
|
||||||
const hint_input = view.el.querySelector('.spoiler-hint');
|
spoiler_toggle.click();
|
||||||
hint_input.value = 'This is the hint';
|
|
||||||
|
|
||||||
view.onKeyDown({
|
spyOn(_converse.connection, 'send');
|
||||||
target: textarea,
|
|
||||||
preventDefault: function preventDefault () {},
|
|
||||||
keyCode: 13
|
|
||||||
});
|
|
||||||
await new Promise(resolve => view.once('messageInserted', resolve));
|
|
||||||
|
|
||||||
/* Test the XML stanza
|
const textarea = view.el.querySelector('.chat-textarea');
|
||||||
*
|
textarea.value = 'This is the spoiler';
|
||||||
* <message from="romeo@montague.lit/orchard"
|
const hint_input = view.el.querySelector('.spoiler-hint');
|
||||||
* to="max.frankfurter@montague.lit"
|
hint_input.value = 'This is the hint';
|
||||||
* type="chat"
|
|
||||||
* id="4547c38b-d98b-45a5-8f44-b4004dbc335e"
|
|
||||||
* xmlns="jabber:client">
|
|
||||||
* <body>This is the spoiler</body>
|
|
||||||
* <active xmlns="http://jabber.org/protocol/chatstates"/>
|
|
||||||
* <spoiler xmlns="urn:xmpp:spoiler:0">This is the hint</spoiler>
|
|
||||||
* </message>"
|
|
||||||
*/
|
|
||||||
const stanza = _converse.connection.send.calls.argsFor(0)[0].tree();
|
|
||||||
const spoiler_el = stanza.querySelector('spoiler[xmlns="urn:xmpp:spoiler:0"]');
|
|
||||||
|
|
||||||
expect(spoiler_el === null).toBeFalsy();
|
view.onKeyDown({
|
||||||
expect(spoiler_el.textContent).toBe('This is the hint');
|
target: textarea,
|
||||||
|
preventDefault: function preventDefault () {},
|
||||||
|
keyCode: 13
|
||||||
|
});
|
||||||
|
await new Promise(resolve => view.once('messageInserted', resolve));
|
||||||
|
|
||||||
const body_el = stanza.querySelector('body');
|
/* Test the XML stanza
|
||||||
expect(body_el.textContent).toBe('This is the spoiler');
|
*
|
||||||
|
* <message from="romeo@montague.lit/orchard"
|
||||||
|
* to="max.frankfurter@montague.lit"
|
||||||
|
* type="chat"
|
||||||
|
* id="4547c38b-d98b-45a5-8f44-b4004dbc335e"
|
||||||
|
* xmlns="jabber:client">
|
||||||
|
* <body>This is the spoiler</body>
|
||||||
|
* <active xmlns="http://jabber.org/protocol/chatstates"/>
|
||||||
|
* <spoiler xmlns="urn:xmpp:spoiler:0">This is the hint</spoiler>
|
||||||
|
* </message>"
|
||||||
|
*/
|
||||||
|
const stanza = _converse.connection.send.calls.argsFor(0)[0].tree();
|
||||||
|
const spoiler_el = stanza.querySelector('spoiler[xmlns="urn:xmpp:spoiler:0"]');
|
||||||
|
|
||||||
/* Test the HTML spoiler message */
|
expect(spoiler_el === null).toBeFalsy();
|
||||||
expect(view.el.querySelector('.chat-msg__author').textContent.trim()).toBe('Romeo Montague');
|
expect(spoiler_el.textContent).toBe('This is the hint');
|
||||||
|
|
||||||
const spoiler_msg_el = view.el.querySelector('.chat-msg__text.spoiler');
|
const body_el = stanza.querySelector('body');
|
||||||
expect(spoiler_msg_el.textContent).toBe('This is the spoiler');
|
expect(body_el.textContent).toBe('This is the spoiler');
|
||||||
expect(_.includes(spoiler_msg_el.classList, 'collapsed')).toBeTruthy();
|
|
||||||
|
|
||||||
spoiler_toggle = view.el.querySelector('.spoiler-toggle');
|
/* Test the HTML spoiler message */
|
||||||
expect(spoiler_toggle.textContent).toBe('Show more');
|
expect(view.el.querySelector('.chat-msg__author').textContent.trim()).toBe('Romeo Montague');
|
||||||
spoiler_toggle.click();
|
|
||||||
expect(_.includes(spoiler_msg_el.classList, 'collapsed')).toBeFalsy();
|
const spoiler_msg_el = view.el.querySelector('.chat-msg__text.spoiler');
|
||||||
expect(spoiler_toggle.textContent).toBe('Show less');
|
expect(spoiler_msg_el.textContent).toBe('This is the spoiler');
|
||||||
spoiler_toggle.click();
|
expect(Array.from(spoiler_msg_el.classList).includes('collapsed')).toBeTruthy();
|
||||||
expect(_.includes(spoiler_msg_el.classList, 'collapsed')).toBeTruthy();
|
|
||||||
done();
|
spoiler_toggle = view.el.querySelector('.spoiler-toggle');
|
||||||
}));
|
expect(spoiler_toggle.textContent).toBe('Show more');
|
||||||
});
|
spoiler_toggle.click();
|
||||||
|
expect(Array.from(spoiler_msg_el.classList).includes('collapsed')).toBeFalsy();
|
||||||
|
expect(spoiler_toggle.textContent).toBe('Show less');
|
||||||
|
spoiler_toggle.click();
|
||||||
|
expect(Array.from(spoiler_msg_el.classList).includes('collapsed')).toBeTruthy();
|
||||||
|
done();
|
||||||
|
}));
|
||||||
});
|
});
|
||||||
|
@ -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();
|
|
||||||
}));
|
|
||||||
});
|
|
||||||
}));
|
|
@ -1,77 +1,75 @@
|
|||||||
window.addEventListener('converse-loaded', () => {
|
/*global mock */
|
||||||
const mock = window.mock;
|
|
||||||
const test_utils = window.test_utils;
|
|
||||||
const u = converse.env.utils;
|
|
||||||
|
|
||||||
return describe("The User Details Modal", function () {
|
const u = converse.env.utils;
|
||||||
|
|
||||||
it("can be used to remove a contact",
|
describe("The User Details Modal", function () {
|
||||||
mock.initConverse(
|
|
||||||
['rosterGroupsFetched', 'chatBoxesFetched'], {},
|
|
||||||
async function (done, _converse) {
|
|
||||||
|
|
||||||
await test_utils.waitForRoster(_converse, 'current', 1);
|
it("can be used to remove a contact",
|
||||||
_converse.api.trigger('rosterContactsFetched');
|
mock.initConverse(
|
||||||
|
['rosterGroupsFetched', 'chatBoxesFetched'], {},
|
||||||
|
async function (done, _converse) {
|
||||||
|
|
||||||
const contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit';
|
await mock.waitForRoster(_converse, 'current', 1);
|
||||||
await test_utils.openChatBoxFor(_converse, contact_jid);
|
_converse.api.trigger('rosterContactsFetched');
|
||||||
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');
|
|
||||||
show_modal_button.click();
|
|
||||||
const modal = view.user_details_modal;
|
|
||||||
await u.waitUntil(() => u.isVisible(modal.el), 1000);
|
|
||||||
spyOn(window, 'confirm').and.returnValue(true);
|
|
||||||
spyOn(view.model.contact, 'removeFromRoster').and.callFake(callback => callback());
|
|
||||||
let remove_contact_button = modal.el.querySelector('button.remove-contact');
|
|
||||||
expect(u.isVisible(remove_contact_button)).toBeTruthy();
|
|
||||||
remove_contact_button.click();
|
|
||||||
await u.waitUntil(() => modal.el.getAttribute('aria-hidden'), 1000);
|
|
||||||
await u.waitUntil(() => !u.isVisible(modal.el));
|
|
||||||
show_modal_button = view.el.querySelector('.show-user-details-modal');
|
|
||||||
show_modal_button.click();
|
|
||||||
remove_contact_button = modal.el.querySelector('button.remove-contact');
|
|
||||||
expect(remove_contact_button === null).toBeTruthy();
|
|
||||||
done();
|
|
||||||
}));
|
|
||||||
|
|
||||||
it("shows an alert when an error happened while removing the contact",
|
const contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit';
|
||||||
mock.initConverse(['rosterGroupsFetched'], {}, async function (done, _converse) {
|
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');
|
||||||
|
show_modal_button.click();
|
||||||
|
const modal = view.user_details_modal;
|
||||||
|
await u.waitUntil(() => u.isVisible(modal.el), 1000);
|
||||||
|
spyOn(window, 'confirm').and.returnValue(true);
|
||||||
|
spyOn(view.model.contact, 'removeFromRoster').and.callFake(callback => callback());
|
||||||
|
let remove_contact_button = modal.el.querySelector('button.remove-contact');
|
||||||
|
expect(u.isVisible(remove_contact_button)).toBeTruthy();
|
||||||
|
remove_contact_button.click();
|
||||||
|
await u.waitUntil(() => modal.el.getAttribute('aria-hidden'), 1000);
|
||||||
|
await u.waitUntil(() => !u.isVisible(modal.el));
|
||||||
|
show_modal_button = view.el.querySelector('.show-user-details-modal');
|
||||||
|
show_modal_button.click();
|
||||||
|
remove_contact_button = modal.el.querySelector('button.remove-contact');
|
||||||
|
expect(remove_contact_button === null).toBeTruthy();
|
||||||
|
done();
|
||||||
|
}));
|
||||||
|
|
||||||
await test_utils.waitForRoster(_converse, 'current', 1);
|
it("shows an alert when an error happened while removing the contact",
|
||||||
_converse.api.trigger('rosterContactsFetched');
|
mock.initConverse(['rosterGroupsFetched'], {}, async function (done, _converse) {
|
||||||
|
|
||||||
const contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit';
|
await mock.waitForRoster(_converse, 'current', 1);
|
||||||
await test_utils.openChatBoxFor(_converse, contact_jid)
|
_converse.api.trigger('rosterContactsFetched');
|
||||||
const view = _converse.chatboxviews.get(contact_jid);
|
|
||||||
let show_modal_button = view.el.querySelector('.show-user-details-modal');
|
|
||||||
show_modal_button.click();
|
|
||||||
const modal = view.user_details_modal;
|
|
||||||
await u.waitUntil(() => u.isVisible(modal.el), 2000);
|
|
||||||
spyOn(window, 'confirm').and.returnValue(true);
|
|
||||||
|
|
||||||
spyOn(view.model.contact, 'removeFromRoster').and.callFake((callback, errback) => errback());
|
const contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit';
|
||||||
let remove_contact_button = modal.el.querySelector('button.remove-contact');
|
await mock.openChatBoxFor(_converse, contact_jid)
|
||||||
expect(u.isVisible(remove_contact_button)).toBeTruthy();
|
const view = _converse.chatboxviews.get(contact_jid);
|
||||||
remove_contact_button.click();
|
let show_modal_button = view.el.querySelector('.show-user-details-modal');
|
||||||
await u.waitUntil(() => u.isVisible(document.querySelector('.alert-danger')), 2000);
|
show_modal_button.click();
|
||||||
|
const modal = view.user_details_modal;
|
||||||
|
await u.waitUntil(() => u.isVisible(modal.el), 2000);
|
||||||
|
spyOn(window, 'confirm').and.returnValue(true);
|
||||||
|
|
||||||
const header = document.querySelector('.alert-danger .modal-title');
|
spyOn(view.model.contact, 'removeFromRoster').and.callFake((callback, errback) => errback());
|
||||||
expect(header.textContent).toBe("Error");
|
let remove_contact_button = modal.el.querySelector('button.remove-contact');
|
||||||
expect(u.ancestor(header, '.modal-content').querySelector('.modal-body p').textContent.trim())
|
expect(u.isVisible(remove_contact_button)).toBeTruthy();
|
||||||
.toBe("Sorry, there was an error while trying to remove Mercutio as a contact.");
|
remove_contact_button.click();
|
||||||
document.querySelector('.alert-danger button.close').click();
|
await u.waitUntil(() => u.isVisible(document.querySelector('.alert-danger')), 2000);
|
||||||
show_modal_button = view.el.querySelector('.show-user-details-modal');
|
|
||||||
show_modal_button.click();
|
|
||||||
await u.waitUntil(() => u.isVisible(modal.el), 2000)
|
|
||||||
|
|
||||||
show_modal_button = view.el.querySelector('.show-user-details-modal');
|
const header = document.querySelector('.alert-danger .modal-title');
|
||||||
show_modal_button.click();
|
expect(header.textContent).toBe("Error");
|
||||||
await u.waitUntil(() => u.isVisible(modal.el), 2000)
|
expect(u.ancestor(header, '.modal-content').querySelector('.modal-body p').textContent.trim())
|
||||||
|
.toBe("Sorry, there was an error while trying to remove Mercutio as a contact.");
|
||||||
|
document.querySelector('.alert-danger button.close').click();
|
||||||
|
show_modal_button = view.el.querySelector('.show-user-details-modal');
|
||||||
|
show_modal_button.click();
|
||||||
|
await u.waitUntil(() => u.isVisible(modal.el), 2000)
|
||||||
|
|
||||||
remove_contact_button = modal.el.querySelector('button.remove-contact');
|
show_modal_button = view.el.querySelector('.show-user-details-modal');
|
||||||
expect(u.isVisible(remove_contact_button)).toBeTruthy();
|
show_modal_button.click();
|
||||||
done();
|
await u.waitUntil(() => u.isVisible(modal.el), 2000)
|
||||||
}));
|
|
||||||
});
|
remove_contact_button = modal.el.querySelector('button.remove-contact');
|
||||||
|
expect(u.isVisible(remove_contact_button)).toBeTruthy();
|
||||||
|
done();
|
||||||
|
}));
|
||||||
});
|
});
|
||||||
|
108
spec/utils.js
108
spec/utils.js
@ -1,62 +1,58 @@
|
|||||||
window.addEventListener('converse-loaded', () => {
|
describe("Converse.js Utilities", function() {
|
||||||
const utils = converse.env.utils;
|
|
||||||
const _ = converse.env._;
|
|
||||||
|
|
||||||
return describe("Converse.js Utilities", function() {
|
it("applySiteSettings: recursively applies user settings", function () {
|
||||||
|
const context = {};
|
||||||
|
const settings = {
|
||||||
|
show_toolbar: true,
|
||||||
|
chatview_avatar_width: 32,
|
||||||
|
chatview_avatar_height: 32,
|
||||||
|
auto_join_rooms: [],
|
||||||
|
visible_toolbar_buttons: {
|
||||||
|
'emojis': true,
|
||||||
|
'call': false,
|
||||||
|
'clear': true,
|
||||||
|
'toggle_occupants': true
|
||||||
|
}
|
||||||
|
};
|
||||||
|
Object.assign(context, settings);
|
||||||
|
|
||||||
it("applySiteSettings: recursively applies user settings", function () {
|
let user_settings = {
|
||||||
var context = {};
|
something_else: 'xxx',
|
||||||
var settings = {
|
show_toolbar: false,
|
||||||
show_toolbar: true,
|
chatview_avatar_width: 32,
|
||||||
chatview_avatar_width: 32,
|
chatview_avatar_height: 48,
|
||||||
chatview_avatar_height: 32,
|
auto_join_rooms: [
|
||||||
auto_join_rooms: [],
|
'anonymous@conference.nomnom.im',
|
||||||
visible_toolbar_buttons: {
|
],
|
||||||
'emojis': true,
|
visible_toolbar_buttons: {
|
||||||
'call': false,
|
'emojis': false,
|
||||||
'clear': true,
|
'call': false,
|
||||||
'toggle_occupants': true
|
'toggle_occupants':false,
|
||||||
}
|
'invalid': false
|
||||||
};
|
}
|
||||||
_.extend(context, settings);
|
};
|
||||||
|
const utils = converse.env.utils;
|
||||||
|
utils.applySiteSettings(context, settings, user_settings);
|
||||||
|
|
||||||
var user_settings = {
|
expect(context.something_else).toBeUndefined();
|
||||||
something_else: 'xxx',
|
expect(context.show_toolbar).toBeFalsy();
|
||||||
show_toolbar: false,
|
expect(context.chatview_avatar_width).toBe(32);
|
||||||
chatview_avatar_width: 32,
|
expect(context.chatview_avatar_height).toBe(48);
|
||||||
chatview_avatar_height: 48,
|
expect(Object.keys(context.visible_toolbar_buttons)).toEqual(Object.keys(settings.visible_toolbar_buttons));
|
||||||
auto_join_rooms: [
|
expect(context.visible_toolbar_buttons.emojis).toBeFalsy();
|
||||||
'anonymous@conference.nomnom.im',
|
expect(context.visible_toolbar_buttons.call).toBeFalsy();
|
||||||
],
|
expect(context.visible_toolbar_buttons.toggle_occupants).toBeFalsy();
|
||||||
visible_toolbar_buttons: {
|
expect(context.visible_toolbar_buttons.invalid).toBeFalsy();
|
||||||
'emojis': false,
|
expect(context.auto_join_rooms.length).toBe(1);
|
||||||
'call': false,
|
expect(context.auto_join_rooms[0]).toBe('anonymous@conference.nomnom.im');
|
||||||
'toggle_occupants':false,
|
|
||||||
'invalid': false
|
|
||||||
}
|
|
||||||
};
|
|
||||||
utils.applySiteSettings(context, settings, user_settings);
|
|
||||||
|
|
||||||
expect(context.something_else).toBeUndefined();
|
user_settings = {
|
||||||
expect(context.show_toolbar).toBeFalsy();
|
visible_toolbar_buttons: {
|
||||||
expect(context.chatview_avatar_width).toBe(32);
|
'toggle_occupants': true
|
||||||
expect(context.chatview_avatar_height).toBe(48);
|
}
|
||||||
expect(_.keys(context.visible_toolbar_buttons)).toEqual(_.keys(settings.visible_toolbar_buttons));
|
};
|
||||||
expect(context.visible_toolbar_buttons.emojis).toBeFalsy();
|
utils.applySiteSettings(context, settings, user_settings);
|
||||||
expect(context.visible_toolbar_buttons.call).toBeFalsy();
|
expect(Object.keys(context.visible_toolbar_buttons)).toEqual(Object.keys(settings.visible_toolbar_buttons));
|
||||||
expect(context.visible_toolbar_buttons.toggle_occupants).toBeFalsy();
|
expect(context.visible_toolbar_buttons.toggle_occupants).toBeTruthy();
|
||||||
expect(context.visible_toolbar_buttons.invalid).toBeFalsy();
|
|
||||||
expect(context.auto_join_rooms.length).toBe(1);
|
|
||||||
expect(context.auto_join_rooms[0]).toBe('anonymous@conference.nomnom.im');
|
|
||||||
|
|
||||||
user_settings = {
|
|
||||||
visible_toolbar_buttons: {
|
|
||||||
'toggle_occupants': true
|
|
||||||
}
|
|
||||||
};
|
|
||||||
utils.applySiteSettings(context, settings, user_settings);
|
|
||||||
expect(_.keys(context.visible_toolbar_buttons)).toEqual(_.keys(settings.visible_toolbar_buttons));
|
|
||||||
expect(context.visible_toolbar_buttons.toggle_occupants).toBeTruthy();
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -1,23 +1,22 @@
|
|||||||
window.addEventListener('converse-loaded', () => {
|
/*global mock */
|
||||||
const mock = window.mock;
|
|
||||||
const u = converse.env.utils;
|
|
||||||
|
|
||||||
return describe("The XMPPStatus model", function () {
|
const u = converse.env.utils;
|
||||||
|
|
||||||
it("won't send <show>online</show> when setting a custom status message",
|
describe("The XMPPStatus model", function () {
|
||||||
mock.initConverse(async (done, _converse) => {
|
|
||||||
_converse.xmppstatus.save({'status': 'online'});
|
it("won't send <show>online</show> when setting a custom status message",
|
||||||
spyOn(_converse.connection, 'send');
|
mock.initConverse(async (done, _converse) => {
|
||||||
_converse.api.user.status.message.set("I'm also happy!");
|
_converse.xmppstatus.save({'status': 'online'});
|
||||||
await u.waitUntil(() => _converse.connection.send.calls.count());
|
spyOn(_converse.connection, 'send');
|
||||||
const stanza = _converse.connection.send.calls.argsFor(0)[0].tree();
|
_converse.api.user.status.message.set("I'm also happy!");
|
||||||
expect(stanza.childNodes.length).toBe(3);
|
await u.waitUntil(() => _converse.connection.send.calls.count());
|
||||||
expect(stanza.querySelectorAll('status').length).toBe(1);
|
const stanza = _converse.connection.send.calls.argsFor(0)[0].tree();
|
||||||
expect(stanza.querySelector('status').textContent).toBe("I'm also happy!");
|
expect(stanza.childNodes.length).toBe(3);
|
||||||
expect(stanza.querySelectorAll('show').length).toBe(0);
|
expect(stanza.querySelectorAll('status').length).toBe(1);
|
||||||
expect(stanza.querySelectorAll('priority').length).toBe(1);
|
expect(stanza.querySelector('status').textContent).toBe("I'm also happy!");
|
||||||
expect(stanza.querySelector('priority').textContent).toBe('0');
|
expect(stanza.querySelectorAll('show').length).toBe(0);
|
||||||
done();
|
expect(stanza.querySelectorAll('priority').length).toBe(1);
|
||||||
}));
|
expect(stanza.querySelector('priority').textContent).toBe('0');
|
||||||
});
|
done();
|
||||||
|
}));
|
||||||
});
|
});
|
||||||
|
394
spec/xss.js
394
spec/xss.js
@ -1,244 +1,242 @@
|
|||||||
window.addEventListener('converse-loaded', () => {
|
/*global mock */
|
||||||
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;
|
|
||||||
|
|
||||||
describe("XSS", function () {
|
const $pres = converse.env.$pres;
|
||||||
describe("A Chat Message", function () {
|
const sizzle = converse.env.sizzle;
|
||||||
|
const u = converse.env.utils;
|
||||||
|
|
||||||
it("will escape IMG payload XSS attempts",
|
describe("XSS", function () {
|
||||||
mock.initConverse(
|
describe("A Chat Message", function () {
|
||||||
['rosterGroupsFetched', 'chatBoxesFetched'], {},
|
|
||||||
async function (done, _converse) {
|
|
||||||
|
|
||||||
spyOn(window, 'alert').and.callThrough();
|
it("will escape IMG payload XSS attempts",
|
||||||
await test_utils.waitForRoster(_converse, 'current');
|
mock.initConverse(
|
||||||
await test_utils.openControlBox(_converse);
|
['rosterGroupsFetched', 'chatBoxesFetched'], {},
|
||||||
|
async function (done, _converse) {
|
||||||
|
|
||||||
const contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit';
|
spyOn(window, 'alert').and.callThrough();
|
||||||
await test_utils.openChatBoxFor(_converse, contact_jid)
|
await mock.waitForRoster(_converse, 'current');
|
||||||
const view = _converse.api.chatviews.get(contact_jid);
|
await mock.openControlBox(_converse);
|
||||||
|
|
||||||
let message = "<img src=x onerror=alert('XSS');>";
|
const contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit';
|
||||||
await test_utils.sendMessage(view, message);
|
await mock.openChatBoxFor(_converse, contact_jid)
|
||||||
let msg = sizzle('.chat-content .chat-msg:last .chat-msg__text', view.el).pop();
|
const view = _converse.api.chatviews.get(contact_jid);
|
||||||
expect(msg.textContent).toEqual(message);
|
|
||||||
expect(msg.innerHTML).toEqual("<img src=x onerror=alert('XSS');>");
|
|
||||||
expect(window.alert).not.toHaveBeenCalled();
|
|
||||||
|
|
||||||
message = "<img src=x onerror=alert('XSS')//";
|
let 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();
|
let msg = sizzle('.chat-content .chat-msg:last .chat-msg__text', view.el).pop();
|
||||||
expect(msg.textContent).toEqual(message);
|
expect(msg.textContent).toEqual(message);
|
||||||
expect(msg.innerHTML).toEqual("<img src=x onerror=alert('XSS')//");
|
expect(msg.innerHTML).toEqual("<img src=x onerror=alert('XSS');>");
|
||||||
|
expect(window.alert).not.toHaveBeenCalled();
|
||||||
|
|
||||||
message = "<img src=x onerror=alert(String.fromCharCode(88,83,83));>";
|
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();
|
msg = sizzle('.chat-content .chat-msg:last .chat-msg__text', view.el).pop();
|
||||||
expect(msg.textContent).toEqual(message);
|
expect(msg.textContent).toEqual(message);
|
||||||
expect(msg.innerHTML).toEqual("<img src=x onerror=alert(String.fromCharCode(88,83,83));>");
|
expect(msg.innerHTML).toEqual("<img src=x onerror=alert('XSS')//");
|
||||||
|
|
||||||
message = "<img src=x oneonerrorrror=alert(String.fromCharCode(88,83,83));>";
|
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();
|
msg = sizzle('.chat-content .chat-msg:last .chat-msg__text', view.el).pop();
|
||||||
expect(msg.textContent).toEqual(message);
|
expect(msg.textContent).toEqual(message);
|
||||||
expect(msg.innerHTML).toEqual("<img src=x oneonerrorrror=alert(String.fromCharCode(88,83,83));>");
|
expect(msg.innerHTML).toEqual("<img src=x onerror=alert(String.fromCharCode(88,83,83));>");
|
||||||
|
|
||||||
message = "<img src=x:alert(alt) onerror=eval(src) alt=xss>";
|
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();
|
msg = sizzle('.chat-content .chat-msg:last .chat-msg__text', view.el).pop();
|
||||||
expect(msg.textContent).toEqual(message);
|
expect(msg.textContent).toEqual(message);
|
||||||
expect(msg.innerHTML).toEqual("<img src=x:alert(alt) onerror=eval(src) alt=xss>");
|
expect(msg.innerHTML).toEqual("<img src=x oneonerrorrror=alert(String.fromCharCode(88,83,83));>");
|
||||||
|
|
||||||
message = "><img src=x onerror=alert('XSS');>";
|
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();
|
msg = sizzle('.chat-content .chat-msg:last .chat-msg__text', view.el).pop();
|
||||||
expect(msg.textContent).toEqual(message);
|
expect(msg.textContent).toEqual(message);
|
||||||
expect(msg.innerHTML).toEqual("><img src=x onerror=alert('XSS');>");
|
expect(msg.innerHTML).toEqual("<img src=x:alert(alt) onerror=eval(src) alt=xss>");
|
||||||
|
|
||||||
message = "><img src=x onerror=alert(String.fromCharCode(88,83,83));>";
|
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();
|
msg = sizzle('.chat-content .chat-msg:last .chat-msg__text', view.el).pop();
|
||||||
expect(msg.textContent).toEqual(message);
|
expect(msg.textContent).toEqual(message);
|
||||||
expect(msg.innerHTML).toEqual("><img src=x onerror=alert(String.fromCharCode(88,83,83));>");
|
expect(msg.innerHTML).toEqual("><img src=x onerror=alert('XSS');>");
|
||||||
|
|
||||||
expect(window.alert).not.toHaveBeenCalled();
|
message = "><img src=x onerror=alert(String.fromCharCode(88,83,83));>";
|
||||||
done();
|
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("><img src=x onerror=alert(String.fromCharCode(88,83,83));>");
|
||||||
|
|
||||||
it("will escape SVG payload XSS attempts",
|
expect(window.alert).not.toHaveBeenCalled();
|
||||||
mock.initConverse(
|
done();
|
||||||
['rosterGroupsFetched', 'chatBoxesFetched'], {},
|
}));
|
||||||
async function (done, _converse) {
|
|
||||||
|
|
||||||
spyOn(window, 'alert').and.callThrough();
|
it("will escape SVG payload XSS attempts",
|
||||||
await test_utils.waitForRoster(_converse, 'current');
|
mock.initConverse(
|
||||||
await test_utils.openControlBox(_converse);
|
['rosterGroupsFetched', 'chatBoxesFetched'], {},
|
||||||
|
async function (done, _converse) {
|
||||||
|
|
||||||
const contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit';
|
spyOn(window, 'alert').and.callThrough();
|
||||||
await test_utils.openChatBoxFor(_converse, contact_jid)
|
await mock.waitForRoster(_converse, 'current');
|
||||||
const view = _converse.api.chatviews.get(contact_jid);
|
await mock.openControlBox(_converse);
|
||||||
|
|
||||||
let message = "<svgonload=alert(1)>";
|
const contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit';
|
||||||
await test_utils.sendMessage(view, message);
|
await mock.openChatBoxFor(_converse, contact_jid)
|
||||||
let msg = sizzle('.chat-content .chat-msg:last .chat-msg__text', view.el).pop();
|
const view = _converse.api.chatviews.get(contact_jid);
|
||||||
expect(msg.textContent).toEqual(message);
|
|
||||||
expect(msg.innerHTML).toEqual('<svgonload=alert(1)>');
|
|
||||||
|
|
||||||
message = "<svg/onload=alert('XSS')>";
|
let message = "<svgonload=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();
|
let msg = sizzle('.chat-content .chat-msg:last .chat-msg__text', view.el).pop();
|
||||||
expect(msg.textContent).toEqual(message);
|
expect(msg.textContent).toEqual(message);
|
||||||
expect(msg.innerHTML).toEqual("<svg/onload=alert('XSS')>");
|
expect(msg.innerHTML).toEqual('<svgonload=alert(1)>');
|
||||||
|
|
||||||
message = "<svg onload=alert(1)//";
|
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();
|
msg = sizzle('.chat-content .chat-msg:last .chat-msg__text', view.el).pop();
|
||||||
expect(msg.textContent).toEqual(message);
|
expect(msg.textContent).toEqual(message);
|
||||||
expect(msg.innerHTML).toEqual("<svg onload=alert(1)//");
|
expect(msg.innerHTML).toEqual("<svg/onload=alert('XSS')>");
|
||||||
|
|
||||||
message = "<svg/onload=alert(String.fromCharCode(88,83,83))>";
|
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();
|
msg = sizzle('.chat-content .chat-msg:last .chat-msg__text', view.el).pop();
|
||||||
expect(msg.textContent).toEqual(message);
|
expect(msg.textContent).toEqual(message);
|
||||||
expect(msg.innerHTML).toEqual("<svg/onload=alert(String.fromCharCode(88,83,83))>");
|
expect(msg.innerHTML).toEqual("<svg onload=alert(1)//");
|
||||||
|
|
||||||
message = "<svg id=alert(1) onload=eval(id)>";
|
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();
|
msg = sizzle('.chat-content .chat-msg:last .chat-msg__text', view.el).pop();
|
||||||
expect(msg.textContent).toEqual(message);
|
expect(msg.textContent).toEqual(message);
|
||||||
expect(msg.innerHTML).toEqual("<svg id=alert(1) onload=eval(id)>");
|
expect(msg.innerHTML).toEqual("<svg/onload=alert(String.fromCharCode(88,83,83))>");
|
||||||
|
|
||||||
message = '"><svg/onload=alert(String.fromCharCode(88,83,83))>';
|
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();
|
msg = sizzle('.chat-content .chat-msg:last .chat-msg__text', view.el).pop();
|
||||||
expect(msg.textContent).toEqual(message);
|
expect(msg.textContent).toEqual(message);
|
||||||
expect(msg.innerHTML).toEqual('"><svg/onload=alert(String.fromCharCode(88,83,83))>');
|
expect(msg.innerHTML).toEqual("<svg id=alert(1) onload=eval(id)>");
|
||||||
|
|
||||||
message = '"><svg/onload=alert(/XSS/)';
|
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();
|
msg = sizzle('.chat-content .chat-msg:last .chat-msg__text', view.el).pop();
|
||||||
expect(msg.textContent).toEqual(message);
|
expect(msg.textContent).toEqual(message);
|
||||||
expect(msg.innerHTML).toEqual('"><svg/onload=alert(/XSS/)');
|
expect(msg.innerHTML).toEqual('"><svg/onload=alert(String.fromCharCode(88,83,83))>');
|
||||||
|
|
||||||
expect(window.alert).not.toHaveBeenCalled();
|
message = '"><svg/onload=alert(/XSS/)';
|
||||||
done();
|
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('"><svg/onload=alert(/XSS/)');
|
||||||
|
|
||||||
it("will have properly escaped URLs",
|
expect(window.alert).not.toHaveBeenCalled();
|
||||||
mock.initConverse(
|
done();
|
||||||
['rosterGroupsFetched', 'chatBoxesFetched'], {},
|
}));
|
||||||
async function (done, _converse) {
|
|
||||||
|
|
||||||
await test_utils.waitForRoster(_converse, 'current');
|
it("will have properly escaped URLs",
|
||||||
await test_utils.openControlBox(_converse);
|
mock.initConverse(
|
||||||
|
['rosterGroupsFetched', 'chatBoxesFetched'], {},
|
||||||
|
async function (done, _converse) {
|
||||||
|
|
||||||
const contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit';
|
await mock.waitForRoster(_converse, 'current');
|
||||||
await test_utils.openChatBoxFor(_converse, contact_jid)
|
await mock.openControlBox(_converse);
|
||||||
const view = _converse.api.chatviews.get(contact_jid);
|
|
||||||
|
|
||||||
let message = "http://www.opkode.com/'onmouseover='alert(1)'whatever";
|
const contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit';
|
||||||
await test_utils.sendMessage(view, message);
|
await mock.openChatBoxFor(_converse, contact_jid)
|
||||||
|
const view = _converse.api.chatviews.get(contact_jid);
|
||||||
|
|
||||||
let msg = sizzle('.chat-content .chat-msg:last .chat-msg__text', view.el).pop();
|
let message = "http://www.opkode.com/'onmouseover='alert(1)'whatever";
|
||||||
expect(msg.textContent).toEqual(message);
|
await mock.sendMessage(view, message);
|
||||||
expect(msg.innerHTML)
|
|
||||||
.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';
|
let msg = sizzle('.chat-content .chat-msg:last .chat-msg__text', view.el).pop();
|
||||||
await test_utils.sendMessage(view, message);
|
expect(msg.textContent).toEqual(message);
|
||||||
|
expect(msg.innerHTML)
|
||||||
|
.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>');
|
||||||
|
|
||||||
msg = sizzle('.chat-content .chat-msg:last .chat-msg__text', view.el).pop();
|
message = 'http://www.opkode.com/"onmouseover="alert(1)"whatever';
|
||||||
expect(msg.textContent).toEqual(message);
|
await mock.sendMessage(view, 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";
|
msg = sizzle('.chat-content .chat-msg:last .chat-msg__text', view.el).pop();
|
||||||
await test_utils.sendMessage(view, message);
|
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>');
|
||||||
|
|
||||||
msg = sizzle('.chat-content .chat-msg:last .chat-msg__text', view.el).pop();
|
message = "https://en.wikipedia.org/wiki/Ender's_Game";
|
||||||
expect(msg.textContent).toEqual(message);
|
await mock.sendMessage(view, 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>";
|
msg = sizzle('.chat-content .chat-msg:last .chat-msg__text', view.el).pop();
|
||||||
await test_utils.sendMessage(view, message);
|
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>');
|
||||||
|
|
||||||
msg = sizzle('.chat-content .chat-msg:last .chat-msg__text', view.el).pop();
|
message = "<https://bugs.documentfoundation.org/show_bug.cgi?id=123737>";
|
||||||
expect(msg.textContent).toEqual(message);
|
await mock.sendMessage(view, message);
|
||||||
expect(msg.innerHTML).toEqual(
|
|
||||||
`<<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>>`);
|
|
||||||
|
|
||||||
message = '<http://www.opkode.com/"onmouseover="alert(1)"whatever>';
|
msg = sizzle('.chat-content .chat-msg:last .chat-msg__text', view.el).pop();
|
||||||
await test_utils.sendMessage(view, message);
|
expect(msg.textContent).toEqual(message);
|
||||||
|
expect(msg.innerHTML).toEqual(
|
||||||
|
`<<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>>`);
|
||||||
|
|
||||||
msg = sizzle('.chat-content .chat-msg:last .chat-msg__text', view.el).pop();
|
message = '<http://www.opkode.com/"onmouseover="alert(1)"whatever>';
|
||||||
expect(msg.textContent).toEqual(message);
|
await mock.sendMessage(view, 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://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`
|
msg = sizzle('.chat-content .chat-msg:last .chat-msg__text', view.el).pop();
|
||||||
await test_utils.sendMessage(view, message);
|
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>>');
|
||||||
|
|
||||||
msg = sizzle('.chat-content .chat-msg:last .chat-msg__text', view.el).pop();
|
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`
|
||||||
expect(msg.textContent).toEqual(message);
|
await mock.sendMessage(view, message);
|
||||||
expect(msg.innerHTML).toEqual(
|
|
||||||
`<a target="_blank" rel="noopener" href="https://www.google.com/maps/place/Kochstraat+6,+2041+CE+Zandvoort/@52.3775999,4.548971,3a,15y,170.85h,88.39t/data=%213m6%211e1%213m4%211sQ7SdHo_bPLPlLlU8GSGWaQ%212e0%217i13312%218i6656%214m5%213m4%211s0x47c5ec1e56f845ad:0x1de0bc4a5771fb08%218m2%213d52.3773668%214d4.5489388%215m1%211e2">https://www.google.com/maps/place/Kochstraat+6,+2041+CE+Zandvoort/@52.3775999,4.548971,3a,15y,170.85h,88.39t/data=!3m6!1e1!3m4!1sQ7SdHo_bPLPlLlU8GSGWaQ!2e0!7i13312!8i6656!4m5!3m4!1s0x47c5ec1e56f845ad:0x1de0bc4a5771fb08!8m2!3d52.3773668!4d4.5489388!5m1!1e2</a>`);
|
|
||||||
done();
|
|
||||||
}));
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("A Groupchat", function () {
|
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://www.google.com/maps/place/Kochstraat+6,+2041+CE+Zandvoort/@52.3775999,4.548971,3a,15y,170.85h,88.39t/data=%213m6%211e1%213m4%211sQ7SdHo_bPLPlLlU8GSGWaQ%212e0%217i13312%218i6656%214m5%213m4%211s0x47c5ec1e56f845ad:0x1de0bc4a5771fb08%218m2%213d52.3773668%214d4.5489388%215m1%211e2">https://www.google.com/maps/place/Kochstraat+6,+2041+CE+Zandvoort/@52.3775999,4.548971,3a,15y,170.85h,88.39t/data=!3m6!1e1!3m4!1sQ7SdHo_bPLPlLlU8GSGWaQ!2e0!7i13312!8i6656!4m5!3m4!1s0x47c5ec1e56f845ad:0x1de0bc4a5771fb08!8m2!3d52.3773668!4d4.5489388!5m1!1e2</a>`);
|
||||||
|
done();
|
||||||
|
}));
|
||||||
|
});
|
||||||
|
|
||||||
it("escapes occupant nicknames when rendering them, to avoid JS-injection attacks",
|
describe("A Groupchat", function () {
|
||||||
mock.initConverse(['rosterGroupsFetched'], {},
|
|
||||||
async function (done, _converse) {
|
|
||||||
|
|
||||||
await test_utils.openAndEnterChatRoom(_converse, 'lounge@montague.lit', 'romeo');
|
it("escapes occupant nicknames when rendering them, to avoid JS-injection attacks",
|
||||||
/* <presence xmlns="jabber:client" to="jc@chat.example.org/converse.js-17184538"
|
mock.initConverse(['rosterGroupsFetched'], {},
|
||||||
* from="oo@conference.chat.example.org/<img src="x" onerror="alert(123)"/>">
|
async function (done, _converse) {
|
||||||
* <x xmlns="http://jabber.org/protocol/muc#user">
|
|
||||||
* <item jid="jc@chat.example.org/converse.js-17184538" affiliation="owner" role="moderator"/>
|
|
||||||
* <status code="110"/>
|
|
||||||
* </x>
|
|
||||||
* </presence>"
|
|
||||||
*/
|
|
||||||
const presence = $pres({
|
|
||||||
to:'romeo@montague.lit/pda',
|
|
||||||
from:"lounge@montague.lit/<img src="x" onerror="alert(123)"/>"
|
|
||||||
}).c('x').attrs({xmlns:'http://jabber.org/protocol/muc#user'})
|
|
||||||
.c('item').attrs({
|
|
||||||
jid: 'someone@montague.lit',
|
|
||||||
role: 'moderator',
|
|
||||||
}).up()
|
|
||||||
.c('status').attrs({code:'110'}).nodeTree;
|
|
||||||
|
|
||||||
_converse.connection._dataRecv(test_utils.createRequest(presence));
|
await mock.openAndEnterChatRoom(_converse, 'lounge@montague.lit', 'romeo');
|
||||||
const view = _converse.chatboxviews.get('lounge@montague.lit');
|
/* <presence xmlns="jabber:client" to="jc@chat.example.org/converse.js-17184538"
|
||||||
await u.waitUntil(() => view.el.querySelectorAll('li .occupant-nick').length, 500);
|
* from="oo@conference.chat.example.org/<img src="x" onerror="alert(123)"/>">
|
||||||
const occupants = view.el.querySelector('.occupant-list').querySelectorAll('li .occupant-nick');
|
* <x xmlns="http://jabber.org/protocol/muc#user">
|
||||||
expect(occupants.length).toBe(2);
|
* <item jid="jc@chat.example.org/converse.js-17184538" affiliation="owner" role="moderator"/>
|
||||||
expect(occupants[0].textContent.trim()).toBe("<img src="x" onerror="alert(123)"/>");
|
* <status code="110"/>
|
||||||
done();
|
* </x>
|
||||||
}));
|
* </presence>"
|
||||||
|
*/
|
||||||
|
const presence = $pres({
|
||||||
|
to:'romeo@montague.lit/pda',
|
||||||
|
from:"lounge@montague.lit/<img src="x" onerror="alert(123)"/>"
|
||||||
|
}).c('x').attrs({xmlns:'http://jabber.org/protocol/muc#user'})
|
||||||
|
.c('item').attrs({
|
||||||
|
jid: 'someone@montague.lit',
|
||||||
|
role: 'moderator',
|
||||||
|
}).up()
|
||||||
|
.c('status').attrs({code:'110'}).nodeTree;
|
||||||
|
|
||||||
it("escapes the subject before rendering it, to avoid JS-injection attacks",
|
_converse.connection._dataRecv(mock.createRequest(presence));
|
||||||
mock.initConverse(
|
const view = _converse.chatboxviews.get('lounge@montague.lit');
|
||||||
['rosterGroupsFetched'], {},
|
await u.waitUntil(() => view.el.querySelectorAll('li .occupant-nick').length, 500);
|
||||||
async function (done, _converse) {
|
const occupants = view.el.querySelector('.occupant-list').querySelectorAll('li .occupant-nick');
|
||||||
|
expect(occupants.length).toBe(2);
|
||||||
|
expect(occupants[0].textContent.trim()).toBe("<img src="x" onerror="alert(123)"/>");
|
||||||
|
done();
|
||||||
|
}));
|
||||||
|
|
||||||
await test_utils.openAndEnterChatRoom(_converse, 'jdev@conference.jabber.org', 'jc');
|
it("escapes the subject before rendering it, to avoid JS-injection attacks",
|
||||||
spyOn(window, 'alert');
|
mock.initConverse(
|
||||||
const subject = '<img src="x" onerror="alert(\'XSS\');"/>';
|
['rosterGroupsFetched'], {},
|
||||||
const view = _converse.chatboxviews.get('jdev@conference.jabber.org');
|
async function (done, _converse) {
|
||||||
view.model.set({'subject': {
|
|
||||||
'text': subject,
|
await mock.openAndEnterChatRoom(_converse, 'jdev@conference.jabber.org', 'jc');
|
||||||
'author': 'ralphm'
|
spyOn(window, 'alert');
|
||||||
}});
|
const subject = '<img src="x" onerror="alert(\'XSS\');"/>';
|
||||||
const text = await u.waitUntil(() => view.el.querySelector('.chat-head__desc')?.textContent.trim());
|
const view = _converse.chatboxviews.get('jdev@conference.jabber.org');
|
||||||
expect(text).toBe(subject);
|
view.model.set({'subject': {
|
||||||
done();
|
'text': subject,
|
||||||
}));
|
'author': 'ralphm'
|
||||||
});
|
}});
|
||||||
|
const text = await u.waitUntil(() => view.el.querySelector('.chat-head__desc')?.textContent.trim());
|
||||||
|
expect(text).toBe(subject);
|
||||||
|
done();
|
||||||
|
}));
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
140
tests.html
140
tests.html
@ -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>
|
|
142
tests/index.html
142
tests/index.html
@ -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>
|
|
437
tests/mock.js
437
tests/mock.js
@ -2,6 +2,8 @@ const mock = {};
|
|||||||
window.mock = mock;
|
window.mock = mock;
|
||||||
let _converse, initConverse;
|
let _converse, initConverse;
|
||||||
|
|
||||||
|
const converseLoaded = new Promise(resolve => window.addEventListener('converse-loaded', resolve));
|
||||||
|
|
||||||
mock.initConverse = function (promise_names=[], settings=null, func) {
|
mock.initConverse = function (promise_names=[], settings=null, func) {
|
||||||
if (typeof promise_names === "function") {
|
if (typeof promise_names === "function") {
|
||||||
func = promise_names;
|
func = promise_names;
|
||||||
@ -19,6 +21,7 @@ mock.initConverse = function (promise_names=[], settings=null, func) {
|
|||||||
}
|
}
|
||||||
document.title = "Converse Tests";
|
document.title = "Converse Tests";
|
||||||
|
|
||||||
|
await converseLoaded;
|
||||||
await initConverse(settings);
|
await initConverse(settings);
|
||||||
await Promise.all((promise_names || []).map(_converse.api.waitUntil));
|
await Promise.all((promise_names || []).map(_converse.api.waitUntil));
|
||||||
try {
|
try {
|
||||||
@ -32,12 +35,432 @@ mock.initConverse = function (promise_names=[], settings=null, func) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
window.addEventListener('converse-loaded', () => {
|
window.addEventListener('converse-loaded', () => {
|
||||||
const _ = converse.env._;
|
const { _, u, sizzle, Strophe, dayjs, $iq, $msg, $pres } = converse.env;
|
||||||
const u = converse.env.utils;
|
|
||||||
const Promise = converse.env.Promise;
|
mock.waitUntilDiscoConfirmed = async function (_converse, entity_jid, identities, features=[], items=[], type='info') {
|
||||||
const Strophe = converse.env.Strophe;
|
const iq = await u.waitUntil(() => {
|
||||||
const dayjs = converse.env.dayjs;
|
return _.filter(
|
||||||
const $iq = converse.env.$iq;
|
_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 = {
|
window.libsignal = {
|
||||||
'SignalProtocolAddress': function (name, device_id) {
|
'SignalProtocolAddress': function (name, device_id) {
|
||||||
@ -335,3 +758,5 @@ window.addEventListener('converse-loaded', () => {
|
|||||||
return _converse;
|
return _converse;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
converse.load();
|
||||||
|
@ -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>
|
|
437
tests/utils.js
437
tests/utils.js
@ -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;
|
|
||||||
};
|
|
||||||
});
|
|
Loading…
Reference in New Issue
Block a user