Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Render the whole app in page-level tests #565

Merged
merged 10 commits into from
Jan 4, 2022
Merged

Render the whole app in page-level tests #565

merged 10 commits into from
Jan 4, 2022

Conversation

david-crespo
Copy link
Collaborator

@david-crespo david-crespo commented Dec 12, 2021

I've felt our test conventions for pages were a little lacking. I didn't really like the tweaks I made in #535 even if asserting on an onSuccess spy is a slight improvement on hacky asserts on window.location. Turns out asserting on window.location is fine, you just have to use history.pushState to set the current route at the beginning of every test. This is easy if you bake it into renderAppAt(url) as I have here.

Summary of changes

  • renderAppAt(url) does what it sounds like
  • InstanceCreatePage and ProjectCreatePage tests use it
  • Refactor InstanceCreatePage and ProjectCreatePage now that we don't need an inner Form with props for route params and onSuccess for testing purposes

Bad stuff

  • fetch-mock is still kind of horrible, but that's orthogonal to this change. I'm just using it slightly better

Outdated commentary about spying on `history` that I don't want to delete

I realized we can non-hackily assert on location if we have access to the history object used by React Router. This SO answer says how to do that with a Router (as opposed to, e.g., MemoryRouter or BrowserRouter) but in RR 6.1 they added a HistoryRouter that makes it as simple as <HistoryRouter history={history}>. (Note that in 6.1.1 they changed the export name to unstable_HistoryRouter because they expect the API to change, but I don't really care about that — we can easily update when they change it.)

So based on that, we would want a helper that renders the component under test inside a HistoryRouter and returns the history object so we can assert on history.location. The problem here is that if we want to use relative routes (we probably do? one could certainly argue otherwise) they will produce weird results unless we're rendering our actual route tree in the tests. And... why not?

@vercel
Copy link

vercel bot commented Dec 12, 2021

This pull request is being automatically deployed with Vercel (learn more).
To see the status of your deployment, click below or on the icon next to each commit.

🔍 Inspect: https://vercel.com/oxidecomputer/console-ui-storybook/LCe29rjY3e3C14m9W2fTssP5shUn
✅ Preview: https://console-ui-storybook-git-render-app-at-oxidecomputer.vercel.app

@github-actions
Copy link
Contributor

Preview will be deployed at https://console-git-render-app-at.internal.oxide.computer

@david-crespo david-crespo temporarily deployed to Preview VM December 12, 2021 22:16 Inactive
@david-crespo david-crespo temporarily deployed to Preview VM December 12, 2021 22:26 Inactive
@david-crespo david-crespo temporarily deployed to Preview VM December 12, 2021 23:11 Inactive
@david-crespo david-crespo mentioned this pull request Dec 13, 2021
@david-crespo david-crespo changed the title Proof of concept: render the whole app in page-level tests Experiment: render the whole app in page-level tests Dec 13, 2021
expect(history.location.pathname).toEqual(
`/orgs/${org.name}/projects/${project.name}/instances`
)
)
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a little funny because we actually navigate to the project route, but that redirects to project instances.

await waitFor(() => expect(submit).toBeDisabled())
expect(mock.done()).toBeTruthy()
expect(submit).not.toBeDisabled()
expect(mock.called(undefined, 'POST')).toBeTruthy()
Copy link
Collaborator Author

@david-crespo david-crespo Dec 13, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This mock variable refers not only, as you would expect, to the post mock but to all mock requests to this URL, which is really annoying and dumb, and requires me to filter here to only the POST. Making this change made me realize how bad fetch-mock is. If we want to keep mocking fetch (which we may not) I think we should find another library or just wrap global.fetch ourselves, as the linked posts do.

https://github.com/jefflau/jest-fetch-mock
https://benjaminjohnson.me/mocking-fetch
https://www.leighhalliday.com/mock-fetch-jest

There's also Kent C. Dodds's post about why Mock Service Workers is better than mocking fetch. I never found it too convincing, but this PR has definitely made me more amenable to it.

@david-crespo
Copy link
Collaborator Author

Tried upgrading react-testing-library to v13.0.0-alpha.5 to get rid of the very noisy React 18 warnings

Warning: ReactDOM.render is no longer supported in React 18. Use createRoot instead. Until you switch to the new API, your app will behave as if it's running React 17. Learn more: https://reactjs.org/link/switch-to-createroot

but it caused weird failures in the "disables submit button" tests that didn't seem worth the time to debug.

@david-crespo david-crespo temporarily deployed to Preview VM December 13, 2021 02:25 Inactive
})
const renderPage = () => {
// fetch projects list for org layout sidebar on project create
fetchMock.get(projectsUrl, { status: 200, body: { items: [] } })
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

feels silly to have to do this. definitely a point against the whole approach

@david-crespo david-crespo changed the title Experiment: render the whole app in page-level tests Render the whole app in page-level tests Jan 3, 2022
@david-crespo david-crespo marked this pull request as ready for review January 3, 2022 19:15
{getServerError(createProject.error, ERROR_CODES)}
</div>
</Form>
</Formik>
</>
)
}
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

changes to this file and InstanceCreatePage are much less interesting than they look, and they shrink quite a bit with whitespace changes hidden — just moving the contents of the Form component into the page since we no longer need the former for testing purposes

@david-crespo david-crespo temporarily deployed to Preview VM January 3, 2022 19:17 Inactive

fireEvent.click(submitButton())

await waitFor(() => expect(mock.called()).toBeTruthy())
await waitFor(() => expect(mock.done()).toBeTruthy())
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

turns out these weren't doing what I thought because fetchMock is horrible? I'll see if I can bring them back properly

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants