From 0d4d0bdbf32582b82af3984b6191ed8ded4e526b Mon Sep 17 00:00:00 2001 From: Kai Vandivier Date: Mon, 21 Oct 2024 14:42:15 +0200 Subject: [PATCH] docs: add links and examples for React 18 test changes --- docs/migration/v12.md | 115 ++++++++++++++++++++++++++++++++++++++---- 1 file changed, 106 insertions(+), 9 deletions(-) diff --git a/docs/migration/v12.md b/docs/migration/v12.md index 8bf25c7b..13cd6e3a 100644 --- a/docs/migration/v12.md +++ b/docs/migration/v12.md @@ -93,17 +93,114 @@ React 18 has minimal effects on the operation of an app in a browser, but it has #### React Testing Library -Testing-library supports React 18 since v13, so the first step is to upgrade that library and the supporting libraries around it. These major versions bumps come with a few breaking changes that we're trying to document here: +Testing-library supports React 18 since v13, so the first step is to upgrade that library and the supporting libraries around it. These major versions bumps come with a few breaking changes that we will document here with some examples to make migration easier. -- `userEvent` is async now in `@testing-library/user-event`. Check the [release notes](https://github.com/testing-library/user-event/releases/tag/v14.0.0) for an idea of the improvements and new API - - In practice, this means mostly that you'd need to add an `await` for `userEvent` interactions like `userEvent.click()` -- `renderHook` is not a separate library anymore; it is part of the `@testing-library/react`, and it has quite a different API. NB: most docs online still point to the old version, which can be confusing. - - Use `import { renderHook } from '@testing-library/react'` instead of `import { renderHook } from '@testing-library/react-hooks` - - The return type for renderHook is different. One major difference is the absence of `waitForNextUpdate` returned from `renderHook`. Now it can be replaced with the `waitFor` from `@testing-library`, and adding an expectation to wait for, for example. - - Testing hooks that throw errors is different. Use `expect(renderHook(() => { ... })).toThrow(....)` -- Faking timers can help with tests that seem to fail with concurrency issues +Examples come from the migration for the Aggregate Data Entry app; you can check out the PR [here](https://github.com/dhis2/aggregate-data-entry-app/pull/396) for more examples in context. -[To do: add details to each bullet; get examples from PRs] +##### `userEvent` + +`userEvent` is async now in `@testing-library/user-event`. Check the [release notes](https://github.com/testing-library/user-event/releases/tag/v14.0.0) for an idea of the improvements and new API. + +In practice, this means mostly that you'd need to add an `await` for `userEvent` interactions like `userEvent.click()`: + +```diff ++ import userEvent from '@testing-library/user-event' + +- it('should allow re-running validation', () => { ++ // Make the function async: ++ it('should allow re-running validation', async () => { + // ... + +- userEvent.click(getByText('Run validation again')) +- // Or this other form: +- fireEvent.click(getByText('Run validation again')) ++ // Now that it's asynchronous, await the event: ++ await userEvent.click(getByText('Run validation again')) + + await findByText('2 medium priority alerts') + expect(queryByText('There was a problem running validation')).toBeNull() +}) +``` + +##### `renderHook` + +`renderHook` is not a separate library anymore; it is part of the `@testing-library/react`, and it has [quite a different API](https://testing-library.com/docs/react-testing-library/api/#renderhook). (NB: Some docs online still point to the old version, which can be confusing.) + +- Use `import { renderHook } from '@testing-library/react'` instead of `import { renderHook } from '@testing-library/react-hooks` +- The [return type](https://testing-library.com/docs/react-testing-library/api/#renderhook-result) for renderHook is different. One major difference is the absence of `waitForNextUpdate` returned from `renderHook`. Now it can be replaced with the `waitFor` from `@testing-library`, and adding an expectation to wait for, for example. +- Testing hooks that throw errors is different. Use `expect(renderHook(() => { ... })).toThrow(....)` + +This example demonstrates some of the changes: + +```diff +- import { renderHook } from '@testing-library/react-hooks' ++ // Update import, and include waitFor: ++ import { renderHook, waitFor } from '@testing-library/react' +import React from 'react' +import { useRootOrgData } from './use-root-org-data.js' + +it('should provide the org unit data', async () => { +- const { result, waitForNextUpdate } = renderHook( +- () => useRootOrgData(['A0000000000']), +- { wrapper } +- ) ++ // waitForNextUpdate is no longer part of the result: ++ const { result } = renderHook(() => useRootOrgData(['A0000000000']), { ++ wrapper, ++ }) + +- await waitForNextUpdate() ++ // Instead, use waitFor: ++ await waitFor(() => {}) + // ... +}) +``` + +##### Fake timers + +Faking timers can help with tests that seem to fail with concurrency issues: + +```diff +describe('', () => { ++ // Set up fake timers: ++ beforeEach(() => { ++ jest.useFakeTimers ++ }) + + afterEach(() => { + // ... + }) + + it('shows a loading indicator when submitting a comment change', async () => { + // ... + +- const { getByRole, queryByRole } = render() ++ const { getByRole, queryByRole, findByRole } = render( ++ ++ ) + +- userEvent.click(getByRole('button', { name: 'Edit comment' })) ++ const editButton = await findByRole('button', { name: 'Edit comment' }) ++ // Set up user event with fake timers: ++ const user = userEvent.setup({ ++ advanceTimers: jest.advanceTimersByTime, ++ }) ++ await user.click(editButton) + + // ... + + expect(queryByRole('progressbar')).not.toBeInTheDocument() +- userEvent.click(getByRole('button', { name: 'Save comment' })) +- expect(getByRole('progressbar')).toBeInTheDocument() ++ // Use the setup from above: ++ const btnSaveComment = await findByRole('button', { ++ name: 'Save comment', ++ }) ++ await user.click(btnSaveComment) ++ await findByRole('progressbar') + }) +}) +``` #### Enzyme