file-tree-root.test.js 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198
  1. import { expect } from 'chai'
  2. import React from 'react'
  3. import sinon from 'sinon'
  4. import { screen, render, fireEvent, waitFor } from '@testing-library/react'
  5. import fetchMock from 'fetch-mock'
  6. import FileTreeRoot from '../../../../../frontend/js/features/file-tree/components/file-tree-root'
  7. describe('<FileTreeRoot/>', function() {
  8. const onSelect = sinon.stub()
  9. const onInit = sinon.stub()
  10. beforeEach(function() {
  11. global.requestAnimationFrame = sinon.stub()
  12. })
  13. afterEach(function() {
  14. delete global.requestAnimationFrame
  15. fetchMock.restore()
  16. onSelect.reset()
  17. onInit.reset()
  18. global.localStorage.clear()
  19. })
  20. it('renders', function() {
  21. const rootFolder = [
  22. {
  23. _id: 'root-folder-id',
  24. docs: [{ _id: '456def', name: 'main.tex' }],
  25. folders: [],
  26. fileRefs: []
  27. }
  28. ]
  29. const { container } = render(
  30. <FileTreeRoot
  31. rootFolder={rootFolder}
  32. projectId="123abc"
  33. hasWritePermissions={false}
  34. rootDocId="456def"
  35. onSelect={onSelect}
  36. onInit={onInit}
  37. isConnected
  38. />
  39. )
  40. screen.queryByRole('tree')
  41. screen.getByRole('treeitem')
  42. screen.getByRole('treeitem', { name: 'main.tex', selected: true })
  43. expect(container.querySelector('.disconnected-overlay')).to.not.exist
  44. })
  45. it('renders with invalid selected doc in local storage', async function() {
  46. global.localStorage.setItem(
  47. 'doc.open_id.123abc',
  48. JSON.stringify('not-a-valid-id')
  49. )
  50. const rootFolder = [
  51. {
  52. _id: 'root-folder-id',
  53. docs: [{ _id: '456def', name: 'main.tex' }],
  54. folders: [],
  55. fileRefs: []
  56. }
  57. ]
  58. render(
  59. <FileTreeRoot
  60. rootFolder={rootFolder}
  61. projectId="123abc"
  62. hasWritePermissions
  63. rootDocId="456def"
  64. onSelect={onSelect}
  65. onInit={onInit}
  66. isConnected
  67. />
  68. )
  69. // as a proxy to check that the invalid entity ha not been select we start
  70. // a delete and ensure the modal is displayed (the cancel button can be
  71. // selected) This is needed to make sure the test fail.
  72. const treeitemFile = screen.getByRole('treeitem', { name: 'main.tex' })
  73. fireEvent.click(treeitemFile, { ctrlKey: true })
  74. const deleteButton = screen.getByRole('menuitem', { name: 'Delete' })
  75. fireEvent.click(deleteButton)
  76. await waitFor(() => screen.getByRole('button', { name: 'Cancel' }))
  77. })
  78. it('renders disconnected overlay', function() {
  79. const rootFolder = [
  80. {
  81. _id: 'root-folder-id',
  82. docs: [{ _id: '456def', name: 'main.tex' }],
  83. folders: [],
  84. fileRefs: []
  85. }
  86. ]
  87. const { container } = render(
  88. <FileTreeRoot
  89. rootFolder={rootFolder}
  90. projectId="123abc"
  91. hasWritePermissions={false}
  92. rootDocId="456def"
  93. onSelect={onSelect}
  94. onInit={onInit}
  95. isConnected={false}
  96. />
  97. )
  98. expect(container.querySelector('.disconnected-overlay')).to.exist
  99. })
  100. it('fire onSelect', function() {
  101. const rootFolder = [
  102. {
  103. _id: 'root-folder-id',
  104. docs: [
  105. { _id: '456def', name: 'main.tex' },
  106. { _id: '789ghi', name: 'other.tex' }
  107. ],
  108. folders: [],
  109. fileRefs: []
  110. }
  111. ]
  112. render(
  113. <FileTreeRoot
  114. rootFolder={rootFolder}
  115. projectId="123abc"
  116. rootDocId="456def"
  117. hasWritePermissions={false}
  118. onSelect={onSelect}
  119. onInit={onInit}
  120. isConnected
  121. />
  122. )
  123. sinon.assert.calledOnce(onSelect)
  124. sinon.assert.calledWithMatch(onSelect, [
  125. sinon.match({
  126. entity: {
  127. _id: '456def',
  128. name: 'main.tex'
  129. }
  130. })
  131. ])
  132. onSelect.reset()
  133. screen.queryByRole('tree')
  134. const treeitem = screen.getByRole('treeitem', { name: 'other.tex' })
  135. fireEvent.click(treeitem)
  136. sinon.assert.calledOnce(onSelect)
  137. sinon.assert.calledWithMatch(onSelect, [
  138. sinon.match({
  139. entity: {
  140. _id: '789ghi',
  141. name: 'other.tex'
  142. }
  143. })
  144. ])
  145. })
  146. it('listen to editor.openDoc', function() {
  147. const rootFolder = [
  148. {
  149. _id: 'root-folder-id',
  150. docs: [
  151. { _id: '456def', name: 'main.tex' },
  152. { _id: '789ghi', name: 'other.tex' }
  153. ],
  154. folders: [],
  155. fileRefs: []
  156. }
  157. ]
  158. render(
  159. <FileTreeRoot
  160. rootFolder={rootFolder}
  161. projectId="123abc"
  162. rootDocId="456def"
  163. hasWritePermissions={false}
  164. onSelect={onSelect}
  165. onInit={onInit}
  166. isConnected
  167. />
  168. )
  169. screen.getByRole('treeitem', { name: 'main.tex', selected: true })
  170. // entities not found should be ignored
  171. window.dispatchEvent(
  172. new CustomEvent('editor.openDoc', { detail: 'not-an-id' })
  173. )
  174. screen.getByRole('treeitem', { name: 'main.tex', selected: true })
  175. window.dispatchEvent(
  176. new CustomEvent('editor.openDoc', { detail: '789ghi' })
  177. )
  178. screen.getByRole('treeitem', { name: 'main.tex', selected: false })
  179. screen.getByRole('treeitem', { name: 'other.tex', selected: true })
  180. })
  181. })