delete-entity.spec.tsx 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282
  1. // @ts-ignore
  2. import MockedSocket from 'socket.io-mock'
  3. import FileTreeRoot from '../../../../../frontend/js/features/file-tree/components/file-tree-root'
  4. import { EditorProviders } from '../../../helpers/editor-providers'
  5. describe('FileTree Delete Entity Flow', function () {
  6. beforeEach(function () {
  7. cy.window().then(win => {
  8. win.metaAttributesCache.set('ol-user', { id: 'user1' })
  9. })
  10. })
  11. describe('single entity', function () {
  12. beforeEach(function () {
  13. const rootFolder = [
  14. {
  15. _id: 'root-folder-id',
  16. name: 'rootFolder',
  17. docs: [
  18. { _id: '123abc', name: 'foo.tex' },
  19. { _id: '456def', name: 'main.tex' },
  20. ],
  21. folders: [],
  22. fileRefs: [],
  23. },
  24. ]
  25. cy.mount(
  26. <EditorProviders
  27. rootFolder={rootFolder as any}
  28. projectId="123abc"
  29. socket={new MockedSocket()}
  30. >
  31. <FileTreeRoot
  32. refProviders={{}}
  33. reindexReferences={cy.stub().as('reindexReferences')}
  34. setRefProviderEnabled={cy.stub()}
  35. setStartedFreeTrial={cy.stub()}
  36. onSelect={cy.stub()}
  37. onInit={cy.stub()}
  38. isConnected
  39. />
  40. </EditorProviders>
  41. )
  42. cy.findByRole('treeitem', { name: 'main.tex' }).click()
  43. cy.findByRole('button', { name: 'Menu' }).click()
  44. cy.findByRole('menuitem', { name: 'Delete' }).click()
  45. })
  46. it('removes item', function () {
  47. cy.intercept('delete', '/project/*/doc/*', { statusCode: 204 }).as(
  48. 'deleteDoc'
  49. )
  50. // check that the confirmation modal is open
  51. cy.findByText(
  52. 'Are you sure you want to permanently delete the following files?'
  53. )
  54. cy.findByRole('button', { name: 'Delete' }).click()
  55. cy.wait('@deleteDoc')
  56. cy.window().then(win => {
  57. // @ts-ignore
  58. win._ide.socket.socketClient.emit('removeEntity', '456def')
  59. })
  60. cy.findByRole('treeitem', {
  61. name: 'main.tex',
  62. hidden: true, // treeitem might be hidden behind the modal
  63. }).should('not.exist')
  64. cy.findByRole('treeitem', {
  65. name: 'main.tex',
  66. }).should('not.exist')
  67. // check that the confirmation modal is closed
  68. cy.findByText(
  69. 'Are you sure you want to permanently delete the following files?'
  70. ).should('not.exist')
  71. cy.get('@deleteDoc.all').should('have.length', 1)
  72. cy.get('@reindexReferences').should('not.have.been.called')
  73. })
  74. it('continues delete on 404s', function () {
  75. cy.intercept('delete', '/project/*/doc/*', { statusCode: 404 }).as(
  76. 'deleteDoc'
  77. )
  78. // check that the confirmation modal is open
  79. cy.findByText(
  80. 'Are you sure you want to permanently delete the following files?'
  81. )
  82. cy.findByRole('button', { name: 'Delete' }).click()
  83. cy.window().then(win => {
  84. // @ts-ignore
  85. win._ide.socket.socketClient.emit('removeEntity', '456def')
  86. })
  87. cy.findByRole('treeitem', {
  88. name: 'main.tex',
  89. hidden: true, // treeitem might be hidden behind the modal
  90. }).should('not.exist')
  91. cy.findByRole('treeitem', {
  92. name: 'main.tex',
  93. }).should('not.exist')
  94. // check that the confirmation modal is closed
  95. // is not, the 404 probably triggered a bug
  96. cy.findByText(
  97. 'Are you sure you want to permanently delete the following files?'
  98. ).should('not.exist')
  99. })
  100. it('aborts delete on error', function () {
  101. cy.intercept('delete', '/project/*/doc/*', { statusCode: 500 }).as(
  102. 'deleteDoc'
  103. )
  104. cy.findByRole('button', { name: 'Delete' }).click()
  105. // The modal should still be open, but the file should not be deleted
  106. cy.findByRole('treeitem', { name: 'main.tex', hidden: true })
  107. })
  108. })
  109. describe('folders', function () {
  110. beforeEach(function () {
  111. const rootFolder = [
  112. {
  113. _id: 'root-folder-id',
  114. name: 'rootFolder',
  115. docs: [{ _id: '456def', name: 'main.tex' }],
  116. folders: [
  117. {
  118. _id: '123abc',
  119. name: 'folder',
  120. docs: [],
  121. folders: [],
  122. fileRefs: [{ _id: '789ghi', name: 'my.bib' }],
  123. },
  124. ],
  125. fileRefs: [],
  126. },
  127. ]
  128. cy.mount(
  129. <EditorProviders
  130. rootFolder={rootFolder as any}
  131. projectId="123abc"
  132. socket={new MockedSocket()}
  133. >
  134. <FileTreeRoot
  135. refProviders={{}}
  136. reindexReferences={cy.stub().as('reindexReferences')}
  137. setRefProviderEnabled={cy.stub()}
  138. setStartedFreeTrial={cy.stub()}
  139. onSelect={cy.stub()}
  140. onInit={cy.stub()}
  141. isConnected
  142. />
  143. </EditorProviders>
  144. )
  145. cy.findByRole('button', { name: 'Expand' }).click()
  146. cy.findByRole('treeitem', { name: 'main.tex' }).click()
  147. cy.findByRole('treeitem', { name: 'my.bib' }).click({
  148. ctrlKey: true,
  149. cmdKey: true,
  150. })
  151. cy.window().then(win => {
  152. // @ts-ignore
  153. win._ide.socket.socketClient.emit('removeEntity', '123abc')
  154. })
  155. })
  156. it('removes the folder', function () {
  157. cy.findByRole('treeitem', { name: 'folder' }).should('not.exist')
  158. })
  159. it('leaves the main file selected', function () {
  160. cy.findByRole('treeitem', { name: 'main.tex', selected: true })
  161. })
  162. it('unselect the child entity', function () {
  163. // as a proxy to check that the child entity has been unselect we start
  164. // a delete and ensure the modal is displayed (the cancel button can be
  165. // selected) This is needed to make sure the test fail.
  166. cy.findByRole('button', { name: 'Menu' }).click()
  167. cy.findByRole('menuitem', { name: 'Delete' }).click()
  168. cy.findByRole('button', { name: 'Cancel' })
  169. })
  170. })
  171. describe('multiple entities', function () {
  172. beforeEach(function () {
  173. const rootFolder = [
  174. {
  175. _id: 'root-folder-id',
  176. name: 'rootFolder',
  177. docs: [{ _id: '456def', name: 'main.tex' }],
  178. folders: [],
  179. fileRefs: [{ _id: '789ghi', name: 'my.bib' }],
  180. },
  181. ]
  182. cy.mount(
  183. <EditorProviders
  184. rootFolder={rootFolder as any}
  185. projectId="123abc"
  186. socket={new MockedSocket()}
  187. >
  188. <FileTreeRoot
  189. refProviders={{}}
  190. reindexReferences={cy.stub().as('reindexReferences')}
  191. setRefProviderEnabled={cy.stub()}
  192. setStartedFreeTrial={cy.stub()}
  193. onSelect={cy.stub()}
  194. onInit={cy.stub()}
  195. isConnected
  196. />
  197. </EditorProviders>
  198. )
  199. // select two files
  200. cy.findByRole('treeitem', { name: 'main.tex' }).click()
  201. cy.findByRole('treeitem', { name: 'my.bib' }).click({
  202. ctrlKey: true,
  203. cmdKey: true,
  204. })
  205. // open the context menu
  206. cy.findByRole('button', { name: 'my.bib' }).trigger('contextmenu')
  207. // make sure the menu has opened, with only a "Delete" item (as multiple files are selected)
  208. cy.findByRole('menu')
  209. cy.findAllByRole('menuitem').should('have.length', 1)
  210. // select the Delete menu item
  211. cy.findByRole('menuitem', { name: 'Delete' }).click()
  212. })
  213. it('removes all items and reindexes references after deleting .bib file', function () {
  214. cy.intercept('delete', '/project/123abc/doc/456def', {
  215. statusCode: 204,
  216. }).as('deleteDoc')
  217. cy.intercept('delete', '/project/123abc/file/789ghi', {
  218. statusCode: 204,
  219. }).as('deleteFile')
  220. cy.findByRole('button', { name: 'Delete' }).click()
  221. cy.window().then(win => {
  222. // @ts-ignore
  223. win._ide.socket.socketClient.emit('removeEntity', '456def')
  224. // @ts-ignore
  225. win._ide.socket.socketClient.emit('removeEntity', '789ghi')
  226. })
  227. for (const name of ['main.tex', 'my.bib']) {
  228. for (const hidden of [true, false]) {
  229. cy.findByRole('treeitem', { name, hidden }).should('not.exist')
  230. }
  231. }
  232. // check that the confirmation modal is closed
  233. cy.findByText('Are you sure').should('not.exist')
  234. cy.get('@deleteDoc.all').should('have.length', 1)
  235. cy.get('@deleteFile.all').should('have.length', 1)
  236. cy.get('@reindexReferences').should('have.been.calledOnce')
  237. })
  238. })
  239. })