|
|
@@ -1,69 +1,84 @@
|
|
|
import React from 'react'
|
|
|
-import { fireEvent, render, screen } from '@testing-library/react'
|
|
|
+import { fireEvent, render, screen, waitFor } from '@testing-library/react'
|
|
|
import { expect } from 'chai'
|
|
|
-import CloneProjectModalContent from '../../../../../frontend/js/features/clone-project-modal/components/clone-project-modal-content'
|
|
|
import CloneProjectModal from '../../../../../frontend/js/features/clone-project-modal/components/clone-project-modal'
|
|
|
import sinon from 'sinon'
|
|
|
import fetchMock from 'fetch-mock'
|
|
|
|
|
|
-const cancel = sinon.stub()
|
|
|
-const cloneProject = sinon.stub()
|
|
|
-const handleHide = sinon.stub()
|
|
|
-
|
|
|
describe('<CloneProjectModal />', function() {
|
|
|
afterEach(function() {
|
|
|
fetchMock.reset()
|
|
|
})
|
|
|
|
|
|
- it('posts the generated project name', async function() {
|
|
|
- const matcher = 'express:/project/:projectId/clone'
|
|
|
+ const modalProps = {
|
|
|
+ handleHide: sinon.stub(),
|
|
|
+ projectId: 'project-1',
|
|
|
+ projectName: 'Test Project',
|
|
|
+ openProject: sinon.stub(),
|
|
|
+ show: true
|
|
|
+ }
|
|
|
|
|
|
- fetchMock.postOnce(
|
|
|
- matcher,
|
|
|
- () => {
|
|
|
- return {
|
|
|
- project_id: 'test'
|
|
|
- }
|
|
|
- },
|
|
|
+ it('renders the translated modal title', async function() {
|
|
|
+ render(<CloneProjectModal {...modalProps} />)
|
|
|
+
|
|
|
+ await screen.findByText('Copy Project')
|
|
|
+ })
|
|
|
+
|
|
|
+ it('posts the generated project name', async function() {
|
|
|
+ fetchMock.post(
|
|
|
+ 'express:/project/:projectId/clone',
|
|
|
{
|
|
|
- body: {
|
|
|
- projectName: 'A Project (Copy)'
|
|
|
- }
|
|
|
- }
|
|
|
+ status: 200,
|
|
|
+ body: { project_id: modalProps.projectId }
|
|
|
+ },
|
|
|
+ { delay: 10 }
|
|
|
)
|
|
|
|
|
|
- render(
|
|
|
- <CloneProjectModal
|
|
|
- handleHide={handleHide}
|
|
|
- projectId="project-1"
|
|
|
- projectName="A Project"
|
|
|
- show
|
|
|
- />
|
|
|
- )
|
|
|
+ const openProject = sinon.stub()
|
|
|
+
|
|
|
+ render(<CloneProjectModal {...modalProps} openProject={openProject} />)
|
|
|
+
|
|
|
+ const cancelButton = await screen.findByRole('button', { name: 'Cancel' })
|
|
|
+ expect(cancelButton.disabled).to.be.false
|
|
|
|
|
|
- const button = await screen.findByRole('button', {
|
|
|
- name: 'Copy',
|
|
|
- hidden: true // TODO: this shouldn't be needed
|
|
|
+ const submitButton = await screen.findByRole('button', { name: 'Copy' })
|
|
|
+ expect(submitButton.disabled).to.be.false
|
|
|
+
|
|
|
+ const input = await screen.getByLabelText('New Name')
|
|
|
+
|
|
|
+ fireEvent.change(input, {
|
|
|
+ target: { value: '' }
|
|
|
})
|
|
|
+ expect(submitButton.disabled).to.be.true
|
|
|
|
|
|
- const cancelButton = await screen.findByRole('button', {
|
|
|
- name: 'Cancel',
|
|
|
- hidden: true // TODO: this shouldn't be needed
|
|
|
+ fireEvent.change(input, {
|
|
|
+ target: { value: 'A Cloned Project' }
|
|
|
})
|
|
|
+ expect(submitButton.disabled).to.be.false
|
|
|
|
|
|
- expect(button.disabled).to.be.false
|
|
|
- expect(cancelButton.disabled).to.be.false
|
|
|
+ fireEvent.click(submitButton)
|
|
|
+ expect(submitButton.disabled).to.be.true
|
|
|
|
|
|
- fireEvent.click(button)
|
|
|
+ await fetchMock.flush(true)
|
|
|
+ expect(fetchMock.done()).to.be.true
|
|
|
+ const [url, options] = fetchMock.lastCall(
|
|
|
+ 'express:/project/:projectId/clone'
|
|
|
+ )
|
|
|
+ expect(url).to.equal('/project/project-1/clone')
|
|
|
|
|
|
- expect(fetchMock.done(matcher)).to.be.true
|
|
|
- // TODO: window.location?
|
|
|
+ expect(JSON.parse(options.body)).to.deep.equal({
|
|
|
+ projectName: 'A Cloned Project'
|
|
|
+ })
|
|
|
+
|
|
|
+ expect(openProject).to.be.calledOnce
|
|
|
|
|
|
const errorMessage = screen.queryByText('Sorry, something went wrong')
|
|
|
expect(errorMessage).to.be.null
|
|
|
|
|
|
- expect(button.disabled).to.be.true
|
|
|
- expect(cancelButton.disabled).to.be.true
|
|
|
+ await waitFor(() => {
|
|
|
+ expect(submitButton.disabled).to.be.false
|
|
|
+ expect(cancelButton.disabled).to.be.false
|
|
|
+ })
|
|
|
})
|
|
|
|
|
|
it('handles a generic error response', async function() {
|
|
|
@@ -74,31 +89,20 @@ describe('<CloneProjectModal />', function() {
|
|
|
body: 'There was an error!'
|
|
|
})
|
|
|
|
|
|
- render(
|
|
|
- <CloneProjectModal
|
|
|
- handleHide={handleHide}
|
|
|
- projectId="project-2"
|
|
|
- projectName="A Project"
|
|
|
- show
|
|
|
- />
|
|
|
- )
|
|
|
-
|
|
|
- const button = await screen.findByRole('button', {
|
|
|
- name: 'Copy',
|
|
|
- hidden: true // TODO: this shouldn't be needed
|
|
|
- })
|
|
|
+ const openProject = sinon.stub()
|
|
|
|
|
|
- const cancelButton = await screen.findByRole('button', {
|
|
|
- name: 'Cancel',
|
|
|
- hidden: true // TODO: this shouldn't be needed
|
|
|
- })
|
|
|
+ render(<CloneProjectModal {...modalProps} openProject={openProject} />)
|
|
|
|
|
|
+ const button = await screen.findByRole('button', { name: 'Copy' })
|
|
|
expect(button.disabled).to.be.false
|
|
|
+
|
|
|
+ const cancelButton = await screen.findByRole('button', { name: 'Cancel' })
|
|
|
expect(cancelButton.disabled).to.be.false
|
|
|
|
|
|
fireEvent.click(button)
|
|
|
|
|
|
expect(fetchMock.done(matcher)).to.be.true
|
|
|
+ expect(openProject).not.to.be.called
|
|
|
|
|
|
await screen.findByText('Sorry, something went wrong')
|
|
|
|
|
|
@@ -114,31 +118,21 @@ describe('<CloneProjectModal />', function() {
|
|
|
body: 'There was an error!'
|
|
|
})
|
|
|
|
|
|
- render(
|
|
|
- <CloneProjectModal
|
|
|
- handleHide={handleHide}
|
|
|
- projectId="project-3"
|
|
|
- projectName="A Project"
|
|
|
- show
|
|
|
- />
|
|
|
- )
|
|
|
+ const openProject = sinon.stub()
|
|
|
|
|
|
- const button = await screen.findByRole('button', {
|
|
|
- name: 'Copy',
|
|
|
- hidden: true // TODO: this shouldn't be needed
|
|
|
- })
|
|
|
-
|
|
|
- const cancelButton = await screen.findByRole('button', {
|
|
|
- name: 'Cancel',
|
|
|
- hidden: true // TODO: this shouldn't be needed
|
|
|
- })
|
|
|
+ render(<CloneProjectModal {...modalProps} openProject={openProject} />)
|
|
|
|
|
|
+ const button = await screen.findByRole('button', { name: 'Copy' })
|
|
|
expect(button.disabled).to.be.false
|
|
|
+
|
|
|
+ const cancelButton = await screen.findByRole('button', { name: 'Cancel' })
|
|
|
expect(cancelButton.disabled).to.be.false
|
|
|
|
|
|
fireEvent.click(button)
|
|
|
+ await fetchMock.flush(true)
|
|
|
|
|
|
expect(fetchMock.done(matcher)).to.be.true
|
|
|
+ expect(openProject).not.to.be.called
|
|
|
|
|
|
await screen.findByText('There was an error!')
|
|
|
|
|
|
@@ -146,92 +140,3 @@ describe('<CloneProjectModal />', function() {
|
|
|
expect(cancelButton.disabled).to.be.false
|
|
|
})
|
|
|
})
|
|
|
-
|
|
|
-describe('<CloneProjectModalContent />', function() {
|
|
|
- it('renders the translated modal title', async function() {
|
|
|
- render(
|
|
|
- <CloneProjectModalContent
|
|
|
- cloneProject={cloneProject}
|
|
|
- cancel={cancel}
|
|
|
- inFlight={false}
|
|
|
- />
|
|
|
- )
|
|
|
-
|
|
|
- await screen.findByText('Copy Project')
|
|
|
- })
|
|
|
-
|
|
|
- it('shows the copy button', async function() {
|
|
|
- render(
|
|
|
- <CloneProjectModalContent
|
|
|
- cloneProject={cloneProject}
|
|
|
- cancel={cancel}
|
|
|
- inFlight={false}
|
|
|
- />
|
|
|
- )
|
|
|
-
|
|
|
- const button = await screen.findByRole('button', { name: 'Copy' })
|
|
|
-
|
|
|
- expect(button.disabled).to.be.false
|
|
|
- })
|
|
|
-
|
|
|
- it('disables the copy button when loading', async function() {
|
|
|
- render(
|
|
|
- <CloneProjectModalContent
|
|
|
- cloneProject={cloneProject}
|
|
|
- cancel={cancel}
|
|
|
- inFlight
|
|
|
- />
|
|
|
- )
|
|
|
-
|
|
|
- const button = await screen.findByText(
|
|
|
- (content, element) =>
|
|
|
- element.nodeName === 'BUTTON' &&
|
|
|
- element.textContent.trim().match(/^Copying…$/)
|
|
|
- )
|
|
|
-
|
|
|
- expect(button.disabled).to.be.true
|
|
|
- })
|
|
|
-
|
|
|
- it('renders a generic error message', async function() {
|
|
|
- render(
|
|
|
- <CloneProjectModalContent
|
|
|
- cloneProject={cloneProject}
|
|
|
- cancel={cancel}
|
|
|
- inFlight={false}
|
|
|
- error
|
|
|
- />
|
|
|
- )
|
|
|
-
|
|
|
- await screen.findByText('Sorry, something went wrong')
|
|
|
- })
|
|
|
-
|
|
|
- it('renders a specific error message', async function() {
|
|
|
- render(
|
|
|
- <CloneProjectModalContent
|
|
|
- cloneProject={cloneProject}
|
|
|
- cancel={cancel}
|
|
|
- inFlight={false}
|
|
|
- error={{
|
|
|
- message: 'Uh oh!'
|
|
|
- }}
|
|
|
- />
|
|
|
- )
|
|
|
-
|
|
|
- await screen.findByText('Uh oh!')
|
|
|
- })
|
|
|
-
|
|
|
- it('displays a project name', async function() {
|
|
|
- render(
|
|
|
- <CloneProjectModalContent
|
|
|
- cloneProject={cloneProject}
|
|
|
- cancel={cancel}
|
|
|
- inFlight={false}
|
|
|
- projectName="A copy of a project"
|
|
|
- />
|
|
|
- )
|
|
|
-
|
|
|
- const input = await screen.getByLabelText('New Name')
|
|
|
-
|
|
|
- expect(input.value).to.equal('A copy of a project (Copy)')
|
|
|
- })
|
|
|
-})
|