rename-entity.test.js 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180
  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. onSelect={onSelect}
  50. onInit={onInit}
  51. />
  52. )
  53. })
  54. it('renames doc', function() {
  55. const fetchMatcher = /\/project\/\w+\/doc\/\w+\/rename/
  56. fetchMock.post(fetchMatcher, 204)
  57. const input = initItemRename('a.tex')
  58. fireEvent.change(input, { target: { value: 'b.tex' } })
  59. fireEvent.keyDown(input, { key: 'Enter' })
  60. screen.getByRole('treeitem', { name: 'b.tex' })
  61. const lastFetchBody = getLastFetchBody(fetchMatcher)
  62. expect(lastFetchBody.name).to.equal('b.tex')
  63. })
  64. it('renames folder', function() {
  65. const fetchMatcher = /\/project\/\w+\/folder\/\w+\/rename/
  66. fetchMock.post(fetchMatcher, 204)
  67. const input = initItemRename('folder')
  68. fireEvent.change(input, { target: { value: 'new folder name' } })
  69. fireEvent.keyDown(input, { key: 'Enter' })
  70. screen.getByRole('treeitem', { name: 'new folder name' })
  71. const lastFetchBody = getLastFetchBody(fetchMatcher)
  72. expect(lastFetchBody.name).to.equal('new folder name')
  73. })
  74. it('renames file in subfolder', function() {
  75. const fetchMatcher = /\/project\/\w+\/file\/\w+\/rename/
  76. fetchMock.post(fetchMatcher, 204)
  77. const expandButton = screen.getByRole('button', { name: 'Expand' })
  78. fireEvent.click(expandButton)
  79. const input = initItemRename('c.tex')
  80. fireEvent.change(input, { target: { value: 'd.tex' } })
  81. fireEvent.keyDown(input, { key: 'Enter' })
  82. screen.getByRole('treeitem', { name: 'folder' })
  83. screen.getByRole('treeitem', { name: 'd.tex' })
  84. const lastFetchBody = getLastFetchBody(fetchMatcher)
  85. expect(lastFetchBody.name).to.equal('d.tex')
  86. })
  87. it('reverts rename on error', async function() {
  88. const fetchMatcher = /\/project\/\w+\/doc\/\w+\/rename/
  89. fetchMock.post(fetchMatcher, 500)
  90. const input = initItemRename('a.tex')
  91. fireEvent.change(input, { target: { value: 'b.tex' } })
  92. fireEvent.keyDown(input, { key: 'Enter' })
  93. screen.getByRole('treeitem', { name: 'b.tex' })
  94. })
  95. it('shows error modal on invalid filename', async function() {
  96. const input = initItemRename('a.tex')
  97. fireEvent.change(input, { target: { value: '///' } })
  98. fireEvent.keyDown(input, { key: 'Enter' })
  99. await screen.findByRole('alert', {
  100. name: 'File name is empty or contains invalid characters',
  101. hidden: true
  102. })
  103. })
  104. it('shows error modal on duplicate filename', async function() {
  105. const input = initItemRename('a.tex')
  106. fireEvent.change(input, { target: { value: 'folder' } })
  107. fireEvent.keyDown(input, { key: 'Enter' })
  108. await screen.findByRole('alert', {
  109. name: 'A file or folder with this name already exists',
  110. hidden: true
  111. })
  112. })
  113. it('shows error modal on duplicate filename in subfolder', async function() {
  114. const expandButton = screen.getByRole('button', { name: 'Expand' })
  115. fireEvent.click(expandButton)
  116. const input = initItemRename('c.tex')
  117. fireEvent.change(input, { target: { value: 'e.tex' } })
  118. fireEvent.keyDown(input, { key: 'Enter' })
  119. await screen.findByRole('alert', {
  120. name: 'A file or folder with this name already exists',
  121. hidden: true
  122. })
  123. })
  124. describe('via socket event', function() {
  125. it('renames doc', function() {
  126. screen.getByRole('treeitem', { name: 'a.tex' })
  127. window._ide.socket.socketClient.emit(
  128. 'reciveEntityRename',
  129. '456def',
  130. 'socket.tex'
  131. )
  132. screen.getByRole('treeitem', { name: 'socket.tex' })
  133. })
  134. })
  135. function initItemRename(treeitemName) {
  136. const treeitem = screen.getByRole('treeitem', { name: treeitemName })
  137. fireEvent.click(treeitem)
  138. const renameButton = screen.getByRole('menuitem', { name: 'Rename' })
  139. fireEvent.click(renameButton)
  140. return screen.getByRole('textbox')
  141. }
  142. function getLastFetchBody(matcher) {
  143. const [, { body }] = fetchMock.lastCall(matcher)
  144. return JSON.parse(body)
  145. }
  146. })