file-tree-root.spec.tsx 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354
  1. import FileTreeRoot from '../../../../../frontend/js/features/file-tree/components/file-tree-root'
  2. import { EditorProviders } from '../../../helpers/editor-providers'
  3. import { SocketIOMock } from '@/ide/connection/SocketIoShim'
  4. describe('<FileTreeRoot/>', function () {
  5. beforeEach(function () {
  6. cy.window().then(win => {
  7. win.metaAttributesCache.set('ol-user', { id: 'user1' })
  8. })
  9. })
  10. it('renders', function () {
  11. const rootFolder = [
  12. {
  13. _id: 'root-folder-id',
  14. name: 'rootFolder',
  15. docs: [{ _id: '456def', name: 'main.tex' }],
  16. folders: [],
  17. fileRefs: [],
  18. },
  19. ]
  20. cy.mount(
  21. <EditorProviders
  22. rootFolder={rootFolder as any}
  23. projectId="123abc"
  24. rootDocId="456def"
  25. features={{} as any}
  26. permissionsLevel="owner"
  27. >
  28. <FileTreeRoot
  29. refProviders={{}}
  30. setRefProviderEnabled={cy.stub()}
  31. setStartedFreeTrial={cy.stub()}
  32. onSelect={cy.stub()}
  33. onInit={cy.stub()}
  34. isConnected
  35. />
  36. </EditorProviders>
  37. )
  38. cy.findByRole('tree')
  39. cy.findByRole('treeitem')
  40. cy.findByRole('treeitem', { name: 'main.tex', selected: true })
  41. cy.get('.disconnected-overlay').should('not.exist')
  42. })
  43. it('renders with invalid selected doc in local storage', function () {
  44. global.localStorage.setItem(
  45. 'doc.open_id.123abc',
  46. JSON.stringify('not-a-valid-id')
  47. )
  48. const rootFolder = [
  49. {
  50. _id: 'root-folder-id',
  51. name: 'rootFolder',
  52. docs: [{ _id: '456def', name: 'main.tex' }],
  53. folders: [],
  54. fileRefs: [],
  55. },
  56. ]
  57. cy.mount(
  58. <div style={{ width: 400 }}>
  59. <EditorProviders
  60. rootFolder={rootFolder as any}
  61. projectId="123abc"
  62. rootDocId="456def"
  63. features={{} as any}
  64. permissionsLevel="owner"
  65. >
  66. <FileTreeRoot
  67. refProviders={{}}
  68. setRefProviderEnabled={cy.stub()}
  69. setStartedFreeTrial={cy.stub()}
  70. onSelect={cy.stub()}
  71. onInit={cy.stub()}
  72. isConnected
  73. />
  74. </EditorProviders>
  75. </div>
  76. )
  77. // as a proxy to check that the invalid entity has not been select we start
  78. // a delete and ensure the modal is displayed (the cancel button can be
  79. // selected) This is needed to make sure the test fail.
  80. cy.findByRole('treeitem', { name: 'main.tex' }).click({
  81. ctrlKey: true,
  82. cmdKey: true,
  83. })
  84. cy.findByRole('button', { name: 'Open main.tex action menu' }).click()
  85. cy.findByRole('menuitem', { name: 'Delete' }).click()
  86. cy.findByRole('button', { name: 'Cancel' })
  87. })
  88. it('renders disconnected overlay', function () {
  89. const rootFolder = [
  90. {
  91. _id: 'root-folder-id',
  92. name: 'rootFolder',
  93. docs: [{ _id: '456def', name: 'main.tex' }],
  94. folders: [],
  95. fileRefs: [],
  96. },
  97. ]
  98. cy.mount(
  99. <EditorProviders
  100. rootFolder={rootFolder as any}
  101. projectId="123abc"
  102. rootDocId="456def"
  103. features={{} as any}
  104. permissionsLevel="owner"
  105. >
  106. <FileTreeRoot
  107. refProviders={{}}
  108. setRefProviderEnabled={cy.stub()}
  109. setStartedFreeTrial={cy.stub()}
  110. onSelect={cy.stub()}
  111. onInit={cy.stub()}
  112. isConnected={false}
  113. />
  114. </EditorProviders>
  115. )
  116. cy.get('.disconnected-overlay')
  117. })
  118. it('fire onSelect', function () {
  119. const rootFolder = [
  120. {
  121. _id: 'root-folder-id',
  122. name: 'rootFolder',
  123. docs: [
  124. { _id: '456def', name: 'main.tex' },
  125. { _id: '789ghi', name: 'other.tex' },
  126. ],
  127. folders: [],
  128. fileRefs: [],
  129. },
  130. ]
  131. cy.mount(
  132. <EditorProviders
  133. rootFolder={rootFolder as any}
  134. projectId="123abc"
  135. rootDocId="456def"
  136. features={{} as any}
  137. permissionsLevel="readOnly"
  138. >
  139. <FileTreeRoot
  140. refProviders={{}}
  141. setRefProviderEnabled={cy.stub()}
  142. setStartedFreeTrial={cy.stub()}
  143. onSelect={cy.stub().as('onSelect')}
  144. onInit={cy.stub()}
  145. isConnected
  146. />
  147. </EditorProviders>
  148. )
  149. cy.get('@onSelect').should('have.been.calledOnceWith', [
  150. Cypress.sinon.match({
  151. entity: Cypress.sinon.match({ _id: '456def', name: 'main.tex' }),
  152. }),
  153. ])
  154. cy.findByRole('tree')
  155. cy.findByRole('treeitem', { name: 'other.tex' }).click()
  156. cy.get('@onSelect').should('have.been.calledWith', [
  157. Cypress.sinon.match({
  158. entity: Cypress.sinon.match({ _id: '789ghi', name: 'other.tex' }),
  159. }),
  160. ])
  161. })
  162. it('only shows a menu button when a single item is selected', function () {
  163. const rootFolder = [
  164. {
  165. _id: 'root-folder-id',
  166. name: 'rootFolder',
  167. docs: [
  168. { _id: '456def', name: 'main.tex' },
  169. { _id: '789ghi', name: 'other.tex' },
  170. ],
  171. folders: [],
  172. fileRefs: [],
  173. },
  174. ]
  175. cy.mount(
  176. <EditorProviders
  177. rootFolder={rootFolder as any}
  178. projectId="123abc"
  179. rootDocId="456def"
  180. features={{} as any}
  181. permissionsLevel="owner"
  182. >
  183. <FileTreeRoot
  184. refProviders={{}}
  185. setRefProviderEnabled={cy.stub()}
  186. setStartedFreeTrial={cy.stub()}
  187. onSelect={cy.stub()}
  188. onInit={cy.stub()}
  189. isConnected
  190. />
  191. </EditorProviders>
  192. )
  193. cy.findByRole('treeitem', { name: 'main.tex', selected: true })
  194. cy.findByRole('treeitem', { name: 'other.tex', selected: false })
  195. // single item selected: menu button is visible
  196. cy.findAllByRole('button', { name: 'Open main.tex action menu' }).should(
  197. 'have.length',
  198. 1
  199. )
  200. // select the other item
  201. cy.findByRole('treeitem', { name: 'other.tex' }).click()
  202. cy.findByRole('treeitem', { name: 'main.tex', selected: false })
  203. cy.findByRole('treeitem', { name: 'other.tex', selected: true })
  204. // single item selected: menu button is visible
  205. cy.findAllByRole('button', { name: 'Open other.tex action menu' }).should(
  206. 'have.length',
  207. 1
  208. )
  209. // multi-select the main item
  210. cy.findByRole('treeitem', { name: 'main.tex' }).click({
  211. ctrlKey: true,
  212. cmdKey: true,
  213. })
  214. cy.findByRole('treeitem', { name: 'main.tex', selected: true })
  215. cy.findByRole('treeitem', { name: 'other.tex', selected: true })
  216. // multiple items selected: no menu button is visible
  217. cy.findAllByRole('button', { name: 'Open main.tex action menu' }).should(
  218. 'have.length',
  219. 0
  220. )
  221. })
  222. describe('when deselecting files', function () {
  223. let socket: SocketIOMock
  224. beforeEach(function () {
  225. socket = new SocketIOMock()
  226. const rootFolder = [
  227. {
  228. _id: 'root-folder-id',
  229. name: 'rootFolder',
  230. docs: [{ _id: '123abc', name: 'main.tex' }],
  231. folders: [
  232. {
  233. _id: '789ghi',
  234. name: 'thefolder',
  235. docs: [{ _id: '456def', name: 'sub.tex' }],
  236. fileRefs: [],
  237. folders: [],
  238. },
  239. ],
  240. fileRefs: [],
  241. },
  242. ]
  243. cy.mount(
  244. <EditorProviders
  245. rootFolder={rootFolder as any}
  246. projectId="123abc"
  247. rootDocId="456def"
  248. features={{} as any}
  249. permissionsLevel="owner"
  250. socket={socket}
  251. >
  252. <FileTreeRoot
  253. refProviders={{}}
  254. setRefProviderEnabled={cy.stub()}
  255. setStartedFreeTrial={cy.stub()}
  256. onSelect={cy.stub()}
  257. onInit={cy.stub()}
  258. isConnected
  259. />
  260. </EditorProviders>
  261. )
  262. // select the sub file
  263. cy.findByRole('treeitem', { name: 'sub.tex' }).click()
  264. cy.findByRole('treeitem', { name: 'sub.tex' }).should(
  265. 'have.attr',
  266. 'aria-selected',
  267. 'true'
  268. )
  269. // click on empty area (after giving it extra height below the tree)
  270. cy.findByTestId('file-tree-inner')
  271. .invoke('attr', 'style', 'height: 400px')
  272. .click()
  273. })
  274. it('removes the selected indicator', function () {
  275. cy.findByRole('treeitem', { selected: true }).should('not.exist')
  276. })
  277. it('disables the "rename" and "delete" buttons', function () {
  278. cy.findByRole('button', { name: 'Rename' }).should('not.exist')
  279. cy.findByRole('button', { name: 'Delete' }).should('not.exist')
  280. })
  281. it('creates new file in the root folder', function () {
  282. cy.intercept('project/*/doc', { statusCode: 200 })
  283. cy.findByRole('button', { name: /new file/i }).click()
  284. cy.findByRole('button', { name: /create/i }).click()
  285. cy.then(() => {
  286. socket.emitToClient('reciveNewDoc', 'root-folder-id', {
  287. _id: '12345',
  288. name: 'abcdef.tex',
  289. docs: [],
  290. fileRefs: [],
  291. folders: [],
  292. })
  293. })
  294. cy.findByRole('treeitem', { name: 'abcdef.tex' }).then($itemEl => {
  295. cy.findByTestId('file-tree-list-root').then($rootEl => {
  296. expect($itemEl.get(0).parentNode?.parentNode).to.equal($rootEl.get(0))
  297. })
  298. })
  299. })
  300. it('starts a new selection', function () {
  301. cy.findByRole('treeitem', { name: 'sub.tex' }).should(
  302. 'have.attr',
  303. 'aria-selected',
  304. 'false'
  305. )
  306. cy.findByRole('treeitem', { name: 'main.tex' }).click({
  307. ctrlKey: true,
  308. cmdKey: true,
  309. })
  310. cy.findByRole('treeitem', { name: 'main.tex' }).should(
  311. 'have.attr',
  312. 'aria-selected',
  313. 'true'
  314. )
  315. })
  316. })
  317. })