diff --git a/index.html b/index.html
index 67800d495..5b0d05be0 100644
--- a/index.html
+++ b/index.html
@@ -128,11 +128,11 @@
Need an XMPP/Jabber account?
No problem! With Converse you can register an account on any public XMPP server that allows in-band registration,
- including our own at conversejs.org .
+ including our own at conversejs.org .
Converse is a community
- Over 130 people have contributed features, bugfixes and translations, and many more have integrated it into their own websites or applications.
- Come and chat with us at discuss@conference.conversejs.org .
+ Over 130 people have contributed features, bugfixes and translations, and many more have integrated it into their own websites or applications.
+ Come and chat with us at discuss@conference.conversejs.org .
@@ -175,6 +175,7 @@
Features
+ Converse supports many XMPP extensions. See here for a list of supported XEPs .
Available as overlayed chat boxes or as a full-page app. See here for the fullscreen version.
A plugin architecture based on pluggable.js
Chat statuses (online, busy, away, offline)
@@ -185,20 +186,14 @@
vCard support (XEP 54 )
Service discovery (XEP 30 )
In-band registration (XEP 77 )
- Roster item exchange (XEP 144 )
- Custom status messages
Typing and chat state notifications (XEP 85 )
File sharing / HTTP File Upload (XEP 363 )
- Messages appear in all connected chat clients / Message Carbons (XEP 280 )
- Third person "/me" messages (XEP 245 )
Server-side archiving of messages (XEP 313 )
Hidden messages (aka Spoilers) (XEP 382 )
Client state indication (XEP 352 )
- Last Message Correction (XEP 308 )
OMEMO encrypted messaging (XEP 384 )
Anonymous logins, see the anonymous login demo
- Message Retractions (XEP 424 )
- Message Moderation (XEP 425 )
+ Message corrections, retractions and moderation
Translated into over 30 languages
diff --git a/karma.conf.js b/karma.conf.js
index cc3fffd03..6952d2561 100644
--- a/karma.conf.js
+++ b/karma.conf.js
@@ -14,8 +14,7 @@ module.exports = function(config) {
"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/mock.js", type: 'module' },
{ pattern: "spec/spoilers.js", type: 'module' },
{ pattern: "spec/roomslist.js", type: 'module' },
diff --git a/package-lock.json b/package-lock.json
index 6e475a573..1ad5d4d10 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -4203,6 +4203,11 @@
"through": ">=2.2.7 <3"
}
},
+ "abab": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.3.tgz",
+ "integrity": "sha512-tsFzPpcttalNjFBCFMqsKYQcWxxen1pgJR56by//QwvJc4/OUS3kPOOttx2tSIfjsylB0pYu7f5D3K1RCxUnUg=="
+ },
"abbrev": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz",
@@ -21120,8 +21125,20 @@
},
"strophe.js": {
"version": "1.3.4",
- "resolved": "https://registry.npmjs.org/strophe.js/-/strophe.js-1.3.4.tgz",
- "integrity": "sha512-jSLDG8jolhAwGOSgiJ7DTMSYK3wVoEJHKtpVRyEacQZ6CWA6z2WRPJpcFMjsIweq5aP9/XIvKUQqHBu/ZhvESA=="
+ "resolved": "github:strophe/strophejs#4556d1d87b9a7650b52a2bc2cc055a97f9801cb5",
+ "requires": {
+ "abab": "^2.0.0",
+ "ws": "^7.0.0",
+ "xmldom": "^0.1.27"
+ },
+ "dependencies": {
+ "ws": {
+ "version": "7.2.5",
+ "resolved": "https://registry.npmjs.org/ws/-/ws-7.2.5.tgz",
+ "integrity": "sha512-C34cIU4+DB2vMyAbmEKossWq2ZQDr6QEyuuCzWrM9zfw1sGc0mYiJ0UnG9zzNykt49C2Fi34hvr2vssFQRS6EA==",
+ "optional": true
+ }
+ }
},
"style-loader": {
"version": "0.23.1",
@@ -22894,6 +22911,12 @@
"integrity": "sha512-HgS+X6zAztGa9zIK3Y3LXuJes33Lz9x+YyTxgrkIdabu2vqcGOWwdfCpf1hWLRrd553wd4QCDf6BBO6FfdsRiQ==",
"dev": true
},
+ "xmldom": {
+ "version": "0.1.31",
+ "resolved": "https://registry.npmjs.org/xmldom/-/xmldom-0.1.31.tgz",
+ "integrity": "sha512-yS2uJflVQs6n+CyjHoaBmVSqIDevTAWrzMmjG1Gc7h1qQ7uVozNhEPJAwZXWyGQ/Gafo3fCwrcaokezLPupVyQ==",
+ "optional": true
+ },
"xmlhttprequest-ssl": {
"version": "1.5.5",
"resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.5.5.tgz",
diff --git a/spec/emojis.js b/spec/emojis.js
index 85f50afca..8c50c0ebb 100644
--- a/spec/emojis.js
+++ b/spec/emojis.js
@@ -2,10 +2,14 @@
const { Promise, $msg, $pres, sizzle } = converse.env;
const u = converse.env.utils;
+const originalTimeout = jasmine.DEFAULT_TIMEOUT_INTERVAL;
describe("Emojis", function () {
describe("The emoji picker", function () {
+ beforeEach(() => (jasmine.DEFAULT_TIMEOUT_INTERVAL = 7000));
+ afterEach(() => (jasmine.DEFAULT_TIMEOUT_INTERVAL = originalTimeout));
+
it("can be opened by clicking a button in the chat toolbar",
mock.initConverse(
['rosterGroupsFetched', 'chatBoxesFetched'], {},
diff --git a/tests/mock.js b/spec/mock.js
similarity index 100%
rename from tests/mock.js
rename to spec/mock.js
diff --git a/spec/muc.js b/spec/muc.js
index 8932542cb..218ff6a1a 100644
--- a/spec/muc.js
+++ b/spec/muc.js
@@ -4754,7 +4754,7 @@ describe("Groupchats", function () {
await u.waitUntil(() => modal.el.querySelectorAll('.available-chatrooms li').length === 11);
const rooms = modal.el.querySelectorAll('.available-chatrooms li');
- expect(rooms[0].textContent.trim()).toBe("Groupchats found:");
+ expect(rooms[0].textContent.trim()).toBe("Groupchats found");
expect(rooms[1].textContent.trim()).toBe("A Lonely Heath");
expect(rooms[2].textContent.trim()).toBe("A Dark Cave");
expect(rooms[3].textContent.trim()).toBe("The Palace");
@@ -4832,7 +4832,7 @@ describe("Groupchats", function () {
await u.waitUntil(() => modal.el.querySelectorAll('.available-chatrooms li').length === 4);
const rooms = modal.el.querySelectorAll('.available-chatrooms li');
- expect(rooms[0].textContent.trim()).toBe("Groupchats found:");
+ expect(rooms[0].textContent.trim()).toBe("Groupchats found");
expect(rooms[1].textContent.trim()).toBe("A Lonely Heath");
expect(rooms[2].textContent.trim()).toBe("A Dark Cave");
expect(rooms[3].textContent.trim()).toBe("The Palace");
diff --git a/tests/console-reporter.js b/tests/console-reporter.js
deleted file mode 100644
index 06a928aaf..000000000
--- a/tests/console-reporter.js
+++ /dev/null
@@ -1,140 +0,0 @@
-const noopTimer = {
- start: function () {},
- elapsed: function () { return 0; }
-};
-
-function ConsoleReporter () {
- var timer = noopTimer,
- specCount,
- failureCount,
- failedSpecs = [],
- pendingCount,
- ansi = {
- green: '\x1B[32m',
- red: '\x1B[31m',
- yellow: '\x1B[33m',
- none: '\x1B[0m'
- },
- failedSuites = [];
-
- var print = function print (message) {
- console.log(message + '\x03\b');
- }
-
- this.jasmineStarted = function () {
- specCount = 0;
- failureCount = 0;
- pendingCount = 0;
- print('Started');
- printNewline();
- timer.start();
- };
-
- this.jasmineDone = function () {
- print("jasmineDone");
- printNewline();
- for (var i = 0; i < failedSpecs.length; i++) {
- specFailureDetails(failedSpecs[i]);
- }
-
- if(specCount > 0) {
- printNewline();
- var specCounts = specCount + ' ' + plural('spec', specCount) + ', ' +
- failureCount + ' ' + plural('failure', failureCount);
- if (pendingCount) {
- specCounts += ', ' + pendingCount + ' pending ' + plural('spec', pendingCount);
- }
- print(specCounts);
- } else {
- print('No specs found');
- }
-
- printNewline();
- var seconds = timer.elapsed() / 1000;
- print('Finished in ' + seconds + ' ' + plural('second', seconds));
- printNewline();
- for (i = 0; i < failedSuites.length; i++) {
- suiteFailureDetails(failedSuites[i]);
- }
- var exitCode = failureCount === 0 ? 0 : 1;
- console.info('All tests completed!' + exitCode);
- };
-
- this.specDone = function (result) {
- specCount++;
- if (result.status == 'pending') {
- pendingCount++;
- print(colored('yellow', '*'));
- return;
- }
- if (result.status == 'passed') {
- print(colored('green', '.'));
- return;
- }
- if (result.status == 'failed') {
- failureCount++;
- failedSpecs.push(result);
- print(colored('red', 'F'));
- }
- };
-
- this.suiteDone = function (result) {
- if (result.failedExpectations && result.failedExpectations.length > 0) {
- failureCount++;
- failedSuites.push(result);
- }
- };
- return this;
-
- function printNewline() {
- print('\n');
- }
-
- function colored (color, str) {
- return ansi[color] + str + ansi.none;
- }
-
- function plural (str, count) {
- return count == 1 ? str : str + 's';
- }
-
- function repeat (thing, times) {
- var arr = [];
- for (var i = 0; i < times; i++) {
- arr.push(thing);
- }
- return arr;
- }
-
- function indent (str, spaces) {
- var lines = (str || '').split('\n');
- var newArr = [];
- for (var i = 0; i < lines.length; i++) {
- newArr.push(repeat(' ', spaces).join('') + lines[i]);
- }
- return newArr.join('\n');
- }
-
- function specFailureDetails (result) {
- printNewline();
- print(result.fullName);
- for (var i = 0; i < result.failedExpectations.length; i++) {
- var failedExpectation = result.failedExpectations[i];
- printNewline();
- print(indent(failedExpectation.message, 2));
- print(indent(failedExpectation.stack, 2));
- }
- printNewline();
- }
-
- function suiteFailureDetails (result) {
- for (var i = 0; i < result.failedExpectations.length; i++) {
- printNewline();
- print(colored('red', 'An error was thrown in an afterAll'));
- printNewline();
- print(colored('red', 'AfterAll ' + result.failedExpectations[i].message));
- }
- printNewline();
- }
-}
-window.ConsoleReporter = ConsoleReporter;
diff --git a/tests/fullpage.html b/tests/fullpage.html
deleted file mode 100644
index ea50d6bbc..000000000
--- a/tests/fullpage.html
+++ /dev/null
@@ -1,23 +0,0 @@
-
-
-
- Converse Tests
-
-
-
-
-
-
-
-
-
-
-
-
-
-