You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

filelistSpec.js 14KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397
  1. /**
  2. * @copyright 2014 Vincent Petry <pvince81@owncloud.com>
  3. *
  4. * @author Abijeet <abijeetpatro@gmail.com>
  5. * @author Christoph Wurst <christoph@winzerhof-wurst.at>
  6. * @author Jan C. Borchardt <hey@jancborchardt.net>
  7. * @author Jan-Christoph Borchardt <hey@jancborchardt.net>
  8. * @author John Molakvoæ <skjnldsv@protonmail.com>
  9. * @author Robin Appelman <robin@icewind.nl>
  10. * @author Vincent Petry <vincent@nextcloud.com>
  11. *
  12. * @license AGPL-3.0-or-later
  13. *
  14. * This program is free software: you can redistribute it and/or modify
  15. * it under the terms of the GNU Affero General Public License as
  16. * published by the Free Software Foundation, either version 3 of the
  17. * License, or (at your option) any later version.
  18. *
  19. * This program is distributed in the hope that it will be useful,
  20. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  21. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  22. * GNU Affero General Public License for more details.
  23. *
  24. * You should have received a copy of the GNU Affero General Public License
  25. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  26. *
  27. */
  28. describe('OCA.Trashbin.FileList tests', function () {
  29. var testFiles, alertStub, notificationStub, fileList, client;
  30. beforeEach(function () {
  31. alertStub = sinon.stub(OC.dialogs, 'alert');
  32. notificationStub = sinon.stub(OC.Notification, 'show');
  33. client = new OC.Files.Client({
  34. host: 'localhost',
  35. port: 80,
  36. root: '/remote.php/dav/trashbin/user',
  37. useHTTPS: OC.getProtocol() === 'https'
  38. });
  39. // init parameters and test table elements
  40. $('#testArea').append(
  41. '<div id="app-content">' +
  42. // set this but it shouldn't be used (could be the one from the
  43. // files app)
  44. '<input type="hidden" id="permissions" value="31"></input>' +
  45. // dummy controls
  46. '<div class="files-controls">' +
  47. ' <div class="actions creatable"></div>' +
  48. ' <div class="notCreatable"></div>' +
  49. '</div>' +
  50. // dummy table
  51. // TODO: at some point this will be rendered by the fileList class itself!
  52. '<table class="files-filestable list-container view-grid">' +
  53. '<thead><tr><th class="hidden column-name">' +
  54. '<input type="checkbox" id="select_all_trash" class="select-all">' +
  55. '<span class="name">Name</span>' +
  56. '<span class="selectedActions hidden">' +
  57. '<a href="" class="actions-selected"><span class="icon icon-more"></span><span>Actions</span>' +
  58. '</span>' +
  59. '</th></tr></thead>' +
  60. '<tbody class="files-fileList"></tbody>' +
  61. '<tfoot></tfoot>' +
  62. '</table>' +
  63. '<div class="emptyfilelist emptycontent">Empty content message</div>' +
  64. '</div>'
  65. );
  66. testFiles = [{
  67. id: 1,
  68. type: 'file',
  69. name: 'One.txt.d11111',
  70. displayName: 'One.txt',
  71. mtime: 11111000,
  72. mimetype: 'text/plain',
  73. etag: 'abc'
  74. }, {
  75. id: 2,
  76. type: 'file',
  77. name: 'Two.jpg.d22222',
  78. displayName: 'Two.jpg',
  79. mtime: 22222000,
  80. mimetype: 'image/jpeg',
  81. etag: 'def',
  82. }, {
  83. id: 3,
  84. type: 'file',
  85. name: 'Three.pdf.d33333',
  86. displayName: 'Three.pdf',
  87. mtime: 33333000,
  88. mimetype: 'application/pdf',
  89. etag: '123',
  90. }, {
  91. id: 4,
  92. type: 'dir',
  93. mtime: 99999000,
  94. name: 'somedir.d99999',
  95. displayName: 'somedir',
  96. mimetype: 'httpd/unix-directory',
  97. etag: '456'
  98. }];
  99. // register file actions like the trashbin App does
  100. var fileActions = OCA.Trashbin.App._createFileActions(fileList);
  101. fileList = new OCA.Trashbin.FileList(
  102. $('#app-content'), {
  103. fileActions: fileActions,
  104. multiSelectMenu: [{
  105. name: 'restore',
  106. displayName: t('files', 'Restore'),
  107. iconClass: 'icon-history',
  108. },
  109. {
  110. name: 'delete',
  111. displayName: t('files', 'Delete'),
  112. iconClass: 'icon-delete',
  113. }
  114. ],
  115. client: client
  116. }
  117. );
  118. });
  119. afterEach(function () {
  120. testFiles = undefined;
  121. fileList.destroy();
  122. fileList = undefined;
  123. notificationStub.restore();
  124. alertStub.restore();
  125. });
  126. describe('Initialization', function () {
  127. it('Sorts by mtime by default', function () {
  128. expect(fileList._sort).toEqual('mtime');
  129. expect(fileList._sortDirection).toEqual('desc');
  130. });
  131. it('Always returns read and delete permission', function () {
  132. expect(fileList.getDirectoryPermissions()).toEqual(OC.PERMISSION_READ | OC.PERMISSION_DELETE);
  133. });
  134. });
  135. describe('Breadcrumbs', function () {
  136. beforeEach(function () {
  137. var data = {
  138. status: 'success',
  139. data: {
  140. files: testFiles,
  141. permissions: 1
  142. }
  143. };
  144. fakeServer.respondWith(/\/index\.php\/apps\/files_trashbin\/ajax\/list.php\?dir=%2Fsubdir/, [
  145. 200, {
  146. "Content-Type": "application/json"
  147. },
  148. JSON.stringify(data)
  149. ]);
  150. });
  151. it('links the breadcrumb to the trashbin view', function () {
  152. fileList.changeDirectory('/subdir', false, true);
  153. fakeServer.respond();
  154. var $crumbs = fileList.$el.find('.files-controls .crumb');
  155. expect($crumbs.length).toEqual(3);
  156. expect($crumbs.eq(1).find('a').text()).toEqual('Home');
  157. expect($crumbs.eq(1).find('a').attr('href'))
  158. .toEqual(OC.getRootPath() + '/index.php/apps/files?view=trashbin&dir=/');
  159. expect($crumbs.eq(2).find('a').text()).toEqual('subdir');
  160. expect($crumbs.eq(2).find('a').attr('href'))
  161. .toEqual(OC.getRootPath() + '/index.php/apps/files?view=trashbin&dir=/subdir');
  162. });
  163. });
  164. describe('Rendering rows', function () {
  165. it('renders rows with the correct data when in root', function () {
  166. // dir listing is false when in root
  167. fileList.setFiles(testFiles);
  168. var $rows = fileList.$el.find('tbody tr');
  169. var $tr = $rows.eq(0);
  170. expect($rows.length).toEqual(4);
  171. expect($tr.attr('data-id')).toEqual('1');
  172. expect($tr.attr('data-type')).toEqual('file');
  173. expect($tr.attr('data-file')).toEqual('One.txt.d11111');
  174. expect($tr.attr('data-size')).not.toBeDefined();
  175. expect($tr.attr('data-etag')).toEqual('abc');
  176. expect($tr.attr('data-permissions')).toEqual('9'); // read and delete
  177. expect($tr.attr('data-mime')).toEqual('text/plain');
  178. expect($tr.attr('data-mtime')).toEqual('11111000');
  179. expect($tr.find('a.name').attr('href')).toEqual('#');
  180. expect($tr.find('.nametext').text().trim()).toEqual('One.txt');
  181. expect(fileList.findFileEl('One.txt.d11111')[0]).toEqual($tr[0]);
  182. });
  183. it('renders rows with the correct data when in root after calling setFiles with the same data set', function () {
  184. // dir listing is false when in root
  185. fileList.setFiles(testFiles);
  186. fileList.setFiles(fileList.files);
  187. var $rows = fileList.$el.find('tbody tr');
  188. var $tr = $rows.eq(0);
  189. expect($rows.length).toEqual(4);
  190. expect($tr.attr('data-id')).toEqual('1');
  191. expect($tr.attr('data-type')).toEqual('file');
  192. expect($tr.attr('data-file')).toEqual('One.txt.d11111');
  193. expect($tr.attr('data-size')).not.toBeDefined();
  194. expect($tr.attr('data-etag')).toEqual('abc');
  195. expect($tr.attr('data-permissions')).toEqual('9'); // read and delete
  196. expect($tr.attr('data-mime')).toEqual('text/plain');
  197. expect($tr.attr('data-mtime')).toEqual('11111000');
  198. expect($tr.find('a.name').attr('href')).toEqual('#');
  199. expect($tr.find('.nametext').text().trim()).toEqual('One.txt');
  200. expect(fileList.findFileEl('One.txt.d11111')[0]).toEqual($tr[0]);
  201. });
  202. it('renders rows with the correct data when in subdirectory', function () {
  203. fileList.setFiles(testFiles.map(function (file) {
  204. file.name = file.displayName;
  205. return file;
  206. }));
  207. var $rows = fileList.$el.find('tbody tr');
  208. var $tr = $rows.eq(0);
  209. expect($rows.length).toEqual(4);
  210. expect($tr.attr('data-id')).toEqual('1');
  211. expect($tr.attr('data-type')).toEqual('file');
  212. expect($tr.attr('data-file')).toEqual('One.txt');
  213. expect($tr.attr('data-size')).not.toBeDefined();
  214. expect($tr.attr('data-etag')).toEqual('abc');
  215. expect($tr.attr('data-permissions')).toEqual('9'); // read and delete
  216. expect($tr.attr('data-mime')).toEqual('text/plain');
  217. expect($tr.attr('data-mtime')).toEqual('11111000');
  218. expect($tr.find('a.name').attr('href')).toEqual('#');
  219. expect($tr.find('.nametext').text().trim()).toEqual('One.txt');
  220. expect(fileList.findFileEl('One.txt')[0]).toEqual($tr[0]);
  221. });
  222. it('does not render a size column', function () {
  223. expect(fileList.$el.find('tbody tr .filesize').length).toEqual(0);
  224. });
  225. });
  226. describe('File actions', function () {
  227. describe('Deleting single files', function () {
  228. // TODO: checks ajax call
  229. // TODO: checks spinner
  230. // TODO: remove item after delete
  231. // TODO: bring back item if delete failed
  232. });
  233. describe('Restoring single files', function () {
  234. // TODO: checks ajax call
  235. // TODO: checks spinner
  236. // TODO: remove item after restore
  237. // TODO: bring back item if restore failed
  238. });
  239. });
  240. describe('file previews', function () {
  241. // TODO: check that preview URL is going through files_trashbin
  242. });
  243. describe('loading file list', function () {
  244. // TODO: check that ajax URL is going through files_trashbin
  245. });
  246. describe('breadcrumbs', function () {
  247. // TODO: test label + URL
  248. });
  249. describe('elementToFile', function () {
  250. var $tr;
  251. beforeEach(function () {
  252. fileList.setFiles(testFiles);
  253. $tr = fileList.findFileEl('One.txt.d11111');
  254. });
  255. it('converts data attributes to file info structure', function () {
  256. var fileInfo = fileList.elementToFile($tr);
  257. expect(fileInfo.id).toEqual(1);
  258. expect(fileInfo.name).toEqual('One.txt.d11111');
  259. expect(fileInfo.displayName).toEqual('One.txt');
  260. expect(fileInfo.mtime).toEqual(11111000);
  261. expect(fileInfo.etag).toEqual('abc');
  262. expect(fileInfo.permissions).toEqual(OC.PERMISSION_READ | OC.PERMISSION_DELETE);
  263. expect(fileInfo.mimetype).toEqual('text/plain');
  264. expect(fileInfo.type).toEqual('file');
  265. });
  266. });
  267. describe('Global Actions', function () {
  268. beforeEach(function () {
  269. fileList.setFiles(testFiles);
  270. fileList.findFileEl('One.txt.d11111').find('input:checkbox').click();
  271. fileList.findFileEl('Three.pdf.d33333').find('input:checkbox').click();
  272. fileList.findFileEl('somedir.d99999').find('input:checkbox').click();
  273. fileList.$el.find('.actions-selected').click();
  274. });
  275. afterEach(function () {
  276. fileList.$el.find('.actions-selected').click();
  277. });
  278. describe('Delete', function () {
  279. it('Shows trashbin actions', function () {
  280. // visible because a few files were selected
  281. expect($('.selectedActions').is(':visible')).toEqual(true);
  282. expect($('.selectedActions .item-delete').is(':visible')).toEqual(true);
  283. expect($('.selectedActions .item-restore').is(':visible')).toEqual(true);
  284. // check
  285. fileList.$el.find('.select-all').click();
  286. // stays visible
  287. expect($('.selectedActions').is(':visible')).toEqual(true);
  288. expect($('.selectedActions .item-delete').is(':visible')).toEqual(true);
  289. expect($('.selectedActions .item-restore').is(':visible')).toEqual(true);
  290. // uncheck
  291. fileList.$el.find('.select-all').click();
  292. // becomes hidden now
  293. expect($('.selectedActions').is(':visible')).toEqual(false);
  294. expect($('.selectedActions .item-delete').is(':visible')).toEqual(false);
  295. expect($('.selectedActions .item-restore').is(':visible')).toEqual(false);
  296. });
  297. it('Deletes selected files when "Delete" clicked', function (done) {
  298. var request;
  299. var promise = fileList._onClickDeleteSelected({
  300. preventDefault: function () {
  301. }
  302. });
  303. var files = ["One.txt.d11111", "Three.pdf.d33333", "somedir.d99999"];
  304. expect(fakeServer.requests.length).toEqual(files.length);
  305. for (var i = 0; i < files.length; i++) {
  306. request = fakeServer.requests[i];
  307. expect(request.url).toEqual(OC.getRootPath() + '/remote.php/dav/trashbin/user/trash/' + files[i]);
  308. request.respond(200);
  309. }
  310. return promise.then(function () {
  311. expect(fileList.findFileEl('One.txt.d11111').length).toEqual(0);
  312. expect(fileList.findFileEl('Three.pdf.d33333').length).toEqual(0);
  313. expect(fileList.findFileEl('somedir.d99999').length).toEqual(0);
  314. expect(fileList.findFileEl('Two.jpg.d22222').length).toEqual(1);
  315. }).then(done, done);
  316. });
  317. it('Deletes all files when all selected when "Delete" clicked', function (done) {
  318. var request;
  319. $('.select-all').click();
  320. var promise = fileList._onClickDeleteSelected({
  321. preventDefault: function () {
  322. }
  323. });
  324. expect(fakeServer.requests.length).toEqual(1);
  325. request = fakeServer.requests[0];
  326. expect(request.url).toEqual(OC.getRootPath() + '/remote.php/dav/trashbin/user/trash');
  327. request.respond(200);
  328. return promise.then(function () {
  329. expect(fileList.isEmpty).toEqual(true);
  330. }).then(done, done);
  331. });
  332. });
  333. describe('Restore', function () {
  334. it('Restores selected files when "Restore" clicked', function (done) {
  335. var request;
  336. var promise = fileList._onClickRestoreSelected({
  337. preventDefault: function () {
  338. }
  339. });
  340. var files = ["One.txt.d11111", "Three.pdf.d33333", "somedir.d99999"];
  341. expect(fakeServer.requests.length).toEqual(files.length);
  342. for (var i = 0; i < files.length; i++) {
  343. request = fakeServer.requests[i];
  344. expect(request.url).toEqual(OC.getRootPath() + '/remote.php/dav/trashbin/user/trash/' + files[i]);
  345. expect(request.requestHeaders.Destination).toEqual(OC.getRootPath() + '/remote.php/dav/trashbin/user/restore/' + files[i]);
  346. request.respond(200);
  347. }
  348. return promise.then(function() {
  349. expect(fileList.findFileEl('One.txt.d11111').length).toEqual(0);
  350. expect(fileList.findFileEl('Three.pdf.d33333').length).toEqual(0);
  351. expect(fileList.findFileEl('somedir.d99999').length).toEqual(0);
  352. expect(fileList.findFileEl('Two.jpg.d22222').length).toEqual(1);
  353. }).then(done, done);
  354. });
  355. it('Restores all files when all selected when "Restore" clicked', function (done) {
  356. var request;
  357. $('.select-all').click();
  358. var promise = fileList._onClickRestoreSelected({
  359. preventDefault: function () {
  360. }
  361. });
  362. var files = ["One.txt.d11111", "Two.jpg.d22222", "Three.pdf.d33333", "somedir.d99999"];
  363. expect(fakeServer.requests.length).toEqual(files.length);
  364. for (var i = 0; i < files.length; i++) {
  365. request = fakeServer.requests[i];
  366. expect(request.url).toEqual(OC.getRootPath() + '/remote.php/dav/trashbin/user/trash/' + files[i]);
  367. expect(request.requestHeaders.Destination).toEqual(OC.getRootPath() + '/remote.php/dav/trashbin/user/restore/' + files[i]);
  368. request.respond(200);
  369. }
  370. return promise.then(function() {
  371. expect(fileList.isEmpty).toEqual(true);
  372. }).then(done, done);
  373. });
  374. });
  375. });
  376. });