diff --git a/docs/dom-testing-library/api-events.mdx b/docs/dom-testing-library/api-events.mdx index 8801f9c24..62578151d 100644 --- a/docs/dom-testing-library/api-events.mdx +++ b/docs/dom-testing-library/api-events.mdx @@ -10,7 +10,7 @@ import TabItem from '@theme/TabItem' > > Most projects have a few use cases for `fireEvent`, but the majority of the > time you should probably use -> [`@testing-library/user-event`](ecosystem-user-event.mdx). +> [`@testing-library/user-event`](user-event/intro.mdx). ## `fireEvent` diff --git a/docs/dom-testing-library/install.mdx b/docs/dom-testing-library/install.mdx index 781517aa9..a39c42cf5 100644 --- a/docs/dom-testing-library/install.mdx +++ b/docs/dom-testing-library/install.mdx @@ -33,7 +33,7 @@ install the wrapper: `DOM Testing Library` works well with these companion libraries: -- [user-event](ecosystem-user-event.mdx) browser event simulation +- [user-event](user-event/intro.mdx) browser event simulation - [jest-dom](ecosystem-jest-dom.mdx) custom Jest matchers - [bs-jest-dom](ecosystem-bs-jest-dom.mdx) companion library for `bs-react-testing-library` diff --git a/docs/ecosystem-user-event.mdx b/docs/ecosystem-user-event.mdx index 2446b8336..44d84a48c 100644 --- a/docs/ecosystem-user-event.mdx +++ b/docs/ecosystem-user-event.mdx @@ -10,9 +10,14 @@ import TabItem from '@theme/TabItem' advanced simulation of browser interactions than the built-in [`fireEvent`](dom-testing-library/api-events.mdx#fireevent) method. -> This page describes `user-event@13.5.0`. -If you are starting or actively working on a project, -we recommend to use [`user-event@14.0.0-beta`](user-event/intro.mdx) instead, as it includes important bug fixes and new features. +:::caution End of life + +This page describes `user-event@13.5.0`. +This version is no longer maintained. Please use +[`user-event@14`](user-event/intro.mdx) instead, as it includes important bug +fixes and new features. + +::: ## Installation @@ -222,7 +227,7 @@ import {render, screen} from '@testing-library/react' import userEvent from '@testing-library/user-event' test('prepend text', () => { - render() + render() const element = screen.getByRole('textbox') // Prepend text diff --git a/docs/example-findByText.md b/docs/example-findByText.md index bb62c789f..f2b02b2d6 100644 --- a/docs/example-findByText.md +++ b/docs/example-findByText.md @@ -8,13 +8,14 @@ title: Using findByText // This is an example of how to use findByText to query for text that // is not visible right away -import {getByRole, findByText, getByPlaceholderText} from '@testing-library/dom' +import {screen} from '@testing-library/dom' import userEvent from '@testing-library/user-event' // provides a set of custom jest matchers that you can use to extend jest // i.e. `.toBeVisible` import '@testing-library/jest-dom' -const renderContent = el => { +function renderApp() { + const el = document.body.appendChild(document.createElement('div')) el.innerHTML = `
@@ -64,8 +65,8 @@ const renderContent = el => { const userInput = el.querySelector('#username_input') const passwordInput = el.querySelector('#password_input') - var userName = userInput.value - var password = passwordInput.value + const userName = userInput.value + const password = passwordInput.value if (!userName) { el.querySelector('#username_required_error').style.display = 'inline' } @@ -88,51 +89,47 @@ const renderContent = el => { window.history.back() }) - return el + return {user: userEvent.setup()} } -describe('findByText Examples', () => { - let div - let container - - beforeEach(() => { - div = document.createElement('div') - container = renderContent(div) - }) +afterEach(() => (document.body.innerHTML = ``)) +describe('findByText Examples', () => { it('should show a required field warning for each empty input field', async () => { - userEvent.click( - getByRole(container, 'button', { + const {user} = renderApp() + await user.click( + screen.getByRole('button', { name: 'Login', }), ) - expect(await findByText(container, 'User Name Required')).toBeVisible() + expect(await screen.findByText('User Name Required')).toBeVisible() - expect(await findByText(container, 'Password Required')).toBeVisible() + expect(await screen.findByText('Password Required')).toBeVisible() }) it('should show invalid field errors for each invalid input field', async () => { - const userNameField = getByPlaceholderText(container, 'Enter user name') - const passwordField = getByPlaceholderText(container, 'Enter password') + const {user} = renderApp() + const userNameField = screen.getByPlaceholderText('Enter user name') + const passwordField = screen.getByPlaceholderText('Enter password') - expect(await findByText(container, 'Invalid Password')).not.toBeVisible() - expect(await findByText(container, 'Invalid User Name')).not.toBeVisible() + expect(await screen.findByText('Invalid Password')).not.toBeVisible() + expect(await screen.findByText('Invalid User Name')).not.toBeVisible() - userEvent.type(userNameField, 'Philchard') - userEvent.type(passwordField, 'theCat') + await user.type(userNameField, 'Philchard') + await user.type(passwordField, 'theCat') expect(userNameField).toHaveValue('Philchard') expect(passwordField).toHaveValue('theCat') - userEvent.click( - getByRole(container, 'button', { + await user.click( + screen.getByRole('button', { name: 'Login', }), ) - expect(await findByText(container, 'Invalid User Name')).toBeVisible() - expect(await findByText(container, 'Invalid Password')).toBeVisible() + expect(await screen.findByText('Invalid User Name')).toBeVisible() + expect(await screen.findByText('Invalid Password')).toBeVisible() }) }) ``` diff --git a/docs/example-formik.md b/docs/example-formik.md index a25b0adc3..211a07ba6 100644 --- a/docs/example-formik.md +++ b/docs/example-formik.md @@ -63,12 +63,13 @@ import {MyForm} from './myForm.js' test('rendering and submitting a basic Formik form', async () => { const handleSubmit = jest.fn() render() + const user = userEvent.setup() - userEvent.type(screen.getByLabelText(/first name/i), 'John') - userEvent.type(screen.getByLabelText(/last name/i), 'Dee') - userEvent.type(screen.getByLabelText(/email/i), 'john.dee@someemail.com') + await user.type(screen.getByLabelText(/first name/i), 'John') + await user.type(screen.getByLabelText(/last name/i), 'Dee') + await user.type(screen.getByLabelText(/email/i), 'john.dee@someemail.com') - userEvent.click(screen.getByRole('button', {name: /submit/i})) + await user.click(screen.getByRole('button', {name: /submit/i})) await waitFor(() => expect(handleSubmit).toHaveBeenCalledWith({ diff --git a/docs/example-input-event.mdx b/docs/example-input-event.mdx index dd0a0c2b7..1bf9acf57 100644 --- a/docs/example-input-event.mdx +++ b/docs/example-input-event.mdx @@ -7,8 +7,7 @@ sidebar_label: Input Event > **Note** > > If you want to simulate a more natural typing behaviour while testing your -> component, consider the companion library -> [`user-event`](ecosystem-user-event.mdx) +> component, consider the companion library [`user-event`](user-event/intro.mdx) ```jsx import React, {useState} from 'react' diff --git a/docs/example-react-router.mdx b/docs/example-react-router.mdx index 00ae687ce..965d1fd18 100644 --- a/docs/example-react-router.mdx +++ b/docs/example-react-router.mdx @@ -55,19 +55,19 @@ import '@testing-library/jest-dom' import {App, LocationDisplay} from './app' -test('full app rendering/navigating', () => { +test('full app rendering/navigating', async () => { const history = createMemoryHistory() render( , ) + const user = userEvent.setup() // verify page content for expected route // often you'd use a data-testid or role query, but this is also possible expect(screen.getByText(/you are home/i)).toBeInTheDocument() - const leftClick = {button: 0} - userEvent.click(screen.getByText(/about/i), leftClick) + await user.click(screen.getByText(/about/i)) // check that the content changed to the new page expect(screen.getByText(/you are on the about page/i)).toBeInTheDocument() @@ -127,18 +127,20 @@ test('full app rendering/navigating', () => { const renderWithRouter = (ui, {route = '/'} = {}) => { window.history.pushState({}, 'Test page', route) - return render(ui, {wrapper: BrowserRouter}) + return { + user: userEvent.setup(), + ...render(ui, {wrapper: BrowserRouter}), + } } ``` ```jsx // app.test.js -test('full app rendering/navigating', () => { - renderWithRouter() +test('full app rendering/navigating', async () => { + const {user} = renderWithRouter() expect(screen.getByText(/you are home/i)).toBeInTheDocument() - const leftClick = {button: 0} - userEvent.click(screen.getByText(/about/i), leftClick) + await user.click(screen.getByText(/about/i)) expect(screen.getByText(/you are on the about page/i)).toBeInTheDocument() }) diff --git a/docs/guide-events.mdx b/docs/guide-events.mdx index 8dbb023ef..1c2e520b4 100644 --- a/docs/guide-events.mdx +++ b/docs/guide-events.mdx @@ -38,7 +38,7 @@ simply using `fireEvent.click` is worth it. We will describe a couple of simple adjustments to your tests that will increase your confidence in the interactive behavior of your components. For other interactions you may want to either consider using -[`user-event`](ecosystem-user-event.mdx) or testing your components in a real +[`user-event`](user-event/intro.mdx) or testing your components in a real environment (e.g. manually, automatic with cypress, etc.). ### Keydown diff --git a/docs/queries/about.mdx b/docs/queries/about.mdx index 9428930fe..90ae6b97a 100644 --- a/docs/queries/about.mdx +++ b/docs/queries/about.mdx @@ -18,9 +18,9 @@ make use of semantic queries to test your page in the most accessible way. After selecting an element, you can use the [Events API](dom-testing-library/api-events.mdx) or -[user-event](ecosystem-user-event.mdx) to fire events and simulate user -interactions with the page, or use Jest and [jest-dom](ecosystem-jest-dom.mdx) -to make assertions about the element. +[user-event](user-event/intro.mdx) to fire events and simulate user interactions +with the page, or use Jest and [jest-dom](ecosystem-jest-dom.mdx) to make +assertions about the element. There are Testing Library helper methods that work with queries. As elements appear and disappear in response to actions, diff --git a/docs/react-testing-library/migrate-from-enzyme.mdx b/docs/react-testing-library/migrate-from-enzyme.mdx index 17b1ea5aa..94ce76863 100644 --- a/docs/react-testing-library/migrate-from-enzyme.mdx +++ b/docs/react-testing-library/migrate-from-enzyme.mdx @@ -20,8 +20,8 @@ some of the project's other libraries that can help you along the way: - **[@testing-library/jest-dom](https://github.com/testing-library/jest-dom)**: `jest-dom` provides a set of custom Jest matchers that you can use to extend - Jest. These make your tests more declarative, clearer to read, and easier - to maintain. + Jest. These make your tests more declarative, clearer to read, and easier to + maintain. - **[@testing-library/user-event](https://github.com/testing-library/user-event):** `user-event` tries to simulate the real events that happen in the browser as @@ -120,8 +120,8 @@ test this component: The following component gets a `name` from `props` and shows a welcome message in an `h1` element. It also has a text input which users can change to a -different name, and the template updates accordingly. Check the live version -on [CodeSandbox](https://codesandbox.io/s/ecstatic-hellman-fh7in). +different name, and the template updates accordingly. Check the live version on +[CodeSandbox](https://codesandbox.io/s/ecstatic-hellman-fh7in). ```jsx const Welcome = props => { @@ -247,15 +247,15 @@ of the query documentation might help you understand the concepts better. > A `` element must have a `name` attribute in order to have an implicit > `role` of `'form'` (as required by the specification). -React Testing Library aims to test the components how users use them. Users -see buttons, headings, forms and other elements by their role, not by their -`id`, `class`, or element tag name. Therefore, when you use React Testing -Library you should avoid accessing the DOM with the `document.querySelector` -API. (You _can_ use it in your tests, but it's not recommended for the reasons -stated in this paragraph.) +React Testing Library aims to test the components how users use them. Users see +buttons, headings, forms and other elements by their role, not by their `id`, +`class`, or element tag name. Therefore, when you use React Testing Library you +should avoid accessing the DOM with the `document.querySelector` API. (You _can_ +use it in your tests, but it's not recommended for the reasons stated in this +paragraph.) -React Testing Library exposes some handy query APIs which help you access -the component elements efficiently. You can see the +React Testing Library exposes some handy query APIs which help you access the +component elements efficiently. You can see the [list of available queries here](queries/about.mdx#types-of-queries). If you're not sure which query you should use in a given situation, we have a great page which explains [which query to use](queries/about.mdx#priority), so check it @@ -330,10 +330,14 @@ input's "checked" property is properly set. Let's see how we might write a test for that case: ```jsx -test('handles click correctly', () => { +test('handles click correctly', async () => { render() + const user = userEvent.setup() + + // You can also call this method directly on userEvent, + // but using the methods from `.setup()` is recommended. + await user.click(screen.getByText('Check')) - userEvent.click(screen.getByText('Check')) expect(screen.getByLabelText('Check')).toBeChecked() }) ``` diff --git a/docs/user-event/api-keyboard.mdx b/docs/user-event/api-keyboard.mdx index ce8790173..85d3c7b27 100644 --- a/docs/user-event/api-keyboard.mdx +++ b/docs/user-event/api-keyboard.mdx @@ -69,7 +69,7 @@ keyboard('{Shift>}A{/Shift}') // translates to: Shift(down), A, Shift(up) ``` The mapping of `key` to `code` is performed by a -[default key map](https://github.com/testing-library/user-event/blob/beta/src/keyboard/keyMap.ts) +[default key map](https://github.com/testing-library/user-event/blob/main/src/keyboard/keyMap.ts) portraying a "default" US-keyboard. You can provide your own local keyboard mapping per [`keyboardMap`](options.mdx#keyboardmap) option. @@ -79,5 +79,5 @@ keys. > Future versions might try to interpolate the modifiers needed to reach a > printable key on the keyboard. E.g. Automatically pressing `{Shift}` when > CapsLock is not active and `A` is referenced. If you don't wish this behavior, -> you can deactivate the [`autoModify`](options.mdx#automodify) option to opt out -> of this non-breaking change. +> you can deactivate the [`autoModify`](options.mdx#automodify) option to opt +> out of this non-breaking change. diff --git a/docs/user-event/install.mdx b/docs/user-event/install.mdx index 13035c067..db2be35f6 100644 --- a/docs/user-event/install.mdx +++ b/docs/user-event/install.mdx @@ -13,14 +13,14 @@ import TabItem from '@theme/TabItem' ```sh -npm install --save-dev @testing-library/user-event@^14.0.0-beta +npm install --save-dev @testing-library/user-event ``` ```sh -yarn add --dev @testing-library/user-event@^14.0.0-beta +yarn add --dev @testing-library/user-event ``` @@ -29,8 +29,8 @@ yarn add --dev @testing-library/user-event@^14.0.0-beta Note that `@testing-library/user-event` requires `@testing-library/dom`. If you use one of the -[framework wrappers](../dom-testing-library/install.mdx#wrappers), it is important -that `@testing-library/dom` is resolved to the same installation required by the -framework wrapper of your choice. +[framework wrappers](../dom-testing-library/install.mdx#wrappers), it is +important that `@testing-library/dom` is resolved to the same installation +required by the framework wrapper of your choice. Usually this means that if you use one of the framework wrappers, you should not add `@testing-library/dom` to your project dependencies. diff --git a/docs/user-event/intro.mdx b/docs/user-event/intro.mdx index 441ef3649..ff397ad1f 100644 --- a/docs/user-event/intro.mdx +++ b/docs/user-event/intro.mdx @@ -3,17 +3,18 @@ id: intro title: Introduction --- -[`user-event`](https://github.com/testing-library/user-event) -is a companion library for Testing Library that simulates user interactions by -dispatching the events that would happen if the interaction took place in a browser. +[`user-event`](https://github.com/testing-library/user-event) is a companion +library for Testing Library that simulates user interactions by dispatching the +events that would happen if the interaction took place in a browser. -> These docs describe `user-event@14.0.0-beta`. -This is still a pre-release and might be subject to breaking changes -if they should be deemed necessary in the light of feedback we receive for this version. -All planned breaking changes are already implemented though. -If you are starting or actively working on a project, -we recommend to use this pre-release, as it includes important bug fixes and new features. -You can find the docs for `user-event@13.5.0` [here](../ecosystem-user-event.mdx). +:::note Latest version + +These docs describe `user-event@14`. +We recommend updating your projects to this version, as it includes important +bug fixes and new features. You can find the docs for `user-event@13.5.0` +[here](../ecosystem-user-event.mdx). + +::: While most examples with `user-event` are for `React`, the library can be used with any framework as long as there is a DOM. @@ -36,8 +37,9 @@ to test interaction with your components. ## Writing tests with `userEvent` -We recommend to use [`userEvent.setup()`](setup.mdx) when rendering your component -and inline that rendering and setup in your test or use a setup function. +We recommend to use [`userEvent.setup()`](setup.mdx) when rendering your +component and inline that rendering and setup in your test or use a setup +function. We discourage rendering or using any `userEvent` functions outside of the test itself - e.g. in a `before`/`after` hook - for reasons described in ["Avoid Nesting When You're Testing"](https://kentcdodds.com/blog/avoid-nesting-when-youre-testing). @@ -55,14 +57,14 @@ test('trigger some awesome feature when clicking the button', async () => { ```js function setup(jsx) { - return { - user: userEvent.setup(), - ...render(jsx), - } + return { + user: userEvent.setup(), + ...render(jsx), + } } test('render with a setup function', async () => { - const { user } = setup() - // ... + const {user} = setup() + // ... }) ``` diff --git a/docs/user-event/options.mdx b/docs/user-event/options.mdx index 6098ae87d..3ecb0044d 100644 --- a/docs/user-event/options.mdx +++ b/docs/user-event/options.mdx @@ -3,13 +3,13 @@ id: options title: Options --- -The following options allow to adjust the behavior of `user-event` APIs. -They can be applied per [`setup()`](setup.mdx). +The following options allow to adjust the behavior of `user-event` APIs. They +can be applied per [`setup()`](setup.mdx). ### applyAccept -When using [`upload()`](api-utility.mdx#upload), automatically discard files that don't -match an `accept` property if such property exists on the element. +When using [`upload()`](api-utility.mdx#upload), automatically discard files +that don't match an `accept` property if such property exists on the element. `default`: `true` @@ -53,7 +53,7 @@ An array of keyboard keys the keyboard device consists of. This allows to plug in different layouts / localizations. `default`: -[A "standard" US-104-QWERTY keyboard.](https://github.com/testing-library/user-event/blob/beta/src/keyboard/keyMap.ts) +[A "standard" US-104-QWERTY keyboard.](https://github.com/testing-library/user-event/blob/main/src/keyboard/keyMap.ts) ### pointerEventsCheck @@ -71,7 +71,7 @@ This is a binary flag option. You can combine multiple Levels. - `PointerEventsCheckLevel.EachTarget`: Check each event target once - `PointerEventsCheckLevel.EachApiCall`: - Check each event target once + Check each event target once per API - `PointerEventsCheckLevel.EachTrigger`: Check pointer events on every user interaction that triggers a bunch of events. E.g. once for releasing a mouse button even though this triggers `pointerup`, `mouseup`, @@ -86,12 +86,12 @@ An array of available pointer keys. This allows to plug in different pointer devices. `default`: -[A simple mouse and a touchscreen](https://github.com/testing-library/user-event/blob/beta/src/pointer/keyMap.ts) +[A simple mouse and a touchscreen](https://github.com/testing-library/user-event/blob/main/src/pointer/keyMap.ts) ### skipAutoClose -[`type()`](api-utility.mdx#type) automatically releases any keys still pressed at the -end of the call. +[`type()`](api-utility.mdx#type) automatically releases any keys still pressed +at the end of the call. This option allows to opt out of this feature. `default`: false @@ -105,8 +105,8 @@ This option allows to opt out of this feature. ### skipHover -[`click()`](api-utility.mdx#click) implies moving the cursor to the target element -first. +[`click()`](api-utility.mdx#click) implies moving the cursor to the target +element first. This options allows to opt out of this feature. ### writeToClipboard @@ -114,8 +114,8 @@ This options allows to opt out of this feature. Write selected data to [Clipboard API](https://developer.mozilla.org/en-US/docs/Web/API/Clipboard) when a `cut` or `copy` is triggered. The Clipboard API is usually not available to -test code. Our [`setup()`](setup.mdx) replaces the `navigator.clipboard` property -with a stub. +test code. Our [`setup()`](setup.mdx) replaces the `navigator.clipboard` +property with a stub. -`default` when calling the APIs [directly](setup.mdx#direct-api): `false` +`default` when calling the APIs [directly](setup.mdx#direct-apis): `false` `default` when calling the APIs on an instance from `setup()`: `true`