(function (root, factory) { define(["jquery", "jasmine", "mock", "converse-core", "test-utils"], factory); } (this, function ($, jasmine, mock, converse, test_utils) { var _ = converse.env._; var Strophe = converse.env.Strophe; var $pres = converse.env.$pres; var $msg = converse.env.$msg; var $iq = converse.env.$iq; var u = converse.env.utils; var checkHeaderToggling = function (group) { var $group = $(group); var toggle = group.querySelector('a.group-toggle'); expect(u.isVisible($group[0])).toBeTruthy(); expect($group.find('ul.collapsed').length).toBe(0); expect(u.hasClass('fa-caret-right', toggle.firstElementChild)).toBeFalsy(); expect(u.hasClass('fa-caret-down', toggle.firstElementChild)).toBeTruthy(); toggle.click(); return test_utils.waitUntil(function () { return $group.find('ul.collapsed').length === 1; }, 500).then(function () { expect(u.hasClass('fa-caret-right', toggle.firstElementChild)).toBeTruthy(); expect(u.hasClass('fa-caret-down', toggle.firstElementChild)).toBeFalsy(); toggle.click(); return test_utils.waitUntil(function () { return $group.find('li').length === $group.find('li:visible').length }, 500); }).then(function () { expect(u.hasClass('fa-caret-right', toggle.firstElementChild)).toBeFalsy(); expect(u.hasClass('fa-caret-down', toggle.firstElementChild)).toBeTruthy(); }); }; describe("The Contacts Roster", function () { describe("The live filter", function () { it("will only appear when roster contacts flow over the visible area", mock.initConverseWithPromises( null, ['rosterGroupsFetched'], {}, function (done, _converse) { var $filter = $(_converse.rosterview.el.querySelector('.roster-filter')); var names = mock.cur_names; test_utils.openControlBox(); _converse.rosterview.update(); // XXX: Will normally called as event handler expect($filter.length).toBe(1); test_utils.waitUntil(function () { return !$filter.is(':visible'); }).then(function () { for (var i=0; i $roster.find('li:visible').length === 15, 600) .then(function (contacts) { expect($roster.find('ul.roster-group-contacts:visible').length).toBe(5); $filter[0].value = "candice"; u.triggerEvent($filter[0], "keydown", "KeyboardEvent"); return test_utils.waitUntil(() => $roster.find('li:visible').length === 1, 600); }).then(function (contacts) { // Only one roster contact is now visible expect($roster.find('li:visible').length).toBe(1); expect($roster.find('li:visible').eq(0).text().trim()).toBe('Candice van der Knijff'); // Only one foster group is still visible expect($roster.find('.roster-group:visible').length).toBe(1); expect(_.trim($roster.find('.roster-group:visible a.group-toggle').eq(0).text())).toBe('colleagues'); $filter = $(_converse.rosterview.el).find('.roster-filter'); $filter.val("an"); u.triggerEvent($filter[0], "keydown", "KeyboardEvent"); return test_utils.waitUntil(function () { return $roster.find('li:visible').length === 5; }, 600) }).then(function (contacts) { // Five roster contact is now visible expect($roster.find('li:visible').length).toBe(5); // Four groups are still visible var $groups = $roster.find('.roster-group:visible a.group-toggle'); expect($groups.length).toBe(4); expect(_.trim($groups.eq(0).text())).toBe('colleagues'); expect(_.trim($groups.eq(1).text())).toBe('Family'); expect(_.trim($groups.eq(2).text())).toBe('friends & acquaintences'); expect(_.trim($groups.eq(3).text())).toBe('ænemies'); $filter = $(_converse.rosterview.el).find('.roster-filter'); $filter.val("xxx"); u.triggerEvent($filter[0], "keydown", "KeyboardEvent"); return test_utils.waitUntil(function () { return $roster.find('li:visible').length === 0; }, 600) }).then(function () { expect($roster.find('ul.roster-group-contacts:visible a.group-toggle').length).toBe(0); $filter = $(_converse.rosterview.el).find('.roster-filter'); $filter.val(""); // Check that contacts are shown again, when the filter string is cleared. u.triggerEvent($filter[0], "keydown", "KeyboardEvent"); return test_utils.waitUntil(function () { return $roster.find('li:visible').length === 15; }, 600) }).then(function () { expect($roster.find('ul.roster-group-contacts:visible').length).toBe(5); _converse.roster_groups = false; done(); }).catch(_.partial(_converse.log, _, Strophe.LogLevel.FATAL)); })); it("will also filter out contacts added afterwards", mock.initConverseWithPromises( null, ['rosterGroupsFetched'], {}, function (done, _converse) { test_utils.openControlBox(); test_utils.createGroupedContacts(_converse); var $filter = $(_converse.rosterview.el).find('.roster-filter'); var $roster = $(_converse.rosterview.roster_el); _converse.rosterview.filter_view.delegateEvents(); test_utils.waitUntil(function () { return $roster.find('li:visible').length === 15; }, 300).then(function (contacts) { $filter.val("an"); u.triggerEvent($filter[0], "keydown", "KeyboardEvent"); return test_utils.waitUntil(function () { return $roster.find('li:visible').length === 5; }, 500) }).then(function (contacts) { // Five roster contact is now visible expect($roster.find('li:visible').length).toBe(5); // Four groups are still visible var $groups = $roster.find('.roster-group:visible a.group-toggle'); expect($groups.length).toBe(4); expect(_.trim($groups.eq(0).text())).toBe('colleagues'); expect(_.trim($groups.eq(1).text())).toBe('Family'); expect(_.trim($groups.eq(2).text())).toBe('friends & acquaintences'); expect(_.trim($groups.eq(3).text())).toBe('ænemies'); _converse.roster.create({ jid: 'latecomer@localhost', subscription: 'both', ask: null, groups: ['newgroup'], fullname: 'Marty McLatecomer' }); return test_utils.waitUntil(function () { return $roster.find('.roster-group[data-group="newgroup"] li').length; }, 300); }).then(function (contacts) { // The "newgroup" group doesn't appear expect($roster.find('.roster-group:visible').length).toBe(4); expect($roster.find('.roster-group').length).toBe(6); done(); }); })); it("can be used to filter the groups shown", mock.initConverseWithPromises( null, ['rosterGroupsFetched'], {}, function (done, _converse) { _converse.roster_groups = true; test_utils.openControlBox(); test_utils.createGroupedContacts(_converse); _converse.rosterview.filter_view.delegateEvents(); var $roster = $(_converse.rosterview.roster_el); var button = _converse.rosterview.el.querySelector('span[data-type="groups"]'); button.click(); test_utils.waitUntil(function () { return $roster.find('li:visible').length === 15; }, 600).then(function () { expect($roster.find('div.roster-group:visible a.group-toggle').length).toBe(5); var filter = _converse.rosterview.el.querySelector('.roster-filter'); filter.value = "colleagues"; u.triggerEvent(filter, "keydown", "KeyboardEvent"); return test_utils.waitUntil(function () { return $roster.find('div.roster-group:not(.collapsed) a.group-toggle').length === 1; }, 600); }).then(function () { expect(_.trim($roster.find('div.roster-group:not(.collapsed) a').eq(0).text())).toBe('colleagues'); expect($roster.find('div.roster-group:not(.collapsed) li:visible').length).toBe(3); // Check that all contacts under the group are shown expect($roster.find('div.roster-group:not(.collapsed) li:hidden').length).toBe(0); var filter = _converse.rosterview.el.querySelector('.roster-filter'); filter.value = "xxx"; u.triggerEvent(filter, "keydown", "KeyboardEvent"); return test_utils.waitUntil(function () { return $roster.find('div.roster-group.collapsed a.group-toggle').length === 5; }, 700); }).then(function () { expect($roster.find('div.roster-group:not(.collapsed) a').length).toBe(0); var filter = _converse.rosterview.el.querySelector('.roster-filter'); filter.value = ""; // Check that groups are shown again, when the filter string is cleared. u.triggerEvent(filter, "keydown", "KeyboardEvent"); return test_utils.waitUntil(function () { return $roster.find('div.roster-group.collapsed a.group-toggle').length === 0; }, 600); }).then(function () { expect($roster.find('div.roster-group:not(collapsed)').length).toBe(5); expect($roster.find('div.roster-group:not(collapsed) li').length).toBe(15); done(); }); })); it("has a button with which its contents can be cleared", mock.initConverseWithPromises( null, ['rosterGroupsFetched'], {}, function (done, _converse) { _converse.roster_groups = true; test_utils.openControlBox(); test_utils.createGroupedContacts(_converse); var filter = _converse.rosterview.el.querySelector('.roster-filter'); filter.value = "xxx"; u.triggerEvent(filter, "keydown", "KeyboardEvent"); expect(_.includes(filter.classList, "x")).toBeFalsy(); expect(u.hasClass('hidden', _converse.rosterview.el.querySelector('.roster-filter-form .clear-input'))).toBeTruthy(); test_utils.waitUntil(function () { return !u.hasClass('hidden', _converse.rosterview.el.querySelector('.roster-filter-form .clear-input')); }, 900).then(function () { var filter = _converse.rosterview.el.querySelector('.roster-filter'); _converse.rosterview.el.querySelector('.clear-input').click(); expect(document.querySelector('.roster-filter').value).toBe(""); done(); }); })); it("can be used to filter contacts by their chat state", mock.initConverseWithPromises( null, ['rosterGroupsFetched'], {}, function (done, _converse) { test_utils.createGroupedContacts(_converse); var jid = mock.cur_names[3].replace(/ /g,'.').toLowerCase() + '@localhost'; _converse.roster.get(jid).presence.set('show', 'online'); jid = mock.cur_names[4].replace(/ /g,'.').toLowerCase() + '@localhost'; _converse.roster.get(jid).presence.set('show', 'dnd'); test_utils.openControlBox(); var button = _converse.rosterview.el.querySelector('span[data-type="state"]'); button.click(); var $roster = $(_converse.rosterview.roster_el); test_utils.waitUntil(() => $roster.find('li:visible').length === 15, 500).then(function () { var filter = _converse.rosterview.el.querySelector('.state-type'); expect($roster.find('ul.roster-group-contacts:visible').length).toBe(5); filter.value = "online"; u.triggerEvent(filter, 'change'); return test_utils.waitUntil(() => $roster.find('li:visible').length === 1, 500); }).then(function () { expect($roster.find('li:visible').eq(0).text().trim()).toBe('Rinse Sommer'); expect($roster.find('ul.roster-group-contacts:visible').length).toBe(1); var filter = _converse.rosterview.el.querySelector('.state-type'); filter.value = "dnd"; u.triggerEvent(filter, 'change'); return test_utils.waitUntil(function () { return $roster.find('li:visible').eq(0).text().trim() === 'Annegreet Gomez'; }, 900) }).then(function () { expect($roster.find('ul.roster-group-contacts:visible').length).toBe(1); done(); }).catch(_.partial(_converse.log, _, Strophe.LogLevel.FATAL)); })); }); describe("A Roster Group", function () { it("can be used to organize existing contacts", mock.initConverseWithPromises( null, ['rosterGroupsFetched'], {}, function (done, _converse) { _converse.roster_groups = true; spyOn(_converse, 'emit'); spyOn(_converse.rosterview, 'update').and.callThrough(); _converse.rosterview.render(); test_utils.openControlBox(); test_utils.createContacts(_converse, 'pending'); test_utils.createContacts(_converse, 'requesting'); test_utils.createGroupedContacts(_converse); // Check that the groups appear alphabetically and that // requesting and pending contacts are last. test_utils.waitUntil(function () { return $(_converse.rosterview.el).find('.roster-group:visible a.group-toggle').length; }, 500).then(function () { var group_titles = $.map( $(_converse.rosterview.el).find('.roster-group:visible a.group-toggle'), function (o) { return $(o).text().trim(); } ); expect(group_titles).toEqual([ "Contact requests", "colleagues", "Family", "friends & acquaintences", "ænemies", "Ungrouped", "Pending contacts" ]); // Check that usernames appear alphabetically per group _.each(_.keys(mock.groups), function (name) { var $contacts = $(_converse.rosterview.el).find('.roster-group[data-group="'+name+'"] ul'); var names = $.map($contacts, function (o) { return $(o).text().trim(); }); expect(names).toEqual(_.clone(names).sort()); }); done(); }); })); it("gets created when a contact's \"groups\" attribute changes", mock.initConverseWithPromises( null, ['rosterGroupsFetched'], {}, function (done, _converse) { _converse.roster_groups = true; spyOn(_converse, 'emit'); spyOn(_converse.rosterview, 'update').and.callThrough(); _converse.rosterview.render(); test_utils.openControlBox(); _converse.roster.create({ jid: 'groupchanger@localhost', subscription: 'both', ask: null, groups: ['firstgroup'], fullname: 'George Groupchanger' }); // Check that the groups appear alphabetically and that // requesting and pending contacts are last. test_utils.waitUntil(function () { return $(_converse.rosterview.el).find('.roster-group:visible a.group-toggle').length; }, 500).then(function () { var group_titles = $.map( $(_converse.rosterview.el).find('.roster-group:visible a.group-toggle'), function (o) { return $(o).text().trim(); } ); expect(group_titles).toEqual(['firstgroup']); var contact = _converse.roster.get('groupchanger@localhost'); contact.set({'groups': ['secondgroup']}); return test_utils.waitUntil(function () { return $(_converse.rosterview.el).find('.roster-group[data-group="secondgroup"]:visible a.group-toggle').length; }, 500); }).then(function () { var group_titles = $.map( $(_converse.rosterview.el).find('.roster-group:visible a.group-toggle'), function (o) { return $(o).text().trim(); } ); expect(group_titles).toEqual(['secondgroup']); done(); }); })); it("can share contacts with other roster groups", mock.initConverseWithPromises( null, ['rosterGroupsFetched'], {}, function (done, _converse) { _converse.roster_groups = true; var groups = ['colleagues', 'friends']; spyOn(_converse, 'emit'); spyOn(_converse.rosterview, 'update').and.callThrough(); test_utils.openControlBox(); _converse.rosterview.render(); for (var i=0; i"+ ""+ ""+ ""+ ""); done(); }); })); it("do not have a header if there aren't any", mock.initConverseWithPromises( null, ['rosterGroupsFetched'], {}, function (done, _converse) { test_utils.openControlBox(); var name = mock.pend_names[0]; _converse.roster.create({ jid: name.replace(/ /g,'.').toLowerCase() + '@localhost', subscription: 'none', ask: 'subscribe', fullname: name }); spyOn(window, 'confirm').and.returnValue(true); spyOn(_converse.connection, 'sendIQ').and.callFake(function (iq, callback) { if (typeof callback === "function") { return callback(); } }); test_utils.waitUntil(function () { var $pending_contacts = $(_converse.rosterview.get('Pending contacts').el); return $pending_contacts.is(':visible') && $pending_contacts.find('li:visible').length; }, 700).then(function () { $(_converse.rosterview.el).find(".pending-contact-name:contains('"+name+"')") .parent().siblings('.remove-xmpp-contact')[0].click(); expect(window.confirm).toHaveBeenCalled(); expect(_converse.connection.sendIQ).toHaveBeenCalled(); expect(u.isVisible(_converse.rosterview.get('Pending contacts').el)).toEqual(false); done(); }); })); it("is shown when a new private message is received", mock.initConverseWithPromises( null, ['rosterGroupsFetched'], {}, function (done, _converse) { _addContacts(_converse); return test_utils.waitUntil(() => _converse.roster.at(0).vcard.get('fullname')) .then(function () { var name; spyOn(window, 'confirm').and.returnValue(true); for (var i=0; i