delete-entity.spec.tsx 8.5 KB

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