rename-entity.test.js 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197
  1. import { expect } from 'chai'
  2. import React from 'react'
  3. import sinon from 'sinon'
  4. import { screen, render, fireEvent } from '@testing-library/react'
  5. import fetchMock from 'fetch-mock'
  6. import MockedSocket from 'socket.io-mock'
  7. import FileTreeRoot from '../../../../../frontend/js/features/file-tree/components/file-tree-root'
  8. describe('FileTree Rename Entity Flow', function() {
  9. const onSelect = sinon.stub()
  10. const onInit = sinon.stub()
  11. beforeEach(function() {
  12. window._ide = {
  13. socket: new MockedSocket()
  14. }
  15. global.requestAnimationFrame = sinon.stub()
  16. })
  17. afterEach(function() {
  18. delete global.requestAnimationFrame
  19. fetchMock.restore()
  20. onSelect.reset()
  21. onInit.reset()
  22. delete window._ide
  23. })
  24. beforeEach(function() {
  25. const rootFolder = [
  26. {
  27. _id: 'root-folder-id',
  28. docs: [{ _id: '456def', name: 'a.tex' }],
  29. folders: [
  30. {
  31. _id: '987jkl',
  32. name: 'folder',
  33. docs: [],
  34. fileRefs: [
  35. { _id: '789ghi', name: 'c.tex' },
  36. { _id: '981gkp', name: 'e.tex' }
  37. ],
  38. folders: []
  39. }
  40. ],
  41. fileRefs: []
  42. }
  43. ]
  44. render(
  45. <FileTreeRoot
  46. rootFolder={rootFolder}
  47. projectId="123abc"
  48. hasWritePermissions
  49. userHasFeature={() => true}
  50. refProviders={{}}
  51. reindexReferences={() => null}
  52. setRefProviderEnabled={() => null}
  53. setStartedFreeTrial={() => null}
  54. onSelect={onSelect}
  55. onInit={onInit}
  56. isConnected
  57. />
  58. )
  59. })
  60. it('renames doc', function() {
  61. const fetchMatcher = /\/project\/\w+\/doc\/\w+\/rename/
  62. fetchMock.post(fetchMatcher, 204)
  63. const input = initItemRename('a.tex')
  64. fireEvent.change(input, { target: { value: 'b.tex' } })
  65. fireEvent.keyDown(input, { key: 'Enter' })
  66. screen.getByRole('treeitem', { name: 'b.tex' })
  67. const lastFetchBody = getLastFetchBody(fetchMatcher)
  68. expect(lastFetchBody.name).to.equal('b.tex')
  69. })
  70. it('renames folder', function() {
  71. const fetchMatcher = /\/project\/\w+\/folder\/\w+\/rename/
  72. fetchMock.post(fetchMatcher, 204)
  73. const input = initItemRename('folder')
  74. fireEvent.change(input, { target: { value: 'new folder name' } })
  75. fireEvent.keyDown(input, { key: 'Enter' })
  76. screen.getByRole('treeitem', { name: 'new folder name' })
  77. const lastFetchBody = getLastFetchBody(fetchMatcher)
  78. expect(lastFetchBody.name).to.equal('new folder name')
  79. })
  80. it('renames file in subfolder', function() {
  81. const fetchMatcher = /\/project\/\w+\/file\/\w+\/rename/
  82. fetchMock.post(fetchMatcher, 204)
  83. const expandButton = screen.queryByRole('button', { name: 'Expand' })
  84. if (expandButton) fireEvent.click(expandButton)
  85. const input = initItemRename('c.tex')
  86. fireEvent.change(input, { target: { value: 'd.tex' } })
  87. fireEvent.keyDown(input, { key: 'Enter' })
  88. screen.getByRole('treeitem', { name: 'folder' })
  89. screen.getByRole('treeitem', { name: 'd.tex' })
  90. const lastFetchBody = getLastFetchBody(fetchMatcher)
  91. expect(lastFetchBody.name).to.equal('d.tex')
  92. })
  93. it('reverts rename on error', async function() {
  94. const fetchMatcher = /\/project\/\w+\/doc\/\w+\/rename/
  95. fetchMock.post(fetchMatcher, 500)
  96. const input = initItemRename('a.tex')
  97. fireEvent.change(input, { target: { value: 'b.tex' } })
  98. fireEvent.keyDown(input, { key: 'Enter' })
  99. screen.getByRole('treeitem', { name: 'b.tex' })
  100. })
  101. it('shows error modal on invalid filename', async function() {
  102. const input = initItemRename('a.tex')
  103. fireEvent.change(input, { target: { value: '///' } })
  104. fireEvent.keyDown(input, { key: 'Enter' })
  105. await screen.findByRole('alert', {
  106. name: 'File name is empty or contains invalid characters',
  107. hidden: true
  108. })
  109. })
  110. it('shows error modal on duplicate filename', async function() {
  111. const input = initItemRename('a.tex')
  112. fireEvent.change(input, { target: { value: 'folder' } })
  113. fireEvent.keyDown(input, { key: 'Enter' })
  114. await screen.findByRole('alert', {
  115. name: 'A file or folder with this name already exists',
  116. hidden: true
  117. })
  118. })
  119. it('shows error modal on duplicate filename in subfolder', async function() {
  120. const expandButton = screen.queryByRole('button', { name: 'Expand' })
  121. if (expandButton) fireEvent.click(expandButton)
  122. const input = initItemRename('c.tex')
  123. fireEvent.change(input, { target: { value: 'e.tex' } })
  124. fireEvent.keyDown(input, { key: 'Enter' })
  125. await screen.findByRole('alert', {
  126. name: 'A file or folder with this name already exists',
  127. hidden: true
  128. })
  129. })
  130. it('shows error modal on blocked filename', async function() {
  131. const input = initItemRename('a.tex')
  132. fireEvent.change(input, { target: { value: 'prototype' } })
  133. fireEvent.keyDown(input, { key: 'Enter' })
  134. await screen.findByRole('alert', {
  135. name: 'This file name is blocked.',
  136. hidden: true
  137. })
  138. })
  139. describe('via socket event', function() {
  140. it('renames doc', function() {
  141. screen.getByRole('treeitem', { name: 'a.tex' })
  142. window._ide.socket.socketClient.emit(
  143. 'reciveEntityRename',
  144. '456def',
  145. 'socket.tex'
  146. )
  147. screen.getByRole('treeitem', { name: 'socket.tex' })
  148. })
  149. })
  150. function initItemRename(treeitemName) {
  151. const treeitem = screen.getByRole('treeitem', { name: treeitemName })
  152. fireEvent.click(treeitem)
  153. const renameButton = screen.getByRole('menuitem', { name: 'Rename' })
  154. fireEvent.click(renameButton)
  155. return screen.getByRole('textbox')
  156. }
  157. function getLastFetchBody(matcher) {
  158. const [, { body }] = fetchMock.lastCall(matcher)
  159. return JSON.parse(body)
  160. }
  161. })