Skip to content

Commit e25e4c4

Browse files
committed
same treatment for project create
1 parent 1c856ba commit e25e4c4

File tree

3 files changed

+36
-29
lines changed

3 files changed

+36
-29
lines changed

app/pages/__tests__/InstanceCreatePage.spec.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import {
22
fireEvent,
3-
lastBody,
3+
lastPostBody,
44
renderAppAt,
55
screen,
66
waitFor,
@@ -82,7 +82,7 @@ describe('InstanceCreatePage', () => {
8282
fireEvent.click(submitButton())
8383

8484
await waitFor(() =>
85-
expect(lastBody(mock)).toEqual({
85+
expect(lastPostBody(mock)).toEqual({
8686
name: 'new-instance',
8787
description: 'An instance in project: mock-project',
8888
hostname: '',
Lines changed: 32 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,17 @@
1-
import React from 'react'
21
import {
32
fireEvent,
4-
lastBody,
5-
renderWithRouter,
3+
lastPostBody,
4+
renderAppAt,
65
screen,
76
waitFor,
87
} from '../../test-utils'
98
import fetchMock from 'fetch-mock'
109

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

13-
import { ProjectCreateForm } from '../ProjectCreatePage'
14-
1512
const projectsUrl = `/api/organizations/${org.name}/projects`
13+
const projectUrl = `${projectsUrl}/${project.name}`
14+
const instancesUrl = `${projectUrl}/instances?limit=10`
1615

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

25-
let successSpy: jest.Mock
26-
27-
describe('ProjectCreateForm', () => {
28-
beforeEach(() => {
29-
successSpy = jest.fn()
30-
renderWithRouter(
31-
<ProjectCreateForm orgName={org.name} onSuccess={successSpy} />
32-
)
33-
enterName('valid-name')
34-
})
24+
const renderPage = () => {
25+
// fetch projects list for org layout sidebar on project create
26+
fetchMock.get(projectsUrl, { status: 200, body: { items: [] } })
27+
const result = renderAppAt(`/orgs/${org.name}/projects/new`)
28+
enterName('valid-name')
29+
return result
30+
}
3531

32+
describe('ProjectCreatePage', () => {
3633
afterEach(() => {
3734
fetchMock.reset()
3835
})
3936

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

4341
const submit = submitButton()
4442
expect(submit).not.toBeDisabled()
4543

4644
fireEvent.click(submit)
4745

48-
expect(mock.called()).toBeFalsy()
4946
await waitFor(() => expect(submit).toBeDisabled())
50-
expect(mock.done()).toBeTruthy()
51-
expect(submit).not.toBeDisabled()
47+
expect(mock.called(undefined, 'POST')).toBeTruthy()
5248
})
5349

5450
it('shows message for known error code in project create code map', async () => {
5551
fetchMock.post(projectsUrl, {
5652
status: 400,
5753
body: { error_code: 'ObjectAlreadyExists' },
5854
})
55+
renderPage()
5956

6057
fireEvent.click(submitButton())
6158

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

7371
fireEvent.click(submitButton())
7472

7573
await screen.findByText('Action not authorized')
7674
})
7775

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

@@ -87,6 +86,7 @@ describe('ProjectCreateForm', () => {
8786
status: 400,
8887
body: { error_code: 'UnknownCode' },
8988
})
89+
renderPage()
9090

9191
fireEvent.click(submitButton())
9292

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

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

99100
fireEvent.click(submitButton())
100101

101102
await waitFor(() =>
102-
expect(lastBody(mock)).toEqual({ name: 'valid-name', description: '' })
103+
expect(lastPostBody(mock)).toEqual({
104+
name: 'valid-name',
105+
description: '',
106+
})
103107
)
104108
})
105109

106-
it('calls onSuccess on success', async () => {
107-
const mock = fetchMock.post(projectsUrl, {
110+
it('navigates to project instances page on success', async () => {
111+
fetchMock.post(projectsUrl, {
108112
status: 201,
109113
body: project,
110114
})
115+
fetchMock.get(projectUrl, { status: 200 })
116+
// instances fetch after success
117+
fetchMock.get(instancesUrl, { status: 200, body: { items: [] } })
111118

112-
expect(successSpy).not.toHaveBeenCalled()
119+
const { history } = renderPage()
120+
const projectPath = `/orgs/${org.name}/projects/${project.name}/instances`
121+
expect(history.location.pathname).not.toEqual(projectPath)
113122

114123
fireEvent.click(submitButton())
115124

116-
await waitFor(() => expect(mock.called()).toBeTruthy())
117-
await waitFor(() => expect(mock.done()).toBeTruthy())
118-
await waitFor(() => expect(successSpy).toHaveBeenCalled())
125+
await waitFor(() => expect(history.location.pathname).toEqual(projectPath))
119126
})
120127
})

app/test-utils.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,8 +46,8 @@ export function renderAppAt(location: string) {
4646
}
4747

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

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

0 commit comments

Comments
 (0)