/*global mock, converse */ const $msg = converse.env.$msg; const u = converse.env.utils; const sizzle = converse.env.sizzle; describe("A chat message", function () { it("received for a minimized chat box will increment a counter on its header", mock.initConverse( ['rosterGroupsFetched', 'chatBoxesFetched'], {}, async function (done, _converse) { if (_converse.view_mode === 'fullscreen') { return done(); } await mock.waitForRoster(_converse, 'current'); const contact_name = mock.cur_names[0]; const contact_jid = contact_name.replace(/ /g,'.').toLowerCase() + '@montague.lit'; await mock.openControlBox(_converse); spyOn(_converse.api, "trigger").and.callThrough(); await u.waitUntil(() => _converse.rosterview.el.querySelectorAll('.roster-group').length); await mock.openChatBoxFor(_converse, contact_jid); const chatview = _converse.api.chatviews.get(contact_jid); expect(u.isVisible(chatview.el)).toBeTruthy(); expect(chatview.model.get('minimized')).toBeFalsy(); chatview.el.querySelector('.toggle-chatbox-button').click(); expect(chatview.model.get('minimized')).toBeTruthy(); var message = 'This message is sent to a minimized chatbox'; var sender_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit'; var msg = $msg({ from: sender_jid, to: _converse.connection.jid, type: 'chat', id: u.getUniqueId() }).c('body').t(message).up() .c('active', {'xmlns': 'http://jabber.org/protocol/chatstates'}).tree(); await _converse.handleMessageStanza(msg); await u.waitUntil(() => chatview.model.messages.length); expect(_converse.api.trigger).toHaveBeenCalledWith('message', jasmine.any(Object)); const trimmed_chatboxes = _converse.minimized_chats; let count = trimmed_chatboxes.el.querySelector('converse-minimized-chat .message-count'); expect(u.isVisible(chatview.el)).toBeFalsy(); expect(chatview.model.get('minimized')).toBeTruthy(); expect(u.isVisible(count)).toBeTruthy(); expect(count.textContent).toBe('1'); _converse.handleMessageStanza( $msg({ from: mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit', to: _converse.connection.jid, type: 'chat', id: u.getUniqueId() }).c('body').t('This message is also sent to a minimized chatbox').up() .c('active', {'xmlns': 'http://jabber.org/protocol/chatstates'}).tree() ); await u.waitUntil(() => (chatview.model.messages.length > 1)); expect(u.isVisible(chatview.el)).toBeFalsy(); expect(chatview.model.get('minimized')).toBeTruthy(); count = trimmed_chatboxes.el.querySelector('converse-minimized-chat .message-count'); expect(u.isVisible(count)).toBeTruthy(); expect(count.textContent).toBe('2'); _converse.minimized_chats.el.querySelector("a.restore-chat").click(); expect(_converse.chatboxes.filter('minimized').length).toBe(0); done(); })); }); describe("A Groupcaht", function () { it("can be minimized by clicking a DOM element with class 'toggle-chatbox-button'", mock.initConverse( ['rosterGroupsFetched', 'chatBoxesFetched'], {}, async function (done, _converse) { await mock.openChatRoom(_converse, 'lounge', 'montague.lit', 'romeo'); const view = _converse.chatboxviews.get('lounge@montague.lit'); spyOn(view, 'onMinimized').and.callThrough(); spyOn(view, 'onMaximized').and.callThrough(); spyOn(_converse.api, "trigger").and.callThrough(); view.delegateEvents(); // We need to rebind all events otherwise our spy won't be called const button = await u.waitUntil(() => view.el.querySelector('.toggle-chatbox-button')); button.click(); expect(view.onMinimized).toHaveBeenCalled(); expect(_converse.api.trigger).toHaveBeenCalledWith('chatBoxMinimized', jasmine.any(Object)); expect(u.isVisible(view.el)).toBeFalsy(); expect(view.model.get('minimized')).toBeTruthy(); expect(view.onMinimized).toHaveBeenCalled(); const el = await u.waitUntil(() => _converse.minimized_chats.el.querySelector("a.restore-chat")); el.click(); expect(view.onMaximized).toHaveBeenCalled(); expect(_converse.api.trigger).toHaveBeenCalledWith('chatBoxMaximized', jasmine.any(Object)); expect(view.model.get('minimized')).toBeFalsy(); expect(_converse.api.trigger.calls.count(), 3); done(); })); }); describe("A Chatbox", function () { it("can be minimized by clicking a DOM element with class 'toggle-chatbox-button'", mock.initConverse( ['rosterGroupsFetched', 'chatBoxesFetched'], {}, async function (done, _converse) { await mock.waitForRoster(_converse, 'current'); await mock.openControlBox(_converse); const contact_jid = mock.cur_names[7].replace(/ /g,'.').toLowerCase() + '@montague.lit'; await u.waitUntil(() => _converse.rosterview.el.querySelectorAll('.roster-group').length); await mock.openChatBoxFor(_converse, contact_jid); const chatview = _converse.chatboxviews.get(contact_jid); spyOn(chatview, 'minimize').and.callThrough(); spyOn(_converse.api, "trigger").and.callThrough(); // We need to rebind all events otherwise our spy won't be called chatview.delegateEvents(); chatview.el.querySelector('.toggle-chatbox-button').click(); expect(chatview.minimize).toHaveBeenCalled(); expect(_converse.api.trigger).toHaveBeenCalledWith('chatBoxMinimized', jasmine.any(Object)); expect(_converse.api.trigger.calls.count(), 2); expect(u.isVisible(chatview.el)).toBeFalsy(); expect(chatview.model.get('minimized')).toBeTruthy(); chatview.el.querySelector('.toggle-chatbox-button').click(); await u.waitUntil(() => _converse.chatboxviews.keys().length); _converse.minimized_chats.el.querySelector("a.restore-chat").click(); expect(_converse.api.trigger).toHaveBeenCalledWith('chatBoxMaximized', jasmine.any(Object)); expect(chatview.model.get('minimized')).toBeFalsy(); done(); })); it("can be opened in minimized mode initially", mock.initConverse( ['rosterGroupsFetched'], {}, async function (done, _converse) { await mock.waitForRoster(_converse, 'current'); const sender_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit'; expect(u.isVisible(_converse.minimized_chats.el.firstElementChild)).toBe(false); await _converse.api.chats.create(sender_jid, {'minimized': true}); await u.waitUntil(() => _converse.chatboxes.length > 1); const chatBoxView = _converse.chatboxviews.get(sender_jid); expect(u.isVisible(chatBoxView.el)).toBeFalsy(); expect(u.isVisible(_converse.minimized_chats.el.firstElementChild)).toBe(true); expect(_converse.minimized_chats.el.firstElementChild.querySelectorAll('converse-minimized-chat').length).toBe(1); expect(_converse.chatboxes.filter('minimized').length).toBe(1); done(); })); it("can be trimmed to conserve space", mock.initConverse(['rosterGroupsFetched'], {}, async function (done, _converse) { spyOn(_converse.chatboxviews, 'trimChats'); await mock.waitForRoster(_converse, 'current'); await mock.openControlBox(_converse); expect(_converse.chatboxviews.trimChats.calls.count()).toBe(1); let jid, chatboxview; // openControlBox was called earlier, so the controlbox is // visible, but no other chat boxes have been created. expect(_converse.chatboxes.length).toEqual(1); expect(document.querySelectorAll("#conversejs .chatbox").length).toBe(1); // Controlbox is open _converse.rosterview.update(); // XXX: Hack to make sure $roster element is attached. await u.waitUntil(() => _converse.rosterview.el.querySelectorAll('.roster-group li').length); // Test that they can be maximized again const online_contacts = _converse.rosterview.el.querySelectorAll('.roster-group .current-xmpp-contact a.open-chat'); expect(online_contacts.length).toBe(17); let i; for (i=0; i _converse.chatboxes.length == 16); expect(_converse.chatboxviews.trimChats.calls.count()).toBe(16); _converse.api.chatviews.get().forEach(v => spyOn(v, 'onMinimized').and.callThrough()); for (i=0; i _converse.chatboxviews.keys().length); var key = _converse.chatboxviews.keys()[1]; const chatbox = _converse.chatboxes.get(key); spyOn(chatbox, 'maximize').and.callThrough(); _converse.minimized_chats.el.querySelector("a.restore-chat").click(); expect(chatbox.maximize).toHaveBeenCalled(); expect(_converse.chatboxviews.trimChats.calls.count()).toBe(17); done(); })); }); describe("A Minimized ChatBoxView's Unread Message Count", function () { it("is displayed when scrolled up chatbox is minimized after receiving unread messages", mock.initConverse( ['rosterGroupsFetched', 'chatBoxesFetched'], {}, async function (done, _converse) { await mock.waitForRoster(_converse, 'current', 1); const sender_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit'; await mock.openChatBoxFor(_converse, sender_jid); const msgFactory = () => mock.createChatMessage(_converse, sender_jid, 'This message will be received as unread, but eventually will be read'); const selectUnreadMsgCount = () => _converse.minimized_chats.el.querySelector('#toggle-minimized-chats .unread-message-count'); const chatbox = _converse.chatboxes.get(sender_jid); chatbox.save('scrolled', true); _converse.handleMessageStanza(msgFactory()); await u.waitUntil(() => chatbox.messages.length); const chatboxview = _converse.chatboxviews.get(sender_jid); chatboxview.minimize(); const unread_count = selectUnreadMsgCount(); expect(u.isVisible(unread_count)).toBeTruthy(); expect(unread_count.innerHTML.replace(//g, '')).toBe('1'); done(); })); it("is incremented when message is received and windows is not focused", mock.initConverse( ['rosterGroupsFetched', 'chatBoxesFetched'], {}, async function (done, _converse) { await mock.waitForRoster(_converse, 'current', 1); const sender_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit'; const view = await mock.openChatBoxFor(_converse, sender_jid) const msgFactory = () => mock.createChatMessage(_converse, sender_jid, 'This message will be received as unread, but eventually will be read'); const selectUnreadMsgCount = () => _converse.minimized_chats.el.querySelector('#toggle-minimized-chats .unread-message-count'); view.minimize(); _converse.handleMessageStanza(msgFactory()); await u.waitUntil(() => view.model.messages.length); const unread_count = selectUnreadMsgCount(); expect(u.isVisible(unread_count)).toBeTruthy(); expect(unread_count.innerHTML.replace(//g, '')).toBe('1'); done(); })); it("will render Openstreetmap-URL from geo-URI", mock.initConverse( ['rosterGroupsFetched', 'chatBoxesFetched'], {}, async function (done, _converse) { await mock.waitForRoster(_converse, 'current', 1); const message = "geo:37.786971,-122.399677"; const contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit'; await mock.openChatBoxFor(_converse, contact_jid); const view = _converse.chatboxviews.get(contact_jid); spyOn(view.model, 'sendMessage').and.callThrough(); mock.sendMessage(view, message); await u.waitUntil(() => view.el.querySelectorAll('.chat-content .chat-msg').length, 1000); expect(view.model.sendMessage).toHaveBeenCalled(); const msg = sizzle('.chat-content .chat-msg:last .chat-msg__text', view.el).pop(); await u.waitUntil(() => msg.innerHTML.replace(/\