settingsSpec.js 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471
  1. /**
  2. * Copyright (c) 2015 Vincent Petry <pvince81@owncloud.com>
  3. *
  4. * @author Christoph Wurst <christoph@winzerhof-wurst.at>
  5. * @author Joas Schilling <coding@schilljs.com>
  6. * @author John Molakvoæ <skjnldsv@protonmail.com>
  7. * @author Juan Pablo Villafáñez <jvillafanez@solidgear.es>
  8. * @author Julius Härtl <jus@bitgrid.net>
  9. * @author Robin Appelman <robin@icewind.nl>
  10. * @author Robin McCorkell <robin@mccorkell.me.uk>
  11. * @author Roeland Jago Douma <roeland@famdouma.nl>
  12. * @author Vincent Petry <vincent@nextcloud.com>
  13. *
  14. * @license AGPL-3.0-or-later
  15. *
  16. * This program is free software: you can redistribute it and/or modify
  17. * it under the terms of the GNU Affero General Public License as
  18. * published by the Free Software Foundation, either version 3 of the
  19. * License, or (at your option) any later version.
  20. *
  21. * This program is distributed in the hope that it will be useful,
  22. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  23. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  24. * GNU Affero General Public License for more details.
  25. *
  26. * You should have received a copy of the GNU Affero General Public License
  27. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  28. *
  29. */
  30. describe('OCA.Files_External.Settings tests', function() {
  31. var clock;
  32. var select2Stub;
  33. var select2ApplicableUsers;
  34. beforeEach(function() {
  35. clock = sinon.useFakeTimers();
  36. select2ApplicableUsers = [];
  37. select2Stub = sinon.stub($.fn, 'select2').callsFake(function(args) {
  38. if (args === 'val') {
  39. return select2ApplicableUsers;
  40. }
  41. return {
  42. on: function() { return this; }
  43. };
  44. });
  45. // view still requires an existing DOM table
  46. $('#testArea').append(
  47. '<table id="externalStorage" data-admin="true">' +
  48. '<thead></thead>' +
  49. '<tbody>' +
  50. '<tr id="addMountPoint" data-id="">' +
  51. '<td class="status"></td>' +
  52. '<td class="mountPoint"><input type="text" name="mountPoint"/></td>' +
  53. '<td class="backend">' +
  54. '<select class="selectBackend">' +
  55. '<option disable selected>Add storage</option>' +
  56. '<option value="\\OC\\TestBackend">Test Backend</option>' +
  57. '<option value="\\OC\\AnotherTestBackend">Another Test Backend</option>' +
  58. '<option value="\\OC\\InputsTestBackend">Inputs test backend</option>' +
  59. '</select>' +
  60. '</td>' +
  61. '<td class="authentication"></td>' +
  62. '<td class="configuration"></td>' +
  63. '<td class="applicable">' +
  64. '<input type="checkbox" class="applicableToAllUsers">' +
  65. '<input type="hidden" class="applicableUsers">' +
  66. '</td>' +
  67. '<td class="mountOptionsToggle">'+
  68. '<div class="icon-more" title="Advanced settings" deluminate_imagetype="unknown"></div>'+
  69. '<input type="hidden" class="mountOptions"/>'+
  70. '</td>'+
  71. '<td class="save">'+
  72. '<div class="icon-checkmark" title="Save" deluminate_imagetype="unknown"></div>'+
  73. '</td>'+
  74. '</tr>' +
  75. '</tbody>' +
  76. '</table>'
  77. );
  78. // these are usually appended into the data attribute
  79. // within the DOM by the server template
  80. $('#externalStorage .selectBackend:first').data('configurations', {
  81. '\\OC\\TestBackend': {
  82. 'identifier': '\\OC\\TestBackend',
  83. 'name': 'Test Backend',
  84. 'configuration': {
  85. 'field1': {
  86. 'value': 'Display Name 1'
  87. },
  88. 'field2': {
  89. 'value': 'Display Name 2',
  90. 'flags': 1
  91. }
  92. },
  93. 'authSchemes': {
  94. 'builtin': true,
  95. },
  96. 'priority': 11
  97. },
  98. '\\OC\\AnotherTestBackend': {
  99. 'identifier': '\\OC\\AnotherTestBackend',
  100. 'name': 'Another Test Backend',
  101. 'configuration': {
  102. 'field1': {
  103. 'value': 'Display Name 1'
  104. },
  105. 'field2': {
  106. 'value': 'Display Name 2',
  107. 'flags': 1
  108. }
  109. },
  110. 'authSchemes': {
  111. 'builtin': true,
  112. },
  113. 'priority': 12
  114. },
  115. '\\OC\\InputsTestBackend': {
  116. 'identifier': '\\OC\\InputsTestBackend',
  117. 'name': 'Inputs test backend',
  118. 'configuration': {
  119. 'field_text': {
  120. 'value': 'Text field'
  121. },
  122. 'field_password': {
  123. 'value': ',Password field',
  124. 'type': 2
  125. },
  126. 'field_bool': {
  127. 'value': 'Boolean field',
  128. 'type': 1
  129. },
  130. 'field_hidden': {
  131. 'value': 'Hidden field',
  132. 'type': 3
  133. },
  134. 'field_text_optional': {
  135. 'value': 'Text field optional',
  136. 'flags': 1
  137. },
  138. 'field_password_optional': {
  139. 'value': 'Password field optional',
  140. 'flags': 1,
  141. 'type': 2
  142. }
  143. },
  144. 'authSchemes': {
  145. 'builtin': true,
  146. },
  147. 'priority': 13
  148. }
  149. }
  150. );
  151. $('#externalStorage #addMountPoint .authentication:first').data('mechanisms', {
  152. 'mechanism1': {
  153. 'identifier': 'mechanism1',
  154. 'name': 'Mechanism 1',
  155. 'configuration': {
  156. },
  157. 'scheme': 'builtin',
  158. 'visibility': 3
  159. },
  160. });
  161. });
  162. afterEach(function() {
  163. select2Stub.restore();
  164. clock.restore();
  165. });
  166. describe('storage configuration', function() {
  167. var view;
  168. function selectBackend(backendName) {
  169. view.$el.find('.selectBackend:first').val(backendName).trigger('change');
  170. view.$el.find('.applicableToAllUsers').prop('checked', true).trigger('change');
  171. }
  172. beforeEach(function() {
  173. var $el = $('#externalStorage');
  174. view = new OCA.Files_External.Settings.MountConfigListView($el, {encryptionEnabled: false});
  175. });
  176. afterEach(function() {
  177. view = null;
  178. });
  179. describe('selecting backend', function() {
  180. it('populates the row and creates a new empty one', function() {
  181. selectBackend('\\OC\\TestBackend');
  182. var $firstRow = view.$el.find('tr:first');
  183. expect($firstRow.find('.backend').text()).toEqual('Test Backend');
  184. expect($firstRow.find('.selectBackend').length).toEqual(0);
  185. // TODO: check "remove" button visibility
  186. // the suggested mount point name
  187. expect($firstRow.find('[name=mountPoint]').val()).toEqual('TestBackend');
  188. // TODO: check that the options have been created
  189. // TODO: check select2 call on the ".applicableUsers" element
  190. var $emptyRow = $firstRow.next('tr');
  191. expect($emptyRow.length).toEqual(1);
  192. expect($emptyRow.find('.selectBackend').length).toEqual(1);
  193. expect($emptyRow.find('.applicable select').length).toEqual(0);
  194. // TODO: check "remove" button visibility
  195. });
  196. it('shows row even if selection row is hidden', function() {
  197. selectBackend('\\OC\\TestBackend');
  198. view.$el.find('tr#addMountPoint').hide();
  199. expect(view.$el.find('tr:first').is(':visible')).toBe(true);
  200. expect(view.$el.find('tr#addMountPoint').is(':visible')).toBe(false);
  201. });
  202. // TODO: test with personal mounts (no applicable fields)
  203. // TODO: test suggested mount point logic
  204. });
  205. describe('saving storages', function() {
  206. var $tr;
  207. beforeEach(function() {
  208. selectBackend('\\OC\\TestBackend');
  209. $tr = view.$el.find('tr:first');
  210. });
  211. it('saves storage after clicking the save button', function() {
  212. var $field1 = $tr.find('input[data-parameter=field1]');
  213. expect($field1.length).toEqual(1);
  214. $field1.val('test');
  215. $field1.trigger(new $.Event('keyup', {keyCode: 97}));
  216. var $mountOptionsField = $tr.find('input.mountOptions');
  217. expect($mountOptionsField.length).toEqual(1);
  218. $mountOptionsField.val(JSON.stringify({previews:true}));
  219. var $saveButton = $tr.find('td.save .icon-checkmark');
  220. $saveButton.click();
  221. expect(fakeServer.requests.length).toEqual(1);
  222. var request = fakeServer.requests[0];
  223. expect(request.url).toEqual(OC.getRootPath() + '/index.php/apps/files_external/globalstorages');
  224. expect(JSON.parse(request.requestBody)).toEqual({
  225. backend: '\\OC\\TestBackend',
  226. authMechanism: 'mechanism1',
  227. backendOptions: {
  228. 'field1': 'test',
  229. 'field2': ''
  230. },
  231. mountPoint: 'TestBackend',
  232. priority: 11,
  233. applicableUsers: [],
  234. applicableGroups: [],
  235. mountOptions: {
  236. 'previews': true
  237. },
  238. testOnly: true
  239. });
  240. // TODO: respond and check data-id
  241. });
  242. it('saves storage with applicable users', function() {
  243. var $field1 = $tr.find('input[data-parameter=field1]');
  244. expect($field1.length).toEqual(1);
  245. $field1.val('test');
  246. $field1.trigger(new $.Event('keyup', {keyCode: 97}));
  247. $tr.find('.applicableToAllUsers').prop('checked', false).trigger('change');
  248. select2ApplicableUsers = ['user1', 'user2', 'group1(group)', 'group2(group)'];
  249. var $saveButton = $tr.find('td.save .icon-checkmark');
  250. $saveButton.click();
  251. expect(fakeServer.requests.length).toEqual(1);
  252. var request = fakeServer.requests[0];
  253. expect(request.url).toEqual(OC.getRootPath() + '/index.php/apps/files_external/globalstorages');
  254. expect(JSON.parse(request.requestBody)).toEqual({
  255. backend: '\\OC\\TestBackend',
  256. authMechanism: 'mechanism1',
  257. backendOptions: {
  258. 'field1': 'test',
  259. 'field2': ''
  260. },
  261. mountPoint: 'TestBackend',
  262. priority: 11,
  263. applicableUsers: ['user1', 'user2'],
  264. applicableGroups: ['group1', 'group2'],
  265. mountOptions: {
  266. encrypt: true,
  267. previews: true,
  268. enable_sharing: false,
  269. filesystem_check_changes: 1,
  270. encoding_compatibility: false,
  271. readonly: false,
  272. },
  273. testOnly: true
  274. });
  275. // TODO: respond and check data-id
  276. });
  277. it('does not saves storage without applicable users and unchecked all users checkbox', function() {
  278. var $field1 = $tr.find('input[data-parameter=field1]');
  279. expect($field1.length).toEqual(1);
  280. $field1.val('test');
  281. $field1.trigger(new $.Event('keyup', {keyCode: 97}));
  282. $tr.find('.applicableToAllUsers').prop('checked', false).trigger('change');
  283. var $saveButton = $tr.find('td.save .icon-checkmark');
  284. $saveButton.click();
  285. expect(fakeServer.requests.length).toEqual(0);
  286. });
  287. it('saves storage after closing mount options popovermenu', function() {
  288. $tr.find('.mountOptionsToggle .icon-more').click();
  289. $tr.find('[name=previews]').trigger(new $.Event('keyup', {keyCode: 97}));
  290. $tr.find('input[data-parameter=field1]').val('test');
  291. // does not save inside the popovermenu
  292. expect(fakeServer.requests.length).toEqual(0);
  293. $('body').mouseup();
  294. // but after closing the popovermenu
  295. expect(fakeServer.requests.length).toEqual(1);
  296. });
  297. // TODO: status indicator
  298. });
  299. describe('validate storage configuration', function() {
  300. var $tr;
  301. beforeEach(function() {
  302. selectBackend('\\OC\\InputsTestBackend');
  303. $tr = view.$el.find('tr:first');
  304. });
  305. it('lists missing fields in storage errors', function() {
  306. $tr.find('.applicableToAllUsers').prop('checked', false).trigger('change');
  307. var storage = view.getStorageConfig($tr);
  308. expect(storage.errors).toEqual({
  309. backendOptions: ['field_text', 'field_password'],
  310. requiredApplicable: true,
  311. });
  312. });
  313. it('does not list applicable when all users checkbox is ticked', function() {
  314. var storage = view.getStorageConfig($tr);
  315. expect(storage.errors).toEqual({
  316. backendOptions: ['field_text', 'field_password']
  317. });
  318. });
  319. it('highlights missing non-optional fields', function() {
  320. _.each([
  321. 'field_text',
  322. 'field_password'
  323. ], function(param) {
  324. expect($tr.find('input[data-parameter='+param+']').hasClass('warning-input')).toBe(true);
  325. });
  326. _.each([
  327. 'field_bool',
  328. 'field_hidden',
  329. 'field_text_optional',
  330. 'field_password_optional'
  331. ], function(param) {
  332. expect($tr.find('input[data-parameter='+param+']').hasClass('warning-input')).toBe(false);
  333. });
  334. });
  335. it('validates correct storage', function() {
  336. $tr.find('[name=mountPoint]').val('mountpoint');
  337. $tr.find('input[data-parameter=field_text]').val('foo');
  338. $tr.find('input[data-parameter=field_password]').val('bar');
  339. $tr.find('input[data-parameter=field_text_optional]').val('foobar');
  340. // don't set field_password_optional
  341. $tr.find('input[data-parameter=field_hidden]').val('baz');
  342. var storage = view.getStorageConfig($tr);
  343. expect(storage.validate()).toBe(true);
  344. });
  345. it('checks missing mount point', function() {
  346. $tr.find('[name=mountPoint]').val('');
  347. $tr.find('input[data-parameter=field_text]').val('foo');
  348. $tr.find('input[data-parameter=field_password]').val('bar');
  349. var storage = view.getStorageConfig($tr);
  350. expect(storage.validate()).toBe(false);
  351. });
  352. });
  353. describe('update storage', function() {
  354. // TODO
  355. });
  356. describe('delete storage', function() {
  357. // TODO
  358. });
  359. describe('recheck storages', function() {
  360. // TODO
  361. });
  362. describe('mount options popovermenu', function() {
  363. var $tr;
  364. var $td;
  365. beforeEach(function() {
  366. selectBackend('\\OC\\TestBackend');
  367. $tr = view.$el.find('tr:first');
  368. $td = $tr.find('.mountOptionsToggle');
  369. });
  370. it('shows popovermenu when clicking on toggle button, hides when clicking outside', function() {
  371. $td.find('.icon-more').click();
  372. expect($td.find('.popovermenu.open').length).toEqual(1);
  373. $('body').mouseup();
  374. expect($td.find('.popovermenu.open').length).toEqual(0);
  375. });
  376. it('doesnt show the encryption option when encryption is disabled', function () {
  377. view._encryptionEnabled = false;
  378. $td.find('.icon-more').click();
  379. expect($td.find('.popovermenu [name=encrypt]:visible').length).toEqual(0);
  380. $('body').mouseup();
  381. expect($td.find('.popovermenu.open').length).toEqual(0);
  382. });
  383. it('reads config from mountOptions field', function() {
  384. $tr.find('input.mountOptions').val(JSON.stringify({previews:false}));
  385. $td.find('.icon-more').click();
  386. expect($td.find('.popovermenu [name=previews]').prop('checked')).toEqual(false);
  387. $('body').mouseup();
  388. $tr.find('input.mountOptions').val(JSON.stringify({previews:true}));
  389. $td.find('.icon-more').click();
  390. expect($td.find('.popovermenu [name=previews]').prop('checked')).toEqual(true);
  391. });
  392. it('writes config into mountOptions field', function() {
  393. $td.find('.icon-more').click();
  394. // defaults to true
  395. var $field = $td.find('.popovermenu [name=previews]');
  396. expect($field.prop('checked')).toEqual(true);
  397. $td.find('.popovermenu [name=filesystem_check_changes]').val(0);
  398. $('body').mouseup();
  399. expect(JSON.parse($tr.find('input.mountOptions').val())).toEqual({
  400. encrypt: true,
  401. previews: true,
  402. enable_sharing: false,
  403. filesystem_check_changes: 0,
  404. encoding_compatibility: false,
  405. readonly: false
  406. });
  407. });
  408. });
  409. });
  410. describe('allow user mounts section', function() {
  411. // TODO: test allowUserMounting section
  412. });
  413. });