converse.js 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338
  1. /*global converse */
  2. (function (root, factory) {
  3. define([
  4. "jquery",
  5. "underscore",
  6. "mock",
  7. "test_utils"
  8. ], function ($, _, mock, test_utils) {
  9. return factory($, _, mock, test_utils);
  10. }
  11. );
  12. } (this, function ($, _, mock, test_utils) {
  13. var b64_sha1 = converse_api.env.b64_sha1;
  14. return describe("Converse", $.proxy(function(mock, test_utils) {
  15. describe("Authentication", function () {
  16. it("needs either a bosh_service_url a websocket_url or both", function () {
  17. var url = converse.bosh_service_url;
  18. var connection = converse.connection;
  19. delete converse.bosh_service_url;
  20. delete converse.connection;
  21. expect(converse.initConnection.bind({})).toThrow(
  22. new Error("initConnection: you must supply a value for either the bosh_service_url or websocket_url or both."));
  23. converse.bosh_service_url = url;
  24. converse.connection = connection;
  25. });
  26. describe("with prebind", function () {
  27. it("needs a jid when also using keepalive", function () {
  28. var authentication = converse.authentication;
  29. var jid = converse.jid;
  30. delete converse.jid;
  31. converse.keepalive = true;
  32. converse.authentication = "prebind";
  33. expect(converse.logIn.bind(converse)).toThrow(
  34. new Error("attemptPreboundSession: when using 'keepalive' with 'prebind, you must supply the JID of the current user."));
  35. converse.authentication= authentication;
  36. converse.jid = jid;
  37. converse.keepalive = false;
  38. });
  39. it("needs jid, rid and sid values when not using keepalive", function () {
  40. var authentication = converse.authentication;
  41. var jid = converse.jid;
  42. delete converse.jid;
  43. converse.authentication = "prebind";
  44. expect(converse.logIn.bind(converse)).toThrow(
  45. new Error("attemptPreboundSession: If you use prebind and not keepalive, then you MUST supply JID, RID and SID values"));
  46. converse.authentication= authentication;
  47. converse.bosh_service_url = undefined;
  48. converse.jid = jid;
  49. });
  50. });
  51. });
  52. describe("A chat state indication", function () {
  53. it("are sent out when the client becomes or stops being idle", function () {
  54. spyOn(converse, 'sendCSI').andCallThrough();
  55. var sent_stanza;
  56. spyOn(converse.connection, 'send').andCallFake(function (stanza) {
  57. sent_stanza = stanza;
  58. });
  59. var i = 0;
  60. converse.idle_seconds = 0; // Usually initialized by registerIntervalHandler
  61. converse.features['urn:xmpp:csi:0'] = true; // Mock that the server supports CSI
  62. converse.csi_waiting_time = 3; // The relevant config option
  63. while (i <= converse.csi_waiting_time) {
  64. expect(converse.sendCSI).not.toHaveBeenCalled();
  65. converse.onEverySecond();
  66. i++;
  67. }
  68. expect(converse.sendCSI).toHaveBeenCalledWith('inactive');
  69. expect(sent_stanza.toLocaleString()).toBe(
  70. "<inactive xmlns='urn:xmpp:csi:0'/>"
  71. );
  72. converse.onUserActivity();
  73. expect(converse.sendCSI).toHaveBeenCalledWith('active');
  74. expect(sent_stanza.toLocaleString()).toBe(
  75. "<active xmlns='urn:xmpp:csi:0'/>"
  76. );
  77. // Reset values
  78. converse.csi_waiting_time = 0;
  79. converse.features['urn:xmpp:csi:0'] = false;
  80. });
  81. });
  82. describe("Automatic status change", function () {
  83. it("happens when the client is idle for long enough", function () {
  84. var i = 0;
  85. // Usually initialized by registerIntervalHandler
  86. converse.idle_seconds = 0;
  87. converse.auto_changed_status = false;
  88. // The relevant config options
  89. converse.auto_away = 3;
  90. converse.auto_xa = 6;
  91. expect(converse.xmppstatus.getStatus()).toBe('online');
  92. while (i <= converse.auto_away) {
  93. converse.onEverySecond();
  94. i++;
  95. }
  96. expect(converse.auto_changed_status).toBe(true);
  97. while (i <= converse.auto_xa) {
  98. expect(converse.xmppstatus.getStatus()).toBe('away');
  99. converse.onEverySecond();
  100. i++;
  101. }
  102. expect(converse.xmppstatus.getStatus()).toBe('xa');
  103. expect(converse.auto_changed_status).toBe(true);
  104. converse.onUserActivity();
  105. expect(converse.xmppstatus.getStatus()).toBe('online');
  106. expect(converse.auto_changed_status).toBe(false);
  107. // Reset values
  108. converse.auto_away = 0;
  109. converse.auto_xa = 0;
  110. converse.auto_changed_status = false;
  111. });
  112. });
  113. describe("The \"user\" grouping", function () {
  114. describe("The \"status\" API", function () {
  115. beforeEach(function () {
  116. test_utils.closeAllChatBoxes();
  117. test_utils.clearBrowserStorage();
  118. converse.rosterview.model.reset();
  119. });
  120. it("has a method for getting the user's availability", function () {
  121. converse.xmppstatus.set('status', 'online');
  122. expect(converse_api.user.status.get()).toBe('online');
  123. converse.xmppstatus.set('status', 'dnd');
  124. expect(converse_api.user.status.get()).toBe('dnd');
  125. });
  126. it("has a method for setting the user's availability", function () {
  127. converse_api.user.status.set('away');
  128. expect(converse.xmppstatus.get('status')).toBe('away');
  129. converse_api.user.status.set('dnd');
  130. expect(converse.xmppstatus.get('status')).toBe('dnd');
  131. converse_api.user.status.set('xa');
  132. expect(converse.xmppstatus.get('status')).toBe('xa');
  133. converse_api.user.status.set('chat');
  134. expect(converse.xmppstatus.get('status')).toBe('chat');
  135. expect(_.partial(converse_api.user.status.set, 'invalid')).toThrow(
  136. new Error('Invalid availability value. See https://xmpp.org/rfcs/rfc3921.html#rfc.section.2.2.2.1')
  137. );
  138. });
  139. it("allows setting the status message as well", function () {
  140. converse_api.user.status.set('away', "I'm in a meeting");
  141. expect(converse.xmppstatus.get('status')).toBe('away');
  142. expect(converse.xmppstatus.get('status_message')).toBe("I'm in a meeting");
  143. });
  144. it("has a method for getting the user's status message", function () {
  145. converse.xmppstatus.set('status_message', undefined);
  146. expect(converse_api.user.status.message.get()).toBe(undefined);
  147. converse.xmppstatus.set('status_message', "I'm in a meeting");
  148. expect(converse_api.user.status.message.get()).toBe("I'm in a meeting");
  149. });
  150. it("has a method for setting the user's status message", function () {
  151. converse.xmppstatus.set('status_message', undefined);
  152. converse_api.user.status.message.set("I'm in a meeting");
  153. expect(converse.xmppstatus.get('status_message')).toBe("I'm in a meeting");
  154. });
  155. });
  156. });
  157. describe("The \"tokens\" API", $.proxy(function () {
  158. beforeEach(function () {
  159. test_utils.closeAllChatBoxes();
  160. test_utils.clearBrowserStorage();
  161. converse.rosterview.model.reset();
  162. test_utils.createContacts('current');
  163. });
  164. it("has a method for retrieving the next RID", $.proxy(function () {
  165. var old_connection = converse.connection;
  166. converse.connection._proto.rid = '1234';
  167. converse.expose_rid_and_sid = false;
  168. expect(converse_api.tokens.get('rid')).toBe(null);
  169. converse.expose_rid_and_sid = true;
  170. expect(converse_api.tokens.get('rid')).toBe('1234');
  171. converse.connection = undefined;
  172. expect(converse_api.tokens.get('rid')).toBe(null);
  173. // Restore the connection
  174. converse.connection = old_connection;
  175. }, converse));
  176. it("has a method for retrieving the SID", $.proxy(function () {
  177. var old_connection = converse.connection;
  178. converse.connection._proto.sid = '1234';
  179. converse.expose_rid_and_sid = false;
  180. expect(converse_api.tokens.get('sid')).toBe(null);
  181. converse.expose_rid_and_sid = true;
  182. expect(converse_api.tokens.get('sid')).toBe('1234');
  183. converse.connection = undefined;
  184. expect(converse_api.tokens.get('sid')).toBe(null);
  185. // Restore the connection
  186. converse.connection = old_connection;
  187. }, converse));
  188. }, converse));
  189. describe("The \"contacts\" API", $.proxy(function () {
  190. beforeEach($.proxy(function () {
  191. test_utils.closeAllChatBoxes();
  192. test_utils.clearBrowserStorage();
  193. converse.rosterview.model.reset();
  194. test_utils.createContacts('current');
  195. }, converse));
  196. it("has a method 'get' which returns wrapped contacts", $.proxy(function () {
  197. // Check that it returns nothing if a non-existing JID is given
  198. expect(converse_api.contacts.get('non-existing@jabber.org')).toBeFalsy();
  199. // Check when a single jid is given
  200. var jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@localhost';
  201. var attrs = converse_api.contacts.get(jid);
  202. expect(typeof attrs).toBe('object');
  203. expect(attrs.fullname).toBe(mock.cur_names[0]);
  204. expect(attrs.jid).toBe(jid);
  205. // You can retrieve multiple contacts by passing in an array
  206. var jid2 = mock.cur_names[1].replace(/ /g,'.').toLowerCase() + '@localhost';
  207. var list = converse_api.contacts.get([jid, jid2]);
  208. expect(Array.isArray(list)).toBeTruthy();
  209. expect(list[0].fullname).toBe(mock.cur_names[0]);
  210. expect(list[1].fullname).toBe(mock.cur_names[1]);
  211. // Check that all JIDs are returned if you call without any parameters
  212. list = converse_api.contacts.get();
  213. expect(list.length).toBe(mock.cur_names.length);
  214. }, converse));
  215. it("has a method 'add' with which contacts can be added", $.proxy(function () {
  216. var error = new TypeError('contacts.add: invalid jid');
  217. expect(converse_api.contacts.add).toThrow(error);
  218. expect(converse_api.contacts.add.bind(converse_api, "invalid jid")).toThrow(error);
  219. spyOn(converse.roster, 'addAndSubscribe');
  220. converse_api.contacts.add("newcontact@example.org");
  221. expect(converse.roster.addAndSubscribe).toHaveBeenCalled();
  222. }, converse));
  223. }, converse));
  224. describe("The \"chats\" API", $.proxy(function() {
  225. beforeEach($.proxy(function () {
  226. test_utils.closeAllChatBoxes();
  227. test_utils.clearBrowserStorage();
  228. converse.rosterview.model.reset();
  229. test_utils.createContacts('current');
  230. }, converse));
  231. it("has a method 'get' which returns a wrapped chat box", function () {
  232. // Test on chat that doesn't exist.
  233. expect(converse_api.chats.get('non-existing@jabber.org')).toBeFalsy();
  234. var jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@localhost';
  235. // Test on chat that's not open
  236. var box = converse_api.chats.get(jid);
  237. expect(box instanceof Object).toBeTruthy();
  238. var chatboxview = converse.chatboxviews.get(jid);
  239. expect(chatboxview.$el.is(':visible')).toBeFalsy();
  240. // Test for single JID
  241. test_utils.openChatBoxFor(jid);
  242. box = converse_api.chats.get(jid);
  243. expect(box instanceof Object).toBeTruthy();
  244. expect(box.get('box_id')).toBe(b64_sha1(jid));
  245. chatboxview = converse.chatboxviews.get(jid);
  246. expect(chatboxview.$el.is(':visible')).toBeTruthy();
  247. // Test for multiple JIDs
  248. var jid2 = mock.cur_names[1].replace(/ /g,'.').toLowerCase() + '@localhost';
  249. test_utils.openChatBoxFor(jid2);
  250. var list = converse_api.chats.get([jid, jid2]);
  251. expect(Array.isArray(list)).toBeTruthy();
  252. expect(list[0].get('box_id')).toBe(b64_sha1(jid));
  253. expect(list[1].get('box_id')).toBe(b64_sha1(jid2));
  254. });
  255. it("has a method 'open' which opens and returns a wrapped chat box", function () {
  256. var jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@localhost';
  257. var chatboxview;
  258. waits('300'); // ChatBox.show() is debounced for 250ms
  259. runs(function () {
  260. // Test on chat that doesn't exist.
  261. expect(converse_api.chats.get('non-existing@jabber.org')).toBeFalsy();
  262. var box = converse_api.chats.open(jid);
  263. expect(box instanceof Object).toBeTruthy();
  264. expect(box.get('box_id')).toBe(b64_sha1(jid));
  265. expect(
  266. Object.keys(box),
  267. ['close', 'endOTR', 'focus', 'get', 'initiateOTR', 'is_chatroom', 'maximize', 'minimize', 'open', 'set']
  268. );
  269. chatboxview = converse.chatboxviews.get(jid);
  270. expect(chatboxview.$el.is(':visible')).toBeTruthy();
  271. // Test for multiple JIDs
  272. var jid2 = mock.cur_names[1].replace(/ /g,'.').toLowerCase() + '@localhost';
  273. var list = converse_api.chats.open([jid, jid2]);
  274. expect(Array.isArray(list)).toBeTruthy();
  275. expect(list[0].get('box_id')).toBe(b64_sha1(jid));
  276. expect(list[1].get('box_id')).toBe(b64_sha1(jid2));
  277. });
  278. });
  279. }, converse));
  280. describe("The \"settings\" API", $.proxy(function() {
  281. beforeEach($.proxy(function () {
  282. test_utils.closeAllChatBoxes();
  283. test_utils.clearBrowserStorage();
  284. converse.rosterview.model.reset();
  285. test_utils.createContacts('current');
  286. }, converse));
  287. it("has methods 'get' and 'set' to set configuration settings", $.proxy(function () {
  288. expect(Object.keys(converse_api.settings)).toEqual(["get", "set"]);
  289. expect(converse_api.settings.get("play_sounds")).toBe(false);
  290. converse_api.settings.set("play_sounds", true);
  291. expect(converse_api.settings.get("play_sounds")).toBe(true);
  292. converse_api.settings.set({"play_sounds": false});
  293. expect(converse_api.settings.get("play_sounds")).toBe(false);
  294. // Only whitelisted settings allowed.
  295. expect(typeof converse_api.settings.get("non_existing")).toBe("undefined");
  296. converse_api.settings.set("non_existing", true);
  297. expect(typeof converse_api.settings.get("non_existing")).toBe("undefined");
  298. }, converse));
  299. }, converse));
  300. }, converse, mock, test_utils));
  301. }));