modtools.js 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504
  1. /*global mock, converse */
  2. const _ = converse.env._;
  3. const $iq = converse.env.$iq;
  4. const $pres = converse.env.$pres;
  5. const sizzle = converse.env.sizzle;
  6. const Strophe = converse.env.Strophe;
  7. const u = converse.env.utils;
  8. async function openModtools (_converse, view) {
  9. const textarea = view.el.querySelector('.chat-textarea');
  10. textarea.value = '/modtools';
  11. const enter = { 'target': textarea, 'preventDefault': function preventDefault () {}, 'keyCode': 13 };
  12. view.onKeyDown(enter);
  13. await u.waitUntil(() => view.showModeratorToolsModal.calls.count());
  14. const modal = _converse.api.modal.get('converse-modtools-modal');
  15. await u.waitUntil(() => u.isVisible(modal.el), 1000);
  16. return modal;
  17. }
  18. describe("The groupchat moderator tool", function () {
  19. it("allows you to set affiliations and roles",
  20. mock.initConverse(
  21. ['rosterGroupsFetched'], {},
  22. async function (done, _converse) {
  23. spyOn(_converse.ChatRoomView.prototype, 'showModeratorToolsModal').and.callThrough();
  24. const muc_jid = 'lounge@montague.lit';
  25. let members = [
  26. {'jid': 'hag66@shakespeare.lit', 'nick': 'witch', 'affiliation': 'member'},
  27. {'jid': 'gower@shakespeare.lit', 'nick': 'gower', 'affiliation': 'member'},
  28. {'jid': 'wiccarocks@shakespeare.lit', 'nick': 'wiccan', 'affiliation': 'admin'},
  29. {'jid': 'crone1@shakespeare.lit', 'nick': 'thirdwitch', 'affiliation': 'owner'},
  30. {'jid': 'romeo@montague.lit', 'nick': 'romeo', 'affiliation': 'owner'},
  31. ];
  32. await mock.openAndEnterChatRoom(_converse, muc_jid, 'romeo', [], members);
  33. const view = _converse.chatboxviews.get(muc_jid);
  34. await u.waitUntil(() => (view.model.occupants.length === 5), 1000);
  35. const modal = await openModtools(_converse, view);
  36. let tab = modal.el.querySelector('#affiliations-tab');
  37. // Clear so that we don't match older stanzas
  38. _converse.connection.IQ_stanzas = [];
  39. tab.click();
  40. let select = modal.el.querySelector('.select-affiliation');
  41. expect(select.value).toBe('owner');
  42. select.value = 'admin';
  43. let button = modal.el.querySelector('.btn-primary[name="users_with_affiliation"]');
  44. button.click();
  45. await u.waitUntil(() => !modal.loading_users_with_affiliation);
  46. let user_els = modal.el.querySelectorAll('.list-group--users > li');
  47. expect(user_els.length).toBe(1);
  48. expect(user_els[0].querySelector('.list-group-item.active').textContent.trim()).toBe('JID: wiccarocks@shakespeare.lit');
  49. expect(user_els[0].querySelector('.list-group-item:nth-child(2n)').textContent.trim()).toBe('Nickname: wiccan');
  50. expect(user_els[0].querySelector('.list-group-item:nth-child(3n) div').textContent.trim()).toBe('Affiliation: admin');
  51. _converse.connection.IQ_stanzas = [];
  52. select.value = 'owner';
  53. button.click();
  54. await u.waitUntil(() => !modal.loading_users_with_affiliation);
  55. user_els = modal.el.querySelectorAll('.list-group--users > li');
  56. expect(user_els.length).toBe(2);
  57. expect(user_els[0].querySelector('.list-group-item.active').textContent.trim()).toBe('JID: romeo@montague.lit');
  58. expect(user_els[0].querySelector('.list-group-item:nth-child(2n)').textContent.trim()).toBe('Nickname: romeo');
  59. expect(user_els[0].querySelector('.list-group-item:nth-child(3n) div').textContent.trim()).toBe('Affiliation: owner');
  60. expect(user_els[1].querySelector('.list-group-item.active').textContent.trim()).toBe('JID: crone1@shakespeare.lit');
  61. expect(user_els[1].querySelector('.list-group-item:nth-child(2n)').textContent.trim()).toBe('Nickname: thirdwitch');
  62. expect(user_els[1].querySelector('.list-group-item:nth-child(3n) div').textContent.trim()).toBe('Affiliation: owner');
  63. const toggle = user_els[1].querySelector('.list-group-item:nth-child(3n) .toggle-form');
  64. const form = user_els[1].querySelector('.list-group-item:nth-child(3n) .affiliation-form');
  65. expect(u.hasClass('hidden', form)).toBeTruthy();
  66. toggle.click();
  67. expect(u.hasClass('hidden', form)).toBeFalsy();
  68. select = form.querySelector('.select-affiliation');
  69. expect(select.value).toBe('owner');
  70. select.value = 'admin';
  71. const input = form.querySelector('input[name="reason"]');
  72. input.value = "You're an admin now";
  73. const submit = form.querySelector('.btn-primary');
  74. submit.click();
  75. spyOn(_converse.ChatRoomOccupants.prototype, 'fetchMembers').and.callThrough();
  76. const sent_IQ = _converse.connection.IQ_stanzas.pop();
  77. expect(Strophe.serialize(sent_IQ)).toBe(
  78. `<iq id="${sent_IQ.getAttribute('id')}" to="lounge@montague.lit" type="set" xmlns="jabber:client">`+
  79. `<query xmlns="http://jabber.org/protocol/muc#admin">`+
  80. `<item affiliation="admin" jid="crone1@shakespeare.lit">`+
  81. `<reason>You&apos;re an admin now</reason>`+
  82. `</item>`+
  83. `</query>`+
  84. `</iq>`);
  85. _converse.connection.IQ_stanzas = [];
  86. const stanza = $iq({
  87. 'type': 'result',
  88. 'id': sent_IQ.getAttribute('id'),
  89. 'from': view.model.get('jid'),
  90. 'to': _converse.connection.jid
  91. });
  92. _converse.connection._dataRecv(mock.createRequest(stanza));
  93. await u.waitUntil(() => view.model.occupants.fetchMembers.calls.count());
  94. members = [
  95. {'jid': 'hag66@shakespeare.lit', 'nick': 'witch', 'affiliation': 'member'},
  96. {'jid': 'gower@shakespeare.lit', 'nick': 'gower', 'affiliation': 'member'},
  97. {'jid': 'wiccarocks@shakespeare.lit', 'nick': 'wiccan', 'affiliation': 'admin'},
  98. {'jid': 'crone1@shakespeare.lit', 'nick': 'thirdwitch', 'affiliation': 'admin'},
  99. {'jid': 'romeo@montague.lit', 'nick': 'romeo', 'affiliation': 'owner'},
  100. ];
  101. await mock.returnMemberLists(_converse, muc_jid, members);
  102. await u.waitUntil(() => view.model.occupants.pluck('affiliation').filter(o => o === 'owner').length === 1);
  103. const alert = modal.el.querySelector('.alert-primary');
  104. expect(alert.textContent.trim()).toBe('Affiliation changed');
  105. user_els = modal.el.querySelectorAll('.list-group--users > li');
  106. expect(user_els.length).toBe(1);
  107. expect(user_els[0].querySelector('.list-group-item.active').textContent.trim()).toBe('JID: romeo@montague.lit');
  108. expect(user_els[0].querySelector('.list-group-item:nth-child(2n)').textContent.trim()).toBe('Nickname: romeo');
  109. expect(user_els[0].querySelector('.list-group-item:nth-child(3n) div').textContent.trim()).toBe('Affiliation: owner');
  110. tab = modal.el.querySelector('#roles-tab');
  111. tab.click();
  112. select = modal.el.querySelector('.select-role');
  113. expect(u.isVisible(select)).toBe(true);
  114. expect(select.value).toBe('moderator');
  115. button = modal.el.querySelector('.btn-primary[name="users_with_role"]');
  116. button.click();
  117. const roles_panel = modal.el.querySelector('#roles-tabpanel');
  118. await u.waitUntil(() => roles_panel.querySelectorAll('.list-group--users > li').length === 1);
  119. select.value = 'participant';
  120. button.click();
  121. await u.waitUntil(() => !modal.loading_users_with_affiliation);
  122. user_els = roles_panel.querySelectorAll('.list-group--users > li')
  123. expect(user_els.length).toBe(1);
  124. expect(user_els[0].textContent.trim()).toBe('No users with that role found.');
  125. done();
  126. }));
  127. it("allows you to filter affiliation search results",
  128. mock.initConverse(
  129. ['rosterGroupsFetched'], {},
  130. async function (done, _converse) {
  131. spyOn(_converse.ChatRoomView.prototype, 'showModeratorToolsModal').and.callThrough();
  132. const muc_jid = 'lounge@montague.lit';
  133. const members = [
  134. {'jid': 'hag66@shakespeare.lit', 'nick': 'witch', 'affiliation': 'member'},
  135. {'jid': 'gower@shakespeare.lit', 'nick': 'gower', 'affiliation': 'member'},
  136. {'jid': 'wiccarocks@shakespeare.lit', 'nick': 'wiccan', 'affiliation': 'member'},
  137. {'jid': 'crone1@shakespeare.lit', 'nick': 'thirdwitch', 'affiliation': 'member'},
  138. {'jid': 'romeo@montague.lit', 'nick': 'romeo', 'affiliation': 'member'},
  139. {'jid': 'juliet@capulet.lit', 'nick': 'juliet', 'affiliation': 'member'},
  140. ];
  141. await mock.openAndEnterChatRoom(_converse, muc_jid, 'romeo', [], members);
  142. const view = _converse.chatboxviews.get(muc_jid);
  143. await u.waitUntil(() => (view.model.occupants.length === 6), 1000);
  144. // Clear so that we don't match older stanzas
  145. _converse.connection.IQ_stanzas = [];
  146. const modal = await openModtools(_converse, view);
  147. const select = modal.el.querySelector('.select-affiliation');
  148. expect(select.value).toBe('owner');
  149. select.value = 'member';
  150. const button = modal.el.querySelector('.btn-primary[name="users_with_affiliation"]');
  151. button.click();
  152. await u.waitUntil(() => !modal.loading_users_with_affiliation);
  153. const user_els = modal.el.querySelectorAll('.list-group--users > li');
  154. expect(user_els.length).toBe(6);
  155. const nicks = Array.from(modal.el.querySelectorAll('.list-group--users > li')).map(el => el.getAttribute('data-nick'));
  156. expect(nicks.join(' ')).toBe('gower juliet romeo thirdwitch wiccan witch');
  157. const filter = modal.el.querySelector('[name="filter"]');
  158. expect(filter).not.toBe(null);
  159. filter.value = 'romeo';
  160. u.triggerEvent(filter, "keyup", "KeyboardEvent");
  161. await u.waitUntil(() => ( modal.el.querySelectorAll('.list-group--users > li').length === 1));
  162. filter.value = 'r';
  163. u.triggerEvent(filter, "keyup", "KeyboardEvent");
  164. await u.waitUntil(() => ( modal.el.querySelectorAll('.list-group--users > li').length === 3));
  165. filter.value = 'gower';
  166. u.triggerEvent(filter, "keyup", "KeyboardEvent");
  167. await u.waitUntil(() => ( modal.el.querySelectorAll('.list-group--users > li').length === 1));
  168. filter.value = 'RoMeO';
  169. u.triggerEvent(filter, "keyup", "KeyboardEvent");
  170. await u.waitUntil(() => ( modal.el.querySelectorAll('.list-group--users > li').length === 1));
  171. done();
  172. }));
  173. it("allows you to filter role search results",
  174. mock.initConverse(
  175. ['rosterGroupsFetched'], {},
  176. async function (done, _converse) {
  177. spyOn(_converse.ChatRoomView.prototype, 'showModeratorToolsModal').and.callThrough();
  178. const muc_jid = 'lounge@montague.lit';
  179. await mock.openAndEnterChatRoom(_converse, muc_jid, 'romeo', []);
  180. const view = _converse.chatboxviews.get(muc_jid);
  181. _converse.connection._dataRecv(mock.createRequest(
  182. $pres({to: _converse.jid, from: `${muc_jid}/nomorenicks`})
  183. .c('x', {xmlns: Strophe.NS.MUC_USER})
  184. .c('item', {
  185. 'affiliation': 'none',
  186. 'jid': `nomorenicks@montague.lit`,
  187. 'role': 'participant'
  188. })
  189. ));
  190. _converse.connection._dataRecv(mock.createRequest(
  191. $pres({to: _converse.jid, from: `${muc_jid}/newb`})
  192. .c('x', {xmlns: Strophe.NS.MUC_USER})
  193. .c('item', {
  194. 'affiliation': 'none',
  195. 'jid': `newb@montague.lit`,
  196. 'role': 'participant'
  197. })
  198. ));
  199. _converse.connection._dataRecv(mock.createRequest(
  200. $pres({to: _converse.jid, from: `${muc_jid}/some1`})
  201. .c('x', {xmlns: Strophe.NS.MUC_USER})
  202. .c('item', {
  203. 'affiliation': 'none',
  204. 'jid': `some1@montague.lit`,
  205. 'role': 'participant'
  206. })
  207. ));
  208. _converse.connection._dataRecv(mock.createRequest(
  209. $pres({to: _converse.jid, from: `${muc_jid}/oldhag`})
  210. .c('x', {xmlns: Strophe.NS.MUC_USER})
  211. .c('item', {
  212. 'affiliation': 'none',
  213. 'jid': `oldhag@montague.lit`,
  214. 'role': 'participant'
  215. })
  216. ));
  217. _converse.connection._dataRecv(mock.createRequest(
  218. $pres({to: _converse.jid, from: `${muc_jid}/crone`})
  219. .c('x', {xmlns: Strophe.NS.MUC_USER})
  220. .c('item', {
  221. 'affiliation': 'none',
  222. 'jid': `crone@montague.lit`,
  223. 'role': 'participant'
  224. })
  225. ));
  226. _converse.connection._dataRecv(mock.createRequest(
  227. $pres({to: _converse.jid, from: `${muc_jid}/tux`})
  228. .c('x', {xmlns: Strophe.NS.MUC_USER})
  229. .c('item', {
  230. 'affiliation': 'none',
  231. 'jid': `tux@montague.lit`,
  232. 'role': 'participant'
  233. })
  234. ));
  235. await u.waitUntil(() => (view.model.occupants.length === 7), 1000);
  236. const textarea = view.el.querySelector('.chat-textarea');
  237. textarea.value = '/modtools';
  238. const enter = { 'target': textarea, 'preventDefault': function preventDefault () {}, 'keyCode': 13 };
  239. view.onKeyDown(enter);
  240. await u.waitUntil(() => view.showModeratorToolsModal.calls.count());
  241. const modal = _converse.api.modal.get('converse-modtools-modal');
  242. await u.waitUntil(() => u.isVisible(modal.el), 1000);
  243. const tab = modal.el.querySelector('#roles-tab');
  244. tab.click();
  245. // Clear so that we don't match older stanzas
  246. _converse.connection.IQ_stanzas = [];
  247. const select = modal.el.querySelector('.select-role');
  248. expect(select.value).toBe('moderator');
  249. select.value = 'participant';
  250. const button = modal.el.querySelector('.btn-primary[name="users_with_role"]');
  251. button.click();
  252. await u.waitUntil(() => !modal.loading_users_with_role);
  253. const user_els = modal.el.querySelectorAll('.list-group--users > li');
  254. expect(user_els.length).toBe(6);
  255. const nicks = Array.from(modal.el.querySelectorAll('.list-group--users > li')).map(el => el.getAttribute('data-nick'));
  256. expect(nicks.join(' ')).toBe('crone newb nomorenicks oldhag some1 tux');
  257. const filter = modal.el.querySelector('[name="filter"]');
  258. expect(filter).not.toBe(null);
  259. filter.value = 'tux';
  260. u.triggerEvent(filter, "keyup", "KeyboardEvent");
  261. await u.waitUntil(() => ( modal.el.querySelectorAll('.list-group--users > li').length === 1));
  262. filter.value = 'r';
  263. u.triggerEvent(filter, "keyup", "KeyboardEvent");
  264. await u.waitUntil(() => ( modal.el.querySelectorAll('.list-group--users > li').length === 2));
  265. filter.value = 'crone';
  266. u.triggerEvent(filter, "keyup", "KeyboardEvent");
  267. await u.waitUntil(() => ( modal.el.querySelectorAll('.list-group--users > li').length === 1));
  268. done();
  269. }));
  270. it("shows an error message if a particular affiliation list may not be retrieved",
  271. mock.initConverse(
  272. ['rosterGroupsFetched'], {},
  273. async function (done, _converse) {
  274. spyOn(_converse.ChatRoomView.prototype, 'showModeratorToolsModal').and.callThrough();
  275. const muc_jid = 'lounge@montague.lit';
  276. const members = [
  277. {'jid': 'hag66@shakespeare.lit', 'nick': 'witch', 'affiliation': 'member'},
  278. {'jid': 'gower@shakespeare.lit', 'nick': 'gower', 'affiliation': 'member'},
  279. {'jid': 'wiccarocks@shakespeare.lit', 'nick': 'wiccan', 'affiliation': 'admin'},
  280. {'jid': 'crone1@shakespeare.lit', 'nick': 'thirdwitch', 'affiliation': 'owner'},
  281. {'jid': 'romeo@montague.lit', 'nick': 'romeo', 'affiliation': 'owner'},
  282. ];
  283. await mock.openAndEnterChatRoom(_converse, muc_jid, 'romeo', [], members);
  284. const view = _converse.chatboxviews.get(muc_jid);
  285. await u.waitUntil(() => (view.model.occupants.length === 5));
  286. const modal = await openModtools(_converse, view);
  287. const tab = modal.el.querySelector('#affiliations-tab');
  288. // Clear so that we don't match older stanzas
  289. _converse.connection.IQ_stanzas = [];
  290. const IQ_stanzas = _converse.connection.IQ_stanzas;
  291. tab.click();
  292. const select = modal.el.querySelector('.select-affiliation');
  293. select.value = 'outcast';
  294. const button = modal.el.querySelector('.btn-primary[name="users_with_affiliation"]');
  295. button.click();
  296. const iq_query = await u.waitUntil(() => _.filter(
  297. IQ_stanzas,
  298. s => sizzle(`iq[to="${muc_jid}"] query[xmlns="${Strophe.NS.MUC_ADMIN}"] item[affiliation="outcast"]`, s).length
  299. ).pop());
  300. const error = u.toStanza(
  301. `<iq from="${muc_jid}"
  302. id="${iq_query.getAttribute('id')}"
  303. type="error"
  304. to="${_converse.jid}">
  305. <error type="auth">
  306. <forbidden xmlns="${Strophe.NS.STANZAS}"/>
  307. </error>
  308. </iq>`);
  309. _converse.connection._dataRecv(mock.createRequest(error));
  310. await u.waitUntil(() => !modal.loading_users_with_affiliation);
  311. const user_els = modal.el.querySelectorAll('.list-group--users > li');
  312. expect(user_els.length).toBe(1);
  313. expect(user_els[0].textContent.trim()).toBe('Error: not allowed to fetch outcast list for MUC lounge@montague.lit');
  314. done();
  315. }));
  316. it("shows an error message if a particular affiliation may not be set",
  317. mock.initConverse(
  318. ['rosterGroupsFetched'], {},
  319. async function (done, _converse) {
  320. spyOn(_converse.ChatRoomView.prototype, 'showModeratorToolsModal').and.callThrough();
  321. const muc_jid = 'lounge@montague.lit';
  322. const members = [
  323. {'jid': 'gower@shakespeare.lit', 'nick': 'gower', 'affiliation': 'member'},
  324. {'jid': 'romeo@montague.lit', 'nick': 'romeo', 'affiliation': 'owner'},
  325. ];
  326. await mock.openAndEnterChatRoom(_converse, muc_jid, 'romeo', [], members);
  327. const view = _converse.chatboxviews.get(muc_jid);
  328. await u.waitUntil(() => (view.model.occupants.length === 2));
  329. const modal = await openModtools(_converse, view);
  330. // Clear so that we don't match older stanzas
  331. _converse.connection.IQ_stanzas = [];
  332. const tab = modal.el.querySelector('#affiliations-tab');
  333. tab.click();
  334. const select = modal.el.querySelector('.select-affiliation');
  335. select.value = 'member';
  336. const button = modal.el.querySelector('.btn-primary[name="users_with_affiliation"]');
  337. button.click();
  338. await u.waitUntil(() => !modal.loading_users_with_affiliation);
  339. const user_els = modal.el.querySelectorAll('.list-group--users > li');
  340. expect(user_els.length).toBe(1);
  341. const toggle = user_els[0].querySelector('.list-group-item:nth-child(3n) .toggle-form');
  342. const form = user_els[0].querySelector('.list-group-item:nth-child(3n) .affiliation-form');
  343. expect(u.hasClass('hidden', form)).toBeTruthy();
  344. toggle.click();
  345. expect(u.hasClass('hidden', form)).toBeFalsy();
  346. const change_affiliation_dropdown = form.querySelector('.select-affiliation');
  347. expect(change_affiliation_dropdown.value).toBe('member');
  348. change_affiliation_dropdown.value = 'admin';
  349. const input = form.querySelector('input[name="reason"]');
  350. input.value = "You're an admin now";
  351. const submit = form.querySelector('.btn-primary');
  352. submit.click();
  353. const sent_IQ = _converse.connection.IQ_stanzas.pop();
  354. expect(Strophe.serialize(sent_IQ)).toBe(
  355. `<iq id="${sent_IQ.getAttribute('id')}" to="lounge@montague.lit" type="set" xmlns="jabber:client">`+
  356. `<query xmlns="http://jabber.org/protocol/muc#admin">`+
  357. `<item affiliation="admin" jid="gower@shakespeare.lit">`+
  358. `<reason>You&apos;re an admin now</reason>`+
  359. `</item>`+
  360. `</query>`+
  361. `</iq>`);
  362. const error = u.toStanza(
  363. `<iq from="${muc_jid}"
  364. id="${sent_IQ.getAttribute('id')}"
  365. type="error"
  366. to="${_converse.jid}">
  367. <error type="cancel">
  368. <not-allowed xmlns="${Strophe.NS.STANZAS}"/>
  369. </error>
  370. </iq>`);
  371. _converse.connection._dataRecv(mock.createRequest(error));
  372. done();
  373. }));
  374. it("doesn't allow admins to make more admins",
  375. mock.initConverse(
  376. ['rosterGroupsFetched'], {},
  377. async function (done, _converse) {
  378. spyOn(_converse.ChatRoomView.prototype, 'showModeratorToolsModal').and.callThrough();
  379. const muc_jid = 'lounge@montague.lit';
  380. const members = [
  381. {'jid': 'hag66@shakespeare.lit', 'nick': 'witch', 'affiliation': 'member'},
  382. {'jid': 'gower@shakespeare.lit', 'nick': 'gower', 'affiliation': 'member'},
  383. {'jid': 'romeo@montague.lit', 'nick': 'romeo', 'affiliation': 'admin'},
  384. ];
  385. await mock.openAndEnterChatRoom(_converse, muc_jid, 'romeo', [], members);
  386. const view = _converse.chatboxviews.get(muc_jid);
  387. await u.waitUntil(() => (view.model.occupants.length === 3));
  388. const modal = await openModtools(_converse, view);
  389. const tab = modal.el.querySelector('#affiliations-tab');
  390. // Clear so that we don't match older stanzas
  391. _converse.connection.IQ_stanzas = [];
  392. tab.click();
  393. const show_affiliation_dropdown = modal.el.querySelector('.select-affiliation');
  394. show_affiliation_dropdown.value = 'member';
  395. const button = modal.el.querySelector('.btn-primary[name="users_with_affiliation"]');
  396. button.click();
  397. await u.waitUntil(() => !modal.loading_users_with_affiliation);
  398. const user_els = modal.el.querySelectorAll('.list-group--users > li');
  399. expect(user_els.length).toBe(2);
  400. let change_affiliation_dropdown = user_els[0].querySelector('.select-affiliation');
  401. expect(Array.from(change_affiliation_dropdown.options).map(o => o.value)).toEqual(['member', 'outcast', 'none']);
  402. change_affiliation_dropdown = user_els[1].querySelector('.select-affiliation');
  403. expect(Array.from(change_affiliation_dropdown.options).map(o => o.value)).toEqual(['member', 'outcast', 'none']);
  404. done();
  405. }));
  406. it("lets the assignable affiliations and roles be configured via modtools_disable_assign",
  407. mock.initConverse(
  408. ['rosterGroupsFetched'], {},
  409. async function (done, _converse) {
  410. spyOn(_converse.ChatRoomView.prototype, 'showModeratorToolsModal').and.callThrough();
  411. const muc_jid = 'lounge@montague.lit';
  412. const members = [{'jid': 'romeo@montague.lit', 'nick': 'romeo', 'affiliation': 'owner'}];
  413. await mock.openAndEnterChatRoom(_converse, muc_jid, 'romeo', [], members);
  414. const view = _converse.chatboxviews.get(muc_jid);
  415. const textarea = view.el.querySelector('.chat-textarea');
  416. textarea.value = '/modtools';
  417. const enter = { 'target': textarea, 'preventDefault': function preventDefault () {}, 'keyCode': 13 };
  418. view.onKeyDown(enter);
  419. await u.waitUntil(() => view.showModeratorToolsModal.calls.count());
  420. const modal = _converse.api.modal.get('converse-modtools-modal');
  421. const occupant = view.model.occupants.findWhere({'jid': _converse.bare_jid});
  422. expect(modal.getAssignableAffiliations(occupant)).toEqual(['owner', 'admin', 'member', 'outcast', 'none']);
  423. _converse.api.settings.set('modtools_disable_assign', ['owner']);
  424. expect(modal.getAssignableAffiliations(occupant)).toEqual(['admin', 'member', 'outcast', 'none']);
  425. _converse.api.settings.set('modtools_disable_assign', ['owner', 'admin']);
  426. expect(modal.getAssignableAffiliations(occupant)).toEqual(['member', 'outcast', 'none']);
  427. _converse.api.settings.set('modtools_disable_assign', ['owner', 'admin', 'outcast']);
  428. expect(modal.getAssignableAffiliations(occupant)).toEqual(['member', 'none']);
  429. expect(modal.getAssignableRoles(occupant)).toEqual(['moderator', 'participant', 'visitor']);
  430. _converse.api.settings.set('modtools_disable_assign', ['admin', 'moderator']);
  431. expect(modal.getAssignableRoles(occupant)).toEqual(['participant', 'visitor']);
  432. done();
  433. }));
  434. });