Skip to content

Commit

Permalink
same treatment for project create
Browse files Browse the repository at this point in the history
  • Loading branch information
david-crespo committed Dec 13, 2021
1 parent 1c856ba commit e25e4c4
Show file tree
Hide file tree
Showing 3 changed files with 36 additions and 29 deletions.
4 changes: 2 additions & 2 deletions app/pages/__tests__/InstanceCreatePage.spec.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import {
fireEvent,
lastBody,
lastPostBody,
renderAppAt,
screen,
waitFor,
Expand Down Expand Up @@ -82,7 +82,7 @@ describe('InstanceCreatePage', () => {
fireEvent.click(submitButton())

await waitFor(() =>
expect(lastBody(mock)).toEqual({
expect(lastPostBody(mock)).toEqual({
name: 'new-instance',
description: 'An instance in project: mock-project',
hostname: '',
Expand Down
57 changes: 32 additions & 25 deletions app/pages/__tests__/ProjectCreatePage.spec.tsx
Original file line number Diff line number Diff line change
@@ -1,18 +1,17 @@
import React from 'react'
import {
fireEvent,
lastBody,
renderWithRouter,
lastPostBody,
renderAppAt,
screen,
waitFor,
} from '../../test-utils'
import fetchMock from 'fetch-mock'

import { org, project } from '@oxide/api-mocks'

import { ProjectCreateForm } from '../ProjectCreatePage'

const projectsUrl = `/api/organizations/${org.name}/projects`
const projectUrl = `${projectsUrl}/${project.name}`
const instancesUrl = `${projectUrl}/instances?limit=10`

const submitButton = () =>
screen.getByRole('button', { name: 'Create project' })
Expand All @@ -22,40 +21,38 @@ function enterName(value: string) {
fireEvent.change(nameInput, { target: { value } })
}

let successSpy: jest.Mock

describe('ProjectCreateForm', () => {
beforeEach(() => {
successSpy = jest.fn()
renderWithRouter(
<ProjectCreateForm orgName={org.name} onSuccess={successSpy} />
)
enterName('valid-name')
})
const renderPage = () => {
// fetch projects list for org layout sidebar on project create
fetchMock.get(projectsUrl, { status: 200, body: { items: [] } })
const result = renderAppAt(`/orgs/${org.name}/projects/new`)
enterName('valid-name')
return result
}

describe('ProjectCreatePage', () => {
afterEach(() => {
fetchMock.reset()
})

it('disables submit button on submit and enables on response', async () => {
const mock = fetchMock.post(projectsUrl, { status: 201 })
renderPage()

const submit = submitButton()
expect(submit).not.toBeDisabled()

fireEvent.click(submit)

expect(mock.called()).toBeFalsy()
await waitFor(() => expect(submit).toBeDisabled())
expect(mock.done()).toBeTruthy()
expect(submit).not.toBeDisabled()
expect(mock.called(undefined, 'POST')).toBeTruthy()
})

it('shows message for known error code in project create code map', async () => {
fetchMock.post(projectsUrl, {
status: 400,
body: { error_code: 'ObjectAlreadyExists' },
})
renderPage()

fireEvent.click(submitButton())

Expand All @@ -69,13 +66,15 @@ describe('ProjectCreateForm', () => {
status: 401,
body: { error_code: 'Forbidden' },
})
renderPage()

fireEvent.click(submitButton())

await screen.findByText('Action not authorized')
})

it('shows field-level validation error and does not POST', async () => {
renderPage()
enterName('Invalid-name')
fireEvent.click(submitButton())

Expand All @@ -87,6 +86,7 @@ describe('ProjectCreateForm', () => {
status: 400,
body: { error_code: 'UnknownCode' },
})
renderPage()

fireEvent.click(submitButton())

Expand All @@ -95,26 +95,33 @@ describe('ProjectCreateForm', () => {

it('posts form on submit', async () => {
const mock = fetchMock.post(projectsUrl, { status: 201 })
renderPage()

fireEvent.click(submitButton())

await waitFor(() =>
expect(lastBody(mock)).toEqual({ name: 'valid-name', description: '' })
expect(lastPostBody(mock)).toEqual({
name: 'valid-name',
description: '',
})
)
})

it('calls onSuccess on success', async () => {
const mock = fetchMock.post(projectsUrl, {
it('navigates to project instances page on success', async () => {
fetchMock.post(projectsUrl, {
status: 201,
body: project,
})
fetchMock.get(projectUrl, { status: 200 })
// instances fetch after success
fetchMock.get(instancesUrl, { status: 200, body: { items: [] } })

expect(successSpy).not.toHaveBeenCalled()
const { history } = renderPage()
const projectPath = `/orgs/${org.name}/projects/${project.name}/instances`
expect(history.location.pathname).not.toEqual(projectPath)

fireEvent.click(submitButton())

await waitFor(() => expect(mock.called()).toBeTruthy())
await waitFor(() => expect(mock.done()).toBeTruthy())
await waitFor(() => expect(successSpy).toHaveBeenCalled())
await waitFor(() => expect(history.location.pathname).toEqual(projectPath))
})
})
4 changes: 2 additions & 2 deletions app/test-utils.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,8 @@ export function renderAppAt(location: string) {
}

// eslint-disable-next-line @typescript-eslint/no-explicit-any
export const lastBody = (mock: FetchMockStatic): any =>
JSON.parse(mock.lastOptions()?.body as unknown as string)
export const lastPostBody = (mock: FetchMockStatic): any =>
JSON.parse(mock.lastOptions(undefined, 'POST')?.body as unknown as string)

export * from '@testing-library/react'
export { customRender as render }

0 comments on commit e25e4c4

Please sign in to comment.