Turn caps plugin into folder.

Move more test files to plugins
This commit is contained in:
JC Brand 2021-05-11 15:46:57 +02:00
parent 7bd0d9a83f
commit 1fc44b9d8e
16 changed files with 181 additions and 158 deletions

View File

@ -38,6 +38,7 @@
theme: 'concord',
view_mode: 'fullscreen',
websocket_url: 'wss://conversejs.org/xmpp-websocket',
// websocket_url: 'ws://chat.example.org:5380/xmpp-websocket',
whitelisted_plugins: ['converse-debug'],
});
</script>

View File

@ -25,26 +25,24 @@ module.exports = function(config) {
{ pattern: "node_modules/sinon/pkg/sinon.js", type: 'module' },
{ pattern: "spec/mock.js", type: 'module' },
{ pattern: "spec/converse.js", type: 'module' },
{ pattern: "spec/corrections.js", type: 'module' },
{ pattern: "spec/emojis.js", type: 'module' },
{ pattern: "spec/eventemitter.js", type: 'module' },
{ pattern: "spec/http-file-upload.js", type: 'module' },
{ pattern: "spec/markers.js", type: 'module' },
{ pattern: "spec/presence.js", type: 'module' },
{ pattern: "spec/protocol.js", type: 'module' },
{ pattern: "spec/push.js", type: 'module' },
{ pattern: "spec/retractions.js", type: 'module' },
{ pattern: "spec/styling.js", type: 'module' },
{ pattern: "spec/unfurls.js", type: 'module' },
{ pattern: "spec/user-details-modal.js", type: 'module' },
{ pattern: "spec/utils.js", type: 'module' },
{ pattern: "spec/xmppstatus.js", type: 'module' },
{ pattern: "src/headless/plugins/caps/tests/caps.js", type: 'module' },
{ pattern: "src/headless/plugins/chat/tests/api.js", type: 'module' },
{ pattern: "src/headless/plugins/disco/tests/disco.js", type: 'module' },
{ pattern: "src/headless/plugins/muc/tests/affiliations.js", type: 'module' },
{ pattern: "src/headless/plugins/ping/tests/ping.js", type: 'module' },
{ pattern: "src/headless/plugins/roster/tests/presence.js", type: 'module' },
{ pattern: "src/headless/plugins/smacks/tests/smacks.js", type: 'module' },
{ pattern: "src/headless/tests/converse.js", type: 'module' },
{ pattern: "src/headless/tests/eventemitter.js", type: 'module' },
{ pattern: "src/plugins/bookmark-views/tests/bookmarks.js", type: 'module' },
{ pattern: "src/plugins/chatview/tests/chatbox.js", type: 'module' },
{ pattern: "src/plugins/chatview/tests/corrections.js", type: 'module' },
@ -73,11 +71,15 @@ module.exports = function(config) {
{ pattern: "src/plugins/muc-views/tests/muclist.js", type: 'module' },
{ pattern: "src/plugins/muc-views/tests/rai.js", type: 'module' },
{ pattern: "src/plugins/muc-views/tests/styling.js", type: 'module' },
{ pattern: "src/plugins/muc-views/tests/unfurls.js", type: 'module' },
{ pattern: "src/plugins/muc-views/tests/xss.js", type: 'module' },
{ pattern: "src/plugins/notifications/tests/notification.js", type: 'module' },
{ pattern: "src/plugins/omemo/tests/omemo.js", type: 'module' },
{ pattern: "src/plugins/register/tests/register.js", type: 'module' },
{ pattern: "src/plugins/rosterview/tests/roster.js", type: 'module' }
{ pattern: "src/plugins/rootview/tests/root.js", type: 'module' },
{ pattern: "src/plugins/rosterview/tests/presence.js", type: 'module' },
{ pattern: "src/plugins/rosterview/tests/roster.js", type: 'module' },
{ pattern: "src/shared/chat/tests/styling.js", type: 'module' },
],
proxies: {

View File

@ -202,7 +202,7 @@ export const api = _converse.api = {
await _converse.setUserJID(api.settings.get("jid"));
}
if (_converse.connection.reconnecting) {
if (_converse.connection?.reconnecting) {
_converse.connection.debouncedReconnect();
} else {
return _converse.connection.reconnect();
@ -987,6 +987,8 @@ async function initSession (jid) {
const bare_jid = Strophe.getBareJidFromJid(jid).toLowerCase();
const id = `converse.session-${bare_jid}`;
if (_converse.session?.get('id') !== id) {
initPersistentStorage();
_converse.session = new Model({ id });
initStorage(_converse.session, id, is_shared_session ? "persistent" : "session");
await new Promise(r => _converse.session.fetch({'success': r, 'error': r}));
@ -998,7 +1000,6 @@ async function initSession (jid) {
_converse.session.save({id});
}
saveJIDtoSession(jid);
initPersistentStorage();
/**
* Triggered once the user's session has been initialized. The session is a
* cache which stores information about the user's current session.

View File

@ -5,7 +5,7 @@
import "./plugins/adhoc.js"; // XEP-0050 Ad Hoc Commands
import "./plugins/bookmarks/index.js"; // XEP-0199 XMPP Ping
import "./plugins/bosh.js"; // XEP-0206 BOSH
import "./plugins/caps.js"; // XEP-0115 Entity Capabilities
import "./plugins/caps/index.js"; // XEP-0115 Entity Capabilities
import "./plugins/carbons.js"; // XEP-0280 Message Carbons
import "./plugins/chat/index.js"; // RFC-6121 Instant messaging
import "./plugins/chatboxes/index.js";

View File

@ -0,0 +1,27 @@
/**
* @copyright 2020, the Converse.js contributors
* @license Mozilla Public License (MPLv2)
*/
import { _converse, converse } from '@converse/headless/core';
import { createCapsNode } from './utils.js';
const { Strophe } = converse.env;
Strophe.addNamespace('CAPS', "http://jabber.org/protocol/caps");
converse.plugins.add('converse-caps', {
overrides: {
// Overrides mentioned here will be picked up by converse.js's
// plugin architecture they will replace existing methods on the
// relevant objects or classes.
XMPPStatus: {
constructPresence () {
const presence = this.__super__.constructPresence.apply(this, arguments);
presence.root().cnode(createCapsNode(_converse)).up();
return presence;
}
}
}
});

View File

@ -0,0 +1,66 @@
/*global mock */
const original_timeout = jasmine.DEFAULT_TIMEOUT_INTERVAL;
describe("A sent presence stanza", function () {
beforeEach(() => (jasmine.DEFAULT_TIMEOUT_INTERVAL = 7000));
afterEach(() => (jasmine.DEFAULT_TIMEOUT_INTERVAL = original_timeout));
it("includes a entity capabilities node",
mock.initConverse([], {}, async (done, _converse) => {
await mock.waitForRoster(_converse, 'current', 0);
_converse.api.disco.own.identities.clear();
_converse.api.disco.own.features.clear();
_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/disco#info");
_converse.api.disco.own.features.add("http://jabber.org/protocol/disco#items");
_converse.api.disco.own.features.add("http://jabber.org/protocol/muc");
const presence = _converse.xmppstatus.constructPresence();
expect(presence.toLocaleString()).toBe(
`<presence xmlns="jabber:client">`+
`<priority>0</priority>`+
`<c hash="sha-1" node="https://conversejs.org" ver="QgayPKawpkPSDYmwT/WM94uAlu0=" xmlns="http://jabber.org/protocol/caps"/>`+
`</presence>`)
done();
}));
it("has a given priority", mock.initConverse(['statusInitialized'], {}, (done, _converse) => {
const { api } = _converse;
let pres = _converse.xmppstatus.constructPresence('online', null, 'Hello world');
expect(pres.toLocaleString()).toBe(
`<presence xmlns="jabber:client">`+
`<status>Hello world</status>`+
`<priority>0</priority>`+
`<c hash="sha-1" node="https://conversejs.org" ver="PxXfr6uz8ClMWIga0OB/MhKNH/M=" xmlns="http://jabber.org/protocol/caps"/>`+
`</presence>`
);
api.settings.set('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="PxXfr6uz8ClMWIga0OB/MhKNH/M=" xmlns="http://jabber.org/protocol/caps"/>`+
`</presence>`
);
api.settings.set('priority', undefined);
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="PxXfr6uz8ClMWIga0OB/MhKNH/M=" xmlns="http://jabber.org/protocol/caps"/>`+
`</presence>`
);
done();
}));
});

View File

@ -1,15 +1,8 @@
/**
* @module converse-caps
* @copyright 2020, the Converse.js contributors
* @license Mozilla Public License (MPLv2)
*/
import SHA1 from 'strophe.js/src/sha1';
import { converse } from "@converse/headless/core";
import { converse } from '@converse/headless/core';
const { Strophe, $build } = converse.env;
Strophe.addNamespace('CAPS', "http://jabber.org/protocol/caps");
function propertySort (array, property) {
return array.sort((a, b) => { return a[property] > b[property] ? -1 : 1 });
}
@ -30,7 +23,7 @@ function generateVerificationString (_converse) {
return SHA1.b64_sha1(S);
}
function createCapsNode (_converse) {
export function createCapsNode (_converse) {
return $build("c", {
'xmlns': Strophe.NS.CAPS,
'hash': "sha-1",
@ -38,19 +31,3 @@ function createCapsNode (_converse) {
'ver': generateVerificationString(_converse)
}).nodeTree;
}
converse.plugins.add('converse-caps', {
overrides: {
// Overrides mentioned here will be picked up by converse.js's
// plugin architecture they will replace existing methods on the
// relevant objects or classes.
XMPPStatus: {
constructPresence () {
const presence = this.__super__.constructPresence.apply(this, arguments);
presence.root().cnode(createCapsNode(this.__super__._converse)).up();
return presence;
}
}
}
});

View File

@ -2,115 +2,6 @@
// See: https://xmpp.org/rfcs/rfc3921.html
const original_timeout = jasmine.DEFAULT_TIMEOUT_INTERVAL;
describe("A sent presence stanza", function () {
beforeEach(() => (jasmine.DEFAULT_TIMEOUT_INTERVAL = 7000));
afterEach(() => (jasmine.DEFAULT_TIMEOUT_INTERVAL = original_timeout));
it("includes a entity capabilities node",
mock.initConverse([], {}, async (done, _converse) => {
await mock.waitForRoster(_converse, 'current', 0);
_converse.api.disco.own.identities.clear();
_converse.api.disco.own.features.clear();
_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/disco#info");
_converse.api.disco.own.features.add("http://jabber.org/protocol/disco#items");
_converse.api.disco.own.features.add("http://jabber.org/protocol/muc");
const presence = _converse.xmppstatus.constructPresence();
expect(presence.toLocaleString()).toBe(
`<presence xmlns="jabber:client">`+
`<priority>0</priority>`+
`<c hash="sha-1" node="https://conversejs.org" ver="QgayPKawpkPSDYmwT/WM94uAlu0=" xmlns="http://jabber.org/protocol/caps"/>`+
`</presence>`)
done();
}));
it("has a given priority", mock.initConverse(['statusInitialized'], {}, (done, _converse) => {
const { api } = _converse;
let pres = _converse.xmppstatus.constructPresence('online', null, 'Hello world');
expect(pres.toLocaleString()).toBe(
`<presence xmlns="jabber:client">`+
`<status>Hello world</status>`+
`<priority>0</priority>`+
`<c hash="sha-1" node="https://conversejs.org" ver="PxXfr6uz8ClMWIga0OB/MhKNH/M=" xmlns="http://jabber.org/protocol/caps"/>`+
`</presence>`
);
api.settings.set('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="PxXfr6uz8ClMWIga0OB/MhKNH/M=" xmlns="http://jabber.org/protocol/caps"/>`+
`</presence>`
);
api.settings.set('priority', undefined);
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="PxXfr6uz8ClMWIga0OB/MhKNH/M=" xmlns="http://jabber.org/protocol/caps"/>`+
`</presence>`
);
done();
}));
it("includes the saved status message",
mock.initConverse([], {}, async (done, _converse) => {
const { u, Strophe } = converse.env;
mock.openControlBox(_converse);
spyOn(_converse.connection, 'send').and.callThrough();
const cbview = _converse.chatboxviews.get('controlbox');
const change_status_el = await u.waitUntil(() => cbview.querySelector('.change-status'));
change_status_el.click()
let modal = _converse.api.modal.get('modal-status-change');
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>`+
`<c hash="sha-1" node="https://conversejs.org" ver="PxXfr6uz8ClMWIga0OB/MhKNH/M=" xmlns="http://jabber.org/protocol/caps"/>`+
`</presence>`)
await u.waitUntil(() => modal.el.getAttribute('aria-hidden') === "true");
await u.waitUntil(() => !u.isVisible(modal.el));
cbview.querySelector('.change-status').click()
modal = _converse.api.modal.get('modal-status-change');
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">`+
`<show>dnd</show>`+
`<status>My custom status</status>`+
`<priority>0</priority>`+
`<c hash="sha-1" node="https://conversejs.org" ver="PxXfr6uz8ClMWIga0OB/MhKNH/M=" xmlns="http://jabber.org/protocol/caps"/>`+
`</presence>`)
done();
}));
});
describe("A received presence stanza", function () {
it("has its priority taken into account",

View File

@ -16,7 +16,7 @@ export function createStore (id, store) {
const name = store || getDefaultStore();
const s = _converse.storage[name];
if (typeof s === 'undefined') {
throw new TypeError(`createStore: Could not find store for %{id}`);
throw new TypeError(`createStore: Could not find store for ${id}`);
}
return new Storage(id, s, api.settings.get('persistent_store') === 'IndexedDB');
}

View File

@ -1,19 +1,7 @@
/* global mock, converse */
const u = converse.env.utils;
describe("Converse", function() {
it("Can be inserted into a custom element after having been initialized",
mock.initConverse([], {'root': new DocumentFragment()}, async (done, _converse) => {
expect(document.body.querySelector('#conversejs')).toBe(null);
expect(_converse.root.firstElementChild.nodeName.toLowerCase()).toBe('converse-root');
document.body.appendChild(document.createElement('converse-root'));
await u.waitUntil(() => document.body.querySelector('#conversejs') !== null);
done();
}));
describe("Authentication", function () {
it("needs either a bosh_service_url a websocket_url or both", mock.initConverse(async (done, _converse) => {

View File

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

View File

@ -0,0 +1,54 @@
/*global mock, converse */
const original_timeout = jasmine.DEFAULT_TIMEOUT_INTERVAL;
describe("A sent presence stanza", function () {
beforeEach(() => (jasmine.DEFAULT_TIMEOUT_INTERVAL = 7000));
afterEach(() => (jasmine.DEFAULT_TIMEOUT_INTERVAL = original_timeout));
it("includes the saved status message",
mock.initConverse([], {}, async (done, _converse) => {
const { u, Strophe } = converse.env;
mock.openControlBox(_converse);
spyOn(_converse.connection, 'send').and.callThrough();
const cbview = _converse.chatboxviews.get('controlbox');
const change_status_el = await u.waitUntil(() => cbview.querySelector('.change-status'));
change_status_el.click()
let modal = _converse.api.modal.get('modal-status-change');
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>`+
`<c hash="sha-1" node="https://conversejs.org" ver="PxXfr6uz8ClMWIga0OB/MhKNH/M=" xmlns="http://jabber.org/protocol/caps"/>`+
`</presence>`)
await u.waitUntil(() => modal.el.getAttribute('aria-hidden') === "true");
await u.waitUntil(() => !u.isVisible(modal.el));
cbview.querySelector('.change-status').click()
modal = _converse.api.modal.get('modal-status-change');
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">`+
`<show>dnd</show>`+
`<status>My custom status</status>`+
`<priority>0</priority>`+
`<c hash="sha-1" node="https://conversejs.org" ver="PxXfr6uz8ClMWIga0OB/MhKNH/M=" xmlns="http://jabber.org/protocol/caps"/>`+
`</presence>`)
done();
}));
});

View File

@ -30,7 +30,7 @@
modtools_disable_assign: ['owner', 'moderator', 'participant', 'visitor'],
modtools_disable_query: ['moderator', 'participant', 'visitor'],
enable_smacks: true,
// connection_options: { 'worker': '/dist/shared-connection-worker.js' },
connection_options: { 'worker': '/dist/shared-connection-worker.js' },
persistent_store: 'IndexedDB',
message_archiving: 'always',
muc_domain: 'conference.chat.example.org',