detailsviewSpec.js 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240
  1. /**
  2. * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors
  3. * SPDX-FileCopyrightText: 2015 ownCloud, Inc.
  4. * SPDX-License-Identifier: AGPL-3.0-or-later
  5. */
  6. describe('OCA.Files.DetailsView tests', function() {
  7. var detailsView;
  8. beforeEach(function() {
  9. detailsView = new OCA.Files.DetailsView();
  10. });
  11. afterEach(function() {
  12. detailsView.remove();
  13. detailsView = undefined;
  14. });
  15. it('renders itself empty when nothing registered', function() {
  16. detailsView.render();
  17. expect(detailsView.$el.find('.detailFileInfoContainer').length).toEqual(1);
  18. expect(detailsView.$el.find('.tabsContainer').length).toEqual(1);
  19. });
  20. describe('file info detail view', function() {
  21. it('returns registered view', function() {
  22. var testView = new OCA.Files.DetailFileInfoView();
  23. var testView2 = new OCA.Files.DetailFileInfoView();
  24. detailsView.addDetailView(testView);
  25. detailsView.addDetailView(testView2);
  26. detailViews = detailsView.getDetailViews();
  27. expect(detailViews).toContain(testView);
  28. expect(detailViews).toContain(testView2);
  29. // Modify array and check that registered detail views are not
  30. // modified
  31. detailViews.pop();
  32. detailViews.pop();
  33. detailViews = detailsView.getDetailViews();
  34. expect(detailViews).toContain(testView);
  35. expect(detailViews).toContain(testView2);
  36. });
  37. it('renders registered view', function() {
  38. var testView = new OCA.Files.DetailFileInfoView();
  39. var testView2 = new OCA.Files.DetailFileInfoView();
  40. detailsView.addDetailView(testView);
  41. detailsView.addDetailView(testView2);
  42. detailsView.render();
  43. expect(detailsView.$el.find('.detailFileInfoContainer .detailFileInfoView').length).toEqual(2);
  44. });
  45. it('updates registered tabs when fileinfo is updated', function() {
  46. var viewRenderStub = sinon.stub(OCA.Files.DetailFileInfoView.prototype, 'render');
  47. var testView = new OCA.Files.DetailFileInfoView();
  48. var testView2 = new OCA.Files.DetailFileInfoView();
  49. detailsView.addDetailView(testView);
  50. detailsView.addDetailView(testView2);
  51. detailsView.render();
  52. var fileInfo = {id: 5, name: 'test.txt'};
  53. viewRenderStub.reset();
  54. detailsView.setFileInfo(fileInfo);
  55. expect(testView.getFileInfo()).toEqual(fileInfo);
  56. expect(testView2.getFileInfo()).toEqual(fileInfo);
  57. expect(viewRenderStub.callCount).toEqual(2);
  58. viewRenderStub.restore();
  59. });
  60. });
  61. describe('tabs', function() {
  62. var testView, testView2;
  63. beforeEach(function() {
  64. testView = new OCA.Files.DetailTabView({id: 'test1'});
  65. testView2 = new OCA.Files.DetailTabView({id: 'test2'});
  66. detailsView.addTabView(testView);
  67. detailsView.addTabView(testView2);
  68. detailsView.render();
  69. });
  70. it('initially renders only the selected tab', function() {
  71. expect(detailsView.$el.find('.tab').length).toEqual(1);
  72. expect(detailsView.$el.find('.tab').attr('id')).toEqual('test1');
  73. });
  74. it('updates tab model and rerenders on-demand as soon as it gets selected', function() {
  75. var tab1RenderStub = sinon.stub(testView, 'render');
  76. var tab2RenderStub = sinon.stub(testView2, 'render');
  77. var fileInfo1 = new OCA.Files.FileInfoModel({id: 5, name: 'test.txt'});
  78. var fileInfo2 = new OCA.Files.FileInfoModel({id: 8, name: 'test2.txt'});
  79. detailsView.setFileInfo(fileInfo1);
  80. // first tab renders, not the second one
  81. expect(tab1RenderStub.calledOnce).toEqual(true);
  82. expect(tab2RenderStub.notCalled).toEqual(true);
  83. // info got set only to the first visible tab
  84. expect(testView.getFileInfo()).toEqual(fileInfo1);
  85. expect(testView2.getFileInfo()).toBeUndefined();
  86. // select second tab for first render
  87. detailsView.$el.find('.tabHeader').eq(1).click();
  88. // second tab got rendered
  89. expect(tab2RenderStub.calledOnce).toEqual(true);
  90. expect(testView2.getFileInfo()).toEqual(fileInfo1);
  91. // select the first tab again
  92. detailsView.$el.find('.tabHeader').eq(0).click();
  93. // no re-render
  94. expect(tab1RenderStub.calledOnce).toEqual(true);
  95. expect(tab2RenderStub.calledOnce).toEqual(true);
  96. tab1RenderStub.reset();
  97. tab2RenderStub.reset();
  98. // switch to another file
  99. detailsView.setFileInfo(fileInfo2);
  100. // only the visible tab was updated and rerendered
  101. expect(tab1RenderStub.calledOnce).toEqual(true);
  102. expect(testView.getFileInfo()).toEqual(fileInfo2);
  103. // second/invisible tab still has old info, not rerendered
  104. expect(tab2RenderStub.notCalled).toEqual(true);
  105. expect(testView2.getFileInfo()).toEqual(fileInfo1);
  106. // reselect the second one
  107. detailsView.$el.find('.tabHeader').eq(1).click();
  108. // second tab becomes visible, updated and rendered
  109. expect(testView2.getFileInfo()).toEqual(fileInfo2);
  110. expect(tab2RenderStub.calledOnce).toEqual(true);
  111. tab1RenderStub.restore();
  112. tab2RenderStub.restore();
  113. });
  114. it('selects the first tab by default', function() {
  115. expect(detailsView.$el.find('.tabHeader').eq(0).hasClass('selected')).toEqual(true);
  116. expect(detailsView.$el.find('.tabHeader').eq(1).hasClass('selected')).toEqual(false);
  117. expect(detailsView.$el.find('.tab').eq(0).hasClass('hidden')).toEqual(false);
  118. expect(detailsView.$el.find('.tab').eq(1).length).toEqual(0);
  119. });
  120. it('switches the current tab when clicking on tab header', function() {
  121. detailsView.$el.find('.tabHeader').eq(1).click();
  122. expect(detailsView.$el.find('.tabHeader').eq(0).hasClass('selected')).toEqual(false);
  123. expect(detailsView.$el.find('.tabHeader').eq(1).hasClass('selected')).toEqual(true);
  124. expect(detailsView.$el.find('.tab').eq(0).hasClass('hidden')).toEqual(true);
  125. expect(detailsView.$el.find('.tab').eq(1).hasClass('hidden')).toEqual(false);
  126. });
  127. describe('tab visibility', function() {
  128. beforeEach(function() {
  129. detailsView.remove();
  130. detailsView = new OCA.Files.DetailsView();
  131. });
  132. it('does not display tab headers when only one tab exists', function() {
  133. testView = new OCA.Files.DetailTabView({id: 'test1'});
  134. detailsView.addTabView(testView);
  135. detailsView.render();
  136. expect(detailsView.$el.find('.tabHeaders').hasClass('hidden')).toEqual(true);
  137. expect(detailsView.$el.find('.tabHeader').length).toEqual(1);
  138. });
  139. it('does not display tab that do not pass visibility check', function() {
  140. testView = new OCA.Files.DetailTabView({id: 'test1'});
  141. testView.canDisplay = sinon.stub().returns(false);
  142. testView2 = new OCA.Files.DetailTabView({id: 'test2'});
  143. var testView3 = new OCA.Files.DetailTabView({id: 'test3'});
  144. detailsView.addTabView(testView);
  145. detailsView.addTabView(testView2);
  146. detailsView.addTabView(testView3);
  147. var fileInfo = {id: 5, name: 'test.txt'};
  148. detailsView.setFileInfo(fileInfo);
  149. expect(testView.canDisplay.calledOnce).toEqual(true);
  150. expect(testView.canDisplay.calledWith(fileInfo)).toEqual(true);
  151. expect(detailsView.$el.find('.tabHeaders').hasClass('hidden')).toEqual(false);
  152. expect(detailsView.$el.find('.tabHeader[data-tabid=test1]').hasClass('hidden')).toEqual(true);
  153. expect(detailsView.$el.find('.tabHeader[data-tabid=test2]').hasClass('hidden')).toEqual(false);
  154. expect(detailsView.$el.find('.tabHeader[data-tabid=test3]').hasClass('hidden')).toEqual(false);
  155. });
  156. it('does not show tab headers if only one header is visible due to visibility check', function() {
  157. testView = new OCA.Files.DetailTabView({id: 'test1'});
  158. testView.canDisplay = sinon.stub().returns(false);
  159. testView2 = new OCA.Files.DetailTabView({id: 'test2'});
  160. detailsView.addTabView(testView);
  161. detailsView.addTabView(testView2);
  162. var fileInfo = {id: 5, name: 'test.txt'};
  163. detailsView.setFileInfo(fileInfo);
  164. expect(testView.canDisplay.calledOnce).toEqual(true);
  165. expect(testView.canDisplay.calledWith(fileInfo)).toEqual(true);
  166. expect(detailsView.$el.find('.tabHeaders').hasClass('hidden')).toEqual(true);
  167. expect(detailsView.$el.find('.tabHeader[data-tabid=test1]').hasClass('hidden')).toEqual(true);
  168. expect(detailsView.$el.find('.tabHeader[data-tabid=test2]').hasClass('hidden')).toEqual(false);
  169. });
  170. it('deselects the current tab if a model update does not pass the visibility check', function() {
  171. testView = new OCA.Files.DetailTabView({id: 'test1'});
  172. testView.canDisplay = function(fileInfo) {
  173. return fileInfo.mimetype !== 'httpd/unix-directory';
  174. };
  175. testView2 = new OCA.Files.DetailTabView({id: 'test2'});
  176. detailsView.addTabView(testView);
  177. detailsView.addTabView(testView2);
  178. var fileInfo = {id: 5, name: 'test.txt', mimetype: 'text/plain'};
  179. detailsView.setFileInfo(fileInfo);
  180. expect(detailsView.$el.find('.tabHeader[data-tabid=test1]').hasClass('selected')).toEqual(true);
  181. expect(detailsView.$el.find('.tabHeader[data-tabid=test2]').hasClass('selected')).toEqual(false);
  182. detailsView.setFileInfo({id: 10, name: 'folder', mimetype: 'httpd/unix-directory'});
  183. expect(detailsView.$el.find('.tabHeader[data-tabid=test1]').hasClass('selected')).toEqual(false);
  184. expect(detailsView.$el.find('.tabHeader[data-tabid=test2]').hasClass('selected')).toEqual(true);
  185. });
  186. });
  187. it('sorts by order and then label', function() {
  188. detailsView.remove();
  189. detailsView = new OCA.Files.DetailsView();
  190. detailsView.addTabView(new OCA.Files.DetailTabView({id: 'abc', order: 20}));
  191. detailsView.addTabView(new OCA.Files.DetailTabView({id: 'def', order: 10}));
  192. detailsView.addTabView(new OCA.Files.DetailTabView({id: 'jkl'}));
  193. detailsView.addTabView(new OCA.Files.DetailTabView({id: 'ghi'}));
  194. detailsView.render();
  195. var tabs = detailsView.$el.find('.tabHeader').map(function() {
  196. return $(this).attr('data-tabid');
  197. }).toArray();
  198. expect(tabs).toEqual(['ghi', 'jkl', 'def', 'abc']);
  199. });
  200. });
  201. });