(function (root, factory) { define(["jasmine", "mock", "test-utils"], factory); } (this, function (jasmine, mock, test_utils) { "use strict"; const _ = converse.env._; const $msg = converse.env.$msg; const u = converse.env.utils; describe("Notifications", function () { // Implement the protocol defined in https://xmpp.org/extensions/xep-0313.html#config describe("When show_desktop_notifications is set to true", function () { describe("And the desktop is not focused", function () { describe("an HTML5 Notification", function () { it("is shown when a new private message is received", mock.initConverse(['rosterGroupsFetched'], {}, async (done, _converse) => { await test_utils.waitForRoster(_converse, 'current'); spyOn(_converse, 'showMessageNotification').and.callThrough(); spyOn(_converse, 'areDesktopNotificationsEnabled').and.returnValue(true); spyOn(_converse, 'isMessageToHiddenChat').and.returnValue(true); const message = 'This message will show a desktop notification'; const sender_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit', msg = $msg({ from: sender_jid, to: _converse.connection.jid, type: 'chat', id: (new Date()).getTime() }).c('body').t(message).up() .c('active', {'xmlns': 'http://jabber.org/protocol/chatstates'}).tree(); await _converse.chatboxes.onMessage(msg); // This will emit 'message' await u.waitUntil(() => _converse.api.chatviews.get(sender_jid)); expect(_converse.areDesktopNotificationsEnabled).toHaveBeenCalled(); expect(_converse.showMessageNotification).toHaveBeenCalled(); done(); })); it("is shown when you are mentioned in a groupchat", mock.initConverse(['rosterGroupsFetched'], {}, async (done, _converse) => { await test_utils.waitForRoster(_converse, 'current'); await test_utils.openAndEnterChatRoom(_converse, 'lounge@montague.lit', 'romeo'); const view = _converse.api.chatviews.get('lounge@montague.lit'); if (!view.el.querySelectorAll('.chat-area').length) { view.renderChatArea(); } let no_notification = false; if (typeof window.Notification === 'undefined') { no_notification = true; window.Notification = function () { return { 'close': function () {} }; }; } spyOn(_converse, 'showMessageNotification').and.callThrough(); spyOn(_converse, 'areDesktopNotificationsEnabled').and.returnValue(true); const message = 'romeo: This message will show a desktop notification'; const nick = mock.chatroom_names[0], msg = $msg({ from: 'lounge@montague.lit/'+nick, id: (new Date()).getTime(), to: 'romeo@montague.lit', type: 'groupchat' }).c('body').t(message).tree(); _converse.connection._dataRecv(test_utils.createRequest(msg)); await new Promise(resolve => view.once('messageInserted', resolve)); await u.waitUntil(() => _converse.areDesktopNotificationsEnabled.calls.count() === 1); expect(_converse.showMessageNotification).toHaveBeenCalled(); if (no_notification) { delete window.Notification; } done(); })); it("is shown for headline messages", mock.initConverse(['rosterGroupsFetched'], {}, async (done, _converse) => { spyOn(_converse, 'showMessageNotification').and.callThrough(); spyOn(_converse, 'isMessageToHiddenChat').and.returnValue(true); spyOn(_converse, 'areDesktopNotificationsEnabled').and.returnValue(true); const stanza = $msg({ 'type': 'headline', 'from': 'notify.example.com', 'to': 'romeo@montague.lit', 'xml:lang': 'en' }) .c('subject').t('SIEVE').up() .c('body').t('<juliet@example.com> You got mail.').up() .c('x', {'xmlns': 'jabber:x:oob'}) .c('url').t('imap://romeo@example.com/INBOX;UIDVALIDITY=385759043/;UID=18'); _converse.connection._dataRecv(test_utils.createRequest(stanza)); await u.waitUntil(() => _converse.chatboxviews.keys().length); const view = _converse.chatboxviews.get('notify.example.com'); await new Promise(resolve => view.once('messageInserted', resolve)); expect( _.includes(_converse.chatboxviews.keys(), 'notify.example.com') ).toBeTruthy(); expect(_converse.showMessageNotification).toHaveBeenCalled(); done(); })); it("is not shown for full JID headline messages if allow_non_roster_messaging is false", mock.initConverse((done, _converse) => { _converse.allow_non_roster_messaging = false; spyOn(_converse, 'showMessageNotification').and.callThrough(); spyOn(_converse, 'areDesktopNotificationsEnabled').and.returnValue(true); const stanza = $msg({ 'type': 'headline', 'from': 'someone@notify.example.com', 'to': 'romeo@montague.lit', 'xml:lang': 'en' }) .c('subject').t('SIEVE').up() .c('body').t('<juliet@example.com> You got mail.').up() .c('x', {'xmlns': 'jabber:x:oob'}) .c('url').t('imap://romeo@example.com/INBOX;UIDVALIDITY=385759043/;UID=18'); _converse.connection._dataRecv(test_utils.createRequest(stanza)); expect( _.includes(_converse.chatboxviews.keys(), 'someone@notify.example.com') ).toBeFalsy(); expect(_converse.showMessageNotification).not.toHaveBeenCalled(); done(); })); it("is shown when a user changes their chat state (if show_chat_state_notifications is true)", mock.initConverse(['rosterGroupsFetched'], {show_chat_state_notifications: true}, async (done, _converse) => { await test_utils.waitForRoster(_converse, 'current', 3); spyOn(_converse, 'areDesktopNotificationsEnabled').and.returnValue(true); spyOn(_converse, 'showChatStateNotification'); const jid = mock.cur_names[2].replace(/ /g,'.').toLowerCase() + '@montague.lit'; _converse.roster.get(jid).presence.set('show', 'busy'); // This will emit 'contactStatusChanged' await u.waitUntil(() => _converse.areDesktopNotificationsEnabled.calls.count() === 1); expect(_converse.showChatStateNotification).toHaveBeenCalled(); done() })); }); }); describe("When a new contact request is received", function () { it("an HTML5 Notification is received", mock.initConverse((done, _converse) => { spyOn(_converse, 'areDesktopNotificationsEnabled').and.returnValue(true); spyOn(_converse, 'showContactRequestNotification'); _converse.api.trigger('contactRequest', {'fullname': 'Peter Parker', 'jid': 'peter@parker.com'}); expect(_converse.areDesktopNotificationsEnabled).toHaveBeenCalled(); expect(_converse.showContactRequestNotification).toHaveBeenCalled(); done(); })); }); }); describe("When play_sounds is set to true", function () { describe("A notification sound", function () { it("is played when the current user is mentioned in a groupchat", mock.initConverse(['rosterGroupsFetched'], {}, async (done, _converse) => { test_utils.createContacts(_converse, 'current'); await test_utils.openAndEnterChatRoom(_converse, 'lounge@montague.lit', 'romeo'); _converse.play_sounds = true; spyOn(_converse, 'playSoundNotification'); const view = _converse.chatboxviews.get('lounge@montague.lit'); if (!view.el.querySelectorAll('.chat-area').length) { view.renderChatArea(); } let text = 'This message will play a sound because it mentions romeo'; let message = $msg({ from: 'lounge@montague.lit/otheruser', id: '1', to: 'romeo@montague.lit', type: 'groupchat' }).c('body').t(text); await view.model.onMessage(message.nodeTree); await u.waitUntil(() => _converse.playSoundNotification.calls.count()); expect(_converse.playSoundNotification).toHaveBeenCalled(); text = "This message won't play a sound"; message = $msg({ from: 'lounge@montague.lit/otheruser', id: '2', to: 'romeo@montague.lit', type: 'groupchat' }).c('body').t(text); await view.model.onMessage(message.nodeTree); expect(_converse.playSoundNotification, 1); _converse.play_sounds = false; text = "This message won't play a sound because it is sent by romeo"; message = $msg({ from: 'lounge@montague.lit/romeo', id: '3', to: 'romeo@montague.lit', type: 'groupchat' }).c('body').t(text); await view.model.onMessage(message.nodeTree); expect(_converse.playSoundNotification, 1); _converse.play_sounds = false; done(); })); }); }); }); }));