MainSpec.js 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406
  1. (function (root, factory) {
  2. define([
  3. "converse"
  4. ], function (xmppchat) {
  5. return factory(xmppchat);
  6. }
  7. );
  8. } (this, function (xmppchat) {
  9. return describe("Converse.js", $.proxy(function() {
  10. // Names from http://www.fakenamegenerator.com/
  11. var req_names = [
  12. 'Louw Spekman', 'Mohamad Stet', 'Dominik Beyer', 'Dirk Eichel', 'Marco Duerr', 'Ute Schiffer',
  13. 'Billie Westerhuis', 'Sarah Kuester', 'Sabrina Loewe', 'Laura Duerr', 'Mathias Meyer',
  14. 'Tijm Keller', 'Lea Gerste', 'Martin Pfeffer', 'Ulrike Abt', 'Zoubida van Rooij',
  15. 'Maylin Hettema', 'Ruwan Bechan', 'Marco Beich', 'Karin Busch', 'Mathias Müller'
  16. ];
  17. var pend_names = [
  18. 'Suleyman van Beusichem', 'Nicole Diederich', 'Nanja van Yperen', 'Delany Bloemendaal',
  19. 'Jannah Hofmeester', 'Christine Trommler', 'Martin Bumgarner', 'Emil Baeten', 'Farshad Brasser',
  20. 'Gabriele Fisher', 'Sofiane Schopman', 'Sky Wismans', 'Jeffery Stoelwinder', 'Ganesh Waaijenberg',
  21. 'Dani Boldewijn', 'Katrin Propst', 'Martina Kaiser', 'Philipp Kappel', 'Meeke Grootendorst'
  22. ];
  23. var cur_names = [
  24. 'Max Frankfurter', 'Candice van der Knijff', 'Irini Vlastuin', 'Rinse Sommer', 'Annegreet Gomez',
  25. 'Robin Schook', 'Marcel Eberhardt', 'Simone Brauer', 'Asmaa Haakman', 'Felix Amsel',
  26. 'Lena Grunewald', 'Laura Grunewald', 'Mandy Seiler', 'Sven Bosch', 'Nuriye Cuypers', 'Ben Zomer',
  27. 'Leah Weiss', 'Francesca Disseldorp', 'Sven Bumgarner', 'Benjamin Zweig'
  28. ];
  29. this.bare_jid = 'dummy@localhost';
  30. mock_connection = {
  31. 'muc': {
  32. 'listRooms': function () {}
  33. },
  34. 'jid': this.bare_jid,
  35. 'addHandler': function (handler, ns, name, type, id, from, options) {
  36. return function () {};
  37. },
  38. 'roster': {
  39. 'registerCallback': function () {},
  40. 'get': function () {}
  41. }
  42. };
  43. // Clear localStorage
  44. window.localStorage.removeItem(
  45. hex_sha1('converse.rosteritems-'+this.bare_jid));
  46. window.localStorage.removeItem(
  47. hex_sha1('converse.chatboxes-'+this.bare_jid));
  48. window.localStorage.removeItem(
  49. hex_sha1('converse.xmppstatus-'+this.bare_jid));
  50. this.prebind = true;
  51. this.onConnected(mock_connection);
  52. this.animate = false; // don't use animations
  53. // The timeout is used to slow down the tests so that one can see
  54. // visually what is happening in the page.
  55. var timeout = 0;
  56. var sleep = function (delay) {
  57. // Yes this is blocking and stupid, but these are tests and this is
  58. // the easiest way to delay execution without having to use
  59. // callbacks.
  60. var start = new Date().getTime();
  61. while (new Date().getTime() < start + delay) {
  62. continue;
  63. }
  64. };
  65. describe("The Contacts Roster", $.proxy(function () {
  66. it("is not shown by default", $.proxy(function () {
  67. expect(this.rosterview.$el.is(':visible')).toEqual(false);
  68. }, xmppchat));
  69. it("can be opened by clicking a DOM element with id 'toggle-online-users'", $.proxy(function () {
  70. spyOn(this, 'toggleControlBox').andCallThrough();
  71. $('#toggle-online-users').click();
  72. expect(this.toggleControlBox).toHaveBeenCalled();
  73. }, xmppchat));
  74. describe("Pending Contacts", $.proxy(function () {
  75. it("do not have a heading if there aren't any", $.proxy(function () {
  76. expect(this.rosterview.$el.find('dt#pending-xmpp-contacts').css('display')).toEqual('none');
  77. }, xmppchat));
  78. it("can be added to the roster and they will be sorted alphabetically", $.proxy(function () {
  79. var i, t, is_last;
  80. spyOn(this.rosterview, 'render').andCallThrough();
  81. for (i=0; i<pend_names.length; i++) {
  82. is_last = i==(pend_names.length-1);
  83. this.roster.create({
  84. jid: pend_names[i].replace(' ','.').toLowerCase() + '@localhost',
  85. subscription: 'none',
  86. ask: 'subscribe',
  87. fullname: pend_names[i],
  88. is_last: is_last
  89. });
  90. // For performance reasons, the roster should only be shown once
  91. // the last contact has been added.
  92. if (is_last) {
  93. expect(this.rosterview.$el.is(':visible')).toEqual(true);
  94. } else {
  95. expect(this.rosterview.$el.is(':visible')).toEqual(false);
  96. }
  97. expect(this.rosterview.render).toHaveBeenCalled();
  98. // Check that they are sorted alphabetically
  99. t = this.rosterview.$el.find('dt#pending-xmpp-contacts').siblings('dd.pending-xmpp-contact').text();
  100. expect(t).toEqual(pend_names.slice(0,i+1).sort().join(''));
  101. }
  102. sleep(timeout);
  103. }, xmppchat));
  104. it("will have their own heading once they have been added", $.proxy(function () {
  105. expect(this.rosterview.$el.find('dt#pending-xmpp-contacts').css('display')).toEqual('block');
  106. }, xmppchat));
  107. }, xmppchat));
  108. describe("Existing Contacts", $.proxy(function () {
  109. it("do not have a heading if there aren't any", $.proxy(function () {
  110. expect(this.rosterview.$el.find('dt#xmpp-contacts').css('display')).toEqual('none');
  111. }, xmppchat));
  112. it("can be added to the roster and they will be sorted alphabetically", $.proxy(function () {
  113. var i, t;
  114. spyOn(this.rosterview, 'render').andCallThrough();
  115. for (i=0; i<cur_names.length; i++) {
  116. this.roster.create({
  117. jid: cur_names[i].replace(' ','.').toLowerCase() + '@localhost',
  118. subscription: 'both',
  119. ask: null,
  120. fullname: cur_names[i],
  121. is_last: i==(cur_names.length-1)
  122. });
  123. expect(this.rosterview.render).toHaveBeenCalled();
  124. // Check that they are sorted alphabetically
  125. t = this.rosterview.$el.find('dt#xmpp-contacts').siblings('dd.current-xmpp-contact.offline').find('a.open-chat').text();
  126. expect(t).toEqual(cur_names.slice(0,i+1).sort().join(''));
  127. }
  128. sleep(timeout);
  129. }, xmppchat));
  130. it("will have their own heading once they have been added", $.proxy(function () {
  131. expect(this.rosterview.$el.find('dt#xmpp-contacts').css('display')).toEqual('block');
  132. }, xmppchat));
  133. it("can change their status to online and be sorted alphabetically", $.proxy(function () {
  134. var item, view, jid, t;
  135. spyOn(this.rosterview, 'render').andCallThrough();
  136. for (i=0; i<5; i++) {
  137. jid = cur_names[i].replace(' ','.').toLowerCase() + '@localhost';
  138. view = this.rosterview.rosteritemviews[jid];
  139. spyOn(view, 'render').andCallThrough();
  140. item = view.model;
  141. item.set('chat_status', 'online');
  142. expect(view.render).toHaveBeenCalled();
  143. expect(this.rosterview.render).toHaveBeenCalled();
  144. // Check that they are sorted alphabetically
  145. t = this.rosterview.$el.find('dt#xmpp-contacts').siblings('dd.current-xmpp-contact.online').find('a.open-chat').text();
  146. expect(t).toEqual(cur_names.slice(0,i+1).sort().join(''));
  147. sleep(timeout);
  148. }
  149. }, xmppchat));
  150. it("can change their status to busy and be sorted alphabetically", $.proxy(function () {
  151. var item, view, jid, t;
  152. spyOn(this.rosterview, 'render').andCallThrough();
  153. for (i=5; i<10; i++) {
  154. jid = cur_names[i].replace(' ','.').toLowerCase() + '@localhost';
  155. view = this.rosterview.rosteritemviews[jid];
  156. spyOn(view, 'render').andCallThrough();
  157. item = view.model;
  158. item.set('chat_status', 'dnd');
  159. expect(view.render).toHaveBeenCalled();
  160. expect(this.rosterview.render).toHaveBeenCalled();
  161. // Check that they are sorted alphabetically
  162. t = this.rosterview.$el.find('dt#xmpp-contacts').siblings('dd.current-xmpp-contact.dnd').find('a.open-chat').text();
  163. expect(t).toEqual(cur_names.slice(5,i+1).sort().join(''));
  164. sleep(timeout);
  165. }
  166. }, xmppchat));
  167. it("can change their status to away and be sorted alphabetically", $.proxy(function () {
  168. var item, view, jid, t;
  169. spyOn(this.rosterview, 'render').andCallThrough();
  170. for (i=10; i<15; i++) {
  171. jid = cur_names[i].replace(' ','.').toLowerCase() + '@localhost';
  172. view = this.rosterview.rosteritemviews[jid];
  173. spyOn(view, 'render').andCallThrough();
  174. item = view.model;
  175. item.set('chat_status', 'away');
  176. expect(view.render).toHaveBeenCalled();
  177. expect(this.rosterview.render).toHaveBeenCalled();
  178. // Check that they are sorted alphabetically
  179. t = this.rosterview.$el.find('dt#xmpp-contacts').siblings('dd.current-xmpp-contact.away').find('a.open-chat').text();
  180. expect(t).toEqual(cur_names.slice(10,i+1).sort().join(''));
  181. sleep(timeout);
  182. }
  183. }, xmppchat));
  184. it("can change their status to unavailable and be sorted alphabetically", $.proxy(function () {
  185. var item, view, jid, t;
  186. spyOn(this.rosterview, 'render').andCallThrough();
  187. for (i=15; i<20; i++) {
  188. jid = cur_names[i].replace(' ','.').toLowerCase() + '@localhost';
  189. view = this.rosterview.rosteritemviews[jid];
  190. spyOn(view, 'render').andCallThrough();
  191. item = view.model;
  192. item.set('chat_status', 'unavailable');
  193. expect(view.render).toHaveBeenCalled();
  194. expect(this.rosterview.render).toHaveBeenCalled();
  195. // Check that they are sorted alphabetically
  196. t = this.rosterview.$el.find('dt#xmpp-contacts').siblings('dd.current-xmpp-contact.unavailable').find('a.open-chat').text();
  197. expect(t).toEqual(cur_names.slice(15, i+1).sort().join(''));
  198. sleep(timeout);
  199. }
  200. }, xmppchat));
  201. it("are ordered according to status: online, busy, away, unavailable, offline", $.proxy(function () {
  202. var contacts = this.rosterview.$el.find('dd.current-xmpp-contact');
  203. var i;
  204. // The first five contacts are online.
  205. for (i=0; i<5; i++) {
  206. expect($(contacts[i]).attr('class').split(' ',1)[0]).toEqual('online');
  207. }
  208. // The next five are busy
  209. for (i=5; i<10; i++) {
  210. expect($(contacts[i]).attr('class').split(' ',1)[0]).toEqual('dnd');
  211. }
  212. // The next five are away
  213. for (i=10; i<15; i++) {
  214. expect($(contacts[i]).attr('class').split(' ',1)[0]).toEqual('away');
  215. }
  216. // The next five are unavailable
  217. for (i=15; i<20; i++) {
  218. expect($(contacts[i]).attr('class').split(' ',1)[0]).toEqual('unavailable');
  219. }
  220. // The next 20 are offline
  221. for (i=20; i<cur_names.length; i++) {
  222. expect($(contacts[i]).attr('class').split(' ',1)[0]).toEqual('offline');
  223. }
  224. }, xmppchat));
  225. }, xmppchat));
  226. describe("Requesting Contacts", $.proxy(function () {
  227. // by default the dts are hidden from css class and only later they will be hidden
  228. // by jQuery therefore for the first check we will see if visible instead of none
  229. it("do not have a heading if there aren't any", $.proxy(function () {
  230. expect(this.rosterview.$el.find('dt#xmpp-contact-requests').is(':visible')).toEqual(false);
  231. }, xmppchat));
  232. it("can be added to the roster and they will be sorted alphabetically", $.proxy(function () {
  233. var i, t;
  234. spyOn(this.rosterview, 'render').andCallThrough();
  235. spyOn(this, 'showControlBox').andCallThrough();
  236. for (i=0; i<req_names.length; i++) {
  237. this.roster.create({
  238. jid: req_names[i].replace(' ','.').toLowerCase() + '@localhost',
  239. subscription: 'none',
  240. ask: 'request',
  241. fullname: req_names[i],
  242. is_last: i==(req_names.length-1)
  243. });
  244. expect(this.rosterview.render).toHaveBeenCalled();
  245. // Check that they are sorted alphabetically
  246. t = this.rosterview.$el.find('dt#xmpp-contact-requests').siblings('dd.requesting-xmpp-contact').text().replace(/AcceptDecline/g, '');
  247. expect(t).toEqual(req_names.slice(0,i+1).sort().join(''));
  248. // When a requesting contact is added, the controlbox must
  249. // be opened.
  250. expect(this.showControlBox).toHaveBeenCalled();
  251. }
  252. sleep(timeout);
  253. }, xmppchat));
  254. it("will have their own heading once they have been added", $.proxy(function () {
  255. expect(this.rosterview.$el.find('dt#xmpp-contact-requests').css('display')).toEqual('block');
  256. }, xmppchat));
  257. it("can have their requests accepted by the user", $.proxy(function () {
  258. // TODO Simulate and test clicking of accept/deny
  259. }, xmppchat));
  260. it("can have their requests denied by the user", $.proxy(function () {
  261. // TODO Simulate and test clicking of accept/deny
  262. }, xmppchat));
  263. }, xmppchat));
  264. describe("All Contacts", $.proxy(function () {
  265. it("are saved to, and can be retrieved from, localStorage", $.proxy(function () {
  266. var new_attrs, old_attrs, attrs, old_roster;
  267. expect(this.roster.length).toEqual(60);
  268. old_roster = this.roster;
  269. this.roster = new this.RosterItems();
  270. expect(this.roster.length).toEqual(0);
  271. this.roster.localStorage = new Backbone.LocalStorage(
  272. hex_sha1('converse.rosteritems-dummy@localhost'));
  273. this.chatboxes.onConnected();
  274. spyOn(this.roster, 'fetch').andCallThrough();
  275. this.rosterview = new this.RosterView({'model':this.roster});
  276. expect(this.roster.fetch).toHaveBeenCalled();
  277. expect(this.roster.length).toEqual(60);
  278. // Check that the roster items retrieved from localStorage
  279. // have the same attributes values as the original ones.
  280. attrs = ['jid', 'fullname', 'subscription', 'ask'];
  281. for (i=0; i<attrs.length; i++) {
  282. new_attrs = _.pluck(_.pluck(this.roster.models, 'attributes'), attrs[i]);
  283. old_attrs = _.pluck(_.pluck(old_roster.models, 'attributes'), attrs[i]);
  284. // Roster items in storage are not necessarily sorted,
  285. // so we have to sort them here to do a proper
  286. // comparison
  287. expect(_.isEqual(new_attrs.sort(), old_attrs.sort())).toEqual(true);
  288. }
  289. this.rosterview.render();
  290. }, xmppchat));
  291. afterEach($.proxy(function () {
  292. // Contacts retrieved from localStorage have chat_status of
  293. // "offline".
  294. // In the next test suite, we need some online contacts, so
  295. // we make some online now
  296. for (i=0; i<5; i++) {
  297. jid = cur_names[i].replace(' ','.').toLowerCase() + '@localhost';
  298. view = this.rosterview.rosteritemviews[jid];
  299. view.model.set('chat_status', 'online');
  300. }
  301. }, xmppchat));
  302. }, xmppchat));
  303. }, xmppchat));
  304. describe("Chatboxes", $.proxy(function () {
  305. it("are created when you click on a roster item", $.proxy(function () {
  306. var i, $el, click, jid, view;
  307. // showControlBox was called earlier, so the controlbox is
  308. // visible, but no other chat boxes have been created.
  309. expect(this.chatboxes.length).toEqual(1);
  310. var online_contacts = this.rosterview.$el.find('dt#xmpp-contacts').siblings('dd.current-xmpp-contact.online').find('a.open-chat');
  311. for (i=0; i<online_contacts.length; i++) {
  312. $el = $(online_contacts[i]);
  313. jid = $el.text().replace(' ','.').toLowerCase() + '@localhost';
  314. view = this.rosterview.rosteritemviews[jid];
  315. spyOn(view, 'openChat').andCallThrough();
  316. view.delegateEvents(); // We need to rebind all events otherwise our spy won't be called
  317. $el.click();
  318. expect(view.openChat).toHaveBeenCalled();
  319. expect(this.chatboxes.length).toEqual(i+2);
  320. sleep(timeout);
  321. }
  322. }, xmppchat));
  323. it("can be saved to, and retrieved from, localStorage", $.proxy(function () {
  324. var old_chatboxes = this.chatboxes;
  325. expect(this.chatboxes.length).toEqual(6);
  326. this.chatboxes = new this.ChatBoxes();
  327. expect(this.chatboxes.length).toEqual(0);
  328. this.chatboxes.onConnected();
  329. expect(this.chatboxes.length).toEqual(6);
  330. // Check that the roster items retrieved from localStorage
  331. // have the same attributes values as the original ones.
  332. attrs = ['id', 'box_id', 'visible'];
  333. for (i=0; i<attrs.length; i++) {
  334. new_attrs = _.pluck(_.pluck(this.chatboxes.models, 'attributes'), attrs[i]);
  335. old_attrs = _.pluck(_.pluck(old_chatboxes.models, 'attributes'), attrs[i]);
  336. expect(_.isEqual(new_attrs, old_attrs)).toEqual(true);
  337. }
  338. this.rosterview.render();
  339. }, xmppchat));
  340. it("can be closed again", $.proxy(function () {
  341. var chatbox, view, $el;
  342. for (i=0; i<this.chatboxes.length; i++) {
  343. chatbox = this.chatboxes.models[i];
  344. view = this.chatboxesview.views[chatbox.get('id')];
  345. spyOn(view, 'closeChat').andCallThrough();
  346. view.delegateEvents(); // We need to rebind all events otherwise our spy won't be called
  347. view.$el.find('.close-chatbox-button').click();
  348. expect(view.closeChat).toHaveBeenCalled();
  349. sleep(timeout);
  350. }
  351. }, xmppchat));
  352. it("will be removed from localStorage when closed", $.proxy(function () {
  353. var old_chatboxes = this.chatboxes;
  354. expect(this.chatboxes.length).toEqual(6);
  355. this.chatboxes = new this.ChatBoxes();
  356. expect(this.chatboxes.length).toEqual(0);
  357. this.chatboxes.onConnected();
  358. expect(this.chatboxes.length).toEqual(0);
  359. }, xmppchat));
  360. }, xmppchat));
  361. }, xmppchat));
  362. }));