notification.js 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223
  1. (function (root, factory) {
  2. define(["jasmine", "mock", "test-utils"], factory);
  3. } (this, function (jasmine, mock, test_utils) {
  4. "use strict";
  5. const Strophe = converse.env.Strophe;
  6. const _ = converse.env._;
  7. const $msg = converse.env.$msg;
  8. const u = converse.env.utils;
  9. describe("Notifications", function () {
  10. // Implement the protocol defined in https://xmpp.org/extensions/xep-0313.html#config
  11. describe("When show_desktop_notifications is set to true", function () {
  12. describe("And the desktop is not focused", function () {
  13. describe("an HTML5 Notification", function () {
  14. it("is shown when a new private message is received",
  15. mock.initConverse(
  16. null, ['rosterGroupsFetched'], {},
  17. async (done, _converse) => {
  18. // TODO: not yet testing show_desktop_notifications setting
  19. await test_utils.createContacts(_converse, 'current');
  20. // Hack to avoid having to fetch the roster again.
  21. _converse.session.set('roster_fetched', true);
  22. spyOn(_converse, 'showMessageNotification').and.callThrough();
  23. spyOn(_converse, 'areDesktopNotificationsEnabled').and.returnValue(true);
  24. spyOn(_converse, 'isMessageToHiddenChat').and.returnValue(true);
  25. const message = 'This message will show a desktop notification';
  26. const sender_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit',
  27. msg = $msg({
  28. from: sender_jid,
  29. to: _converse.connection.jid,
  30. type: 'chat',
  31. id: (new Date()).getTime()
  32. }).c('body').t(message).up()
  33. .c('active', {'xmlns': 'http://jabber.org/protocol/chatstates'}).tree();
  34. await _converse.chatboxes.onMessage(msg); // This will emit 'message'
  35. await u.waitUntil(() => _converse.api.chatviews.get(sender_jid));
  36. expect(_converse.areDesktopNotificationsEnabled).toHaveBeenCalled();
  37. expect(_converse.showMessageNotification).toHaveBeenCalled();
  38. done();
  39. }));
  40. it("is shown when you are mentioned in a groupchat",
  41. mock.initConverse(
  42. null, ['rosterGroupsFetched'], {},
  43. async (done, _converse) => {
  44. await test_utils.createContacts(_converse, 'current');
  45. await test_utils.openAndEnterChatRoom(_converse, 'lounge@montague.lit', 'romeo');
  46. const view = _converse.api.chatviews.get('lounge@montague.lit');
  47. if (!view.el.querySelectorAll('.chat-area').length) {
  48. view.renderChatArea();
  49. }
  50. let no_notification = false;
  51. if (typeof window.Notification === 'undefined') {
  52. no_notification = true;
  53. window.Notification = function () {
  54. return {
  55. 'close': function () {}
  56. };
  57. };
  58. }
  59. spyOn(_converse, 'showMessageNotification').and.callThrough();
  60. spyOn(_converse, 'areDesktopNotificationsEnabled').and.returnValue(true);
  61. const message = 'romeo: This message will show a desktop notification';
  62. const nick = mock.chatroom_names[0],
  63. msg = $msg({
  64. from: 'lounge@montague.lit/'+nick,
  65. id: (new Date()).getTime(),
  66. to: 'romeo@montague.lit',
  67. type: 'groupchat'
  68. }).c('body').t(message).tree();
  69. _converse.connection._dataRecv(test_utils.createRequest(msg));
  70. await new Promise((resolve, reject) => view.once('messageInserted', resolve));
  71. expect(_converse.areDesktopNotificationsEnabled).toHaveBeenCalled();
  72. expect(_converse.showMessageNotification).toHaveBeenCalled();
  73. if (no_notification) {
  74. delete window.Notification;
  75. }
  76. done();
  77. }));
  78. it("is shown for headline messages",
  79. mock.initConverse(
  80. null, ['rosterGroupsFetched'], {},
  81. async (done, _converse) => {
  82. spyOn(_converse, 'showMessageNotification').and.callThrough();
  83. spyOn(_converse, 'isMessageToHiddenChat').and.returnValue(true);
  84. spyOn(_converse, 'areDesktopNotificationsEnabled').and.returnValue(true);
  85. const stanza = $msg({
  86. 'type': 'headline',
  87. 'from': 'notify.example.com',
  88. 'to': 'romeo@montague.lit',
  89. 'xml:lang': 'en'
  90. })
  91. .c('subject').t('SIEVE').up()
  92. .c('body').t('<juliet@example.com> You got mail.').up()
  93. .c('x', {'xmlns': 'jabber:x:oob'})
  94. .c('url').t('imap://romeo@example.com/INBOX;UIDVALIDITY=385759043/;UID=18');
  95. _converse.connection._dataRecv(test_utils.createRequest(stanza));
  96. await u.waitUntil(() => _converse.chatboxviews.keys().length);
  97. const view = _converse.chatboxviews.get('notify.example.com');
  98. await new Promise((resolve, reject) => view.once('messageInserted', resolve));
  99. expect(
  100. _.includes(_converse.chatboxviews.keys(),
  101. 'notify.example.com')
  102. ).toBeTruthy();
  103. expect(_converse.showMessageNotification).toHaveBeenCalled();
  104. done();
  105. }));
  106. it("is not shown for full JID headline messages if allow_non_roster_messaging is false", mock.initConverse((done, _converse) => {
  107. _converse.allow_non_roster_messaging = false;
  108. spyOn(_converse, 'showMessageNotification').and.callThrough();
  109. spyOn(_converse, 'areDesktopNotificationsEnabled').and.returnValue(true);
  110. const stanza = $msg({
  111. 'type': 'headline',
  112. 'from': 'someone@notify.example.com',
  113. 'to': 'romeo@montague.lit',
  114. 'xml:lang': 'en'
  115. })
  116. .c('subject').t('SIEVE').up()
  117. .c('body').t('<juliet@example.com> You got mail.').up()
  118. .c('x', {'xmlns': 'jabber:x:oob'})
  119. .c('url').t('imap://romeo@example.com/INBOX;UIDVALIDITY=385759043/;UID=18');
  120. _converse.connection._dataRecv(test_utils.createRequest(stanza));
  121. expect(
  122. _.includes(_converse.chatboxviews.keys(),
  123. 'someone@notify.example.com')
  124. ).toBeFalsy();
  125. expect(_converse.showMessageNotification).not.toHaveBeenCalled();
  126. done();
  127. }));
  128. it("is shown when a user changes their chat state (if show_chat_state_notifications is true)", mock.initConverse((done, _converse) => {
  129. // TODO: not yet testing show_desktop_notifications setting
  130. _converse.show_chat_state_notifications = true;
  131. test_utils.createContacts(_converse, 'current');
  132. spyOn(_converse, 'areDesktopNotificationsEnabled').and.returnValue(true);
  133. spyOn(_converse, 'showChatStateNotification');
  134. const jid = mock.cur_names[2].replace(/ /g,'.').toLowerCase() + '@montague.lit';
  135. _converse.roster.get(jid).presence.set('show', 'busy'); // This will emit 'contactStatusChanged'
  136. expect(_converse.areDesktopNotificationsEnabled).toHaveBeenCalled();
  137. expect(_converse.showChatStateNotification).toHaveBeenCalled();
  138. done()
  139. }));
  140. });
  141. });
  142. describe("When a new contact request is received", function () {
  143. it("an HTML5 Notification is received", mock.initConverse((done, _converse) => {
  144. spyOn(_converse, 'areDesktopNotificationsEnabled').and.returnValue(true);
  145. spyOn(_converse, 'showContactRequestNotification');
  146. _converse.api.trigger('contactRequest', {'fullname': 'Peter Parker', 'jid': 'peter@parker.com'});
  147. expect(_converse.areDesktopNotificationsEnabled).toHaveBeenCalled();
  148. expect(_converse.showContactRequestNotification).toHaveBeenCalled();
  149. done();
  150. }));
  151. });
  152. });
  153. describe("When play_sounds is set to true", function () {
  154. describe("A notification sound", function () {
  155. it("is played when the current user is mentioned in a groupchat",
  156. mock.initConverse(
  157. null, ['rosterGroupsFetched'], {},
  158. async (done, _converse) => {
  159. test_utils.createContacts(_converse, 'current');
  160. await test_utils.openAndEnterChatRoom(_converse, 'lounge@montague.lit', 'romeo');
  161. _converse.play_sounds = true;
  162. spyOn(_converse, 'playSoundNotification');
  163. const view = _converse.chatboxviews.get('lounge@montague.lit');
  164. if (!view.el.querySelectorAll('.chat-area').length) {
  165. view.renderChatArea();
  166. }
  167. let text = 'This message will play a sound because it mentions romeo';
  168. let message = $msg({
  169. from: 'lounge@montague.lit/otheruser',
  170. id: '1',
  171. to: 'romeo@montague.lit',
  172. type: 'groupchat'
  173. }).c('body').t(text);
  174. await view.model.onMessage(message.nodeTree);
  175. await u.waitUntil(() => _converse.playSoundNotification.calls.count());
  176. expect(_converse.playSoundNotification).toHaveBeenCalled();
  177. text = "This message won't play a sound";
  178. message = $msg({
  179. from: 'lounge@montague.lit/otheruser',
  180. id: '2',
  181. to: 'romeo@montague.lit',
  182. type: 'groupchat'
  183. }).c('body').t(text);
  184. await view.model.onMessage(message.nodeTree);
  185. expect(_converse.playSoundNotification, 1);
  186. _converse.play_sounds = false;
  187. text = "This message won't play a sound because it is sent by romeo";
  188. message = $msg({
  189. from: 'lounge@montague.lit/romeo',
  190. id: '3',
  191. to: 'romeo@montague.lit',
  192. type: 'groupchat'
  193. }).c('body').t(text);
  194. await view.model.onMessage(message.nodeTree);
  195. expect(_converse.playSoundNotification, 1);
  196. _converse.play_sounds = false;
  197. done();
  198. }));
  199. });
  200. });
  201. });
  202. }));