filelistSpec.js 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398
  1. /**
  2. * ownCloud
  3. *
  4. * @author Vincent Petry
  5. * @copyright 2014 Vincent Petry <pvince81@owncloud.com>
  6. *
  7. * This library is free software; you can redistribute it and/or
  8. * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
  9. * License as published by the Free Software Foundation; either
  10. * version 3 of the License, or any later version.
  11. *
  12. * This library is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. * GNU AFFERO GENERAL PUBLIC LICENSE for more details.
  16. *
  17. * You should have received a copy of the GNU Affero General Public
  18. * License along with this library. If not, see <http://www.gnu.org/licenses/>.
  19. *
  20. */
  21. describe('OCA.Trashbin.FileList tests', function () {
  22. var testFiles, alertStub, notificationStub, fileList, client;
  23. beforeEach(function () {
  24. alertStub = sinon.stub(OC.dialogs, 'alert');
  25. notificationStub = sinon.stub(OC.Notification, 'show');
  26. client = new OC.Files.Client({
  27. host: 'localhost',
  28. port: 80,
  29. root: '/remote.php/dav/trashbin/user',
  30. useHTTPS: OC.getProtocol() === 'https'
  31. });
  32. // init parameters and test table elements
  33. $('#testArea').append(
  34. '<div id="app-content-trashbin">' +
  35. // init horrible parameters
  36. '<input type="hidden" id="dir" value="/"></input>' +
  37. // set this but it shouldn't be used (could be the one from the
  38. // files app)
  39. '<input type="hidden" id="permissions" value="31"></input>' +
  40. // dummy controls
  41. '<div id="controls">' +
  42. ' <div class="actions creatable"></div>' +
  43. ' <div class="notCreatable"></div>' +
  44. '</div>' +
  45. // dummy table
  46. // TODO: at some point this will be rendered by the fileList class itself!
  47. '<table id="filestable" class="list-container view-grid">' +
  48. '<thead><tr><th id="headerName" class="hidden">' +
  49. '<input type="checkbox" id="select_all_trash" class="select-all">' +
  50. '<span class="name">Name</span>' +
  51. '<span class="selectedActions hidden">' +
  52. '<a href="" class="actions-selected"><span class="icon icon-more"></span><span>Actions</span>' +
  53. '</span>' +
  54. '</th></tr></thead>' +
  55. '<tbody id="fileList"></tbody>' +
  56. '<tfoot></tfoot>' +
  57. '</table>' +
  58. '<div id="emptycontent">Empty content message</div>' +
  59. '</div>'
  60. );
  61. testFiles = [{
  62. id: 1,
  63. type: 'file',
  64. name: 'One.txt.d11111',
  65. displayName: 'One.txt',
  66. mtime: 11111000,
  67. mimetype: 'text/plain',
  68. etag: 'abc'
  69. }, {
  70. id: 2,
  71. type: 'file',
  72. name: 'Two.jpg.d22222',
  73. displayName: 'Two.jpg',
  74. mtime: 22222000,
  75. mimetype: 'image/jpeg',
  76. etag: 'def',
  77. }, {
  78. id: 3,
  79. type: 'file',
  80. name: 'Three.pdf.d33333',
  81. displayName: 'Three.pdf',
  82. mtime: 33333000,
  83. mimetype: 'application/pdf',
  84. etag: '123',
  85. }, {
  86. id: 4,
  87. type: 'dir',
  88. mtime: 99999000,
  89. name: 'somedir.d99999',
  90. displayName: 'somedir',
  91. mimetype: 'httpd/unix-directory',
  92. etag: '456'
  93. }];
  94. // register file actions like the trashbin App does
  95. var fileActions = OCA.Trashbin.App._createFileActions(fileList);
  96. fileList = new OCA.Trashbin.FileList(
  97. $('#app-content-trashbin'), {
  98. fileActions: fileActions,
  99. multiSelectMenu: [{
  100. name: 'restore',
  101. displayName: t('files', 'Restore'),
  102. iconClass: 'icon-history',
  103. },
  104. {
  105. name: 'delete',
  106. displayName: t('files', 'Delete'),
  107. iconClass: 'icon-delete',
  108. }
  109. ],
  110. client: client
  111. }
  112. );
  113. });
  114. afterEach(function () {
  115. testFiles = undefined;
  116. fileList.destroy();
  117. fileList = undefined;
  118. $('#dir').remove();
  119. notificationStub.restore();
  120. alertStub.restore();
  121. });
  122. describe('Initialization', function () {
  123. it('Sorts by mtime by default', function () {
  124. expect(fileList._sort).toEqual('mtime');
  125. expect(fileList._sortDirection).toEqual('desc');
  126. });
  127. it('Always returns read and delete permission', function () {
  128. expect(fileList.getDirectoryPermissions()).toEqual(OC.PERMISSION_READ | OC.PERMISSION_DELETE);
  129. });
  130. });
  131. describe('Breadcrumbs', function () {
  132. beforeEach(function () {
  133. var data = {
  134. status: 'success',
  135. data: {
  136. files: testFiles,
  137. permissions: 1
  138. }
  139. };
  140. fakeServer.respondWith(/\/index\.php\/apps\/files_trashbin\/ajax\/list.php\?dir=%2Fsubdir/, [
  141. 200, {
  142. "Content-Type": "application/json"
  143. },
  144. JSON.stringify(data)
  145. ]);
  146. });
  147. it('links the breadcrumb to the trashbin view', function () {
  148. fileList.changeDirectory('/subdir', false, true);
  149. fakeServer.respond();
  150. var $crumbs = fileList.$el.find('#controls .crumb');
  151. expect($crumbs.length).toEqual(3);
  152. expect($crumbs.eq(1).find('a').text()).toEqual('Home');
  153. expect($crumbs.eq(1).find('a').attr('href'))
  154. .toEqual(OC.getRootPath() + '/index.php/apps/files?view=trashbin&dir=/');
  155. expect($crumbs.eq(2).find('a').text()).toEqual('subdir');
  156. expect($crumbs.eq(2).find('a').attr('href'))
  157. .toEqual(OC.getRootPath() + '/index.php/apps/files?view=trashbin&dir=/subdir');
  158. });
  159. });
  160. describe('Rendering rows', function () {
  161. it('renders rows with the correct data when in root', function () {
  162. // dir listing is false when in root
  163. $('#dir').val('/');
  164. fileList.setFiles(testFiles);
  165. var $rows = fileList.$el.find('tbody tr');
  166. var $tr = $rows.eq(0);
  167. expect($rows.length).toEqual(4);
  168. expect($tr.attr('data-id')).toEqual('1');
  169. expect($tr.attr('data-type')).toEqual('file');
  170. expect($tr.attr('data-file')).toEqual('One.txt.d11111');
  171. expect($tr.attr('data-size')).not.toBeDefined();
  172. expect($tr.attr('data-etag')).toEqual('abc');
  173. expect($tr.attr('data-permissions')).toEqual('9'); // read and delete
  174. expect($tr.attr('data-mime')).toEqual('text/plain');
  175. expect($tr.attr('data-mtime')).toEqual('11111000');
  176. expect($tr.find('a.name').attr('href')).toEqual('#');
  177. expect($tr.find('.nametext').text().trim()).toEqual('One.txt');
  178. expect(fileList.findFileEl('One.txt.d11111')[0]).toEqual($tr[0]);
  179. });
  180. it('renders rows with the correct data when in root after calling setFiles with the same data set', function () {
  181. // dir listing is false when in root
  182. $('#dir').val('/');
  183. fileList.setFiles(testFiles);
  184. fileList.setFiles(fileList.files);
  185. var $rows = fileList.$el.find('tbody tr');
  186. var $tr = $rows.eq(0);
  187. expect($rows.length).toEqual(4);
  188. expect($tr.attr('data-id')).toEqual('1');
  189. expect($tr.attr('data-type')).toEqual('file');
  190. expect($tr.attr('data-file')).toEqual('One.txt.d11111');
  191. expect($tr.attr('data-size')).not.toBeDefined();
  192. expect($tr.attr('data-etag')).toEqual('abc');
  193. expect($tr.attr('data-permissions')).toEqual('9'); // read and delete
  194. expect($tr.attr('data-mime')).toEqual('text/plain');
  195. expect($tr.attr('data-mtime')).toEqual('11111000');
  196. expect($tr.find('a.name').attr('href')).toEqual('#');
  197. expect($tr.find('.nametext').text().trim()).toEqual('One.txt');
  198. expect(fileList.findFileEl('One.txt.d11111')[0]).toEqual($tr[0]);
  199. });
  200. it('renders rows with the correct data when in subdirectory', function () {
  201. // dir listing is true when in a subdir
  202. $('#dir').val('/subdir');
  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 () {
  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. });
  316. });
  317. it('Deletes all files when all selected when "Delete" clicked', function () {
  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. });
  331. });
  332. });
  333. describe('Restore', function () {
  334. it('Restores selected files when "Restore" clicked', function () {
  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. });
  354. });
  355. it('Restores all files when all selected when "Restore" clicked', function () {
  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. });
  373. });
  374. });
  375. });
  376. });