Skip to content

Commit f23f475

Browse files
committed
proof of concept for making all page-level tests into integration tests
1 parent e34afcb commit f23f475

File tree

4 files changed

+51
-25
lines changed

4 files changed

+51
-25
lines changed

app/pages/__tests__/InstanceCreateForm.spec.tsx

Lines changed: 14 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,14 @@ import React from 'react'
22
import {
33
fireEvent,
44
lastBody,
5-
renderWithRouter,
5+
renderAppAt,
66
screen,
77
waitFor,
88
} from '../../test-utils'
99
import fetchMock from 'fetch-mock'
1010

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

13-
import { InstanceCreateForm } from '../project/instances/create/InstancesCreatePage'
14-
1513
const submitButton = () =>
1614
screen.getByRole('button', { name: 'Create instance' })
1715

@@ -20,21 +18,14 @@ const instancesUrl = `${projectUrl}/instances`
2018
const disksUrl = `${projectUrl}/disks`
2119
const vpcsUrl = `${projectUrl}/vpcs`
2220

23-
let successSpy: jest.Mock
21+
const renderPage = () =>
22+
renderAppAt(`/orgs/${org.name}/projects/${project.name}/instances/new`)
2423

2524
describe('InstanceCreateForm', () => {
2625
beforeEach(() => {
2726
// existing disk modal fetches disks on render even if it's not visible
2827
fetchMock.get(disksUrl, 200)
2928
fetchMock.get(vpcsUrl, 200)
30-
successSpy = jest.fn()
31-
renderWithRouter(
32-
<InstanceCreateForm
33-
orgName={org.name}
34-
projectName={project.name}
35-
onSuccess={successSpy}
36-
/>
37-
)
3829
})
3930

4031
afterEach(() => {
@@ -43,6 +34,7 @@ describe('InstanceCreateForm', () => {
4334

4435
it('disables submit button on submit and enables on response', async () => {
4536
const mock = fetchMock.post(instancesUrl, 201)
37+
renderPage()
4638

4739
const submit = submitButton()
4840
expect(submit).not.toBeDisabled()
@@ -52,14 +44,14 @@ describe('InstanceCreateForm', () => {
5244
expect(mock.called(instancesUrl)).toBeFalsy()
5345
await waitFor(() => expect(submit).toBeDisabled())
5446
expect(mock.done()).toBeTruthy()
55-
expect(submit).not.toBeDisabled()
5647
})
5748

5849
it('shows specific message for known server error code', async () => {
5950
fetchMock.post(instancesUrl, {
6051
status: 400,
6152
body: { error_code: 'ObjectAlreadyExists' },
6253
})
54+
renderPage()
6355

6456
fireEvent.click(submitButton())
6557

@@ -73,6 +65,7 @@ describe('InstanceCreateForm', () => {
7365
status: 400,
7466
body: { error_code: 'UnknownCode' },
7567
})
68+
renderPage()
7669

7770
fireEvent.click(submitButton())
7871

@@ -81,6 +74,7 @@ describe('InstanceCreateForm', () => {
8174

8275
it('posts form on submit', async () => {
8376
const mock = fetchMock.post(instancesUrl, 201)
77+
renderPage()
8478

8579
fireEvent.change(screen.getByLabelText('Choose a name'), {
8680
target: { value: 'new-instance' },
@@ -99,15 +93,18 @@ describe('InstanceCreateForm', () => {
9993
)
10094
})
10195

102-
it('calls onSuccess on success', async () => {
96+
it('navigates to project instances page on success', async () => {
10397
const mock = fetchMock.post(instancesUrl, { status: 201, body: instance })
104-
105-
expect(successSpy).not.toHaveBeenCalled()
98+
const { history } = renderPage()
10699

107100
fireEvent.click(submitButton())
108101

109102
await waitFor(() => expect(mock.called(instancesUrl)).toBeTruthy())
110103
await waitFor(() => expect(mock.done()).toBeTruthy())
111-
await waitFor(() => expect(successSpy).toHaveBeenCalled())
104+
await waitFor(() =>
105+
expect(history.location.pathname).toEqual(
106+
`/orgs/${org.name}/projects/${project.name}/instances`
107+
)
108+
)
112109
})
113110
})

app/test-utils.tsx

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,12 @@
1-
import React from 'react'
2-
import { BrowserRouter as Router } from 'react-router-dom'
1+
import {
2+
BrowserRouter,
3+
unstable_HistoryRouter as HistoryRouter,
4+
} from 'react-router-dom'
5+
import { createMemoryHistory } from 'history'
36
import { render } from '@testing-library/react'
47
import { QueryClient, QueryClientProvider } from 'react-query'
58
import type { FetchMockStatic } from 'fetch-mock'
9+
import { routes } from './routes'
610

711
const queryClient = new QueryClient({
812
defaultOptions: {
@@ -22,14 +26,24 @@ const customRender = (ui: React.ReactElement) =>
2226
export const renderWithRouter = (ui: React.ReactElement) =>
2327
render(ui, {
2428
wrapper: ({ children }) => (
25-
<Router>
29+
<BrowserRouter>
2630
<QueryClientProvider client={queryClient}>
2731
{children}
2832
</QueryClientProvider>
29-
</Router>
33+
</BrowserRouter>
3034
),
3135
})
3236

37+
export function renderAppAt(location: string) {
38+
const history = createMemoryHistory({ initialEntries: [location] })
39+
const rendered = render(
40+
<HistoryRouter history={history}>
41+
<QueryClientProvider client={queryClient}>{routes}</QueryClientProvider>
42+
</HistoryRouter>
43+
)
44+
return { history, rendered }
45+
}
46+
3347
// eslint-disable-next-line @typescript-eslint/no-explicit-any
3448
export const lastBody = (mock: FetchMockStatic): any =>
3549
JSON.parse(mock.lastOptions()?.body as unknown as string)

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,8 @@
4141
"react-is": "^17.0.2",
4242
"react-popper": "^2.2.5",
4343
"react-query": "^3.13.12",
44-
"react-router": "^6.0.0",
45-
"react-router-dom": "^6.0.0",
44+
"react-router": "^6.1.1",
45+
"react-router-dom": "^6.1.1",
4646
"react-table": "^7.7.0",
4747
"react-transition-group": "^4.4.1",
4848
"recharts": "^2.1.6",

yarn.lock

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12175,21 +12175,36 @@ react-resize-detector@^6.6.3:
1217512175
lodash.throttle "^4.1.1"
1217612176
resize-observer-polyfill "^1.5.1"
1217712177

12178-
react-router-dom@^6.0.0, react-router-dom@^6.0.0-beta.8:
12178+
react-router-dom@^6.0.0-beta.8:
1217912179
version "6.0.2"
1218012180
resolved "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.0.2.tgz"
1218112181
integrity sha512-cOpJ4B6raFutr0EG8O/M2fEoyQmwvZWomf1c6W2YXBZuFBx8oTk/zqjXghwScyhfrtnt0lANXV2182NQblRxFA==
1218212182
dependencies:
1218312183
history "^5.1.0"
1218412184
react-router "6.0.2"
1218512185

12186-
[email protected], react-router@^6.0.0, react-router@^6.0.0-beta.8:
12186+
react-router-dom@^6.1.1:
12187+
version "6.1.1"
12188+
resolved "https://registry.yarnpkg.com/react-router-dom/-/react-router-dom-6.1.1.tgz#ed59376ff9115bc49227e87982a32e91e9530ca3"
12189+
integrity sha512-O3UH89DI4o+swd2q6lF4dSmpuNCxwkUXcj0zAFcVc1H+YoPE6T7uwoFMX0ws1pUvCY8lYDucFpOqCCdal6VFzg==
12190+
dependencies:
12191+
history "^5.1.0"
12192+
react-router "6.1.1"
12193+
12194+
[email protected], react-router@^6.0.0-beta.8:
1218712195
version "6.0.2"
1218812196
resolved "https://registry.npmjs.org/react-router/-/react-router-6.0.2.tgz"
1218912197
integrity sha512-8/Wm3Ed8t7TuedXjAvV39+c8j0vwrI5qVsYqjFr5WkJjsJpEvNSoLRUbtqSEYzqaTUj1IV+sbPJxvO+accvU0Q==
1219012198
dependencies:
1219112199
history "^5.1.0"
1219212200

12201+
[email protected], react-router@^6.1.1:
12202+
version "6.1.1"
12203+
resolved "https://registry.yarnpkg.com/react-router/-/react-router-6.1.1.tgz#16f41bf54e87d995bcd4d447720a693f77d8fcb9"
12204+
integrity sha512-55o96RiDZmC0uD17DPqVmzzfdNd2Dc+EjkYvMAmHl43du/GItaTdFr5WwjTryNWPXZ+OOVQxQhwAX25UwxpHtw==
12205+
dependencies:
12206+
history "^5.1.0"
12207+
1219312208
react-sizeme@^3.0.1:
1219412209
version "3.0.2"
1219512210
resolved "https://registry.npmjs.org/react-sizeme/-/react-sizeme-3.0.2.tgz"

0 commit comments

Comments
 (0)