2
0

receipts.js 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154
  1. /*global mock, converse */
  2. const { Promise, Strophe, $msg, sizzle, _ } = converse.env;
  3. const u = converse.env.utils;
  4. describe("A delivery receipt", function () {
  5. it("is emitted for a received message which requests it",
  6. mock.initConverse(
  7. ['rosterGroupsFetched', 'chatBoxesFetched'], {},
  8. async function (done, _converse) {
  9. await mock.waitForRoster(_converse, 'current');
  10. const sender_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit';
  11. const msg_id = u.getUniqueId();
  12. const sent_stanzas = [];
  13. spyOn(_converse.connection, 'send').and.callFake(stanza => sent_stanzas.push(stanza));
  14. const msg = $msg({
  15. 'from': sender_jid,
  16. 'to': _converse.connection.jid,
  17. 'type': 'chat',
  18. 'id': msg_id,
  19. }).c('body').t('Message!').up()
  20. .c('request', {'xmlns': Strophe.NS.RECEIPTS}).tree();
  21. await _converse.handleMessageStanza(msg);
  22. const sent_messages = sent_stanzas.map(s => _.isElement(s) ? s : s.nodeTree).filter(s => s.nodeName === 'message');
  23. // A chat state message is also included
  24. expect(sent_messages.length).toBe(2);
  25. const receipt = sizzle(`received[xmlns="${Strophe.NS.RECEIPTS}"]`, sent_messages[1]).pop();
  26. expect(Strophe.serialize(receipt)).toBe(`<received id="${msg_id}" xmlns="${Strophe.NS.RECEIPTS}"/>`);
  27. done();
  28. }));
  29. it("is not emitted for a carbon message",
  30. mock.initConverse(
  31. ['rosterGroupsFetched', 'chatBoxesFetched'], {},
  32. async function (done, _converse) {
  33. await mock.waitForRoster(_converse, 'current', 1);
  34. const sender_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit';
  35. const msg_id = u.getUniqueId();
  36. const view = await mock.openChatBoxFor(_converse, sender_jid);
  37. spyOn(view.model, 'sendReceiptStanza').and.callThrough();
  38. const msg = $msg({
  39. 'from': sender_jid,
  40. 'to': _converse.connection.jid,
  41. 'type': 'chat',
  42. 'id': u.getUniqueId(),
  43. }).c('received', {'xmlns': 'urn:xmpp:carbons:2'})
  44. .c('forwarded', {'xmlns': 'urn:xmpp:forward:0'})
  45. .c('message', {
  46. 'xmlns': 'jabber:client',
  47. 'from': sender_jid,
  48. 'to': _converse.bare_jid+'/another-resource',
  49. 'type': 'chat',
  50. 'id': msg_id
  51. }).c('body').t('Message!').up()
  52. .c('request', {'xmlns': Strophe.NS.RECEIPTS}).tree();
  53. await _converse.handleMessageStanza(msg);
  54. expect(view.model.sendReceiptStanza).not.toHaveBeenCalled();
  55. done();
  56. }));
  57. it("is not emitted for an archived message",
  58. mock.initConverse(
  59. ['rosterGroupsFetched', 'chatBoxesFetched'], {},
  60. async function (done, _converse) {
  61. await mock.waitForRoster(_converse, 'current', 1);
  62. const sender_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit';
  63. const view = await mock.openChatBoxFor(_converse, sender_jid);
  64. spyOn(view.model, 'sendReceiptStanza').and.callThrough();
  65. const stanza = u.toStanza(
  66. `<message xmlns="jabber:client" to="${_converse.jid}">
  67. <result xmlns="urn:xmpp:mam:2" id="9ZWxmXMR8SVor-tC" queryid="f543c5f9-55e7-400e-860a-56baac121e6a">
  68. <forwarded xmlns="urn:xmpp:forward:0">
  69. <delay xmlns="urn:xmpp:delay" stamp="2020-01-10T22:19:30Z"/>
  70. <message xmlns="jabber:client" type="chat" to="${_converse.jid}" from="${sender_jid}" id="id8b6426b4-40fe-4151-941e-4c64e380acb9">
  71. <body>Please confirm receipt</body>
  72. <request xmlns="urn:xmpp:receipts"/>
  73. <origin-id xmlns="urn:xmpp:sid:0" id="id8b6426b4-40fe-4151-941e-4c64e380acb9"/>
  74. </message>
  75. </forwarded>
  76. </result>
  77. </message>`);
  78. spyOn(view.model, 'getDuplicateMessage').and.callThrough();
  79. view.model.handleMAMResult({ 'messages': [stanza] });
  80. let message_attrs;
  81. _converse.api.listen.on('MAMResult', async data => {
  82. message_attrs = await data.messages[0];
  83. });
  84. await u.waitUntil(() => view.model.getDuplicateMessage.calls.count());
  85. expect(message_attrs.is_archived).toBe(true);
  86. expect(message_attrs.is_valid_receipt_request).toBe(false);
  87. expect(view.model.sendReceiptStanza).not.toHaveBeenCalled();
  88. done();
  89. }));
  90. it("can be received for a sent message",
  91. mock.initConverse(
  92. ['rosterGroupsFetched', 'chatBoxesFetched'], {},
  93. async function (done, _converse) {
  94. await mock.waitForRoster(_converse, 'current', 1);
  95. const contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit';
  96. await mock.openChatBoxFor(_converse, contact_jid);
  97. const view = _converse.chatboxviews.get(contact_jid);
  98. const textarea = view.el.querySelector('textarea.chat-textarea');
  99. textarea.value = 'But soft, what light through yonder airlock breaks?';
  100. view.onKeyDown({
  101. target: textarea,
  102. preventDefault: function preventDefault () {},
  103. keyCode: 13 // Enter
  104. });
  105. const chatbox = _converse.chatboxes.get(contact_jid);
  106. expect(chatbox).toBeDefined();
  107. await new Promise(resolve => view.model.messages.once('rendered', resolve));
  108. let msg_obj = chatbox.messages.models[0];
  109. let msg_id = msg_obj.get('msgid');
  110. let msg = $msg({
  111. 'from': contact_jid,
  112. 'to': _converse.connection.jid,
  113. 'id': u.getUniqueId(),
  114. }).c('received', {'id': msg_id, xmlns: Strophe.NS.RECEIPTS}).up().tree();
  115. _converse.connection._dataRecv(mock.createRequest(msg));
  116. await u.waitUntil(() => view.el.querySelectorAll('.chat-msg__receipt').length === 1);
  117. // Also handle receipts with type 'chat'. See #1353
  118. spyOn(_converse, 'handleMessageStanza').and.callThrough();
  119. textarea.value = 'Another message';
  120. view.onKeyDown({
  121. target: textarea,
  122. preventDefault: function preventDefault () {},
  123. keyCode: 13 // Enter
  124. });
  125. await new Promise(resolve => view.model.messages.once('rendered', resolve));
  126. msg_obj = chatbox.messages.models[1];
  127. msg_id = msg_obj.get('msgid');
  128. msg = $msg({
  129. 'from': contact_jid,
  130. 'type': 'chat',
  131. 'to': _converse.connection.jid,
  132. 'id': u.getUniqueId(),
  133. }).c('received', {'id': msg_id, xmlns: Strophe.NS.RECEIPTS}).up().tree();
  134. _converse.connection._dataRecv(mock.createRequest(msg));
  135. await u.waitUntil(() => view.el.querySelectorAll('.chat-msg__receipt').length === 2);
  136. expect(_converse.handleMessageStanza.calls.count()).toBe(1);
  137. done();
  138. }));
  139. });