clone-project-modal.test.js 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177
  1. import { fireEvent, screen, waitFor } from '@testing-library/react'
  2. import { expect } from 'chai'
  3. import sinon from 'sinon'
  4. import fetchMock from 'fetch-mock'
  5. import EditorCloneProjectModalWrapper from '../../../../../frontend/js/features/clone-project-modal/components/editor-clone-project-modal-wrapper'
  6. import { renderWithEditorContext } from '../../../helpers/render-with-context'
  7. describe('<EditorCloneProjectModalWrapper />', function () {
  8. beforeEach(function () {
  9. fetchMock.reset()
  10. })
  11. after(function () {
  12. fetchMock.reset()
  13. })
  14. const project = {
  15. _id: 'project-1',
  16. name: 'Test Project',
  17. }
  18. it('renders the translated modal title', async function () {
  19. const handleHide = sinon.stub()
  20. const openProject = sinon.stub()
  21. renderWithEditorContext(
  22. <EditorCloneProjectModalWrapper
  23. handleHide={handleHide}
  24. openProject={openProject}
  25. show
  26. />,
  27. { scope: { project } }
  28. )
  29. await screen.findByText('Copy Project')
  30. })
  31. it('posts the generated project name', async function () {
  32. fetchMock.post(
  33. 'express:/project/:projectId/clone',
  34. {
  35. status: 200,
  36. body: { project_id: 'cloned-project' },
  37. },
  38. { delay: 10 }
  39. )
  40. const handleHide = sinon.stub()
  41. const openProject = sinon.stub()
  42. renderWithEditorContext(
  43. <EditorCloneProjectModalWrapper
  44. handleHide={handleHide}
  45. openProject={openProject}
  46. show
  47. />,
  48. { scope: { project } }
  49. )
  50. const cancelButton = await screen.findByRole('button', { name: 'Cancel' })
  51. expect(cancelButton.disabled).to.be.false
  52. const submitButton = await screen.findByRole('button', { name: 'Copy' })
  53. expect(submitButton.disabled).to.be.false
  54. const input = await screen.getByLabelText('New Name')
  55. fireEvent.change(input, {
  56. target: { value: '' },
  57. })
  58. expect(submitButton.disabled).to.be.true
  59. fireEvent.change(input, {
  60. target: { value: 'A Cloned Project' },
  61. })
  62. expect(submitButton.disabled).to.be.false
  63. fireEvent.click(submitButton)
  64. expect(submitButton.disabled).to.be.true
  65. await fetchMock.flush(true)
  66. expect(fetchMock.done()).to.be.true
  67. const [url, options] = fetchMock.lastCall(
  68. 'express:/project/:projectId/clone'
  69. )
  70. expect(url).to.equal('/project/project-1/clone')
  71. expect(JSON.parse(options.body)).to.deep.equal({
  72. projectName: 'A Cloned Project',
  73. })
  74. expect(openProject).to.be.calledOnce
  75. const errorMessage = screen.queryByText('Sorry, something went wrong')
  76. expect(errorMessage).to.be.null
  77. await waitFor(() => {
  78. expect(submitButton.disabled).to.be.false
  79. expect(cancelButton.disabled).to.be.false
  80. })
  81. })
  82. it('handles a generic error response', async function () {
  83. const matcher = 'express:/project/:projectId/clone'
  84. fetchMock.postOnce(matcher, {
  85. status: 500,
  86. body: 'There was an error!',
  87. })
  88. const handleHide = sinon.stub()
  89. const openProject = sinon.stub()
  90. renderWithEditorContext(
  91. <EditorCloneProjectModalWrapper
  92. handleHide={handleHide}
  93. openProject={openProject}
  94. show
  95. />,
  96. { scope: { project } }
  97. )
  98. const button = await screen.findByRole('button', { name: 'Copy' })
  99. expect(button.disabled).to.be.false
  100. const cancelButton = await screen.findByRole('button', { name: 'Cancel' })
  101. expect(cancelButton.disabled).to.be.false
  102. fireEvent.click(button)
  103. expect(fetchMock.done(matcher)).to.be.true
  104. expect(openProject).not.to.be.called
  105. await screen.findByText('Sorry, something went wrong')
  106. expect(button.disabled).to.be.false
  107. expect(cancelButton.disabled).to.be.false
  108. })
  109. it('handles a specific error response', async function () {
  110. const matcher = 'express:/project/:projectId/clone'
  111. fetchMock.postOnce(matcher, {
  112. status: 400,
  113. body: 'There was an error!',
  114. })
  115. const handleHide = sinon.stub()
  116. const openProject = sinon.stub()
  117. renderWithEditorContext(
  118. <EditorCloneProjectModalWrapper
  119. handleHide={handleHide}
  120. openProject={openProject}
  121. show
  122. />,
  123. { scope: { project } }
  124. )
  125. const button = await screen.findByRole('button', { name: 'Copy' })
  126. expect(button.disabled).to.be.false
  127. const cancelButton = await screen.findByRole('button', { name: 'Cancel' })
  128. expect(cancelButton.disabled).to.be.false
  129. fireEvent.click(button)
  130. await fetchMock.flush(true)
  131. expect(fetchMock.done(matcher)).to.be.true
  132. expect(openProject).not.to.be.called
  133. await screen.findByText('There was an error!')
  134. expect(button.disabled).to.be.false
  135. expect(cancelButton.disabled).to.be.false
  136. })
  137. })