(function (root, factory) { define(["jasmine", "mock", "test-utils"], factory); } (this, function (jasmine, mock, test_utils) { "use strict"; const $iq = converse.env.$iq; const Strophe = converse.env.Strophe; const sizzle = converse.env.sizzle; const u = converse.env.utils; describe("XEP-0198 Stream Management", function () { it("gets enabled with an stanza and resumed with a stanza", 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'); spyOn(view, 'renderControlBoxPane').and.callThrough(); _converse.api.user.login('romeo@montague.lit/orchard', 'secret'); const sent_stanzas = _converse.connection.sent_stanzas; let stanza = await u.waitUntil(() => sent_stanzas.filter(s => (s.tagName === 'enable')).pop()); expect(_converse.session.get('smacks_enabled')).toBe(false); expect(Strophe.serialize(stanza)).toEqual(''); let result = u.toStanza(``); _converse.connection._dataRecv(test_utils.createRequest(result)); expect(_converse.session.get('smacks_enabled')).toBe(true); await u.waitUntil(() => view.renderControlBoxPane.calls.count()); let IQ_stanzas = _converse.connection.IQ_stanzas; await u.waitUntil(() => IQ_stanzas.length === 4); let iq = IQ_stanzas[IQ_stanzas.length-1]; expect(Strophe.serialize(iq)).toBe( ``); await test_utils.waitForRoster(_converse, 'current', 1); IQ_stanzas.pop(); const disco_iq = IQ_stanzas.pop(); expect(Strophe.serialize(disco_iq)).toBe( ``+ ``); iq = IQ_stanzas.pop(); expect(Strophe.serialize(iq)).toBe( ``+ ``); iq = IQ_stanzas.pop(); expect(Strophe.serialize(iq)).toBe( ``+ ``); expect(sent_stanzas.filter(s => (s.nodeName === 'r')).length).toBe(2); expect(_converse.session.get('unacked_stanzas').length).toBe(5); // test handling of acks let ack = u.toStanza(``); _converse.connection._dataRecv(test_utils.createRequest(ack)); expect(_converse.session.get('unacked_stanzas').length).toBe(3); // test handling of ack requests let r = u.toStanza(``); _converse.connection._dataRecv(test_utils.createRequest(r)); ack = await u.waitUntil(() => sent_stanzas.filter(s => (s.nodeName === 'a')).pop()); expect(Strophe.serialize(ack)).toBe(''); const disco_result = $iq({ 'type': 'result', 'from': 'montague.lit', 'to': 'romeo@montague.lit/orchard', 'id': disco_iq.getAttribute('id'), }).c('query', {'xmlns': 'http://jabber.org/protocol/disco#info'}) .c('identity', { 'category': 'server', 'type': 'im' }).up() .c('feature', {'var': 'http://jabber.org/protocol/disco#info'}).up() .c('feature', {'var': 'http://jabber.org/protocol/disco#items'}); _converse.connection._dataRecv(test_utils.createRequest(disco_result)); ack = u.toStanza(``); _converse.connection._dataRecv(test_utils.createRequest(ack)); expect(_converse.session.get('unacked_stanzas').length).toBe(2); r = u.toStanza(``); _converse.connection._dataRecv(test_utils.createRequest(r)); ack = await u.waitUntil(() => sent_stanzas.filter(s => (s.nodeName === 'a' && s.getAttribute('h') === '1')).pop()); expect(Strophe.serialize(ack)).toBe(''); // test session resumption _converse.connection.IQ_stanzas = []; IQ_stanzas = _converse.connection.IQ_stanzas; await _converse.api.connection.reconnect(); stanza = await u.waitUntil(() => sent_stanzas.filter(s => (s.tagName === 'resume')).pop()); expect(Strophe.serialize(stanza)).toEqual(''); result = u.toStanza(``); _converse.connection._dataRecv(test_utils.createRequest(result)); // Another stanza doesn't get sent out expect(sent_stanzas.filter(s => (s.tagName === 'enable')).length).toBe(1); expect(_converse.session.get('smacks_enabled')).toBe(true); await u.waitUntil(() => IQ_stanzas.length === 1); // Test that unacked stanzas get resent out iq = IQ_stanzas.pop(); expect(Strophe.serialize(iq)).toBe(``); expect(IQ_stanzas.filter(iq => sizzle('query[xmlns="jabber:iq:roster"]', iq).pop()).length).toBe(0); await _converse.api.waitUntil('statusInitialized'); done(); })); it("might not resume and the session will then be reset", mock.initConverse( ['chatBoxesInitialized'], { 'auto_login': false, 'enable_smacks': true, 'show_controlbox_by_default': true, 'smacks_max_unacked_stanzas': 2 }, async function (done, _converse) { _converse.api.user.login('romeo@montague.lit/orchard', 'secret'); const sent_stanzas = _converse.connection.sent_stanzas; let stanza = await u.waitUntil(() => sent_stanzas.filter(s => (s.tagName === 'enable')).pop()); expect(Strophe.serialize(stanza)).toEqual(''); let result = u.toStanza(``); _converse.connection._dataRecv(test_utils.createRequest(result)); await test_utils.waitForRoster(_converse, 'current', 1); // test session resumption await _converse.api.connection.reconnect(); stanza = await u.waitUntil(() => sent_stanzas.filter(s => (s.tagName === 'resume')).pop()); expect(Strophe.serialize(stanza)).toEqual(''); result = u.toStanza( ``+ ``+ ``); _converse.connection._dataRecv(test_utils.createRequest(result)); // Session data gets reset expect(_converse.session.get('smacks_enabled')).toBe(false); 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_since_last_ack')).toBe(0); expect(_converse.session.get('unacked_stanzas').length).toBe(0); expect(_converse.session.get('roster_cached')).toBeFalsy(); await u.waitUntil(() => sent_stanzas.filter(s => (s.tagName === 'enable')).length === 2); stanza = sent_stanzas.filter(s => (s.tagName === 'enable')).pop(); expect(Strophe.serialize(stanza)).toEqual(''); result = u.toStanza(``); _converse.connection._dataRecv(test_utils.createRequest(result)); expect(_converse.session.get('smacks_enabled')).toBe(true); // Check that the roster gets fetched await test_utils.waitForRoster(_converse, 'current', 1); done(); })); }); }));