2
0

markers.js 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180
  1. /*global mock, converse */
  2. const Strophe = converse.env.Strophe;
  3. const u = converse.env.utils;
  4. // See: https://xmpp.org/rfcs/rfc3921.html
  5. describe("A XEP-0333 Chat Marker", function () {
  6. it("is sent when a markable message is received from a roster contact",
  7. mock.initConverse([], {}, async function (done, _converse) {
  8. await mock.waitForRoster(_converse, 'current', 1);
  9. const contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit';
  10. await mock.openChatBoxFor(_converse, contact_jid);
  11. const msgid = u.getUniqueId();
  12. const stanza = u.toStanza(`
  13. <message from='${contact_jid}'
  14. id='${msgid}'
  15. type="chat"
  16. to='${_converse.jid}'>
  17. <body>My lord, dispatch; read o'er these articles.</body>
  18. <markable xmlns='urn:xmpp:chat-markers:0'/>
  19. </message>`);
  20. const sent_stanzas = [];
  21. spyOn(_converse.connection, 'send').and.callFake(s => sent_stanzas.push(s?.nodeTree ?? s));
  22. _converse.connection._dataRecv(mock.createRequest(stanza));
  23. await u.waitUntil(() => sent_stanzas.length === 2);
  24. expect(Strophe.serialize(sent_stanzas[0])).toBe(
  25. `<message from="romeo@montague.lit/orchard" `+
  26. `id="${sent_stanzas[0].getAttribute('id')}" `+
  27. `to="${contact_jid}" type="chat" xmlns="jabber:client">`+
  28. `<received id="${msgid}" xmlns="urn:xmpp:chat-markers:0"/>`+
  29. `</message>`);
  30. done();
  31. }));
  32. it("is not sent when a markable message is received from someone not on the roster",
  33. mock.initConverse([], {'allow_non_roster_messaging': true}, async function (done, _converse) {
  34. await mock.waitForRoster(_converse, 'current', 0);
  35. const contact_jid = 'someone@montague.lit';
  36. const msgid = u.getUniqueId();
  37. const stanza = u.toStanza(`
  38. <message from='${contact_jid}'
  39. id='${msgid}'
  40. type="chat"
  41. to='${_converse.jid}'>
  42. <body>My lord, dispatch; read o'er these articles.</body>
  43. <markable xmlns='urn:xmpp:chat-markers:0'/>
  44. </message>`);
  45. const sent_stanzas = [];
  46. spyOn(_converse.connection, 'send').and.callFake(s => sent_stanzas.push(s));
  47. await _converse.handleMessageStanza(stanza);
  48. const sent_messages = sent_stanzas
  49. .map(s => s?.nodeTree ?? s)
  50. .filter(e => e.nodeName === 'message');
  51. await u.waitUntil(() => sent_messages.length === 2);
  52. expect(Strophe.serialize(sent_messages[0])).toBe(
  53. `<message id="${sent_messages[0].getAttribute('id')}" to="${contact_jid}" type="chat" xmlns="jabber:client">`+
  54. `<active xmlns="http://jabber.org/protocol/chatstates"/>`+
  55. `<no-store xmlns="urn:xmpp:hints"/>`+
  56. `<no-permanent-store xmlns="urn:xmpp:hints"/>`+
  57. `</message>`
  58. );
  59. done();
  60. }));
  61. it("is ignored if it's a carbon copy of one that I sent from a different client",
  62. mock.initConverse([], {}, async function (done, _converse) {
  63. await mock.waitForRoster(_converse, 'current', 1);
  64. await mock.waitUntilDiscoConfirmed(_converse, _converse.bare_jid, [], [Strophe.NS.SID]);
  65. const contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit';
  66. await mock.openChatBoxFor(_converse, contact_jid);
  67. const view = _converse.api.chatviews.get(contact_jid);
  68. let stanza = u.toStanza(`
  69. <message xmlns="jabber:client"
  70. to="${_converse.bare_jid}"
  71. type="chat"
  72. id="2e972ea0-0050-44b7-a830-f6638a2595b3"
  73. from="${contact_jid}">
  74. <body>😊</body>
  75. <markable xmlns="urn:xmpp:chat-markers:0"/>
  76. <origin-id xmlns="urn:xmpp:sid:0" id="2e972ea0-0050-44b7-a830-f6638a2595b3"/>
  77. <stanza-id xmlns="urn:xmpp:sid:0" id="IxVDLJ0RYbWcWvqC" by="${_converse.bare_jid}"/>
  78. </message>`);
  79. _converse.connection._dataRecv(mock.createRequest(stanza));
  80. await u.waitUntil(() => view.querySelectorAll('.chat-msg__text').length);
  81. expect(view.querySelectorAll('.chat-msg').length).toBe(1);
  82. expect(view.model.messages.length).toBe(1);
  83. stanza = u.toStanza(
  84. `<message xmlns="jabber:client" to="${_converse.bare_jid}" type="chat" from="${contact_jid}">
  85. <sent xmlns="urn:xmpp:carbons:2">
  86. <forwarded xmlns="urn:xmpp:forward:0">
  87. <message xmlns="jabber:client" to="${contact_jid}" type="chat" from="${_converse.bare_jid}/other-resource">
  88. <received xmlns="urn:xmpp:chat-markers:0" id="2e972ea0-0050-44b7-a830-f6638a2595b3"/>
  89. <store xmlns="urn:xmpp:hints"/>
  90. <stanza-id xmlns="urn:xmpp:sid:0" id="F4TC6CvHwzqRbeHb" by="${_converse.bare_jid}"/>
  91. </message>
  92. </forwarded>
  93. </sent>
  94. </message>`);
  95. spyOn(_converse.api, "trigger").and.callThrough();
  96. _converse.connection._dataRecv(mock.createRequest(stanza));
  97. await u.waitUntil(() => _converse.api.trigger.calls.count(), 500);
  98. expect(view.querySelectorAll('.chat-msg').length).toBe(1);
  99. expect(view.model.messages.length).toBe(1);
  100. done();
  101. }));
  102. it("may be returned for a MUC message",
  103. mock.initConverse([], {}, async function (done, _converse) {
  104. await mock.waitForRoster(_converse, 'current');
  105. const muc_jid = 'lounge@montague.lit';
  106. await mock.openAndEnterChatRoom(_converse, muc_jid, 'romeo');
  107. const view = _converse.api.chatviews.get(muc_jid);
  108. const textarea = await u.waitUntil(() => view.querySelector('.chat-textarea'));
  109. textarea.value = 'But soft, what light through yonder airlock breaks?';
  110. const bottom_panel = view.querySelector('converse-muc-bottom-panel');
  111. bottom_panel.onKeyDown({
  112. target: textarea,
  113. preventDefault: function preventDefault () {},
  114. keyCode: 13 // Enter
  115. });
  116. await u.waitUntil(() => view.querySelectorAll('.chat-msg__text').length);
  117. expect(view.querySelectorAll('.chat-msg').length).toBe(1);
  118. expect(view.querySelector('.chat-msg .chat-msg__text').textContent.trim())
  119. .toBe("But soft, what light through yonder airlock breaks?");
  120. const msg_obj = view.model.messages.at(0);
  121. let stanza = u.toStanza(`
  122. <message xml:lang="en" to="romeo@montague.lit/orchard"
  123. from="lounge@montague.lit/some1" type="groupchat" xmlns="jabber:client">
  124. <received xmlns="urn:xmpp:chat-markers:0" id="${msg_obj.get('msgid')}"/>
  125. </message>`);
  126. _converse.connection._dataRecv(mock.createRequest(stanza));
  127. await u.waitUntil(() => view.querySelectorAll('.chat-msg').length === 1);
  128. expect(view.querySelectorAll('.chat-msg__receipt').length).toBe(0);
  129. stanza = u.toStanza(`
  130. <message xml:lang="en" to="romeo@montague.lit/orchard"
  131. from="lounge@montague.lit/some1" type="groupchat" xmlns="jabber:client">
  132. <displayed xmlns="urn:xmpp:chat-markers:0" id="${msg_obj.get('msgid')}"/>
  133. </message>`);
  134. _converse.connection._dataRecv(mock.createRequest(stanza));
  135. expect(view.querySelectorAll('.chat-msg').length).toBe(1);
  136. expect(view.querySelectorAll('.chat-msg__receipt').length).toBe(0);
  137. stanza = u.toStanza(`
  138. <message xml:lang="en" to="romeo@montague.lit/orchard"
  139. from="lounge@montague.lit/some1" type="groupchat" xmlns="jabber:client">
  140. <acknowledged xmlns="urn:xmpp:chat-markers:0" id="${msg_obj.get('msgid')}"/>
  141. </message>`);
  142. _converse.connection._dataRecv(mock.createRequest(stanza));
  143. expect(view.querySelectorAll('.chat-msg').length).toBe(1);
  144. expect(view.querySelectorAll('.chat-msg__receipt').length).toBe(0);
  145. stanza = u.toStanza(`
  146. <message xml:lang="en" to="romeo@montague.lit/orchard"
  147. from="lounge@montague.lit/some1" type="groupchat" xmlns="jabber:client">
  148. <body>'tis I!</body>
  149. <stanza-id xmlns='urn:xmpp:sid:0' id='stanza-id-1' by='${muc_jid}'/>
  150. <markable xmlns="urn:xmpp:chat-markers:0"/>
  151. </message>`);
  152. _converse.connection._dataRecv(mock.createRequest(stanza));
  153. await u.waitUntil(() => view.querySelectorAll('.chat-msg').length === 2);
  154. expect(view.querySelectorAll('.chat-msg__receipt').length).toBe(0);
  155. done();
  156. }));
  157. });