chatbox.js 87 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656
  1. (function (root, factory) {
  2. define([
  3. "jquery",
  4. "jasmine",
  5. "utils",
  6. "converse-core",
  7. "mock",
  8. "test-utils"
  9. ], factory);
  10. } (this, function ($, jasmine, utils, converse, mock, test_utils) {
  11. "use strict";
  12. var _ = converse.env._;
  13. var $iq = converse.env.$iq;
  14. var $msg = converse.env.$msg;
  15. var Strophe = converse.env.Strophe;
  16. var u = converse.env.utils;
  17. return describe("Chatboxes", function () {
  18. describe("A Chatbox", function () {
  19. it("has a /help command to show the available commands",
  20. mock.initConverseWithPromises(
  21. null, ['rosterGroupsFetched'], {},
  22. function (done, _converse) {
  23. test_utils.createContacts(_converse, 'current');
  24. test_utils.openControlBox();
  25. var contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@localhost';
  26. test_utils.openChatBoxFor(_converse, contact_jid);
  27. var view = _converse.chatboxviews.get(contact_jid);
  28. test_utils.sendMessage(view, '/help');
  29. const info_messages = Array.prototype.slice.call(view.el.querySelectorAll('.chat-info:not(.chat-date)'), 0);
  30. expect(info_messages.length).toBe(3);
  31. expect(info_messages.pop().textContent).toBe('/help: Show this menu');
  32. expect(info_messages.pop().textContent).toBe('/me: Write in the third person');
  33. expect(info_messages.pop().textContent).toBe('/clear: Remove messages');
  34. var msg = $msg({
  35. from: contact_jid,
  36. to: _converse.connection.jid,
  37. type: 'chat',
  38. id: (new Date()).getTime()
  39. }).c('body').t('hello world').tree();
  40. _converse.chatboxes.onMessage(msg);
  41. expect(view.content.lastElementChild.textContent.trim().indexOf('hello world')).not.toBe(-1);
  42. done();
  43. }));
  44. it("supports the /me command",
  45. mock.initConverseWithPromises(
  46. null, ['rosterGroupsFetched'], {},
  47. function (done, _converse) {
  48. var view;
  49. test_utils.createContacts(_converse, 'current');
  50. test_utils.waitUntilDiscoConfirmed(_converse, 'localhost', [], ['vcard-temp'])
  51. .then(function () {
  52. return test_utils.waitUntil(function () {
  53. return _converse.xmppstatus.get('fullname');
  54. }, 300);
  55. }).then(function () {
  56. test_utils.openControlBox();
  57. expect(_converse.chatboxes.length).toEqual(1);
  58. var sender_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@localhost';
  59. var message = '/me is tired';
  60. var msg = $msg({
  61. from: sender_jid,
  62. to: _converse.connection.jid,
  63. type: 'chat',
  64. id: (new Date()).getTime()
  65. }).c('body').t(message).up()
  66. .c('active', {'xmlns': 'http://jabber.org/protocol/chatstates'}).tree();
  67. _converse.chatboxes.onMessage(msg);
  68. view = _converse.chatboxviews.get(sender_jid);
  69. test_utils.waitUntil(function () {
  70. return u.isVisible(view.el);
  71. }).then(function () {
  72. expect(_.includes(view.el.querySelector('.chat-msg-author').textContent, '**Max Frankfurter')).toBeTruthy();
  73. expect($(view.el).find('.chat-msg-text').text()).toBe(' is tired');
  74. message = '/me is as well';
  75. test_utils.sendMessage(view, message);
  76. expect(_.includes($(view.el).find('.chat-msg-author:last').text(), '**Max Mustermann')).toBeTruthy();
  77. expect($(view.el).find('.chat-msg-text:last').text()).toBe(' is as well');
  78. expect($(view.el).find('.chat-msg:last').hasClass('chat-msg-followup')).toBe(false);
  79. done();
  80. });
  81. });
  82. }));
  83. it("is created when you click on a roster item",
  84. mock.initConverseWithPromises(
  85. null, ['rosterGroupsFetched'], {},
  86. function (done, _converse) {
  87. test_utils.createContacts(_converse, 'current');
  88. test_utils.openControlBox();
  89. var i, $el, jid, chatboxview;
  90. // openControlBox was called earlier, so the controlbox is
  91. // visible, but no other chat boxes have been created.
  92. expect(_converse.chatboxes.length).toEqual(1);
  93. spyOn(_converse.chatboxviews, 'trimChats');
  94. expect($("#conversejs .chatbox").length).toBe(1); // Controlbox is open
  95. test_utils.waitUntil(function () {
  96. return $(_converse.rosterview.el).find('.roster-group li').length;
  97. }, 700).then(function () {
  98. var online_contacts = $(_converse.rosterview.el).find('.roster-group .current-xmpp-contact a.open-chat');
  99. expect(online_contacts.length).toBe(15);
  100. for (i=0; i<online_contacts.length; i++) {
  101. $el = $(online_contacts[i]);
  102. jid = $el.text().trim().replace(/ /g,'.').toLowerCase() + '@localhost';
  103. $el[0].click();
  104. chatboxview = _converse.chatboxviews.get(jid);
  105. expect(_converse.chatboxes.length).toEqual(i+2);
  106. expect(_converse.chatboxviews.trimChats).toHaveBeenCalled();
  107. // Check that new chat boxes are created to the left of the
  108. // controlbox (but to the right of all existing chat boxes)
  109. expect($("#conversejs .chatbox").length).toBe(i+2);
  110. expect($("#conversejs .chatbox")[1].id).toBe(chatboxview.model.get('box_id'));
  111. }
  112. done();
  113. });
  114. }));
  115. it("can be trimmed to conserve space",
  116. mock.initConverseWithPromises(
  117. null, ['rosterGroupsFetched'], {},
  118. function (done, _converse) {
  119. test_utils.createContacts(_converse, 'current');
  120. test_utils.openControlBox();
  121. var i, $el, jid, chatbox, chatboxview, trimmedview;
  122. // openControlBox was called earlier, so the controlbox is
  123. // visible, but no other chat boxes have been created.
  124. var trimmed_chatboxes = _converse.minimized_chats;
  125. expect(_converse.chatboxes.length).toEqual(1);
  126. spyOn(_converse.chatboxviews, 'trimChats');
  127. spyOn(trimmed_chatboxes, 'addChat').and.callThrough();
  128. spyOn(trimmed_chatboxes, 'removeChat').and.callThrough();
  129. expect($("#conversejs .chatbox").length).toBe(1); // Controlbox is open
  130. _converse.rosterview.update(); // XXX: Hack to make sure $roster element is attached.
  131. test_utils.waitUntil(function () {
  132. return $(_converse.rosterview.el).find('.roster-group li').length;
  133. }, 700).then(function () {
  134. // Test that they can be maximized again
  135. var online_contacts = $(_converse.rosterview.el).find('.roster-group .current-xmpp-contact a.open-chat');
  136. expect(online_contacts.length).toBe(15);
  137. for (i=0; i<online_contacts.length; i++) {
  138. $el = $(online_contacts[i]);
  139. jid = _.trim($el.text().trim()).replace(/ /g,'.').toLowerCase() + '@localhost';
  140. $el[0].click();
  141. expect(_converse.chatboxviews.trimChats).toHaveBeenCalled();
  142. chatboxview = _converse.chatboxviews.get(jid);
  143. spyOn(chatboxview, 'minimize').and.callThrough();
  144. chatboxview.model.set({'minimized': true});
  145. expect(trimmed_chatboxes.addChat).toHaveBeenCalled();
  146. expect(chatboxview.minimize).toHaveBeenCalled();
  147. }
  148. return test_utils.waitUntil(function () {
  149. return _converse.chatboxviews.keys().length > 1;
  150. }, 500);
  151. }).then(function () {
  152. var key = _converse.chatboxviews.keys()[1];
  153. trimmedview = trimmed_chatboxes.get(key);
  154. chatbox = trimmedview.model;
  155. spyOn(chatbox, 'maximize').and.callThrough();
  156. spyOn(trimmedview, 'restore').and.callThrough();
  157. trimmedview.delegateEvents();
  158. trimmedview.el.querySelector("a.restore-chat").click();
  159. expect(trimmedview.restore).toHaveBeenCalled();
  160. expect(chatbox.maximize).toHaveBeenCalled();
  161. expect(_converse.chatboxviews.trimChats).toHaveBeenCalled();
  162. done();
  163. });
  164. done();
  165. }));
  166. it("can be opened in minimized mode initially",
  167. mock.initConverseWithPromises(
  168. null, ['rosterGroupsFetched'], {},
  169. function (done, _converse) {
  170. test_utils.createContacts(_converse, 'current');
  171. var sender_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@localhost';
  172. var chat = _converse.api.chats.create(sender_jid, {
  173. minimized: true
  174. });
  175. var chatBoxView = _converse.chatboxviews.get(sender_jid);
  176. expect(u.isVisible(chatBoxView.el)).toBeFalsy();
  177. var minimized_chat = _converse.minimized_chats.get(sender_jid);
  178. expect(minimized_chat).toBeTruthy();
  179. expect($(minimized_chat.el).is(':visible')).toBeTruthy();
  180. done();
  181. }));
  182. it("is focused if its already open and you click on its corresponding roster item",
  183. mock.initConverseWithPromises(
  184. null, ['rosterGroupsFetched'], {},
  185. function (done, _converse) {
  186. test_utils.createContacts(_converse, 'current');
  187. _converse.rosterview.update(); // XXX: Hack to make sure $roster element is attaced.
  188. test_utils.openControlBox();
  189. var contact_jid = mock.cur_names[2].replace(/ /g,'.').toLowerCase() + '@localhost';
  190. var $el, jid, chatbox;
  191. // openControlBox was called earlier, so the controlbox is
  192. // visible, but no other chat boxes have been created.
  193. expect(_converse.chatboxes.length).toEqual(1);
  194. chatbox = test_utils.openChatBoxFor(_converse, contact_jid);
  195. $el = $(_converse.rosterview.el).find('a.open-chat:contains("'+chatbox.get('fullname')+'")');
  196. jid = $el.text().replace(/ /g,'.').toLowerCase() + '@localhost';
  197. spyOn(_converse, 'emit');
  198. $el[0].click();
  199. test_utils.waitUntil(function () {
  200. return _converse.emit.calls.count();
  201. }, 300).then(function () {
  202. expect(_converse.chatboxes.length).toEqual(2);
  203. expect(_converse.emit).toHaveBeenCalledWith('chatBoxFocused', jasmine.any(Object));
  204. done();
  205. });
  206. }));
  207. it("can be saved to, and retrieved from, browserStorage",
  208. mock.initConverseWithPromises(
  209. null, ['rosterGroupsFetched'], {},
  210. function (done, _converse) {
  211. test_utils.createContacts(_converse, 'current');
  212. test_utils.openControlBox();
  213. spyOn(_converse, 'emit');
  214. spyOn(_converse.chatboxviews, 'trimChats');
  215. test_utils.openControlBox();
  216. test_utils.openChatBoxes(_converse, 6);
  217. expect(_converse.chatboxviews.trimChats).toHaveBeenCalled();
  218. // We instantiate a new ChatBoxes collection, which by default
  219. // will be empty.
  220. var newchatboxes = new _converse.ChatBoxes();
  221. expect(newchatboxes.length).toEqual(0);
  222. // The chatboxes will then be fetched from browserStorage inside the
  223. // onConnected method
  224. newchatboxes.onConnected();
  225. expect(newchatboxes.length).toEqual(7);
  226. // Check that the chatboxes items retrieved from browserStorage
  227. // have the same attributes values as the original ones.
  228. var attrs = ['id', 'box_id', 'visible'];
  229. var new_attrs, old_attrs;
  230. for (var i=0; i<attrs.length; i++) {
  231. new_attrs = _.map(_.map(newchatboxes.models, 'attributes'), attrs[i]);
  232. old_attrs = _.map(_.map(_converse.chatboxes.models, 'attributes'), attrs[i]);
  233. expect(_.isEqual(new_attrs, old_attrs)).toEqual(true);
  234. }
  235. _converse.rosterview.render();
  236. done();
  237. }));
  238. it("can be closed by clicking a DOM element with class 'close-chatbox-button'",
  239. mock.initConverseWithPromises(
  240. null, ['rosterGroupsFetched'], {},
  241. function (done, _converse) {
  242. test_utils.createContacts(_converse, 'current');
  243. test_utils.openControlBox();
  244. test_utils.waitUntil(function () {
  245. return $(_converse.rosterview.el).find('.roster-group').length;
  246. }, 300).then(function () {
  247. var chatbox = test_utils.openChatBoxes(_converse, 1)[0],
  248. controlview = _converse.chatboxviews.get('controlbox'), // The controlbox is currently open
  249. chatview = _converse.chatboxviews.get(chatbox.get('jid'));
  250. spyOn(chatview, 'close').and.callThrough();
  251. spyOn(controlview, 'close').and.callThrough();
  252. spyOn(_converse, 'emit');
  253. // We need to rebind all events otherwise our spy won't be called
  254. controlview.delegateEvents();
  255. chatview.delegateEvents();
  256. controlview.el.querySelector('.close-chatbox-button').click();
  257. expect(controlview.close).toHaveBeenCalled();
  258. expect(_converse.emit).toHaveBeenCalledWith('chatBoxClosed', jasmine.any(Object));
  259. expect(_converse.emit.calls.count(), 1);
  260. chatview.el.querySelector('.close-chatbox-button').click();
  261. expect(chatview.close).toHaveBeenCalled();
  262. expect(_converse.emit).toHaveBeenCalledWith('chatBoxClosed', jasmine.any(Object));
  263. expect(_converse.emit.calls.count(), 2);
  264. done();
  265. });
  266. }));
  267. it("can be minimized by clicking a DOM element with class 'toggle-chatbox-button'",
  268. mock.initConverseWithPromises(
  269. null, ['rosterGroupsFetched'], {},
  270. function (done, _converse) {
  271. var chatview;
  272. test_utils.createContacts(_converse, 'current');
  273. test_utils.openControlBox();
  274. test_utils.waitUntil(function () {
  275. return $(_converse.rosterview.el).find('.roster-group').length;
  276. }, 300)
  277. .then(function () {
  278. var chatbox = test_utils.openChatBoxes(_converse, 1)[0],
  279. trimmed_chatboxes = _converse.minimized_chats,
  280. trimmedview;
  281. chatview = _converse.chatboxviews.get(chatbox.get('jid'));
  282. spyOn(chatview, 'minimize').and.callThrough();
  283. spyOn(_converse, 'emit');
  284. // We need to rebind all events otherwise our spy won't be called
  285. chatview.delegateEvents();
  286. chatview.el.querySelector('.toggle-chatbox-button').click();
  287. expect(chatview.minimize).toHaveBeenCalled();
  288. expect(_converse.emit).toHaveBeenCalledWith('chatBoxMinimized', jasmine.any(Object));
  289. expect(_converse.emit.calls.count(), 2);
  290. expect(u.isVisible(chatview.el)).toBeFalsy();
  291. expect(chatview.model.get('minimized')).toBeTruthy();
  292. chatview.el.querySelector('.toggle-chatbox-button').click();
  293. trimmedview = trimmed_chatboxes.get(chatview.model.get('id'));
  294. spyOn(trimmedview, 'restore').and.callThrough();
  295. trimmedview.delegateEvents();
  296. trimmedview.el.querySelector("a.restore-chat").click();
  297. expect(trimmedview.restore).toHaveBeenCalled();
  298. expect(_converse.emit).toHaveBeenCalledWith('chatBoxMaximized', jasmine.any(Object));
  299. return test_utils.waitUntil(function () {
  300. return $(chatview.el).find('.chat-body').is(':visible');
  301. }, 500);
  302. }).then(function () {
  303. expect($(chatview.el).find('.toggle-chatbox-button').hasClass('fa-minus')).toBeTruthy();
  304. expect($(chatview.el).find('.toggle-chatbox-button').hasClass('fa-plus')).toBeFalsy();
  305. expect(chatview.model.get('minimized')).toBeFalsy();
  306. done();
  307. });
  308. }));
  309. it("will be removed from browserStorage when closed",
  310. mock.initConverseWithPromises(
  311. null, ['rosterGroupsFetched'], {},
  312. function (done, _converse) {
  313. test_utils.createContacts(_converse, 'current');
  314. test_utils.openControlBox();
  315. test_utils.waitUntil(function () {
  316. return $(_converse.rosterview.el).find('.roster-group').length;
  317. }, 300).then(function () {
  318. spyOn(_converse, 'emit');
  319. spyOn(_converse.chatboxviews, 'trimChats');
  320. _converse.chatboxes.browserStorage._clear();
  321. test_utils.closeControlBox();
  322. expect(_converse.emit).toHaveBeenCalledWith('chatBoxClosed', jasmine.any(Object));
  323. expect(_converse.chatboxes.length).toEqual(1);
  324. expect(_converse.chatboxes.pluck('id')).toEqual(['controlbox']);
  325. test_utils.openChatBoxes(_converse, 6);
  326. expect(_converse.chatboxviews.trimChats).toHaveBeenCalled();
  327. expect(_converse.chatboxes.length).toEqual(7);
  328. expect(_converse.emit).toHaveBeenCalledWith('chatBoxOpened', jasmine.any(Object));
  329. test_utils.closeAllChatBoxes(_converse);
  330. expect(_converse.chatboxes.length).toEqual(1);
  331. expect(_converse.chatboxes.pluck('id')).toEqual(['controlbox']);
  332. expect(_converse.emit).toHaveBeenCalledWith('chatBoxClosed', jasmine.any(Object));
  333. var newchatboxes = new _converse.ChatBoxes();
  334. expect(newchatboxes.length).toEqual(0);
  335. expect(_converse.chatboxes.pluck('id')).toEqual(['controlbox']);
  336. // onConnected will fetch chatboxes in browserStorage, but
  337. // because there aren't any open chatboxes, there won't be any
  338. // in browserStorage either. XXX except for the controlbox
  339. newchatboxes.onConnected();
  340. expect(newchatboxes.length).toEqual(1);
  341. expect(newchatboxes.models[0].id).toBe("controlbox");
  342. done();
  343. });
  344. }));
  345. describe("A chat toolbar", function () {
  346. it("can be found on each chat box",
  347. mock.initConverseWithPromises(
  348. null, ['rosterGroupsFetched'], {},
  349. function (done, _converse) {
  350. test_utils.createContacts(_converse, 'current');
  351. test_utils.openControlBox();
  352. var contact_jid = mock.cur_names[2].replace(/ /g,'.').toLowerCase() + '@localhost';
  353. test_utils.openChatBoxFor(_converse, contact_jid);
  354. var chatbox = _converse.chatboxes.get(contact_jid);
  355. var view = _converse.chatboxviews.get(contact_jid);
  356. expect(chatbox).toBeDefined();
  357. expect(view).toBeDefined();
  358. var $toolbar = $(view.el).find('ul.chat-toolbar');
  359. expect($toolbar.length).toBe(1);
  360. expect($toolbar.children('li').length).toBe(2);
  361. done();
  362. }));
  363. it("contains a button for inserting emojis",
  364. mock.initConverseWithPromises(
  365. null, ['rosterGroupsFetched'], {},
  366. function (done, _converse) {
  367. test_utils.createContacts(_converse, 'current');
  368. test_utils.openControlBox();
  369. var contact_jid = mock.cur_names[2].replace(/ /g,'.').toLowerCase() + '@localhost';
  370. test_utils.openChatBoxFor(_converse, contact_jid);
  371. var view = _converse.chatboxviews.get(contact_jid);
  372. var toolbar = view.el.querySelector('ul.chat-toolbar');
  373. expect(toolbar.querySelectorAll('li.toggle-smiley').length).toBe(1);
  374. // Register spies
  375. spyOn(view, 'toggleEmojiMenu').and.callThrough();
  376. spyOn(view, 'insertEmoji').and.callThrough();
  377. view.delegateEvents(); // We need to rebind all events otherwise our spy won't be called
  378. toolbar.querySelector('li.toggle-smiley').click();
  379. var timeout = false;
  380. test_utils.waitUntil(function () {
  381. return utils.isVisible(view.el.querySelector('.toggle-smiley .emoji-picker-container'));
  382. }, 150).then(function () {
  383. var picker = view.el.querySelector('.toggle-smiley .emoji-picker-container');
  384. var items = picker.querySelectorAll('.emoji-picker li');
  385. items[0].click()
  386. expect(view.insertEmoji).toHaveBeenCalled();
  387. setTimeout(function () { timeout = true; }, 100);
  388. return test_utils.waitUntil(function () {
  389. return timeout;
  390. }, 300);
  391. }).then(function () {
  392. timeout = false;
  393. toolbar.querySelector('li.toggle-smiley').click(); // Close the panel again
  394. return test_utils.waitUntil(function () {
  395. return !view.el.querySelector('.toggle-smiley .toolbar-menu').offsetHeight;
  396. }, 300);
  397. }).then(function () {
  398. setTimeout(function () { timeout = true; }, 100);
  399. return test_utils.waitUntil(function () {
  400. return timeout;
  401. }, 300);
  402. }).then(function () {
  403. toolbar.querySelector('li.toggle-smiley').click();
  404. expect(view.toggleEmojiMenu).toHaveBeenCalled();
  405. return test_utils.waitUntil(function () {
  406. var $picker = $(view.el).find('.toggle-smiley .emoji-picker-container');
  407. return u.isVisible($picker[0]);
  408. }, 300);
  409. }).then(function () {
  410. var nodes = view.el.querySelectorAll('.toggle-smiley ul li');
  411. nodes[nodes.length-1].click();
  412. expect(view.el.querySelector('textarea.chat-textarea').value).toBe(':grinning: ');
  413. expect(view.insertEmoji).toHaveBeenCalled();
  414. done();
  415. }).catch(_.partial(_converse.log, _, Strophe.LogLevel.FATAL));
  416. }));
  417. it("contains a button for starting an encrypted chat session",
  418. mock.initConverseWithPromises(
  419. null, ['rosterGroupsFetched'], {},
  420. function (done, _converse) {
  421. var timeout = true, $toolbar, view;
  422. test_utils.createContacts(_converse, 'current');
  423. test_utils.openControlBox();
  424. test_utils.waitUntil(function () {
  425. return $(_converse.rosterview.el).find('.roster-group').length;
  426. }, 300).then(function () {
  427. // TODO: More tests can be added here...
  428. var contact_jid = mock.cur_names[2].replace(/ /g,'.').toLowerCase() + '@localhost';
  429. test_utils.openChatBoxFor(_converse, contact_jid);
  430. view = _converse.chatboxviews.get(contact_jid);
  431. $toolbar = $(view.el).find('ul.chat-toolbar');
  432. expect($toolbar.find('.toggle-otr').length).toBe(1);
  433. // Register spies
  434. spyOn(view, 'toggleOTRMenu').and.callThrough();
  435. view.delegateEvents(); // We need to rebind all events otherwise our spy won't be called
  436. timeout = false;
  437. $toolbar[0].querySelector('.toggle-otr').click();
  438. return test_utils.waitUntil(function () {
  439. return view.el.querySelector('.otr-menu').offsetHeight;
  440. }, 300)
  441. }).then(function () {
  442. expect(view.toggleOTRMenu).toHaveBeenCalled();
  443. done();
  444. });
  445. }));
  446. it("can contain a button for starting a call",
  447. mock.initConverseWithPromises(
  448. null, ['rosterGroupsFetched'], {},
  449. function (done, _converse) {
  450. test_utils.createContacts(_converse, 'current');
  451. test_utils.openControlBox();
  452. var view;
  453. var contact_jid = mock.cur_names[2].replace(/ /g,'.').toLowerCase() + '@localhost';
  454. spyOn(_converse, 'emit');
  455. // First check that the button doesn't show if it's not enabled
  456. // via "visible_toolbar_buttons"
  457. _converse.visible_toolbar_buttons.call = false;
  458. test_utils.openChatBoxFor(_converse, contact_jid);
  459. view = _converse.chatboxviews.get(contact_jid);
  460. var toolbar = view.el.querySelector('ul.chat-toolbar');
  461. var call_button = toolbar.querySelector('.toggle-call');
  462. expect(_.isNull(call_button)).toBeTruthy();
  463. view.close();
  464. // Now check that it's shown if enabled and that it emits
  465. // callButtonClicked
  466. _converse.visible_toolbar_buttons.call = true; // enable the button
  467. test_utils.openChatBoxFor(_converse, contact_jid);
  468. view = _converse.chatboxviews.get(contact_jid);
  469. toolbar = view.el.querySelector('ul.chat-toolbar');
  470. call_button = toolbar.querySelector('.toggle-call');
  471. call_button.click();
  472. expect(_converse.emit).toHaveBeenCalledWith('callButtonClicked', jasmine.any(Object));
  473. done();
  474. }));
  475. });
  476. describe("A Chat Status Notification", function () {
  477. it("does not open a new chatbox",
  478. mock.initConverseWithPromises(
  479. null, ['rosterGroupsFetched'], {},
  480. function (done, _converse) {
  481. test_utils.createContacts(_converse, 'current');
  482. test_utils.openControlBox();
  483. spyOn(_converse, 'emit');
  484. var sender_jid = mock.cur_names[1].replace(/ /g,'.').toLowerCase() + '@localhost';
  485. // <composing> state
  486. var msg = $msg({
  487. 'from': sender_jid,
  488. 'to': _converse.connection.jid,
  489. 'type': 'chat',
  490. 'id': (new Date()).getTime()
  491. }).c('composing', {'xmlns': Strophe.NS.CHATSTATES}).tree();
  492. _converse.chatboxes.onMessage(msg);
  493. expect(_converse.emit).toHaveBeenCalledWith('message', jasmine.any(Object));
  494. done();
  495. }));
  496. describe("An active notification", function () {
  497. it("is sent when the user opens a chat box",
  498. mock.initConverseWithPromises(
  499. null, ['rosterGroupsFetched'], {},
  500. function (done, _converse) {
  501. test_utils.createContacts(_converse, 'current');
  502. test_utils.openControlBox();
  503. test_utils.waitUntil(function () {
  504. return $(_converse.rosterview.el).find('.roster-group').length;
  505. }, 300).then(function () {
  506. spyOn(_converse.connection, 'send');
  507. var contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@localhost';
  508. test_utils.openChatBoxFor(_converse, contact_jid);
  509. var view = _converse.chatboxviews.get(contact_jid);
  510. expect(view.model.get('chat_state')).toBe('active');
  511. expect(_converse.connection.send).toHaveBeenCalled();
  512. var $stanza = $(_converse.connection.send.calls.argsFor(0)[0].tree());
  513. expect($stanza.attr('to')).toBe(contact_jid);
  514. expect($stanza.children().length).toBe(3);
  515. expect($stanza.children().get(0).tagName).toBe('active');
  516. expect($stanza.children().get(1).tagName).toBe('no-store');
  517. expect($stanza.children().get(2).tagName).toBe('no-permanent-store');
  518. done();
  519. });
  520. }));
  521. it("is sent when the user maximizes a minimized a chat box", mock.initConverseWithPromises(
  522. null, ['rosterGroupsFetched'], {},
  523. function (done, _converse) {
  524. test_utils.createContacts(_converse, 'current');
  525. test_utils.openControlBox();
  526. var contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@localhost';
  527. test_utils.waitUntil(function () {
  528. return $(_converse.rosterview.el).find('.roster-group').length;
  529. }, 500).then(function () {
  530. test_utils.openChatBoxFor(_converse, contact_jid);
  531. var view = _converse.chatboxviews.get(contact_jid);
  532. view.model.minimize();
  533. expect(view.model.get('chat_state')).toBe('inactive');
  534. spyOn(_converse.connection, 'send');
  535. view.model.maximize();
  536. return test_utils.waitUntil(function () {
  537. return view.model.get('chat_state') === 'active';
  538. }, 700);
  539. }).then(function () {
  540. expect(_converse.connection.send).toHaveBeenCalled();
  541. var calls = _.filter(_converse.connection.send.calls.all(), function (call) {
  542. return call.args[0] instanceof Strophe.Builder;
  543. });
  544. expect(calls.length).toBe(1);
  545. var $stanza = $(calls[0].args[0].tree());
  546. expect($stanza.attr('to')).toBe(contact_jid);
  547. expect($stanza.children().length).toBe(3);
  548. expect($stanza.children().get(0).tagName).toBe('active');
  549. expect($stanza.children().get(1).tagName).toBe('no-store');
  550. expect($stanza.children().get(2).tagName).toBe('no-permanent-store');
  551. done();
  552. });
  553. }));
  554. });
  555. describe("A composing notification", function () {
  556. it("is sent as soon as the user starts typing a message which is not a command",
  557. mock.initConverseWithPromises(
  558. null, ['rosterGroupsFetched'], {},
  559. function (done, _converse) {
  560. test_utils.createContacts(_converse, 'current');
  561. test_utils.openControlBox();
  562. test_utils.waitUntil(function () {
  563. return $(_converse.rosterview.el).find('.roster-group').length;
  564. }, 300).then(function () {
  565. var contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@localhost';
  566. test_utils.openChatBoxFor(_converse, contact_jid);
  567. var view = _converse.chatboxviews.get(contact_jid);
  568. expect(view.model.get('chat_state')).toBe('active');
  569. spyOn(_converse.connection, 'send');
  570. spyOn(_converse, 'emit');
  571. view.keyPressed({
  572. target: $(view.el).find('textarea.chat-textarea'),
  573. keyCode: 1
  574. });
  575. expect(view.model.get('chat_state')).toBe('composing');
  576. expect(_converse.connection.send).toHaveBeenCalled();
  577. var $stanza = $(_converse.connection.send.calls.argsFor(0)[0].tree());
  578. expect($stanza.attr('to')).toBe(contact_jid);
  579. expect($stanza.children().get(0).tagName).toBe('composing');
  580. expect($stanza.children().get(1).tagName).toBe('no-store');
  581. expect($stanza.children().get(2).tagName).toBe('no-permanent-store');
  582. // The notification is not sent again
  583. view.keyPressed({
  584. target: $(view.el).find('textarea.chat-textarea'),
  585. keyCode: 1
  586. });
  587. expect(view.model.get('chat_state')).toBe('composing');
  588. expect(_converse.emit.calls.count(), 1);
  589. done();
  590. });
  591. }));
  592. it("will be shown if received",
  593. mock.initConverseWithPromises(
  594. null, ['rosterGroupsFetched'], {},
  595. function (done, _converse) {
  596. test_utils.createContacts(_converse, 'current');
  597. test_utils.openControlBox();
  598. // See XEP-0085 http://xmpp.org/extensions/xep-0085.html#definitions
  599. spyOn(_converse, 'emit');
  600. var sender_jid = mock.cur_names[1].replace(/ /g,'.').toLowerCase() + '@localhost';
  601. test_utils.openChatBoxFor(_converse, sender_jid);
  602. // <composing> state
  603. var msg = $msg({
  604. from: sender_jid,
  605. to: _converse.connection.jid,
  606. type: 'chat',
  607. id: (new Date()).getTime()
  608. }).c('body').c('composing', {'xmlns': Strophe.NS.CHATSTATES}).tree();
  609. _converse.chatboxes.onMessage(msg);
  610. expect(_converse.emit).toHaveBeenCalledWith('message', jasmine.any(Object));
  611. var chatboxview = _converse.chatboxviews.get(sender_jid);
  612. expect(chatboxview).toBeDefined();
  613. // Check that the notification appears inside the chatbox in the DOM
  614. var events = chatboxview.el.querySelectorAll('.chat-state-notification');
  615. expect(events.length).toBe(1);
  616. expect(events[0].textContent).toEqual(mock.cur_names[1] + ' is typing');
  617. // Check that it doesn't appear twice
  618. msg = $msg({
  619. from: sender_jid,
  620. to: _converse.connection.jid,
  621. type: 'chat',
  622. id: (new Date()).getTime()
  623. }).c('body').c('composing', {'xmlns': Strophe.NS.CHATSTATES}).tree();
  624. _converse.chatboxes.onMessage(msg);
  625. events = chatboxview.el.querySelectorAll('.chat-state-notification');
  626. expect(events.length).toBe(1);
  627. expect(events[0].textContent).toEqual(mock.cur_names[1] + ' is typing');
  628. done();
  629. }));
  630. it("can be a composing carbon message that this user sent from a different client",
  631. mock.initConverseWithPromises(
  632. null, ['rosterGroupsFetched'], {},
  633. function (done, _converse) {
  634. var contact, sent_stanza, IQ_id, stanza;
  635. test_utils.waitUntilDiscoConfirmed(_converse, 'localhost', [], ['vcard-temp'])
  636. .then(function () {
  637. return test_utils.waitUntil(function () {
  638. return _converse.xmppstatus.get('fullname');
  639. }, 300);
  640. }).then(function () {
  641. test_utils.createContacts(_converse, 'current');
  642. // Send a message from a different resource
  643. spyOn(_converse, 'log');
  644. var recipient_jid = mock.cur_names[5].replace(/ /g,'.').toLowerCase() + '@localhost';
  645. test_utils.openChatBoxFor(_converse, recipient_jid);
  646. var msg = $msg({
  647. 'from': _converse.bare_jid,
  648. 'id': (new Date()).getTime(),
  649. 'to': _converse.connection.jid,
  650. 'type': 'chat',
  651. 'xmlns': 'jabber:client'
  652. }).c('sent', {'xmlns': 'urn:xmpp:carbons:2'})
  653. .c('forwarded', {'xmlns': 'urn:xmpp:forward:0'})
  654. .c('message', {
  655. 'xmlns': 'jabber:client',
  656. 'from': _converse.bare_jid+'/another-resource',
  657. 'to': recipient_jid,
  658. 'type': 'chat'
  659. }).c('composing', {'xmlns': Strophe.NS.CHATSTATES}).tree();
  660. _converse.chatboxes.onMessage(msg);
  661. // Check that the chatbox and its view now exist
  662. var chatbox = _converse.chatboxes.get(recipient_jid);
  663. var chatboxview = _converse.chatboxviews.get(recipient_jid);
  664. // Check that the message was received and check the message parameters
  665. expect(chatbox.messages.length).toEqual(1);
  666. var msg_obj = chatbox.messages.models[0];
  667. expect(msg_obj.get('fullname')).toEqual(_converse.xmppstatus.get('fullname'));
  668. expect(msg_obj.get('sender')).toEqual('me');
  669. expect(msg_obj.get('delayed')).toEqual(false);
  670. var $chat_content = $(chatboxview.el).find('.chat-content');
  671. var status_text = $chat_content.find('.chat-info.chat-state-notification').text();
  672. expect(status_text).toBe('Typing from another device');
  673. done();
  674. });
  675. }));
  676. });
  677. describe("A paused notification", function () {
  678. it("is sent if the user has stopped typing since 30 seconds",
  679. mock.initConverseWithPromises(
  680. null, ['rosterGroupsFetched'], {},
  681. function (done, _converse) {
  682. var view, contact_jid;
  683. test_utils.createContacts(_converse, 'current');
  684. test_utils.openControlBox();
  685. test_utils.waitUntil(function () {
  686. return $(_converse.rosterview.el).find('.roster-group li').length;
  687. }, 700).then(function () {
  688. _converse.TIMEOUTS.PAUSED = 200; // Make the timeout shorter so that we can test
  689. contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@localhost';
  690. test_utils.openChatBoxFor(_converse, contact_jid);
  691. view = _converse.chatboxviews.get(contact_jid);
  692. spyOn(_converse.connection, 'send');
  693. spyOn(view, 'setChatState').and.callThrough();
  694. expect(view.model.get('chat_state')).toBe('active');
  695. view.keyPressed({
  696. target: $(view.el).find('textarea.chat-textarea'),
  697. keyCode: 1
  698. });
  699. expect(view.model.get('chat_state')).toBe('composing');
  700. expect(_converse.connection.send).toHaveBeenCalled();
  701. var $stanza = $(_converse.connection.send.calls.argsFor(0)[0].tree());
  702. expect($stanza.children().get(0).tagName).toBe('composing');
  703. return test_utils.waitUntil(function () {
  704. return view.model.get('chat_state') === 'paused';
  705. }, 500);
  706. }).then(function () {
  707. expect(_converse.connection.send).toHaveBeenCalled();
  708. var calls = _.filter(_converse.connection.send.calls.all(), function (call) {
  709. return call.args[0] instanceof Strophe.Builder;
  710. });
  711. expect(calls.length).toBe(2);
  712. var $stanza = $(calls[1].args[0].tree());
  713. expect($stanza.attr('to')).toBe(contact_jid);
  714. expect($stanza.children().length).toBe(3);
  715. expect($stanza.children().get(0).tagName).toBe('paused');
  716. expect($stanza.children().get(1).tagName).toBe('no-store');
  717. expect($stanza.children().get(2).tagName).toBe('no-permanent-store');
  718. // Test #359. A paused notification should not be sent
  719. // out if the user simply types longer than the
  720. // timeout.
  721. view.keyPressed({
  722. target: $(view.el).find('textarea.chat-textarea'),
  723. keyCode: 1
  724. });
  725. expect(view.setChatState).toHaveBeenCalled();
  726. expect(view.model.get('chat_state')).toBe('composing');
  727. view.keyPressed({
  728. target: $(view.el).find('textarea.chat-textarea'),
  729. keyCode: 1
  730. });
  731. expect(view.model.get('chat_state')).toBe('composing');
  732. done();
  733. });
  734. }));
  735. it("will be shown if received",
  736. mock.initConverseWithPromises(
  737. null, ['rosterGroupsFetched'], {},
  738. function (done, _converse) {
  739. test_utils.createContacts(_converse, 'current');
  740. test_utils.openControlBox();
  741. test_utils.waitUntil(function () {
  742. return $(_converse.rosterview.el).find('.roster-group').length;
  743. }, 300)
  744. .then(function () {
  745. // TODO: only show paused state if the previous state was composing
  746. // See XEP-0085 http://xmpp.org/extensions/xep-0085.html#definitions
  747. spyOn(_converse, 'emit');
  748. var sender_jid = mock.cur_names[1].replace(/ /g,'.').toLowerCase() + '@localhost';
  749. // <paused> state
  750. var msg = $msg({
  751. from: sender_jid,
  752. to: _converse.connection.jid,
  753. type: 'chat',
  754. id: (new Date()).getTime()
  755. }).c('body').c('paused', {'xmlns': Strophe.NS.CHATSTATES}).tree();
  756. _converse.chatboxes.onMessage(msg);
  757. expect(_converse.emit).toHaveBeenCalledWith('message', jasmine.any(Object));
  758. var chatboxview = _converse.chatboxviews.get(sender_jid);
  759. var $events = $(chatboxview.el).find('.chat-info.chat-state-notification');
  760. expect($events.text()).toEqual(mock.cur_names[1] + ' has stopped typing');
  761. done();
  762. });
  763. }));
  764. it("can be a paused carbon message that this user sent from a different client",
  765. mock.initConverseWithPromises(
  766. null, ['rosterGroupsFetched'], {},
  767. function (done, _converse) {
  768. var contact, sent_stanza, IQ_id, stanza;
  769. test_utils.waitUntilDiscoConfirmed(_converse, 'localhost', [], ['vcard-temp'])
  770. .then(function () {
  771. return test_utils.waitUntil(function () {
  772. return _converse.xmppstatus.get('fullname');
  773. }, 300);
  774. }).then(function () {
  775. test_utils.createContacts(_converse, 'current');
  776. // Send a message from a different resource
  777. spyOn(_converse, 'log');
  778. var recipient_jid = mock.cur_names[5].replace(/ /g,'.').toLowerCase() + '@localhost';
  779. test_utils.openChatBoxFor(_converse, recipient_jid);
  780. var msg = $msg({
  781. 'from': _converse.bare_jid,
  782. 'id': (new Date()).getTime(),
  783. 'to': _converse.connection.jid,
  784. 'type': 'chat',
  785. 'xmlns': 'jabber:client'
  786. }).c('sent', {'xmlns': 'urn:xmpp:carbons:2'})
  787. .c('forwarded', {'xmlns': 'urn:xmpp:forward:0'})
  788. .c('message', {
  789. 'xmlns': 'jabber:client',
  790. 'from': _converse.bare_jid+'/another-resource',
  791. 'to': recipient_jid,
  792. 'type': 'chat'
  793. }).c('paused', {'xmlns': Strophe.NS.CHATSTATES}).tree();
  794. _converse.chatboxes.onMessage(msg);
  795. // Check that the chatbox and its view now exist
  796. var chatbox = _converse.chatboxes.get(recipient_jid);
  797. var chatboxview = _converse.chatboxviews.get(recipient_jid);
  798. // Check that the message was received and check the message parameters
  799. expect(chatbox.messages.length).toEqual(1);
  800. var msg_obj = chatbox.messages.models[0];
  801. expect(msg_obj.get('fullname')).toEqual(_converse.xmppstatus.get('fullname'));
  802. expect(msg_obj.get('sender')).toEqual('me');
  803. expect(msg_obj.get('delayed')).toEqual(false);
  804. var $chat_content = $(chatboxview.el).find('.chat-content');
  805. var status_text = $chat_content.find('.chat-info.chat-state-notification').text();
  806. expect(status_text).toBe('Stopped typing on the other device');
  807. done();
  808. });
  809. }));
  810. });
  811. describe("An inactive notifciation", function () {
  812. it("is sent if the user has stopped typing since 2 minutes",
  813. mock.initConverseWithPromises(
  814. null, ['rosterGroupsFetched'], {},
  815. function (done, _converse) {
  816. var view, contact_jid;
  817. test_utils.createContacts(_converse, 'current');
  818. test_utils.openControlBox();
  819. test_utils.waitUntil(function () {
  820. return $(_converse.rosterview.el).find('.roster-group').length;
  821. }, 500).then(function () {
  822. // Make the timeouts shorter so that we can test
  823. _converse.TIMEOUTS.PAUSED = 200;
  824. _converse.TIMEOUTS.INACTIVE = 200;
  825. contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@localhost';
  826. test_utils.openChatBoxFor(_converse, contact_jid);
  827. view = _converse.chatboxviews.get(contact_jid);
  828. return test_utils.waitUntil(function () {
  829. return view.model.get('chat_state') === 'active';
  830. }, 500);
  831. }).then(function () {
  832. console.log('chat_state set to active');
  833. view = _converse.chatboxviews.get(contact_jid);
  834. expect(view.model.get('chat_state')).toBe('active');
  835. view.keyPressed({
  836. target: $(view.el).find('textarea.chat-textarea'),
  837. keyCode: 1
  838. });
  839. return test_utils.waitUntil(function () {
  840. return view.model.get('chat_state') === 'composing';
  841. }, 500);
  842. }).then(function () {
  843. console.log('chat_state set to composing');
  844. view = _converse.chatboxviews.get(contact_jid);
  845. expect(view.model.get('chat_state')).toBe('composing');
  846. spyOn(_converse.connection, 'send');
  847. return test_utils.waitUntil(function () {
  848. return view.model.get('chat_state') === 'paused';
  849. }, 500);
  850. }).then(function () {
  851. console.log('chat_state set to paused');
  852. return test_utils.waitUntil(function () {
  853. return view.model.get('chat_state') === 'inactive';
  854. }, 500);
  855. }).then(function () {
  856. console.log('chat_state set to inactive');
  857. expect(_converse.connection.send).toHaveBeenCalled();
  858. var calls = _.filter(_converse.connection.send.calls.all(), function (call) {
  859. return call.args[0] instanceof Strophe.Builder;
  860. });
  861. expect(calls.length).toBe(2);
  862. var $stanza = $(calls[0].args[0].tree());
  863. expect($stanza.attr('to')).toBe(contact_jid);
  864. expect($stanza.children().length).toBe(3);
  865. expect($stanza.children().get(0).tagName).toBe('paused');
  866. expect($stanza.children().get(1).tagName).toBe('no-store');
  867. expect($stanza.children().get(2).tagName).toBe('no-permanent-store');
  868. $stanza = $(_converse.connection.send.calls.mostRecent().args[0].tree());
  869. expect($stanza.attr('to')).toBe(contact_jid);
  870. expect($stanza.children().length).toBe(3);
  871. expect($stanza.children().get(0).tagName).toBe('inactive');
  872. expect($stanza.children().get(1).tagName).toBe('no-store');
  873. expect($stanza.children().get(2).tagName).toBe('no-permanent-store');
  874. }).catch(_.partial(_converse.log, _, Strophe.LogLevel.FATAL))
  875. .then(done);
  876. }));
  877. it("is sent when the user a minimizes a chat box",
  878. mock.initConverseWithPromises(
  879. null, ['rosterGroupsFetched'], {},
  880. function (done, _converse) {
  881. test_utils.createContacts(_converse, 'current');
  882. test_utils.openControlBox();
  883. var contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@localhost';
  884. test_utils.openChatBoxFor(_converse, contact_jid);
  885. var view = _converse.chatboxviews.get(contact_jid);
  886. spyOn(_converse.connection, 'send');
  887. view.minimize();
  888. expect(view.model.get('chat_state')).toBe('inactive');
  889. expect(_converse.connection.send).toHaveBeenCalled();
  890. var $stanza = $(_converse.connection.send.calls.argsFor(0)[0].tree());
  891. expect($stanza.attr('to')).toBe(contact_jid);
  892. expect($stanza.children().get(0).tagName).toBe('inactive');
  893. done();
  894. }));
  895. it("is sent if the user closes a chat box",
  896. mock.initConverseWithPromises(
  897. null, ['rosterGroupsFetched'], {},
  898. function (done, _converse) {
  899. test_utils.createContacts(_converse, 'current');
  900. test_utils.openControlBox();
  901. test_utils.waitUntil(function () {
  902. return $(_converse.rosterview.el).find('.roster-group').length;
  903. }, 300).then(function () {
  904. var contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@localhost';
  905. test_utils.openChatBoxFor(_converse, contact_jid);
  906. var view = _converse.chatboxviews.get(contact_jid);
  907. expect(view.model.get('chat_state')).toBe('active');
  908. spyOn(_converse.connection, 'send');
  909. view.close();
  910. expect(view.model.get('chat_state')).toBe('inactive');
  911. expect(_converse.connection.send).toHaveBeenCalled();
  912. var $stanza = $(_converse.connection.send.calls.argsFor(0)[0].tree());
  913. expect($stanza.attr('to')).toBe(contact_jid);
  914. expect($stanza.children().length).toBe(3);
  915. expect($stanza.children().get(0).tagName).toBe('inactive');
  916. expect($stanza.children().get(1).tagName).toBe('no-store');
  917. expect($stanza.children().get(2).tagName).toBe('no-permanent-store');
  918. done();
  919. });
  920. }));
  921. it("will clear any other chat status notifications",
  922. mock.initConverseWithPromises(
  923. null, ['rosterGroupsFetched'], {},
  924. function (done, _converse) {
  925. test_utils.createContacts(_converse, 'current');
  926. test_utils.openControlBox();
  927. // See XEP-0085 http://xmpp.org/extensions/xep-0085.html#definitions
  928. spyOn(_converse, 'emit');
  929. var sender_jid = mock.cur_names[1].replace(/ /g,'.').toLowerCase() + '@localhost';
  930. test_utils.openChatBoxFor(_converse, sender_jid);
  931. var view = _converse.chatboxviews.get(sender_jid);
  932. expect(view.el.querySelectorAll('.chat-event').length).toBe(0);
  933. // Insert <composing> message, to also check that
  934. // text messages are inserted correctly with
  935. // temporary chat events in the chat contents.
  936. var msg = $msg({
  937. 'to': _converse.bare_jid,
  938. 'xmlns': 'jabber:client',
  939. 'from': sender_jid,
  940. 'type': 'chat'})
  941. .c('composing', {'xmlns': Strophe.NS.CHATSTATES}).up()
  942. .tree();
  943. _converse.chatboxes.onMessage(msg);
  944. expect(view.el.querySelectorAll('.chat-state-notification').length).toBe(1);
  945. msg = $msg({
  946. from: sender_jid,
  947. to: _converse.connection.jid,
  948. type: 'chat',
  949. id: (new Date()).getTime()
  950. }).c('body').c('inactive', {'xmlns': Strophe.NS.CHATSTATES}).tree();
  951. _converse.chatboxes.onMessage(msg);
  952. expect(_converse.emit).toHaveBeenCalledWith('message', jasmine.any(Object));
  953. expect($(view.el).find('.chat-state-notification').length).toBe(0);
  954. done();
  955. }));
  956. });
  957. describe("A gone notifciation", function () {
  958. it("will be shown if received",
  959. mock.initConverseWithPromises(
  960. null, ['rosterGroupsFetched'], {},
  961. function (done, _converse) {
  962. test_utils.createContacts(_converse, 'current');
  963. test_utils.openControlBox();
  964. spyOn(_converse, 'emit');
  965. var sender_jid = mock.cur_names[1].replace(/ /g,'.').toLowerCase() + '@localhost';
  966. // <paused> state
  967. var msg = $msg({
  968. from: sender_jid,
  969. to: _converse.connection.jid,
  970. type: 'chat',
  971. id: (new Date()).getTime()
  972. }).c('body').c('gone', {'xmlns': Strophe.NS.CHATSTATES}).tree();
  973. _converse.chatboxes.onMessage(msg);
  974. expect(_converse.emit).toHaveBeenCalledWith('message', jasmine.any(Object));
  975. var chatboxview = _converse.chatboxviews.get(sender_jid);
  976. var $events = $(chatboxview.el).find('.chat-state-notification');
  977. expect($events.text()).toEqual(mock.cur_names[1] + ' has gone away');
  978. done();
  979. }));
  980. });
  981. });
  982. });
  983. describe("Special Messages", function () {
  984. it("'/clear' can be used to clear messages in a conversation",
  985. mock.initConverseWithPromises(
  986. null, ['rosterGroupsFetched'], {},
  987. function (done, _converse) {
  988. test_utils.createContacts(_converse, 'current');
  989. test_utils.openControlBox();
  990. spyOn(_converse, 'emit');
  991. var contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@localhost';
  992. test_utils.openChatBoxFor(_converse, contact_jid);
  993. var view = _converse.chatboxviews.get(contact_jid);
  994. var message = 'This message is another sent from this chatbox';
  995. // Lets make sure there is at least one message already
  996. // (e.g for when this test is run on its own).
  997. test_utils.sendMessage(view, message);
  998. expect(view.model.messages.length > 0).toBeTruthy();
  999. expect(view.model.messages.browserStorage.records.length > 0).toBeTruthy();
  1000. expect(_converse.emit).toHaveBeenCalledWith('messageSend', message);
  1001. message = '/clear';
  1002. spyOn(view, 'onMessageSubmitted').and.callThrough();
  1003. spyOn(view, 'clearMessages').and.callThrough();
  1004. spyOn(window, 'confirm').and.callFake(function () {
  1005. return true;
  1006. });
  1007. test_utils.sendMessage(view, message);
  1008. expect(view.onMessageSubmitted).toHaveBeenCalled();
  1009. expect(view.clearMessages).toHaveBeenCalled();
  1010. expect(window.confirm).toHaveBeenCalled();
  1011. expect(view.model.messages.length, 0); // The messages must be removed from the chatbox
  1012. expect(view.model.messages.browserStorage.records.length, 0); // And also from browserStorage
  1013. expect(_converse.emit.calls.count(), 1);
  1014. expect(_converse.emit.calls.mostRecent().args, ['messageSend', message]);
  1015. done();
  1016. }));
  1017. });
  1018. describe("A Message Counter", function () {
  1019. it("is incremented when the message is received and the window is not focused",
  1020. mock.initConverseWithPromises(
  1021. null, ['rosterGroupsFetched'], {},
  1022. function (done, _converse) {
  1023. test_utils.createContacts(_converse, 'current');
  1024. test_utils.openControlBox();
  1025. spyOn(_converse, 'emit');
  1026. expect(_converse.msg_counter).toBe(0);
  1027. spyOn(_converse, 'incrementMsgCounter').and.callThrough();
  1028. spyOn(_converse, 'clearMsgCounter').and.callThrough();
  1029. var previous_state = _converse.windowState;
  1030. var message = 'This message will increment the message counter';
  1031. var sender_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@localhost',
  1032. msg = $msg({
  1033. from: sender_jid,
  1034. to: _converse.connection.jid,
  1035. type: 'chat',
  1036. id: (new Date()).getTime()
  1037. }).c('body').t(message).up()
  1038. .c('active', {'xmlns': Strophe.NS.CHATSTATES}).tree();
  1039. _converse.windowState = 'hidden';
  1040. _converse.chatboxes.onMessage(msg);
  1041. expect(_converse.incrementMsgCounter).toHaveBeenCalled();
  1042. expect(_converse.clearMsgCounter).not.toHaveBeenCalled();
  1043. expect(_converse.msg_counter).toBe(1);
  1044. expect(_converse.emit).toHaveBeenCalledWith('message', jasmine.any(Object));
  1045. _converse.windowSate = previous_state;
  1046. done();
  1047. }));
  1048. it("is cleared when the window is focused",
  1049. mock.initConverseWithPromises(
  1050. null, ['rosterGroupsFetched'], {},
  1051. function (done, _converse) {
  1052. test_utils.createContacts(_converse, 'current');
  1053. test_utils.openControlBox();
  1054. _converse.windowState = 'hidden';
  1055. spyOn(_converse, 'clearMsgCounter').and.callThrough();
  1056. _converse.saveWindowState(null, 'focus');
  1057. _converse.saveWindowState(null, 'blur');
  1058. expect(_converse.clearMsgCounter).toHaveBeenCalled();
  1059. done();
  1060. }));
  1061. it("is not incremented when the message is received and the window is focused",
  1062. mock.initConverseWithPromises(
  1063. null, ['rosterGroupsFetched'], {},
  1064. function (done, _converse) {
  1065. test_utils.createContacts(_converse, 'current');
  1066. test_utils.openControlBox();
  1067. expect(_converse.msg_counter).toBe(0);
  1068. spyOn(_converse, 'incrementMsgCounter').and.callThrough();
  1069. _converse.saveWindowState(null, 'focus');
  1070. var message = 'This message will not increment the message counter';
  1071. var sender_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@localhost',
  1072. msg = $msg({
  1073. from: sender_jid,
  1074. to: _converse.connection.jid,
  1075. type: 'chat',
  1076. id: (new Date()).getTime()
  1077. }).c('body').t(message).up()
  1078. .c('active', {'xmlns': Strophe.NS.CHATSTATES}).tree();
  1079. _converse.chatboxes.onMessage(msg);
  1080. expect(_converse.incrementMsgCounter).not.toHaveBeenCalled();
  1081. expect(_converse.msg_counter).toBe(0);
  1082. done();
  1083. }));
  1084. it("is incremented from zero when chatbox was closed after viewing previously received messages and the window is not focused now",
  1085. mock.initConverseWithPromises(
  1086. null, ['rosterGroupsFetched'], {},
  1087. function (done, _converse) {
  1088. test_utils.createContacts(_converse, 'current');
  1089. // initial state
  1090. expect(_converse.msg_counter).toBe(0);
  1091. var message = 'This message will always increment the message counter from zero',
  1092. sender_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@localhost',
  1093. msgFactory = function () {
  1094. return $msg({
  1095. from: sender_jid,
  1096. to: _converse.connection.jid,
  1097. type: 'chat',
  1098. id: (new Date()).getTime()
  1099. })
  1100. .c('body').t(message).up()
  1101. .c('active', {'xmlns': Strophe.NS.CHATSTATES})
  1102. .tree();
  1103. };
  1104. // leave converse-chat page
  1105. _converse.windowState = 'hidden';
  1106. _converse.chatboxes.onMessage(msgFactory());
  1107. expect(_converse.msg_counter).toBe(1);
  1108. // come back to converse-chat page
  1109. _converse.saveWindowState(null, 'focus');
  1110. var view = _converse.chatboxviews.get(sender_jid);
  1111. expect(u.isVisible(view.el)).toBeTruthy();
  1112. expect(_converse.msg_counter).toBe(0);
  1113. // close chatbox and leave converse-chat page again
  1114. view.close();
  1115. _converse.windowState = 'hidden';
  1116. // check that msg_counter is incremented from zero again
  1117. _converse.chatboxes.onMessage(msgFactory());
  1118. view = _converse.chatboxviews.get(sender_jid);
  1119. expect(u.isVisible(view.el)).toBeTruthy();
  1120. expect(_converse.msg_counter).toBe(1);
  1121. done();
  1122. }));
  1123. });
  1124. describe("A ChatBox's Unread Message Count", function () {
  1125. it("is incremented when the message is received and ChatBoxView is scrolled up",
  1126. mock.initConverseWithPromises(
  1127. null, ['rosterGroupsFetched'], {},
  1128. function (done, _converse) {
  1129. test_utils.createContacts(_converse, 'current');
  1130. var sender_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@localhost',
  1131. msg = test_utils.createChatMessage(_converse, sender_jid, 'This message will be unread');
  1132. test_utils.openChatBoxFor(_converse, sender_jid);
  1133. var chatbox = _converse.chatboxes.get(sender_jid);
  1134. chatbox.save('scrolled', true);
  1135. _converse.chatboxes.onMessage(msg);
  1136. expect(chatbox.get('num_unread')).toBe(1);
  1137. done();
  1138. }));
  1139. it("is not incremented when the message is received and ChatBoxView is scrolled down",
  1140. mock.initConverseWithPromises(
  1141. null, ['rosterGroupsFetched'], {},
  1142. function (done, _converse) {
  1143. test_utils.createContacts(_converse, 'current');
  1144. var sender_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@localhost',
  1145. msg = test_utils.createChatMessage(_converse, sender_jid, 'This message will be read');
  1146. test_utils.openChatBoxFor(_converse, sender_jid);
  1147. var chatbox = _converse.chatboxes.get(sender_jid);
  1148. _converse.chatboxes.onMessage(msg);
  1149. expect(chatbox.get('num_unread')).toBe(0);
  1150. done();
  1151. }));
  1152. it("is incremeted when message is received, chatbox is scrolled down and the window is not focused",
  1153. mock.initConverseWithPromises(
  1154. null, ['rosterGroupsFetched'], {},
  1155. function (done, _converse) {
  1156. test_utils.createContacts(_converse, 'current');
  1157. var sender_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@localhost';
  1158. var msgFactory = function () {
  1159. return test_utils.createChatMessage(_converse, sender_jid, 'This message will be unread');
  1160. };
  1161. test_utils.openChatBoxFor(_converse, sender_jid);
  1162. var chatbox = _converse.chatboxes.get(sender_jid);
  1163. _converse.windowState = 'hidden';
  1164. _converse.chatboxes.onMessage(msgFactory());
  1165. expect(chatbox.get('num_unread')).toBe(1);
  1166. done();
  1167. }));
  1168. it("is incremeted when message is received, chatbox is scrolled up and the window is not focused",
  1169. mock.initConverseWithPromises(
  1170. null, ['rosterGroupsFetched'], {},
  1171. function (done, _converse) {
  1172. test_utils.createContacts(_converse, 'current');
  1173. var sender_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@localhost';
  1174. var msgFactory = function () {
  1175. return test_utils.createChatMessage(_converse, sender_jid, 'This message will be unread');
  1176. };
  1177. test_utils.openChatBoxFor(_converse, sender_jid);
  1178. var chatbox = _converse.chatboxes.get(sender_jid);
  1179. chatbox.save('scrolled', true);
  1180. _converse.windowState = 'hidden';
  1181. _converse.chatboxes.onMessage(msgFactory());
  1182. expect(chatbox.get('num_unread')).toBe(1);
  1183. done();
  1184. }));
  1185. it("is cleared when ChatBoxView was scrolled down and the window become focused",
  1186. mock.initConverseWithPromises(
  1187. null, ['rosterGroupsFetched'], {},
  1188. function (done, _converse) {
  1189. test_utils.createContacts(_converse, 'current');
  1190. var sender_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@localhost';
  1191. var msgFactory = function () {
  1192. return test_utils.createChatMessage(_converse, sender_jid, 'This message will be unread');
  1193. };
  1194. test_utils.openChatBoxFor(_converse, sender_jid);
  1195. var chatbox = _converse.chatboxes.get(sender_jid);
  1196. _converse.windowState = 'hidden';
  1197. _converse.chatboxes.onMessage(msgFactory());
  1198. expect(chatbox.get('num_unread')).toBe(1);
  1199. _converse.saveWindowState(null, 'focus');
  1200. expect(chatbox.get('num_unread')).toBe(0);
  1201. done();
  1202. }));
  1203. it("is not cleared when ChatBoxView was scrolled up and the windows become focused",
  1204. mock.initConverseWithPromises(
  1205. null, ['rosterGroupsFetched'], {},
  1206. function (done, _converse) {
  1207. test_utils.createContacts(_converse, 'current');
  1208. var sender_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@localhost';
  1209. var msgFactory = function () {
  1210. return test_utils.createChatMessage(_converse, sender_jid, 'This message will be unread');
  1211. };
  1212. test_utils.openChatBoxFor(_converse, sender_jid);
  1213. var chatbox = _converse.chatboxes.get(sender_jid);
  1214. chatbox.save('scrolled', true);
  1215. _converse.windowState = 'hidden';
  1216. _converse.chatboxes.onMessage(msgFactory());
  1217. expect(chatbox.get('num_unread')).toBe(1);
  1218. _converse.saveWindowState(null, 'focus');
  1219. expect(chatbox.get('num_unread')).toBe(1);
  1220. done();
  1221. }));
  1222. });
  1223. describe("A RosterView's Unread Message Count", function () {
  1224. it("is updated when message is received and chatbox is scrolled up",
  1225. mock.initConverseWithPromises(
  1226. null, ['rosterGroupsFetched'], {},
  1227. function (done, _converse) {
  1228. test_utils.createContacts(_converse, 'current');
  1229. test_utils.waitUntil(function () {
  1230. return $(_converse.rosterview.el).find('.roster-group').length;
  1231. }, 500)
  1232. .then(function () {
  1233. var sender_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@localhost';
  1234. test_utils.openChatBoxFor(_converse, sender_jid);
  1235. var chatbox = _converse.chatboxes.get(sender_jid);
  1236. chatbox.save('scrolled', true);
  1237. var msg = test_utils.createChatMessage(_converse, sender_jid, 'This message will be unread');
  1238. _converse.chatboxes.onMessage(msg);
  1239. var msgIndicatorSelector = 'a.open-chat:contains("' + chatbox.get('fullname') + '") .msgs-indicator',
  1240. $msgIndicator = $($(_converse.rosterview.el).find(msgIndicatorSelector));
  1241. expect($msgIndicator.text()).toBe('1');
  1242. msg = test_utils.createChatMessage(_converse, sender_jid, 'This message will be unread too');
  1243. _converse.chatboxes.onMessage(msg);
  1244. $msgIndicator = $($(_converse.rosterview.el).find(msgIndicatorSelector));
  1245. expect($msgIndicator.text()).toBe('2');
  1246. done();
  1247. });
  1248. }));
  1249. it("is updated when message is received and chatbox is minimized",
  1250. mock.initConverseWithPromises(
  1251. null, ['rosterGroupsFetched'], {},
  1252. function (done, _converse) {
  1253. test_utils.createContacts(_converse, 'current');
  1254. test_utils.waitUntil(function () {
  1255. return $(_converse.rosterview.el).find('.roster-group').length;
  1256. }, 500)
  1257. .then(function () {
  1258. var sender_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@localhost';
  1259. test_utils.openChatBoxFor(_converse, sender_jid);
  1260. var chatbox = _converse.chatboxes.get(sender_jid);
  1261. var chatboxview = _converse.chatboxviews.get(sender_jid);
  1262. chatboxview.minimize();
  1263. var msg = test_utils.createChatMessage(_converse, sender_jid, 'This message will be unread');
  1264. _converse.chatboxes.onMessage(msg);
  1265. var msgIndicatorSelector = 'a.open-chat:contains("' + chatbox.get('fullname') + '") .msgs-indicator',
  1266. $msgIndicator = $($(_converse.rosterview.el).find(msgIndicatorSelector));
  1267. expect($msgIndicator.text()).toBe('1');
  1268. msg = test_utils.createChatMessage(_converse, sender_jid, 'This message will be unread too');
  1269. _converse.chatboxes.onMessage(msg);
  1270. $msgIndicator = $($(_converse.rosterview.el).find(msgIndicatorSelector));
  1271. expect($msgIndicator.text()).toBe('2');
  1272. done();
  1273. });
  1274. }));
  1275. it("is cleared when chatbox is maximzied after receiving messages in minimized mode",
  1276. mock.initConverseWithPromises(
  1277. null, ['rosterGroupsFetched'], {},
  1278. function (done, _converse) {
  1279. test_utils.createContacts(_converse, 'current');
  1280. test_utils.waitUntil(function () {
  1281. return $(_converse.rosterview.el).find('.roster-group').length;
  1282. }, 500)
  1283. .then(function () {
  1284. var sender_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@localhost';
  1285. test_utils.openChatBoxFor(_converse, sender_jid);
  1286. var chatbox = _converse.chatboxes.get(sender_jid);
  1287. var chatboxview = _converse.chatboxviews.get(sender_jid);
  1288. var msgsIndicatorSelector = 'a.open-chat:contains("' + chatbox.get('fullname') + '") .msgs-indicator';
  1289. var selectMsgsIndicator = function () { return $($(_converse.rosterview.el).find(msgsIndicatorSelector)); };
  1290. var msgFactory = function () {
  1291. return test_utils.createChatMessage(_converse, sender_jid, 'This message will be received as unread, but eventually will be read');
  1292. };
  1293. chatboxview.minimize();
  1294. _converse.chatboxes.onMessage(msgFactory());
  1295. expect(selectMsgsIndicator().text()).toBe('1');
  1296. _converse.chatboxes.onMessage(msgFactory());
  1297. expect(selectMsgsIndicator().text()).toBe('2');
  1298. chatboxview.maximize();
  1299. expect(selectMsgsIndicator().length).toBe(0);
  1300. done();
  1301. });
  1302. }));
  1303. it("is cleared when unread messages are viewed which were received in scrolled-up chatbox",
  1304. mock.initConverseWithPromises(
  1305. null, ['rosterGroupsFetched'], {},
  1306. function (done, _converse) {
  1307. test_utils.createContacts(_converse, 'current');
  1308. test_utils.waitUntil(function () {
  1309. return $(_converse.rosterview.el).find('.roster-group').length;
  1310. }, 500)
  1311. .then(function () {
  1312. var sender_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@localhost';
  1313. test_utils.openChatBoxFor(_converse, sender_jid);
  1314. var chatbox = _converse.chatboxes.get(sender_jid);
  1315. var chatboxview = _converse.chatboxviews.get(sender_jid);
  1316. var msgFactory = function () {
  1317. return test_utils.createChatMessage(_converse, sender_jid, 'This message will be received as unread, but eventually will be read');
  1318. };
  1319. var msgsIndicatorSelector = 'a.open-chat:contains("' + chatbox.get('fullname') + '") .msgs-indicator',
  1320. selectMsgsIndicator = function () { return $($(_converse.rosterview.el).find(msgsIndicatorSelector)); };
  1321. chatbox.save('scrolled', true);
  1322. _converse.chatboxes.onMessage(msgFactory());
  1323. expect(selectMsgsIndicator().text()).toBe('1');
  1324. chatboxview.viewUnreadMessages();
  1325. _converse.rosterview.render();
  1326. expect(selectMsgsIndicator().length).toBe(0);
  1327. done();
  1328. });
  1329. }));
  1330. it("is not cleared after user clicks on roster view when chatbox is already opened and scrolled up",
  1331. mock.initConverseWithPromises(
  1332. null, ['rosterGroupsFetched'], {},
  1333. function (done, _converse) {
  1334. test_utils.createContacts(_converse, 'current');
  1335. test_utils.waitUntil(function () {
  1336. return $(_converse.rosterview.el).find('.roster-group').length;
  1337. }, 500)
  1338. .then(function () {
  1339. var sender_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@localhost';
  1340. test_utils.openChatBoxFor(_converse, sender_jid);
  1341. var chatbox = _converse.chatboxes.get(sender_jid);
  1342. var chatboxview = _converse.chatboxviews.get(sender_jid);
  1343. var msgFactory = function () {
  1344. return test_utils.createChatMessage(_converse, sender_jid, 'This message will be received as unread, but eventually will be read');
  1345. };
  1346. var msgsIndicatorSelector = 'a.open-chat:contains("' + chatbox.get('fullname') + '") .msgs-indicator',
  1347. selectMsgsIndicator = function () { return $($(_converse.rosterview.el).find(msgsIndicatorSelector)); };
  1348. chatbox.save('scrolled', true);
  1349. _converse.chatboxes.onMessage(msgFactory());
  1350. expect(selectMsgsIndicator().text()).toBe('1');
  1351. test_utils.openChatBoxFor(_converse, sender_jid);
  1352. expect(selectMsgsIndicator().text()).toBe('1');
  1353. done();
  1354. });
  1355. }));
  1356. });
  1357. describe("A Minimized ChatBoxView's Unread Message Count", function () {
  1358. it("is displayed when scrolled up chatbox is minimized after receiving unread messages",
  1359. mock.initConverseWithPromises(
  1360. null, ['rosterGroupsFetched'], {},
  1361. function (done, _converse) {
  1362. test_utils.createContacts(_converse, 'current');
  1363. var sender_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@localhost';
  1364. test_utils.openChatBoxFor(_converse, sender_jid);
  1365. var msgFactory = function () {
  1366. return test_utils.createChatMessage(_converse, sender_jid, 'This message will be received as unread, but eventually will be read');
  1367. };
  1368. var selectUnreadMsgCount = function () {
  1369. var minimizedChatBoxView = _converse.minimized_chats.get(sender_jid);
  1370. return $(minimizedChatBoxView.el).find('.message-count');
  1371. };
  1372. var chatbox = _converse.chatboxes.get(sender_jid);
  1373. chatbox.save('scrolled', true);
  1374. _converse.chatboxes.onMessage(msgFactory());
  1375. var chatboxview = _converse.chatboxviews.get(sender_jid);
  1376. chatboxview.minimize();
  1377. var $unreadMsgCount = selectUnreadMsgCount();
  1378. expect(u.isVisible($unreadMsgCount[0])).toBeTruthy();
  1379. expect($unreadMsgCount.html()).toBe('1');
  1380. done();
  1381. }));
  1382. it("is incremented when message is received and windows is not focused",
  1383. mock.initConverseWithPromises(
  1384. null, ['rosterGroupsFetched'], {},
  1385. function (done, _converse) {
  1386. test_utils.createContacts(_converse, 'current');
  1387. var sender_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@localhost';
  1388. test_utils.openChatBoxFor(_converse, sender_jid);
  1389. var msgFactory = function () {
  1390. return test_utils.createChatMessage(_converse, sender_jid, 'This message will be received as unread, but eventually will be read');
  1391. };
  1392. var selectUnreadMsgCount = function () {
  1393. var minimizedChatBoxView = _converse.minimized_chats.get(sender_jid);
  1394. return $(minimizedChatBoxView.el).find('.message-count');
  1395. };
  1396. var chatboxview = _converse.chatboxviews.get(sender_jid);
  1397. chatboxview.minimize();
  1398. _converse.chatboxes.onMessage(msgFactory());
  1399. var $unreadMsgCount = selectUnreadMsgCount();
  1400. expect(u.isVisible($unreadMsgCount[0])).toBeTruthy();
  1401. expect($unreadMsgCount.html()).toBe('1');
  1402. done();
  1403. }));
  1404. it("will render Openstreetmap-URL from geo-URI",
  1405. mock.initConverseWithPromises(
  1406. null, ['rosterGroupsFetched'], {},
  1407. function (done, _converse) {
  1408. test_utils.createContacts(_converse, 'current');
  1409. var base_url = document.URL.split(window.location.pathname)[0];
  1410. var message = "geo:37.786971,-122.399677";
  1411. var contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@localhost';
  1412. test_utils.openChatBoxFor(_converse, contact_jid);
  1413. var view = _converse.chatboxviews.get(contact_jid);
  1414. spyOn(view.model, 'sendMessage').and.callThrough();
  1415. test_utils.sendMessage(view, message);
  1416. test_utils.waitUntil(function () {
  1417. return $(view.el).find('.chat-content').find('.chat-msg').length;
  1418. }, 1000).then(function () {
  1419. expect(view.model.sendMessage).toHaveBeenCalled();
  1420. var msg = $(view.el).find('.chat-content').find('.chat-msg').last().find('.chat-msg-text');
  1421. expect(msg.html()).toEqual(
  1422. '<a target="_blank" rel="noopener" href="https://www.openstreetmap.org/?mlat=37.786971&amp;'+
  1423. 'mlon=-122.399677#map=18/37.786971/-122.399677">https://www.openstreetmap.org/?mlat=37.7869'+
  1424. '71&amp;mlon=-122.399677#map=18/37.786971/-122.399677</a>');
  1425. done();
  1426. });
  1427. }));
  1428. });
  1429. });
  1430. }));