From 6360263b97839581fd8d4c47da44a10f8f1dfad8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kim=20R=C3=B8en?= Date: Fri, 12 Jun 2020 12:11:12 +0200 Subject: [PATCH 1/4] docs: rework disappearance guide to provide guidance Makes a number of changes to the disappearance guide, moving it in a direction where it recommends more of the best practices that have appeared since the last time it was uses, as well as taking a stronger stance of which of multiple options are recommended. In more detail, the changes are: - Prioritize `findBy` over `waitFor` - Use matchers from `jest-dom` in examples instead of checking for `null` and then mentioning `jest-dom` later - Remove inline setup-instructions for `jest-dom` and instead link to docs - Recommend `waitForElementToBeRemoved` over `waitFor` - Smaller code example changes (split up separate examples in the same code fence to multiple fences) - Use the word `document` instead of `DOM` most places - Use `screen.` in all examples - Add explicit `expect` statements in all the examples for consistency --- docs/guide-disappearance.md | 115 +++++++++++++++++++++++++----------- 1 file changed, 79 insertions(+), 36 deletions(-) diff --git a/docs/guide-disappearance.md b/docs/guide-disappearance.md index 6ccf1194f..7408e69da 100644 --- a/docs/guide-disappearance.md +++ b/docs/guide-disappearance.md @@ -3,93 +3,136 @@ id: guide-disappearance title: Appearance and Disappearance --- -Sometimes you need to test that an element is present and then disappears or -vice versa. +Sometimes you need to test that an element is present and then disappears or the +other way around. ## Waiting for appearance -If you need to wait for an element to appear, the [async wait -utilities][async-api] allow you to wait for an assertion to be satisfied before -proceeding. The wait utilities retry until the query passes or times out. +If you need to wait for an element to appear, [`findBy`][find-by] and the [async +wait utility][async-api] `waitFor` allow you to wait for an assertion to be +satisfied before proceeding. The wait utilities retry until the query passes or +times out. -```jsx +Wait for appearance and return the element using `findBy`: + +```javascript +test('movie title appears', async () => { + // element is initially not present... + + const movieTitle = await screen.findByText('the lion king') + expect(movieTitle).toBeInTheDocument() +}) +``` + +Or wait for appearance using `waitFor` and `getBy`: + +```javascript test('movie title appears', async () => { // element is initially not present... - // wait for appearance await waitFor(() => { - expect(getByText('the lion king')).toBeInTheDocument() + expect(screen.getByText('the lion king')).toBeInTheDocument() }) - - // wait for appearance and return the element - const movie = await findByText('the lion king') }) ``` +These do more or less the same thing (`findBy` uses `waitFor` under the hood), +but the `findBy` version results in simpler code and a better error message. + +_Note: `toBeInTheDocument()` comes from [`@testing-library/jest-dom`][jest-dom]_ + ## Waiting for disappearance -The `waitForElementToBeRemoved` [async helper][async-api] function uses a -callback to query for the element on each DOM mutation and resolves to `true` -when the element is removed. +When you want to wait until an element has disappeared, you can use +`waitForElementToBeRemoved` or `waitFor`. + +The `waitForElementToBeRemoved` [async wait utility][async-api] takes an element +as an argument and waits until that element has been removed from the document. + +```javascript +test('movie title no longer present in document', async () => { + // element is present + const movie = screen.queryByText('the mummy') + await waitForElementToBeRemoved(movie) -```jsx -test('movie title no longer present in DOM', async () => { - // element is removed - await waitForElementToBeRemoved(() => queryByText('the mummy')) + // element has been removed + expect(movie).not.toBeInTheDocument() }) ``` -Using +`waitForElementToBeRemoved` works by using a [`MutationObserver`](https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver) -is more efficient than polling the DOM at regular intervals with `waitFor`. +internally, which means it responds to the element being removed in a very +efficient way. + +You can also pass an array or a callback to `waitForElementToBeRemoved` - +[see the documentation for more options](dom-testing-library/api-async.md#waitforelementtoberemoved). + +Another option is using the `waitFor` helper. -The `waitFor` [async helper][async-api] function retries until the wrapped function -stops throwing an error. This can be used to assert that an element disappears -from the page. +The `waitFor` [async wait utility][async-api] retries until the wrapped function +stops throwing an error. Because expectations throw errors when they fail, +putting one in the wrapped function can be used to wait for the element to be +removed. -```jsx +```javascript test('movie title goes away', async () => { // element is initially present... // note use of queryBy instead of getBy to return null // instead of throwing in the query itself await waitFor(() => { - expect(queryByText('i, robot')).not.toBeInTheDocument() + expect(screen.queryByText('i, robot')).not.toBeInTheDocument() }) }) ``` +Polling like this is not as efficient as observing for mutations using +`waitForElementToBeRemoved`, but sometimes it's the best option. + ## Asserting elements are not present -The standard `getBy` methods throw an error when they can't find an element, so -if you want to make an assertion that an element is _not_ present in the DOM, -you can use `queryBy` APIs instead: +As opposed to waiting for removal, this is for when you are at a point in your +test where you know an element shouldn't be present. + +You might reach for `getBy` to check that something is not present, but `getBy` +queries throw an error when they can't find an element, which means you don't +get the chance to use the result in an expectation. If you want to make an +assertion that an element is _not_ present in the document, you can use +`queryBy` queries instead: ```javascript const submitButton = screen.queryByText('submit') -expect(submitButton).toBeNull() // it doesn't exist +expect(submitButton).not.toBeInTheDocument() // it doesn't exist in the document ``` -The `queryAll` APIs version return an array of matching nodes. The length of the -array can be useful for assertions after elements are added or removed from the -DOM. +The `queryAll` query methods return an array of matching elements. The length of +the array can be useful for assertions after elements are added or removed from +the document. ```javascript const submitButtons = screen.queryAllByText('submit') expect(submitButtons).toHaveLength(2) // expect 2 elements ``` -### `not.toBeInTheDocument` +_Note: `not.toBeInTheDocument()` comes from +[`@testing-library/jest-dom`][jest-dom]_ -The [`jest-dom`](ecosystem-jest-dom.md) utility library provides the +## The `toBeInTheDocument()` matcher + +The [`@testing-library/jest-dom`][jest-dom] utility library provides the `.toBeInTheDocument()` matcher, which can be used to assert that an element is in the body of the document, or not. This can be more meaningful than asserting -a query result is `null`. +a query result is `null`, and it also provides more helpful error messages when +your tests fail. ```javascript -import '@testing-library/jest-dom/extend-expect' // use `queryBy` to avoid throwing an error with `getBy` const submitButton = screen.queryByText('submit') expect(submitButton).not.toBeInTheDocument() ``` +Read about how to set this up [in the documentation](jest-dom). + [async-api]: dom-testing-library/api-async.md +[find-by]: dom-testing-library/api-queries.md#findby +[jest-dom]: ecosystem-jest-dom.md From 01849883c1bf5ddeeead4c8d2054e4dd7e2c8cdf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kim=20R=C3=B8en?= Date: Fri, 12 Jun 2020 13:03:06 +0200 Subject: [PATCH 2/4] use stronger language and shorten sentence MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Changes "you can use" to "you need to use" and removes a redundant clause from the sentence. Co-authored-by: AdriĆ  Fontcuberta --- docs/guide-disappearance.md | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/docs/guide-disappearance.md b/docs/guide-disappearance.md index 7408e69da..37ad31871 100644 --- a/docs/guide-disappearance.md +++ b/docs/guide-disappearance.md @@ -95,9 +95,8 @@ As opposed to waiting for removal, this is for when you are at a point in your test where you know an element shouldn't be present. You might reach for `getBy` to check that something is not present, but `getBy` -queries throw an error when they can't find an element, which means you don't -get the chance to use the result in an expectation. If you want to make an -assertion that an element is _not_ present in the document, you can use +queries throw an error when they can't find an element. If you want to make an +assertion that an element is _not_ present in the document, you need to use `queryBy` queries instead: ```javascript From 1df6369de1750bfce5dc6e1c7b43d36b7ff5a149 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kim=20R=C3=B8en?= Date: Fri, 12 Jun 2020 13:03:27 +0200 Subject: [PATCH 3/4] fix link to jest-dom --- docs/guide-disappearance.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/guide-disappearance.md b/docs/guide-disappearance.md index 37ad31871..07f012674 100644 --- a/docs/guide-disappearance.md +++ b/docs/guide-disappearance.md @@ -130,7 +130,7 @@ const submitButton = screen.queryByText('submit') expect(submitButton).not.toBeInTheDocument() ``` -Read about how to set this up [in the documentation](jest-dom). +Read about how to set this up [in the jest-dom documentation][jest-dom]. [async-api]: dom-testing-library/api-async.md [find-by]: dom-testing-library/api-queries.md#findby From 6d3b3e5300cef02451dfccd4173433b512ca8ee9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kim=20R=C3=B8en?= Date: Tue, 16 Jun 2020 09:44:11 +0200 Subject: [PATCH 4/4] remove waitFor as a recommended way to wait for removal --- docs/guide-disappearance.md | 23 +---------------------- 1 file changed, 1 insertion(+), 22 deletions(-) diff --git a/docs/guide-disappearance.md b/docs/guide-disappearance.md index 07f012674..93f1e3458 100644 --- a/docs/guide-disappearance.md +++ b/docs/guide-disappearance.md @@ -44,7 +44,7 @@ _Note: `toBeInTheDocument()` comes from [`@testing-library/jest-dom`][jest-dom]_ ## Waiting for disappearance When you want to wait until an element has disappeared, you can use -`waitForElementToBeRemoved` or `waitFor`. +`waitForElementToBeRemoved`. The `waitForElementToBeRemoved` [async wait utility][async-api] takes an element as an argument and waits until that element has been removed from the document. @@ -68,27 +68,6 @@ efficient way. You can also pass an array or a callback to `waitForElementToBeRemoved` - [see the documentation for more options](dom-testing-library/api-async.md#waitforelementtoberemoved). -Another option is using the `waitFor` helper. - -The `waitFor` [async wait utility][async-api] retries until the wrapped function -stops throwing an error. Because expectations throw errors when they fail, -putting one in the wrapped function can be used to wait for the element to be -removed. - -```javascript -test('movie title goes away', async () => { - // element is initially present... - // note use of queryBy instead of getBy to return null - // instead of throwing in the query itself - await waitFor(() => { - expect(screen.queryByText('i, robot')).not.toBeInTheDocument() - }) -}) -``` - -Polling like this is not as efficient as observing for mutations using -`waitForElementToBeRemoved`, but sometimes it's the best option. - ## Asserting elements are not present As opposed to waiting for removal, this is for when you are at a point in your