From e5c1866de7aacb9ec9642ab251ace96015ba651a Mon Sep 17 00:00:00 2001 From: Alex Krolick Date: Thu, 3 May 2018 20:31:08 -0700 Subject: [PATCH 1/3] Copy in waitForElement docs --- README.md | 63 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) diff --git a/README.md b/README.md index e13bfefb..e2794a32 100644 --- a/README.md +++ b/README.md @@ -86,6 +86,7 @@ facilitate testing implementation details). Read more about this in * [`cleanup`](#cleanup) * [`Simulate`](#simulate) * [`wait`](#wait) + * [`waitForElement`](#waitforelement) * [`fireEvent(node: HTMLElement, event: Event)`](#fireeventnode-htmlelement-event-event) * [`TextMatch`](#textmatch) * [`query` APIs](#query-apis) @@ -373,6 +374,68 @@ The default `interval` is `50ms`. However it will run your callback immediately on the next tick of the event loop (in a `setTimeout`) before starting the intervals. +### `waitForElement` + +Defined as: + +```typescript +function waitForElement( + callback?: () => T | null | undefined, + options?: { + container?: HTMLElement + timeout?: number + mutationObserverOptions?: MutationObserverInit + }, +): Promise +``` + +When in need to wait for DOM elements to appear, disappear, or change you can use `waitForElement`. +The `waitForElement` function is a small wrapper +around the +[`MutationObserver`](https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver). +Here's a simple example: + +```javascript +// ... +// Wait until the callback does not throw an error and returns a truthy value. In this case, that means +// it'll wait until we can get a form control with a label that matches "username". +// The difference from `wait` is that rather than running your callback on +// an interval, it's run as soon as there are DOM changes in the container +// and returns the value returned by the callback. +const usernameElement = await waitForElement( + () => getByLabelText(container, 'username'), + {container}, +) +usernameElement.value = 'chucknorris' +// ... +``` + +You can also wait for multiple elements at once: + +```javascript +const [usernameElement, passwordElement] = waitForElement( + () => [ + getByLabelText(container, 'username'), + getByLabelText(container, 'password'), + ], + {container}, +) +``` + +Using [`MutationObserver`](https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver) is more efficient than polling the DOM at regular intervals with `wait`. This library sets up a [`'mutationobserver-shim'`](https://github.com/megawac/MutationObserver.js) on the global `window` object for cross-platform compatibility with older browsers and the [`jsdom`](https://github.com/jsdom/jsdom/issues/639) thatis usually used in Node-based tests. + +The default `callback` is a no-op function (used like `await waitForElement()`). This can +be helpful if you only need to wait for the next DOM change (see [`mutationObserverOptions`](#mutationobserveroptions) to learn which changes are detected). + +The default `container` is the global `document`. Make sure the elements you wait for will be attached to it, or set a different `container`. + +The default `timeout` is `4500ms` which will keep you under +[Jest's default timeout of `5000ms`](https://facebook.github.io/jest/docs/en/jest-object.html#jestsettimeouttimeout). + +The default `mutationObserverOptions` is `{subtree: true, childList: true}` which will detect +additions and removals of child elements (including text nodes) in the `container`and any of its descendants. +It won't detect attribute changes unless you add `attributes: true` to the options. + ### `fireEvent(node: HTMLElement, event: Event)` Fire DOM events. From 8877bbbf81298efb0430da0083850b2dbbb69cfc Mon Sep 17 00:00:00 2001 From: Alex Krolick Date: Thu, 3 May 2018 21:49:42 -0700 Subject: [PATCH 2/3] Link out to source --- README.md | 49 +------------------------------------------------ 1 file changed, 1 insertion(+), 48 deletions(-) diff --git a/README.md b/README.md index e2794a32..0f1b6ca6 100644 --- a/README.md +++ b/README.md @@ -376,7 +376,7 @@ intervals. ### `waitForElement` -Defined as: +See [dom-testing-library#waitForElement](https://github.com/kentcdodds/dom-testing-library#waitforelement) ```typescript function waitForElement( @@ -389,53 +389,6 @@ function waitForElement( ): Promise ``` -When in need to wait for DOM elements to appear, disappear, or change you can use `waitForElement`. -The `waitForElement` function is a small wrapper -around the -[`MutationObserver`](https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver). -Here's a simple example: - -```javascript -// ... -// Wait until the callback does not throw an error and returns a truthy value. In this case, that means -// it'll wait until we can get a form control with a label that matches "username". -// The difference from `wait` is that rather than running your callback on -// an interval, it's run as soon as there are DOM changes in the container -// and returns the value returned by the callback. -const usernameElement = await waitForElement( - () => getByLabelText(container, 'username'), - {container}, -) -usernameElement.value = 'chucknorris' -// ... -``` - -You can also wait for multiple elements at once: - -```javascript -const [usernameElement, passwordElement] = waitForElement( - () => [ - getByLabelText(container, 'username'), - getByLabelText(container, 'password'), - ], - {container}, -) -``` - -Using [`MutationObserver`](https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver) is more efficient than polling the DOM at regular intervals with `wait`. This library sets up a [`'mutationobserver-shim'`](https://github.com/megawac/MutationObserver.js) on the global `window` object for cross-platform compatibility with older browsers and the [`jsdom`](https://github.com/jsdom/jsdom/issues/639) thatis usually used in Node-based tests. - -The default `callback` is a no-op function (used like `await waitForElement()`). This can -be helpful if you only need to wait for the next DOM change (see [`mutationObserverOptions`](#mutationobserveroptions) to learn which changes are detected). - -The default `container` is the global `document`. Make sure the elements you wait for will be attached to it, or set a different `container`. - -The default `timeout` is `4500ms` which will keep you under -[Jest's default timeout of `5000ms`](https://facebook.github.io/jest/docs/en/jest-object.html#jestsettimeouttimeout). - -The default `mutationObserverOptions` is `{subtree: true, childList: true}` which will detect -additions and removals of child elements (including text nodes) in the `container`and any of its descendants. -It won't detect attribute changes unless you add `attributes: true` to the options. - ### `fireEvent(node: HTMLElement, event: Event)` Fire DOM events. From 654637303aaaf0ad7f8a54a206b171477f9e6fa0 Mon Sep 17 00:00:00 2001 From: Alex Krolick Date: Fri, 4 May 2018 11:53:52 -0700 Subject: [PATCH 3/3] Add waitForElement examples --- README.md | 36 +++++++++++++++++++++++++++--------- 1 file changed, 27 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 0f1b6ca6..d617a07e 100644 --- a/README.md +++ b/README.md @@ -378,17 +378,35 @@ intervals. See [dom-testing-library#waitForElement](https://github.com/kentcdodds/dom-testing-library#waitforelement) -```typescript -function waitForElement( - callback?: () => T | null | undefined, - options?: { - container?: HTMLElement - timeout?: number - mutationObserverOptions?: MutationObserverInit - }, -): Promise +```js +await waitForElement(() => getByText('Search')) ``` +
+ + Example + + +```diff +test('should submit form when valid', async () => { + const mockSubmit = jest.fn() + const { + container, + getByLabelText, + getByText + } = render(
) + const nameInput = getByLabelText('Name') + nameInput.value = 'Chewbacca' + Simulate.change(nameInput) ++ // wait for button to appear and click it ++ const submitButton = await waitForElement(() => getByText('Search')) ++ Simulate.click(submitButton) ++ expect(mockSubmit).toBeCalled() +}) +``` + +
+ ### `fireEvent(node: HTMLElement, event: Event)` Fire DOM events.