2
0

bookmarks.js 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622
  1. (function (root, factory) {
  2. define([
  3. "jasmine",
  4. "mock",
  5. "test-utils"
  6. ], factory);
  7. } (this, function (jasmine, mock, test_utils) {
  8. "use strict";
  9. const $iq = converse.env.$iq,
  10. $msg = converse.env.$msg,
  11. Strophe = converse.env.Strophe,
  12. sizzle = converse.env.sizzle,
  13. _ = converse.env._,
  14. u = converse.env.utils;
  15. describe("A chat room", function () {
  16. it("can be bookmarked", mock.initConverse(['rosterGroupsFetched'], {}, async function (done, _converse) {
  17. await test_utils.waitUntilDiscoConfirmed(
  18. _converse, _converse.bare_jid,
  19. [{'category': 'pubsub', 'type': 'pep'}],
  20. ['http://jabber.org/protocol/pubsub#publish-options']
  21. );
  22. let sent_stanza, IQ_id;
  23. const sendIQ = _converse.connection.sendIQ;
  24. spyOn(_converse.connection, 'sendIQ').and.callFake(function (iq, callback, errback) {
  25. sent_stanza = iq;
  26. IQ_id = sendIQ.bind(this)(iq, callback, errback);
  27. });
  28. spyOn(_converse.connection, 'getUniqueId').and.callThrough();
  29. await test_utils.openChatRoom(_converse, 'theplay', 'conference.shakespeare.lit', 'JC');
  30. var jid = 'theplay@conference.shakespeare.lit';
  31. const view = _converse.chatboxviews.get(jid);
  32. spyOn(view, 'renderBookmarkForm').and.callThrough();
  33. spyOn(view, 'closeForm').and.callThrough();
  34. await u.waitUntil(() => view.el.querySelector('.toggle-bookmark') !== null);
  35. let toggle = view.el.querySelector('.toggle-bookmark');
  36. expect(toggle.title).toBe('Bookmark this groupchat');
  37. toggle.click();
  38. expect(view.renderBookmarkForm).toHaveBeenCalled();
  39. view.el.querySelector('.button-cancel').click();
  40. expect(view.closeForm).toHaveBeenCalled();
  41. expect(u.hasClass('on-button', toggle), false);
  42. expect(toggle.title).toBe('Bookmark this groupchat');
  43. toggle.click();
  44. expect(view.renderBookmarkForm).toHaveBeenCalled();
  45. /* Client uploads data:
  46. * --------------------
  47. * <iq from='juliet@capulet.lit/balcony' type='set' id='pip1'>
  48. * <pubsub xmlns='http://jabber.org/protocol/pubsub'>
  49. * <publish node='storage:bookmarks'>
  50. * <item id='current'>
  51. * <storage xmlns='storage:bookmarks'>
  52. * <conference name='The Play&apos;s the Thing'
  53. * autojoin='true'
  54. * jid='theplay@conference.shakespeare.lit'>
  55. * <nick>JC</nick>
  56. * </conference>
  57. * </storage>
  58. * </item>
  59. * </publish>
  60. * <publish-options>
  61. * <x xmlns='jabber:x:data' type='submit'>
  62. * <field var='FORM_TYPE' type='hidden'>
  63. * <value>http://jabber.org/protocol/pubsub#publish-options</value>
  64. * </field>
  65. * <field var='pubsub#persist_items'>
  66. * <value>true</value>
  67. * </field>
  68. * <field var='pubsub#access_model'>
  69. * <value>whitelist</value>
  70. * </field>
  71. * </x>
  72. * </publish-options>
  73. * </pubsub>
  74. * </iq>
  75. */
  76. expect(view.model.get('bookmarked')).toBeFalsy();
  77. const form = view.el.querySelector('.chatroom-form');
  78. form.querySelector('input[name="name"]').value = 'Play&apos;s the Thing';
  79. form.querySelector('input[name="autojoin"]').checked = 'checked';
  80. form.querySelector('input[name="nick"]').value = 'JC';
  81. _converse.connection.IQ_stanzas = [];
  82. view.el.querySelector('.btn-primary').click();
  83. await u.waitUntil(() => sent_stanza);
  84. expect(sent_stanza.toLocaleString()).toBe(
  85. `<iq from="romeo@montague.lit/orchard" id="${IQ_id}" type="set" xmlns="jabber:client">`+
  86. `<pubsub xmlns="http://jabber.org/protocol/pubsub">`+
  87. `<publish node="storage:bookmarks">`+
  88. `<item id="current">`+
  89. `<storage xmlns="storage:bookmarks">`+
  90. `<conference autojoin="true" jid="theplay@conference.shakespeare.lit" name="Play&amp;apos;s the Thing">`+
  91. `<nick>JC</nick>`+
  92. `</conference>`+
  93. `</storage>`+
  94. `</item>`+
  95. `</publish>`+
  96. `<publish-options>`+
  97. `<x type="submit" xmlns="jabber:x:data">`+
  98. `<field type="hidden" var="FORM_TYPE">`+
  99. `<value>http://jabber.org/protocol/pubsub#publish-options</value>`+
  100. `</field>`+
  101. `<field var="pubsub#persist_items">`+
  102. `<value>true</value>`+
  103. `</field>`+
  104. `<field var="pubsub#access_model">`+
  105. `<value>whitelist</value>`+
  106. `</field>`+
  107. `</x>`+
  108. `</publish-options>`+
  109. `</pubsub>`+
  110. `</iq>`
  111. );
  112. /* Server acknowledges successful storage
  113. *
  114. * <iq to='juliet@capulet.lit/balcony' type='result' id='pip1'/>
  115. */
  116. const stanza = $iq({
  117. 'to':_converse.connection.jid,
  118. 'type':'result',
  119. 'id':IQ_id
  120. });
  121. _converse.connection._dataRecv(test_utils.createRequest(stanza));
  122. await u.waitUntil(() => view.model.get('bookmarked'));
  123. toggle = await u.waitUntil(() => view.el.querySelector('.toggle-bookmark'));
  124. expect(view.model.get('bookmarked')).toBeTruthy();
  125. expect(toggle.title).toBe('Unbookmark this groupchat');
  126. expect(u.hasClass('on-button', toggle), true);
  127. // We ignore this IQ stanza... (unless it's an error stanza), so
  128. // nothing to test for here.
  129. done();
  130. }));
  131. it("will be automatically opened if 'autojoin' is set on the bookmark", mock.initConverse(
  132. ['rosterGroupsFetched'], {},
  133. async function (done, _converse) {
  134. await test_utils.waitUntilDiscoConfirmed(
  135. _converse, _converse.bare_jid,
  136. [{'category': 'pubsub', 'type': 'pep'}],
  137. ['http://jabber.org/protocol/pubsub#publish-options']
  138. );
  139. await u.waitUntil(() => _converse.bookmarks);
  140. let jid = 'lounge@montague.lit';
  141. _converse.bookmarks.create({
  142. 'jid': jid,
  143. 'autojoin': false,
  144. 'name': 'The Lounge',
  145. 'nick': ' Othello'
  146. });
  147. expect(_converse.chatboxviews.get(jid) === undefined).toBeTruthy();
  148. jid = 'theplay@conference.shakespeare.lit';
  149. _converse.bookmarks.create({
  150. 'jid': jid,
  151. 'autojoin': true,
  152. 'name': 'The Play',
  153. 'nick': ' Othello'
  154. });
  155. await new Promise(resolve => _converse.api.listen.once('chatRoomViewInitialized', resolve));
  156. expect(_.isUndefined(_converse.chatboxviews.get(jid))).toBeFalsy();
  157. // Check that we don't auto-join if muc_respect_autojoin is false
  158. _converse.muc_respect_autojoin = false;
  159. jid = 'balcony@conference.shakespeare.lit';
  160. _converse.bookmarks.create({
  161. 'jid': jid,
  162. 'autojoin': true,
  163. 'name': 'Balcony',
  164. 'nick': ' Othello'
  165. });
  166. expect(_converse.chatboxviews.get(jid) === undefined).toBe(true);
  167. done();
  168. }));
  169. describe("when bookmarked", function () {
  170. it("will use the nickname from the bookmark", mock.initConverse(
  171. ['rosterGroupsFetched'], {}, async function (done, _converse) {
  172. await test_utils.waitUntilBookmarksReturned(_converse);
  173. const muc_jid = 'coven@chat.shakespeare.lit';
  174. _converse.bookmarks.create({
  175. 'jid': muc_jid,
  176. 'autojoin': false,
  177. 'name': 'The Play',
  178. 'nick': 'Othello'
  179. });
  180. spyOn(_converse.ChatRoom.prototype, 'getAndPersistNickname').and.callThrough();
  181. const room_creation_promise = _converse.api.rooms.open(muc_jid);
  182. await test_utils.getRoomFeatures(_converse, muc_jid);
  183. const room = await room_creation_promise;
  184. await u.waitUntil(() => room.getAndPersistNickname.calls.count());
  185. expect(room.get('nick')).toBe('Othello');
  186. done();
  187. }));
  188. it("displays that it's bookmarked through its bookmark icon", mock.initConverse(
  189. ['rosterGroupsFetched'], {},
  190. async function (done, _converse) {
  191. test_utils.waitUntilDiscoConfirmed(
  192. _converse, _converse.bare_jid,
  193. [{'category': 'pubsub', 'type': 'pep'}],
  194. ['http://jabber.org/protocol/pubsub#publish-options']
  195. );
  196. await _converse.api.rooms.open(`lounge@montague.lit`);
  197. const view = _converse.chatboxviews.get('lounge@montague.lit');
  198. expect(view.el.querySelector('.chatbox-title__text .fa-bookmark')).toBe(null);
  199. _converse.bookmarks.create({
  200. 'jid': view.model.get('jid'),
  201. 'autojoin': false,
  202. 'name': 'The lounge',
  203. 'nick': ' some1'
  204. });
  205. view.model.set('bookmarked', true);
  206. expect(view.el.querySelector('.chatbox-title__text .fa-bookmark')).not.toBe(null);
  207. view.model.set('bookmarked', false);
  208. expect(view.el.querySelector('.chatbox-title__text .fa-bookmark')).toBe(null);
  209. done();
  210. }));
  211. it("can be unbookmarked", mock.initConverse(
  212. ['rosterGroupsFetched'], {}, async function (done, _converse) {
  213. await test_utils.waitUntilBookmarksReturned(_converse);
  214. const muc_jid = 'theplay@conference.shakespeare.lit';
  215. await _converse.api.rooms.open(muc_jid);
  216. const view = _converse.chatboxviews.get(muc_jid);
  217. await u.waitUntil(() => view.el.querySelector('.toggle-bookmark'));
  218. spyOn(view, 'toggleBookmark').and.callThrough();
  219. spyOn(_converse.bookmarks, 'sendBookmarkStanza').and.callThrough();
  220. view.delegateEvents();
  221. _converse.bookmarks.create({
  222. 'jid': view.model.get('jid'),
  223. 'autojoin': false,
  224. 'name': 'The Play',
  225. 'nick': ' Othello'
  226. });
  227. expect(_converse.bookmarks.length).toBe(1);
  228. await u.waitUntil(() => _converse.chatboxes.length >= 1);
  229. expect(view.model.get('bookmarked')).toBeTruthy();
  230. expect(view.el.querySelector('.chatbox-title__text .fa-bookmark')).not.toBe(null);
  231. spyOn(_converse.connection, 'getUniqueId').and.callThrough();
  232. const bookmark_icon = view.el.querySelector('.toggle-bookmark');
  233. bookmark_icon.click();
  234. expect(view.toggleBookmark).toHaveBeenCalled();
  235. expect(view.el.querySelector('.chatbox-title__text .fa-bookmark')).toBe(null);
  236. expect(_converse.bookmarks.length).toBe(0);
  237. // Check that an IQ stanza is sent out, containing no
  238. // conferences to bookmark (since we removed the one and
  239. // only bookmark).
  240. const sent_stanza = _converse.connection.IQ_stanzas.pop();
  241. expect(Strophe.serialize(sent_stanza)).toBe(
  242. `<iq from="romeo@montague.lit/orchard" id="${sent_stanza.getAttribute('id')}" type="set" xmlns="jabber:client">`+
  243. `<pubsub xmlns="http://jabber.org/protocol/pubsub">`+
  244. `<publish node="storage:bookmarks">`+
  245. `<item id="current">`+
  246. `<storage xmlns="storage:bookmarks"/>`+
  247. `</item>`+
  248. `</publish>`+
  249. `<publish-options>`+
  250. `<x type="submit" xmlns="jabber:x:data">`+
  251. `<field type="hidden" var="FORM_TYPE">`+
  252. `<value>http://jabber.org/protocol/pubsub#publish-options</value>`+
  253. `</field>`+
  254. `<field var="pubsub#persist_items">`+
  255. `<value>true</value>`+
  256. `</field>`+
  257. `<field var="pubsub#access_model">`+
  258. `<value>whitelist</value>`+
  259. `</field>`+
  260. `</x>`+
  261. `</publish-options>`+
  262. `</pubsub>`+
  263. `</iq>`
  264. );
  265. done();
  266. }));
  267. });
  268. describe("and when autojoin is set", function () {
  269. it("will be be opened and joined automatically upon login", mock.initConverse(
  270. ['rosterGroupsFetched'], {},
  271. async function (done, _converse) {
  272. await test_utils.waitUntilBookmarksReturned(_converse);
  273. spyOn(_converse.api.rooms, 'create').and.callThrough();
  274. const jid = 'theplay@conference.shakespeare.lit';
  275. const model = _converse.bookmarks.create({
  276. 'jid': jid,
  277. 'autojoin': false,
  278. 'name': 'The Play',
  279. 'nick': ''
  280. });
  281. expect(_converse.api.rooms.create).not.toHaveBeenCalled();
  282. _converse.bookmarks.remove(model);
  283. _converse.bookmarks.create({
  284. 'jid': jid,
  285. 'autojoin': true,
  286. 'name': 'Hamlet',
  287. 'nick': ''
  288. });
  289. expect(_converse.api.rooms.create).toHaveBeenCalled();
  290. done();
  291. }));
  292. });
  293. });
  294. describe("Bookmarks", function () {
  295. it("can be pushed from the XMPP server", mock.initConverse(
  296. ['rosterGroupsFetched', 'connected'], {}, async function (done, _converse) {
  297. await test_utils.waitUntilBookmarksReturned(_converse);
  298. /* The stored data is automatically pushed to all of the user's
  299. * connected resources.
  300. *
  301. * Publisher receives event notification
  302. * -------------------------------------
  303. * <message from='juliet@capulet.lit'
  304. * to='juliet@capulet.lit/balcony'
  305. * type='headline'
  306. * id='rnfoo1'>
  307. * <event xmlns='http://jabber.org/protocol/pubsub#event'>
  308. * <items node='storage:bookmarks'>
  309. * <item id='current'>
  310. * <storage xmlns='storage:bookmarks'>
  311. * <conference name='The Play&apos;s the Thing'
  312. * autojoin='true'
  313. * jid='theplay@conference.shakespeare.lit'>
  314. * <nick>JC</nick>
  315. * </conference>
  316. * </storage>
  317. * </item>
  318. * </items>
  319. * </event>
  320. * </message>
  321. */
  322. const stanza = $msg({
  323. 'from': 'romeo@montague.lit',
  324. 'to': 'romeo@montague.lit/orchard',
  325. 'type': 'headline',
  326. 'id': 'rnfoo1'
  327. }).c('event', {'xmlns': 'http://jabber.org/protocol/pubsub#event'})
  328. .c('items', {'node': 'storage:bookmarks'})
  329. .c('item', {'id': 'current'})
  330. .c('storage', {'xmlns': 'storage:bookmarks'})
  331. .c('conference', {'name': 'The Play&apos;s the Thing',
  332. 'autojoin': 'true',
  333. 'jid':'theplay@conference.shakespeare.lit'})
  334. .c('nick').t('JC');
  335. _converse.connection._dataRecv(test_utils.createRequest(stanza));
  336. await u.waitUntil(() => _converse.bookmarks.length);
  337. expect(_converse.bookmarks.length).toBe(1);
  338. expect(_converse.chatboxviews.get('theplay@conference.shakespeare.lit')).not.toBeUndefined();
  339. done();
  340. }));
  341. it("can be retrieved from the XMPP server", mock.initConverse(
  342. ['chatBoxesFetched', 'roomsPanelRendered', 'rosterGroupsFetched'], {},
  343. async function (done, _converse) {
  344. await test_utils.waitUntilDiscoConfirmed(
  345. _converse, _converse.bare_jid,
  346. [{'category': 'pubsub', 'type': 'pep'}],
  347. ['http://jabber.org/protocol/pubsub#publish-options']
  348. );
  349. /* Client requests all items
  350. * -------------------------
  351. *
  352. * <iq from='juliet@capulet.lit/randomID' type='get' id='retrieve1'>
  353. * <pubsub xmlns='http://jabber.org/protocol/pubsub'>
  354. * <items node='storage:bookmarks'/>
  355. * </pubsub>
  356. * </iq>
  357. */
  358. const IQ_stanzas = _converse.connection.IQ_stanzas;
  359. const sent_stanza = await u.waitUntil(
  360. () => IQ_stanzas.filter(s => sizzle('items[node="storage:bookmarks"]', s).length).pop());
  361. expect(Strophe.serialize(sent_stanza)).toBe(
  362. `<iq from="romeo@montague.lit/orchard" id="${sent_stanza.getAttribute('id')}" type="get" xmlns="jabber:client">`+
  363. '<pubsub xmlns="http://jabber.org/protocol/pubsub">'+
  364. '<items node="storage:bookmarks"/>'+
  365. '</pubsub>'+
  366. '</iq>');
  367. /*
  368. * Server returns all items
  369. * ------------------------
  370. * <iq type='result'
  371. * to='juliet@capulet.lit/randomID'
  372. * id='retrieve1'>
  373. * <pubsub xmlns='http://jabber.org/protocol/pubsub'>
  374. * <items node='storage:bookmarks'>
  375. * <item id='current'>
  376. * <storage xmlns='storage:bookmarks'>
  377. * <conference name='The Play&apos;s the Thing'
  378. * autojoin='true'
  379. * jid='theplay@conference.shakespeare.lit'>
  380. * <nick>JC</nick>
  381. * </conference>
  382. * </storage>
  383. * </item>
  384. * </items>
  385. * </pubsub>
  386. * </iq>
  387. */
  388. expect(_converse.bookmarks.models.length).toBe(0);
  389. spyOn(_converse.bookmarks, 'onBookmarksReceived').and.callThrough();
  390. var stanza = $iq({'to': _converse.connection.jid, 'type':'result', 'id':sent_stanza.getAttribute('id')})
  391. .c('pubsub', {'xmlns': Strophe.NS.PUBSUB})
  392. .c('items', {'node': 'storage:bookmarks'})
  393. .c('item', {'id': 'current'})
  394. .c('storage', {'xmlns': 'storage:bookmarks'})
  395. .c('conference', {
  396. 'name': 'The Play&apos;s the Thing',
  397. 'autojoin': 'true',
  398. 'jid': 'theplay@conference.shakespeare.lit'
  399. }).c('nick').t('JC').up().up()
  400. .c('conference', {
  401. 'name': 'Another room',
  402. 'autojoin': 'false',
  403. 'jid': 'another@conference.shakespeare.lit'
  404. }); // Purposefully exclude the <nick> element to test #1043
  405. _converse.connection._dataRecv(test_utils.createRequest(stanza));
  406. await u.waitUntil(() => _converse.bookmarks.onBookmarksReceived.calls.count());
  407. await _converse.api.waitUntil('bookmarksInitialized');
  408. expect(_converse.bookmarks.models.length).toBe(2);
  409. expect(_converse.bookmarks.findWhere({'jid': 'theplay@conference.shakespeare.lit'}).get('autojoin')).toBe(true);
  410. expect(_converse.bookmarks.findWhere({'jid': 'another@conference.shakespeare.lit'}).get('autojoin')).toBe(false);
  411. done();
  412. }));
  413. describe("The rooms panel", function () {
  414. it("shows a list of bookmarks", mock.initConverse(
  415. ['rosterGroupsFetched'], {},
  416. async function (done, _converse) {
  417. await test_utils.waitUntilDiscoConfirmed(
  418. _converse, _converse.bare_jid,
  419. [{'category': 'pubsub', 'type': 'pep'}],
  420. ['http://jabber.org/protocol/pubsub#publish-options']
  421. );
  422. test_utils.openControlBox(_converse);
  423. const IQ_stanzas = _converse.connection.IQ_stanzas;
  424. const sent_stanza = await u.waitUntil(
  425. () => IQ_stanzas.filter(s => sizzle('items[node="storage:bookmarks"]', s).length).pop());
  426. expect(Strophe.serialize(sent_stanza)).toBe(
  427. `<iq from="romeo@montague.lit/orchard" id="${sent_stanza.getAttribute('id')}" type="get" xmlns="jabber:client">`+
  428. '<pubsub xmlns="http://jabber.org/protocol/pubsub">'+
  429. '<items node="storage:bookmarks"/>'+
  430. '</pubsub>'+
  431. '</iq>'
  432. );
  433. const stanza = $iq({'to': _converse.connection.jid, 'type':'result', 'id':sent_stanza.getAttribute('id')})
  434. .c('pubsub', {'xmlns': Strophe.NS.PUBSUB})
  435. .c('items', {'node': 'storage:bookmarks'})
  436. .c('item', {'id': 'current'})
  437. .c('storage', {'xmlns': 'storage:bookmarks'})
  438. .c('conference', {
  439. 'name': 'The Play&apos;s the Thing',
  440. 'autojoin': 'false',
  441. 'jid': 'theplay@conference.shakespeare.lit'
  442. }).c('nick').t('JC').up().up()
  443. .c('conference', {
  444. 'name': '1st Bookmark',
  445. 'autojoin': 'false',
  446. 'jid': 'first@conference.shakespeare.lit'
  447. }).c('nick').t('JC').up().up()
  448. .c('conference', {
  449. 'autojoin': 'false',
  450. 'jid': 'noname@conference.shakespeare.lit'
  451. }).c('nick').t('JC').up().up()
  452. .c('conference', {
  453. 'name': 'Bookmark with a very very long name that will be shortened',
  454. 'autojoin': 'false',
  455. 'jid': 'longname@conference.shakespeare.lit'
  456. }).c('nick').t('JC').up().up()
  457. .c('conference', {
  458. 'name': 'Another room',
  459. 'autojoin': 'false',
  460. 'jid': 'another@conference.shakespeare.lit'
  461. }).c('nick').t('JC').up().up();
  462. _converse.connection._dataRecv(test_utils.createRequest(stanza));
  463. await u.waitUntil(() => document.querySelectorAll('#chatrooms div.bookmarks.rooms-list .room-item').length);
  464. expect(document.querySelectorAll('#chatrooms div.bookmarks.rooms-list .room-item').length).toBe(5);
  465. let els = document.querySelectorAll('#chatrooms div.bookmarks.rooms-list .room-item a.list-item-link');
  466. expect(els[0].textContent).toBe("1st Bookmark");
  467. expect(els[1].textContent).toBe("Another room");
  468. expect(els[2].textContent).toBe("Bookmark with a very very long name that will be shortened");
  469. expect(els[3].textContent).toBe("noname@conference.shakespeare.lit");
  470. expect(els[4].textContent).toBe("The Play's the Thing");
  471. spyOn(window, 'confirm').and.returnValue(true);
  472. document.querySelector('#chatrooms .bookmarks.rooms-list .room-item:nth-child(2) a:nth-child(2)').click();
  473. expect(window.confirm).toHaveBeenCalled();
  474. await u.waitUntil(() => document.querySelectorAll('#chatrooms div.bookmarks.rooms-list .room-item').length === 4)
  475. els = document.querySelectorAll('#chatrooms div.bookmarks.rooms-list .room-item a.list-item-link');
  476. expect(els[0].textContent).toBe("1st Bookmark");
  477. expect(els[1].textContent).toBe("Bookmark with a very very long name that will be shortened");
  478. expect(els[2].textContent).toBe("noname@conference.shakespeare.lit");
  479. expect(els[3].textContent).toBe("The Play's the Thing");
  480. done();
  481. }));
  482. it("remembers the toggle state of the bookmarks list", mock.initConverse(
  483. ['rosterGroupsFetched'], {}, async function (done, _converse) {
  484. await test_utils.openControlBox(_converse);
  485. await test_utils.waitUntilDiscoConfirmed(
  486. _converse, _converse.bare_jid,
  487. [{'category': 'pubsub', 'type': 'pep'}],
  488. ['http://jabber.org/protocol/pubsub#publish-options']
  489. );
  490. const IQ_stanzas = _converse.connection.IQ_stanzas;
  491. const sent_stanza = await u.waitUntil(
  492. () => IQ_stanzas.filter(s => sizzle('iq items[node="storage:bookmarks"]', s).length).pop());
  493. expect(Strophe.serialize(sent_stanza)).toBe(
  494. `<iq from="romeo@montague.lit/orchard" id="${sent_stanza.getAttribute('id')}" type="get" xmlns="jabber:client">`+
  495. '<pubsub xmlns="http://jabber.org/protocol/pubsub">'+
  496. '<items node="storage:bookmarks"/>'+
  497. '</pubsub>'+
  498. '</iq>'
  499. );
  500. const stanza = $iq({'to': _converse.connection.jid, 'type':'result', 'id': sent_stanza.getAttribute('id')})
  501. .c('pubsub', {'xmlns': Strophe.NS.PUBSUB})
  502. .c('items', {'node': 'storage:bookmarks'})
  503. .c('item', {'id': 'current'})
  504. .c('storage', {'xmlns': 'storage:bookmarks'});
  505. _converse.connection._dataRecv(test_utils.createRequest(stanza));
  506. await _converse.api.waitUntil('bookmarksInitialized');
  507. _converse.bookmarks.create({
  508. 'jid': 'theplay@conference.shakespeare.lit',
  509. 'autojoin': false,
  510. 'name': 'The Play',
  511. 'nick': ''
  512. });
  513. const el = _converse.chatboxviews.el
  514. const selector = '#chatrooms .bookmarks.rooms-list .room-item';
  515. await u.waitUntil(() => sizzle(selector, el).filter(u.isVisible).length);
  516. expect(u.hasClass('collapsed', sizzle('#chatrooms .bookmarks.rooms-list', el).pop())).toBeFalsy();
  517. expect(sizzle(selector, el).filter(u.isVisible).length).toBe(1);
  518. expect(_converse.bookmarksview.list_model.get('toggle-state')).toBe(_converse.OPENED);
  519. sizzle('#chatrooms .bookmarks-toggle', el).pop().click();
  520. expect(u.hasClass('collapsed', sizzle('#chatrooms .bookmarks.rooms-list', el).pop())).toBeTruthy();
  521. expect(_converse.bookmarksview.list_model.get('toggle-state')).toBe(_converse.CLOSED);
  522. sizzle('#chatrooms .bookmarks-toggle', el).pop().click();
  523. expect(u.hasClass('collapsed', sizzle('#chatrooms .bookmarks.rooms-list', el).pop())).toBeFalsy();
  524. expect(sizzle(selector, el).filter(u.isVisible).length).toBe(1);
  525. expect(_converse.bookmarksview.list_model.get('toggle-state')).toBe(_converse.OPENED);
  526. done();
  527. }));
  528. });
  529. });
  530. describe("When hide_open_bookmarks is true and a bookmarked room is opened", function () {
  531. it("can be closed", mock.initConverse(
  532. ['rosterGroupsFetched'],
  533. { hide_open_bookmarks: true },
  534. async function (done, _converse) {
  535. await test_utils.openControlBox(_converse);
  536. await test_utils.waitUntilBookmarksReturned(_converse);
  537. // Check that it's there
  538. const jid = 'room@conference.example.org';
  539. _converse.bookmarks.create({
  540. 'jid': jid,
  541. 'autojoin': false,
  542. 'name': 'The Play',
  543. 'nick': ' Othello'
  544. });
  545. expect(_converse.bookmarks.length).toBe(1);
  546. const bmarks_view = _converse.bookmarksview;
  547. await u.waitUntil(() => bmarks_view.el.querySelectorAll(".open-room").length, 500);
  548. const room_els = bmarks_view.el.querySelectorAll(".open-room");
  549. expect(room_els.length).toBe(1);
  550. const bookmark = _converse.bookmarksview.el.querySelector(".open-room");
  551. bookmark.click();
  552. await u.waitUntil(() => _converse.chatboxviews.get(jid));
  553. expect(u.hasClass('hidden', _converse.bookmarksview.el.querySelector(".available-chatroom"))).toBeTruthy();
  554. // Check that it reappears once the room is closed
  555. const view = _converse.chatboxviews.get(jid);
  556. view.close();
  557. await u.waitUntil(() => !u.hasClass('hidden', _converse.bookmarksview.el.querySelector(".available-chatroom")));
  558. done();
  559. }));
  560. });
  561. }));