2
0

modtools.js 24 KB

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