Commit 79bfb456 authored by JC Brand's avatar JC Brand

Use async/await in MAM code and tests

parent 6e05f3b6
...@@ -2,12 +2,12 @@ ...@@ -2,12 +2,12 @@
define(["jasmine", "mock", "test-utils"], factory); define(["jasmine", "mock", "test-utils"], factory);
} (this, function (jasmine, mock, test_utils) { } (this, function (jasmine, mock, test_utils) {
"use strict"; "use strict";
var _ = converse.env._; const _ = converse.env._;
var Backbone = converse.env.Backbone; const Backbone = converse.env.Backbone;
var Strophe = converse.env.Strophe; const Strophe = converse.env.Strophe;
var $iq = converse.env.$iq; const $iq = converse.env.$iq;
var $msg = converse.env.$msg; const $msg = converse.env.$msg;
var moment = converse.env.moment; const moment = converse.env.moment;
// See: https://xmpp.org/rfcs/rfc3921.html // See: https://xmpp.org/rfcs/rfc3921.html
describe("Message Archive Management", function () { describe("Message Archive Management", function () {
...@@ -18,48 +18,46 @@ ...@@ -18,48 +18,46 @@
it("aren't shown as duplicates", it("aren't shown as duplicates",
mock.initConverseWithPromises( mock.initConverseWithPromises(
null, ['discoInitialized'], {}, null, ['discoInitialized'], {},
function (done, _converse) { async function (done, _converse) {
await test_utils.openAndEnterChatRoom(_converse, 'trek-radio', 'conference.lightwitch.org', 'jcbrand');
const view = _converse.chatboxviews.get('trek-radio@conference.lightwitch.org');
let stanza = Strophe.xmlHtmlNode(
`<message xmlns="jabber:client" to="jcbrand@lightwitch.org/converse.js-73057452" type="groupchat" from="trek-radio@conference.lightwitch.org/comndrdukath#0805 (STO)">
<body>negan</body>
<stanza-id xmlns="urn:xmpp:sid:0" id="45fbbf2a-1059-479d-9283-c8effaf05621" by="trek-radio@conference.lightwitch.org"/>
</message>`
).firstElementChild;
_converse.connection._dataRecv(test_utils.createRequest(stanza));
await test_utils.waitUntil(() => view.content.querySelectorAll('.chat-msg').length);
// XXX: we wait here until the first message appears before
// sending the duplicate. If we don't do that, then the
// duplicate appears before the promise for `createMessage`
// has been resolved, which means that the `isDuplicate`
// check fails because the first message doesn't exist yet.
//
// Not sure whether such a race-condition might pose a problem
// in "real-world" situations.
stanza = Strophe.xmlHtmlNode(
`<message xmlns="jabber:client" to="jcbrand@lightwitch.org/converse.js-73057452">
<result xmlns="urn:xmpp:mam:2" queryid="82d9db27-6cf8-4787-8c2c-5a560263d823" id="45fbbf2a-1059-479d-9283-c8effaf05621">
<forwarded xmlns="urn:xmpp:forward:0">
<delay xmlns="urn:xmpp:delay" stamp="2018-01-09T06:17:23Z"/>
<message from="trek-radio@conference.lightwitch.org/comndrdukath#0805 (STO)" type="groupchat">
<body>negan</body>
</message>
</forwarded>
</result>
</message>`).firstElementChild;
spyOn(view.model, 'isDuplicate').and.callThrough();
view.model.onMessage(stanza);
await test_utils.waitUntil(() => view.model.isDuplicate.calls.count());
expect(view.content.querySelectorAll('.chat-msg').length).toBe(1);
done();
}));
let view, stanza;
test_utils.openAndEnterChatRoom(_converse, 'trek-radio', 'conference.lightwitch.org', 'jcbrand')
.then(() => {
view = _converse.chatboxviews.get('trek-radio@conference.lightwitch.org');
stanza = Strophe.xmlHtmlNode(
`<message xmlns="jabber:client" to="jcbrand@lightwitch.org/converse.js-73057452" type="groupchat" from="trek-radio@conference.lightwitch.org/comndrdukath#0805 (STO)">
<body>negan</body>
<stanza-id xmlns="urn:xmpp:sid:0" id="45fbbf2a-1059-479d-9283-c8effaf05621" by="trek-radio@conference.lightwitch.org"/>
</message>`).firstElementChild;
_converse.connection._dataRecv(test_utils.createRequest(stanza));
return test_utils.waitUntil(() => view.content.querySelectorAll('.chat-msg').length)
}).then(() => {
// XXX: we wait here until the first message appears before
// sending the duplicate. If we don't do that, then the
// duplicate appears before the promise for `createMessage`
// has been resolved, which means that the `isDuplicate`
// check fails because the first message doesn't exist yet.
//
// Not sure whether such a race-condition might pose a problem
// in "real-world" situations.
stanza = Strophe.xmlHtmlNode(
`<message xmlns="jabber:client" to="jcbrand@lightwitch.org/converse.js-73057452">
<result xmlns="urn:xmpp:mam:2" queryid="82d9db27-6cf8-4787-8c2c-5a560263d823" id="45fbbf2a-1059-479d-9283-c8effaf05621">
<forwarded xmlns="urn:xmpp:forward:0"><delay xmlns="urn:xmpp:delay" stamp="2018-01-09T06:17:23Z"/>
<message from="trek-radio@conference.lightwitch.org/comndrdukath#0805 (STO)" type="groupchat">
<body>negan</body>
</message>
</forwarded>
</result>
</message>`).firstElementChild;
spyOn(view.model, 'isDuplicate').and.callThrough();
view.model.onMessage(stanza);
return test_utils.waitUntil(() => view.model.isDuplicate.calls.count());
}).then(() => {
expect(view.content.querySelectorAll('.chat-msg').length).toBe(1);
done();
}).catch(_.partial(_converse.log, _, Strophe.LogLevel.FATAL));
}))
}); });
describe("The archive.query API", function () { describe("The archive.query API", function () {
...@@ -86,78 +84,76 @@ ...@@ -86,78 +84,76 @@
})); }));
it("can be used to query for all messages to/from a particular JID", it("can be used to query for all messages to/from a particular JID",
mock.initConverseWithPromises( mock.initConverseWithPromises(
null, [], {}, null, [], {},
function (done, _converse) { async function (done, _converse) {
_converse.api.disco.entities.get(_converse.domain).then(function (entity) { const entity = await _converse.api.disco.entities.get(_converse.domain);
if (!entity.features.findWhere({'var': Strophe.NS.MAM})) { if (!entity.features.findWhere({'var': Strophe.NS.MAM})) {
_converse.disco_entities.get(_converse.domain).features.create({'var': Strophe.NS.MAM}); _converse.disco_entities.get(_converse.domain).features.create({'var': Strophe.NS.MAM});
} }
var sent_stanza, IQ_id; let sent_stanza, IQ_id;
var sendIQ = _converse.connection.sendIQ; const sendIQ = _converse.connection.sendIQ;
spyOn(_converse.connection, 'sendIQ').and.callFake(function (iq, callback, errback) { spyOn(_converse.connection, 'sendIQ').and.callFake(function (iq, callback, errback) {
sent_stanza = iq; sent_stanza = iq;
IQ_id = sendIQ.bind(this)(iq, callback, errback); IQ_id = sendIQ.bind(this)(iq, callback, errback);
});
_converse.api.archive.query({'with':'juliet@capulet.lit'});
var queryid = sent_stanza.nodeTree.querySelector('query').getAttribute('queryid');
expect(sent_stanza.toString()).toBe(
`<iq id="${IQ_id}" type="set" xmlns="jabber:client">`+
`<query queryid="${queryid}" xmlns="urn:xmpp:mam:2">`+
`<x type="submit" xmlns="jabber:x:data">`+
`<field type="hidden" var="FORM_TYPE">`+
`<value>urn:xmpp:mam:2</value>`+
`</field>`+
`<field var="with">`+
`<value>juliet@capulet.lit</value>`+
`</field>`+
`</x>`+
`</query>`+
`</iq>`);
done();
}); });
_converse.api.archive.query({'with':'juliet@capulet.lit'});
const queryid = sent_stanza.nodeTree.querySelector('query').getAttribute('queryid');
expect(sent_stanza.toString()).toBe(
`<iq id="${IQ_id}" type="set" xmlns="jabber:client">`+
`<query queryid="${queryid}" xmlns="urn:xmpp:mam:2">`+
`<x type="submit" xmlns="jabber:x:data">`+
`<field type="hidden" var="FORM_TYPE">`+
`<value>urn:xmpp:mam:2</value>`+
`</field>`+
`<field var="with">`+
`<value>juliet@capulet.lit</value>`+
`</field>`+
`</x>`+
`</query>`+
`</iq>`);
done();
})); }));
it("can be used to query for archived messages from a chat room", it("can be used to query for archived messages from a chat room",
mock.initConverseWithPromises( mock.initConverseWithPromises(
null, [], {}, null, [], {},
function (done, _converse) { async function (done, _converse) {
_converse.api.disco.entities.get(_converse.domain).then(function (entity) { const entity = await _converse.api.disco.entities.get(_converse.domain);
if (!entity.features.findWhere({'var': Strophe.NS.MAM})) { if (!entity.features.findWhere({'var': Strophe.NS.MAM})) {
_converse.disco_entities.get(_converse.domain).features.create({'var': Strophe.NS.MAM}); _converse.disco_entities.get(_converse.domain).features.create({'var': Strophe.NS.MAM});
} }
var sent_stanza, IQ_id; let sent_stanza, IQ_id;
var sendIQ = _converse.connection.sendIQ; const sendIQ = _converse.connection.sendIQ;
spyOn(_converse.connection, 'sendIQ').and.callFake(function (iq, callback, errback) { spyOn(_converse.connection, 'sendIQ').and.callFake(function (iq, callback, errback) {
sent_stanza = iq; sent_stanza = iq;
IQ_id = sendIQ.bind(this)(iq, callback, errback); IQ_id = sendIQ.bind(this)(iq, callback, errback);
});
var callback = jasmine.createSpy('callback');
_converse.api.archive.query({'with': 'coven@chat.shakespeare.lit', 'groupchat': true}, callback);
var queryid = sent_stanza.nodeTree.querySelector('query').getAttribute('queryid');
expect(sent_stanza.toString()).toBe(
`<iq id="${IQ_id}" to="coven@chat.shakespeare.lit" type="set" xmlns="jabber:client">`+
`<query queryid="${queryid}" xmlns="urn:xmpp:mam:2">`+
`<x type="submit" xmlns="jabber:x:data">`+
`<field type="hidden" var="FORM_TYPE">`+
`<value>urn:xmpp:mam:2</value>`+
`</field>`+
`</x>`+
`</query>`+
`</iq>`);
done();
}); });
const callback = jasmine.createSpy('callback');
_converse.api.archive.query({'with': 'coven@chat.shakespeare.lit', 'groupchat': true}, callback);
const queryid = sent_stanza.nodeTree.querySelector('query').getAttribute('queryid');
expect(sent_stanza.toString()).toBe(
`<iq id="${IQ_id}" to="coven@chat.shakespeare.lit" type="set" xmlns="jabber:client">`+
`<query queryid="${queryid}" xmlns="urn:xmpp:mam:2">`+
`<x type="submit" xmlns="jabber:x:data">`+
`<field type="hidden" var="FORM_TYPE">`+
`<value>urn:xmpp:mam:2</value>`+
`</field>`+
`</x>`+
`</query>`+
`</iq>`);
done();
})); }));
it("checks whether returned MAM messages from a MUC room are from the right JID", it("checks whether returned MAM messages from a MUC room are from the right JID",
mock.initConverseWithPromises( mock.initConverseWithPromises(
null, [], {}, null, [], {},
async function (done, _converse) { async function (done, _converse) {
const entity = await _converse.api.disco.entities.get(_converse.domain); const entity = await _converse.api.disco.entities.get(_converse.domain);
if (!entity.features.findWhere({'var': Strophe.NS.MAM})) { if (!entity.features.findWhere({'var': Strophe.NS.MAM})) {
...@@ -233,47 +229,46 @@ ...@@ -233,47 +229,46 @@
})); }));
it("can be used to query for all messages in a certain timespan", it("can be used to query for all messages in a certain timespan",
mock.initConverseWithPromises( mock.initConverseWithPromises(
null, [], {}, null, [], {},
function (done, _converse) { async function (done, _converse) {
var sent_stanza, IQ_id; let sent_stanza, IQ_id;
var sendIQ = _converse.connection.sendIQ; const sendIQ = _converse.connection.sendIQ;
spyOn(_converse.connection, 'sendIQ').and.callFake(function (iq, callback, errback) { spyOn(_converse.connection, 'sendIQ').and.callFake(function (iq, callback, errback) {
sent_stanza = iq; sent_stanza = iq;
IQ_id = sendIQ.bind(this)(iq, callback, errback); IQ_id = sendIQ.bind(this)(iq, callback, errback);
}); });
_converse.api.disco.entities.get().then(function (entities) { const entities = await _converse.api.disco.entities.get();
if (!entities.get(_converse.domain).features.findWhere({'var': Strophe.NS.MAM})) { if (!entities.get(_converse.domain).features.findWhere({'var': Strophe.NS.MAM})) {
_converse.disco_entities.get(_converse.domain).features.create({'var': Strophe.NS.MAM}); _converse.disco_entities.get(_converse.domain).features.create({'var': Strophe.NS.MAM});
} }
var start = '2010-06-07T00:00:00Z'; const start = '2010-06-07T00:00:00Z';
var end = '2010-07-07T13:23:54Z'; const end = '2010-07-07T13:23:54Z';
_converse.api.archive.query({ _converse.api.archive.query({
'start': start, 'start': start,
'end': end 'end': end
});
var queryid = sent_stanza.nodeTree.querySelector('query').getAttribute('queryid');
expect(sent_stanza.toString()).toBe(
`<iq id="${IQ_id}" type="set" xmlns="jabber:client">`+
`<query queryid="${queryid}" xmlns="urn:xmpp:mam:2">`+
`<x type="submit" xmlns="jabber:x:data">`+
`<field type="hidden" var="FORM_TYPE">`+
`<value>urn:xmpp:mam:2</value>`+
`</field>`+
`<field var="start">`+
`<value>${moment(start).format()}</value>`+
`</field>`+
`<field var="end">`+
`<value>${moment(end).format()}</value>`+
`</field>`+
`</x>`+
`</query>`+
`</iq>`
);
done();
}); });
const queryid = sent_stanza.nodeTree.querySelector('query').getAttribute('queryid');
expect(sent_stanza.toString()).toBe(
`<iq id="${IQ_id}" type="set" xmlns="jabber:client">`+
`<query queryid="${queryid}" xmlns="urn:xmpp:mam:2">`+
`<x type="submit" xmlns="jabber:x:data">`+
`<field type="hidden" var="FORM_TYPE">`+
`<value>urn:xmpp:mam:2</value>`+
`</field>`+
`<field var="start">`+
`<value>${moment(start).format()}</value>`+
`</field>`+
`<field var="end">`+
`<value>${moment(end).format()}</value>`+
`</field>`+
`</x>`+
`</query>`+
`</iq>`
);
done();
})); }));
it("throws a TypeError if an invalid date is provided", it("throws a TypeError if an invalid date is provided",
...@@ -292,208 +287,202 @@ ...@@ -292,208 +287,202 @@
})); }));
it("can be used to query for all messages after a certain time", it("can be used to query for all messages after a certain time",
mock.initConverseWithPromises( mock.initConverseWithPromises(
null, [], {}, null, [], {},
function (done, _converse) { async function (done, _converse) {
_converse.api.disco.entities.get(_converse.domain).then(function (entity) { const entity = await _converse.api.disco.entities.get(_converse.domain);
if (!entity.features.findWhere({'var': Strophe.NS.MAM})) { if (!entity.features.findWhere({'var': Strophe.NS.MAM})) {
_converse.disco_entities.get(_converse.domain).features.create({'var': Strophe.NS.MAM}); _converse.disco_entities.get(_converse.domain).features.create({'var': Strophe.NS.MAM});
} }
var sent_stanza, IQ_id; let sent_stanza, IQ_id;
var sendIQ = _converse.connection.sendIQ; const sendIQ = _converse.connection.sendIQ;
spyOn(_converse.connection, 'sendIQ').and.callFake(function (iq, callback, errback) { spyOn(_converse.connection, 'sendIQ').and.callFake(function (iq, callback, errback) {
sent_stanza = iq; sent_stanza = iq;
IQ_id = sendIQ.bind(this)(iq, callback, errback); IQ_id = sendIQ.bind(this)(iq, callback, errback);
}); });
if (!_converse.disco_entities.get(_converse.domain).features.findWhere({'var': Strophe.NS.MAM})) { if (!_converse.disco_entities.get(_converse.domain).features.findWhere({'var': Strophe.NS.MAM})) {
_converse.disco_entities.get(_converse.domain).features.create({'var': Strophe.NS.MAM}); _converse.disco_entities.get(_converse.domain).features.create({'var': Strophe.NS.MAM});
} }
var start = '2010-06-07T00:00:00Z'; const start = '2010-06-07T00:00:00Z';
_converse.api.archive.query({'start': start}); _converse.api.archive.query({'start': start});
var queryid = sent_stanza.nodeTree.querySelector('query').getAttribute('queryid'); const queryid = sent_stanza.nodeTree.querySelector('query').getAttribute('queryid');
expect(sent_stanza.toString()).toBe( expect(sent_stanza.toString()).toBe(
`<iq id="${IQ_id}" type="set" xmlns="jabber:client">`+ `<iq id="${IQ_id}" type="set" xmlns="jabber:client">`+
`<query queryid="${queryid}" xmlns="urn:xmpp:mam:2">`+ `<query queryid="${queryid}" xmlns="urn:xmpp:mam:2">`+
`<x type="submit" xmlns="jabber:x:data">`+ `<x type="submit" xmlns="jabber:x:data">`+
`<field type="hidden" var="FORM_TYPE">`+
`<value>urn:xmpp:mam:2</value>`+
`</field>`+
`<field var="start">`+
`<value>${moment(start).format()}</value>`+
`</field>`+
`</x>`+
`</query>`+
`</iq>`
);
done();
}));
it("can be used to query for a limited set of results",
mock.initConverseWithPromises(
null, [], {},
async function (done, _converse) {
const entity = await _converse.api.disco.entities.get(_converse.domain);
if (!entity.features.findWhere({'var': Strophe.NS.MAM})) {
_converse.disco_entities.get(_converse.domain).features.create({'var': Strophe.NS.MAM});
}
let sent_stanza, IQ_id;
const sendIQ = _converse.connection.sendIQ;
spyOn(_converse.connection, 'sendIQ').and.callFake(function (iq, callback, errback) {
sent_stanza = iq;
IQ_id = sendIQ.bind(this)(iq, callback, errback);
});
const start = '2010-06-07T00:00:00Z';
_converse.api.archive.query({'start': start, 'max':10});
const queryid = sent_stanza.nodeTree.querySelector('query').getAttribute('queryid');
expect(sent_stanza.toString()).toBe(
`<iq id="${IQ_id}" type="set" xmlns="jabber:client">`+
`<query queryid="${queryid}" xmlns="urn:xmpp:mam:2">`+
`<x type="submit" xmlns="jabber:x:data">`+
`<field type="hidden" var="FORM_TYPE">`+ `<field type="hidden" var="FORM_TYPE">`+
`<value>urn:xmpp:mam:2</value>`+ `<value>urn:xmpp:mam:2</value>`+
`</field>`+ `</field>`+
`<field var="start">`+ `<field var="start">`+
`<value>${moment(start).format()}</value>`+ `<value>${moment(start).format()}</value>`+
`</field>`+ `</field>`+
`</x>`+ `</x>`+
`</query>`+ `<set xmlns="http://jabber.org/protocol/rsm">`+
`</iq>` `<max>10</max>`+
); `</set>`+
done(); `</query>`+
}); `</iq>`
})); );
done();
it("can be used to query for a limited set of results",
mock.initConverseWithPromises(
null, [], {},
function (done, _converse) {
_converse.api.disco.entities.get(_converse.domain).then(function (entity) {
if (!entity.features.findWhere({'var': Strophe.NS.MAM})) {
_converse.disco_entities.get(_converse.domain).features.create({'var': Strophe.NS.MAM});
}
var sent_stanza, IQ_id;
var sendIQ = _converse.connection.sendIQ;
spyOn(_converse.connection, 'sendIQ').and.callFake(function (iq, callback, errback) {
sent_stanza = iq;
IQ_id = sendIQ.bind(this)(iq, callback, errback);
});
var start = '2010-06-07T00:00:00Z';
_converse.api.archive.query({'start': start, 'max':10});
var queryid = sent_stanza.nodeTree.querySelector('query').getAttribute('queryid');
expect(sent_stanza.toString()).toBe(
`<iq id="${IQ_id}" type="set" xmlns="jabber:client">`+
`<query queryid="${queryid}" xmlns="urn:xmpp:mam:2">`+
`<x type="submit" xmlns="jabber:x:data">`+
`<field type="hidden" var="FORM_TYPE">`+
`<value>urn:xmpp:mam:2</value>`+
`</field>`+
`<field var="start">`+
`<value>${moment(start).format()}</value>`+
`</field>`+
`</x>`+
`<set xmlns="http://jabber.org/protocol/rsm">`+
`<max>10</max>`+
`</set>`+
`</query>`+
`</iq>`
);
done();
});
})); }));
it("can be used to page through results", it("can be used to page through results",
mock.initConverseWithPromises( mock.initConverseWithPromises(
null, [], {}, null, [], {},
function (done, _converse) { async function (done, _converse) {
_converse.api.disco.entities.get(_converse.domain).then(function (entity) { const entity = await _converse.api.disco.entities.get(_converse.domain);
if (!entity.features.findWhere({'var': Strophe.NS.MAM})) { if (!entity.features.findWhere({'var': Strophe.NS.MAM})) {
_converse.disco_entities.get(_converse.domain).features.create({'var': Strophe.NS.MAM}); _converse.disco_entities.get(_converse.domain).features.create({'var': Strophe.NS.MAM});
} }
var sent_stanza, IQ_id; let sent_stanza, IQ_id;
var sendIQ = _converse.connection.sendIQ; const sendIQ = _converse.connection.sendIQ;
spyOn(_converse.connection, 'sendIQ').and.callFake(function (iq, callback, errback) { spyOn(_converse.connection, 'sendIQ').and.callFake(function (iq, callback, errback) {
sent_stanza = iq; sent_stanza = iq;
IQ_id = sendIQ.bind(this)(iq, callback, errback); IQ_id = sendIQ.bind(this)(iq, callback, errback);
});
var start = '2010-06-07T00:00:00Z';
_converse.api.archive.query({
'start': start,
'after': '09af3-cc343-b409f',
'max':10
});
var queryid = sent_stanza.nodeTree.querySelector('query').getAttribute('queryid');
expect(sent_stanza.toString()).toBe(
`<iq id="${IQ_id}" type="set" xmlns="jabber:client">`+
`<query queryid="${queryid}" xmlns="urn:xmpp:mam:2">`+
`<x type="submit" xmlns="jabber:x:data">`+
`<field type="hidden" var="FORM_TYPE">`+
`<value>urn:xmpp:mam:2</value>`+
`</field>`+
`<field var="start">`+
`<value>${moment(start).format()}</value>`+
`</field>`+
`</x>`+
`<set xmlns="http://jabber.org/protocol/rsm">`+
`<max>10</max>`+
`<after>09af3-cc343-b409f</after>`+
`</set>`+
`</query>`+
`</iq>`);
done();
}); });
const start = '2010-06-07T00:00:00Z';
_converse.api.archive.query({
'start': start,
'after': '09af3-cc343-b409f',
'max':10
});
const queryid = sent_stanza.nodeTree.querySelector('query').getAttribute('queryid');
expect(sent_stanza.toString()).toBe(
`<iq id="${IQ_id}" type="set" xmlns="jabber:client">`+
`<query queryid="${queryid}" xmlns="urn:xmpp:mam:2">`+
`<x type="submit" xmlns="jabber:x:data">`+
`<field type="hidden" var="FORM_TYPE">`+
`<value>urn:xmpp:mam:2</value>`+
`</field>`+
`<field var="start">`+
`<value>${moment(start).format()}</value>`+
`</field>`+
`</x>`+
`<set xmlns="http://jabber.org/protocol/rsm">`+
`<max>10</max>`+
`<after>09af3-cc343-b409f</after>`+
`</set>`+
`</query>`+
`</iq>`);
done();
})); }));
it("accepts \"before\" with an empty string as value to reverse the order", it("accepts \"before\" with an empty string as value to reverse the order",
mock.initConverseWithPromises( mock.initConverseWithPromises(
null, [], {}, null, [], {},
function (done, _converse) { async function (done, _converse) {
_converse.api.disco.entities.get(_converse.domain).then(function (entity) { const entity = await _converse.api.disco.entities.get(_converse.domain);
if (!entity.features.findWhere({'var': Strophe.NS.MAM})) { if (!entity.features.findWhere({'var': Strophe.NS.MAM})) {
_converse.disco_entities.get(_converse.domain).features.create({'var': Strophe.NS.MAM}); _converse.disco_entities.get(_converse.domain).features.create({'var': Strophe.NS.MAM});
} }
var sent_stanza, IQ_id; let sent_stanza, IQ_id;
var sendIQ = _converse.connection.sendIQ; const sendIQ = _converse.connection.sendIQ;
spyOn(_converse.connection, 'sendIQ').and.callFake(function (iq, callback, errback) { spyOn(_converse.connection, 'sendIQ').and.callFake(function (iq, callback, errback) {
sent_stanza = iq; sent_stanza = iq;
IQ_id = sendIQ.bind(this)(iq, callback, errback); IQ_id = sendIQ.bind(this)(iq, callback, errback);
});
_converse.api.archive.query({'before': '', 'max':10});
var queryid = sent_stanza.nodeTree.querySelector('query').getAttribute('queryid');
expect(sent_stanza.toString()).toBe(
`<iq id="${IQ_id}" type="set" xmlns="jabber:client">`+
`<query queryid="${queryid}" xmlns="urn:xmpp:mam:2">`+
`<x type="submit" xmlns="jabber:x:data">`+
`<field type="hidden" var="FORM_TYPE">`+
`<value>urn:xmpp:mam:2</value>`+
`</field>`+
`</x>`+
`<set xmlns="http://jabber.org/protocol/rsm">`+
`<max>10</max>`+
`<before></before>`+
`</set>`+
`</query>`+
`</iq>`);
done();
}); });
_converse.api.archive.query({'before': '', 'max':10});
const queryid = sent_stanza.nodeTree.querySelector('query').getAttribute('queryid');
expect(sent_stanza.toString()).toBe(
`<iq id="${IQ_id}" type="set" xmlns="jabber:client">`+
`<query queryid="${queryid}" xmlns="urn:xmpp:mam:2">`+
`<x type="submit" xmlns="jabber:x:data">`+
`<field type="hidden" var="FORM_TYPE">`+
`<value>urn:xmpp:mam:2</value>`+
`</field>`+
`</x>`+
`<set xmlns="http://jabber.org/protocol/rsm">`+
`<max>10</max>`+
`<before></before>`+
`</set>`+
`</query>`+
`</iq>`);
done();
})); }));
it("accepts a Strophe.RSM object for the query options", it("accepts a Strophe.RSM object for the query options",
mock.initConverseWithPromises( mock.initConverseWithPromises(
null, [], {}, null, [], {},
function (done, _converse) { async function (done, _converse) {
_converse.api.disco.entities.get(_converse.domain).then(function (entity) { const entity = await _converse.api.disco.entities.get(_converse.domain);
if (!entity.features.findWhere({'var': Strophe.NS.MAM})) { if (!entity.features.findWhere({'var': Strophe.NS.MAM})) {
_converse.disco_entities.get(_converse.domain).features.create({'var': Strophe.NS.MAM}); _converse.disco_entities.get(_converse.domain).features.create({'var': Strophe.NS.MAM});
} }
var sent_stanza, IQ_id; let sent_stanza, IQ_id;
var sendIQ = _converse.connection.sendIQ; const sendIQ = _converse.connection.sendIQ;
spyOn(_converse.connection, 'sendIQ').and.callFake(function (iq, callback, errback) { spyOn(_converse.connection, 'sendIQ').and.callFake(function (iq, callback, errback) {
sent_stanza = iq; sent_stanza = iq;
IQ_id = sendIQ.bind(this)(iq, callback, errback); IQ_id = sendIQ.bind(this)(iq, callback, errback);
});
// Normally the user wouldn't manually make a Strophe.RSM object
// and pass it in. However, in the callback method an RSM object is
// returned which can be reused for easy paging. This test is
// more for that usecase.
var rsm = new Strophe.RSM({'max': '10'});
rsm['with'] = 'romeo@montague.lit'; // eslint-disable-line dot-notation
rsm.start = '2010-06-07T00:00:00Z';
_converse.api.archive.query(rsm);
var queryid = sent_stanza.nodeTree.querySelector('query').getAttribute('queryid');
expect(sent_stanza.toString()).toBe(
`<iq id="${IQ_id}" type="set" xmlns="jabber:client">`+
`<query queryid="${queryid}" xmlns="urn:xmpp:mam:2">`+
`<x type="submit" xmlns="jabber:x:data">`+
`<field type="hidden" var="FORM_TYPE">`+
`<value>urn:xmpp:mam:2</value>`+
`</field>`+
`<field var="with">`+
`<value>romeo@montague.lit</value>`+
`</field>`+
`<field var="start">`+
`<value>${moment(rsm.start).format()}</value>`+
`</field>`+
`</x>`+
`<set xmlns="http://jabber.org/protocol/rsm">`+
`<max>10</max>`+
`</set>`+
`</query>`+
`</iq>`);
done();
}); });
// Normally the user wouldn't manually make a Strophe.RSM object
// and pass it in. However, in the callback method an RSM object is
// returned which can be reused for easy paging. This test is
// more for that usecase.
const rsm = new Strophe.RSM({'max': '10'});
rsm['with'] = 'romeo@montague.lit'; // eslint-disable-line dot-notation
rsm.start = '2010-06-07T00:00:00Z';
_converse.api.archive.query(rsm);
const queryid = sent_stanza.nodeTree.querySelector('query').getAttribute('queryid');
expect(sent_stanza.toString()).toBe(
`<iq id="${IQ_id}" type="set" xmlns="jabber:client">`+
`<query queryid="${queryid}" xmlns="urn:xmpp:mam:2">`+
`<x type="submit" xmlns="jabber:x:data">`+
`<field type="hidden" var="FORM_TYPE">`+
`<value>urn:xmpp:mam:2</value>`+
`</field>`+
`<field var="with">`+
`<value>romeo@montague.lit</value>`+
`</field>`+
`<field var="start">`+
`<value>${moment(rsm.start).format()}</value>`+
`</field>`+
`</x>`+
`<set xmlns="http://jabber.org/protocol/rsm">`+
`<max>10</max>`+
`</set>`+
`</query>`+
`</iq>`);
done();
})); }));
it("accepts a callback function, which it passes the messages and a Strophe.RSM object", it("accepts a callback function, which it passes the messages and a Strophe.RSM object",
......
...@@ -331,10 +331,10 @@ converse.plugins.add('converse-omemo', { ...@@ -331,10 +331,10 @@ converse.plugins.add('converse-omemo', {
} }
}, },
getMessageAttributesFromStanza (stanza, original_stanza) { async getMessageAttributesFromStanza (stanza, original_stanza) {
const { _converse } = this.__super__, const { _converse } = this.__super__,
encrypted = sizzle(`encrypted[xmlns="${Strophe.NS.OMEMO}"]`, original_stanza).pop(), encrypted = sizzle(`encrypted[xmlns="${Strophe.NS.OMEMO}"]`, original_stanza).pop(),
attrs = this.__super__.getMessageAttributesFromStanza.apply(this, arguments); attrs = await this.__super__.getMessageAttributesFromStanza.apply(this, arguments);
if (!encrypted || !_converse.config.get('trusted')) { if (!encrypted || !_converse.config.get('trusted')) {
return attrs; return attrs;
......
...@@ -557,31 +557,22 @@ converse.plugins.add('converse-chatboxes', { ...@@ -557,31 +557,22 @@ converse.plugins.add('converse-chatboxes', {
return attrs; return attrs;
}, },
createMessage (message, original_stanza) { async createMessage (message, original_stanza) {
/* Create a Backbone.Message object inside this chat box /* Create a Backbone.Message object inside this chat box
* based on the identified message stanza. * based on the identified message stanza.
*/ */
const that = this; const attrs = await this.getMessageAttributesFromStanza(message, original_stanza),
function _create (attrs) { is_csn = u.isOnlyChatStateNotification(attrs);
const is_csn = u.isOnlyChatStateNotification(attrs);
if (is_csn && (attrs.is_delayed || if (is_csn && (attrs.is_delayed || (attrs.type === 'groupchat' && Strophe.getResourceFromJid(attrs.from) == this.get('nick')))) {
(attrs.type === 'groupchat' && Strophe.getResourceFromJid(attrs.from) == that.get('nick')))) { // XXX: MUC leakage
// XXX: MUC leakage // No need showing delayed or our own CSN messages
// No need showing delayed or our own CSN messages return;
return; } else if (!is_csn && !attrs.file && !attrs.plaintext && !attrs.message && !attrs.oob_url && attrs.type !== 'error') {
} else if (!is_csn && !attrs.file && !attrs.plaintext && !attrs.message && !attrs.oob_url && attrs.type !== 'error') { // TODO: handle <subject> messages (currently being done by ChatRoom)
// TODO: handle <subject> messages (currently being done by ChatRoom) return;
return;
} else {
return that.messages.create(attrs);
}
}
const result = this.getMessageAttributesFromStanza(message, original_stanza)
if (typeof result.then === "function") {
return new Promise((resolve, reject) => result.then(attrs => resolve(_create(attrs))));
} else { } else {
const message = _create(result) return this.messages.create(attrs);
return Promise.resolve(message);
} }
}, },
......
...@@ -133,20 +133,10 @@ converse.plugins.add('converse-mam', { ...@@ -133,20 +133,10 @@ converse.plugins.add('converse-mam', {
// New functions which don't exist yet can also be added. // New functions which don't exist yet can also be added.
ChatBox: { ChatBox: {
getMessageAttributesFromStanza (message, original_stanza) { async getMessageAttributesFromStanza (message, original_stanza) {
function _process (attrs) { const attrs = await this.__super__.getMessageAttributesFromStanza.apply(this, arguments);
const archive_id = getMessageArchiveID(original_stanza); attrs.archive_id = getMessageArchiveID(original_stanza);
if (archive_id) { return attrs;
attrs.archive_id = archive_id;
}
return attrs;
}
const result = this.__super__.getMessageAttributesFromStanza.apply(this, arguments)
if (result instanceof Promise) {
return new Promise((resolve, reject) => result.then((attrs) => resolve(_process(attrs))).catch(reject));
} else {
return _process(result);
}
} }
}, },
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment