From b94c648b0120f3437365eea764df133705be686d Mon Sep 17 00:00:00 2001 From: Sherman Hui Date: Mon, 14 Sep 2020 18:55:11 -0700 Subject: [PATCH 1/4] docs: add findByText example Add a simple JS login form to show examples of how to use the `findBy*` query, in particular `findByText` for DOM elements that may not be visible immediately. Add two tests that assert for warnings that appear when the user tries to submit the form with no username and password and when the user enters invalid field values. --- docs/example-findByText.md | 147 +++++++++++++++++++++++++++++++++++++ 1 file changed, 147 insertions(+) create mode 100644 docs/example-findByText.md diff --git a/docs/example-findByText.md b/docs/example-findByText.md new file mode 100644 index 000000000..62e28fa7a --- /dev/null +++ b/docs/example-findByText.md @@ -0,0 +1,147 @@ +--- +id: example-findByText +title: example `findByText` +sidebar_label: findByText +--- + +```javascript +// src/__tests__/example.test.js +// 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 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 => { + el.innerHTML = ` +
+ + + + + + + + + + + + + + + + + +
+ ` + + const submitButton = el.querySelector('#submit') + const formEl = el.querySelector('#login_form') + + submitButton.addEventListener('click', () => { + const userInput = el.querySelector('#username_input') + const passwordInput = el.querySelector('#password_input') + + var userName = userInput.value + var password = passwordInput.value + if (!userName) { + el.querySelector('#username_required_error').style.display = 'inline' + } + + if (!password) { + el.querySelector('#password_required_error').style.display = 'inline' + } + + if (userName && userName !== 'Bob') { + el.querySelector('#invalid_username_error').style.display = 'inline' + } + + if (password && password !== 'theBuilder') { + el.querySelector('#invalid_password_error').style.display = 'inline' + } + }) + + formEl.addEventListener('submit', function(evt) { + evt.preventDefault() + window.history.back() + }) + + return el +} + +describe('findByText Examples', () => { + let div + let container + + beforeEach(() => { + div = document.createElement('div') + container = renderContent(div) + }) + + it('should show a required field warning for each empty input field', async () => { + userEvent.click( + getByRole(container, 'button', { + name: 'Login', + }) + ) + + expect( + await findByText(container, "User Name Required") + ).toBeVisible(); + + expect( + await findByText(container, "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') + + expect(await findByText(container, 'Invalid Password')).not.toBeVisible() + expect(await findByText(container, 'Invalid User Name')).not.toBeVisible() + + userEvent.type(userNameField, 'Philchard') + userEvent.type(passwordField, 'theCat') + + expect(userNameField).toHaveValue('Philchard') + expect(passwordField).toHaveValue('theCat') + + userEvent.click( + getByRole(container, 'button', { + name: 'Login', + }) + ) + + expect(await findByText(container, 'Invalid User Name')).toBeVisible() + expect(await findByText(container, 'Invalid Password')).toBeVisible() + }) +}) +``` From 2ba97de8899e4fb0688cc8cac90af3de34b9ef39 Mon Sep 17 00:00:00 2001 From: Sherman Hui Date: Fri, 2 Oct 2020 18:33:19 -0700 Subject: [PATCH 2/4] chore: add `findByText` example to navigation Reorganize Examples to be alphabetically sorted by example file name --- website/sidebars.json | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/website/sidebars.json b/website/sidebars.json index 1a432a686..f7b13e584 100755 --- a/website/sidebars.json +++ b/website/sidebars.json @@ -128,8 +128,9 @@ ], "Examples": [ "example-codesandbox", + "example-external", + "example-findByText", "example-input-event", - "example-update-props", "example-react-context", "example-react-hooks-useReducer", "example-react-intl", @@ -138,7 +139,7 @@ "example-reach-router", "example-react-transition-group", "example-react-modal", - "example-external" + "example-update-props" ], "Help": ["faq", "learning", "contributing"] } From 62ce8b5272d1fcbd03e8da87d32c68729641e692 Mon Sep 17 00:00:00 2001 From: Sherman Hui Date: Fri, 2 Oct 2020 18:34:54 -0700 Subject: [PATCH 3/4] chore: format docs Commit the results of `format-docs` to ensure files follow documentation format --- docs/dom-testing-library/api-events.md | 16 +++++++++------- docs/ecosystem-user-event.md | 7 ++++--- docs/example-update-props.md | 8 ++++---- docs/guide-disappearance.md | 6 +++--- docs/react-testing-library/cheatsheet.md | 4 ++-- 5 files changed, 22 insertions(+), 19 deletions(-) diff --git a/docs/dom-testing-library/api-events.md b/docs/dom-testing-library/api-events.md index a6a6c57ab..c0d7b00e9 100644 --- a/docs/dom-testing-library/api-events.md +++ b/docs/dom-testing-library/api-events.md @@ -62,8 +62,8 @@ fireEvent.change(getByLabelText(/picture/i), { }, }) -// Note: The 'value' attribute must use ISO 8601 format when firing a -// change event on an input of type "date". Otherwise the element will not +// Note: The 'value' attribute must use ISO 8601 format when firing a +// change event on an input of type "date". Otherwise the element will not // reflect the changed value. // Invalid: @@ -133,10 +133,10 @@ fireEvent( ## Using Jest Function Mocks -[Jest's Mock functions](https://jestjs.io/docs/en/mock-functions) can be used to test -that a callback passed to the function was called, or what it was called when the event -that **should** trigger the callback function does trigger the bound callback. - +[Jest's Mock functions](https://jestjs.io/docs/en/mock-functions) can be used to +test that a callback passed to the function was called, or what it was called +when the event that **should** trigger the callback function does trigger the +bound callback. @@ -145,7 +145,9 @@ that **should** trigger the callback function does trigger the bound callback. ```jsx import { render, screen } from '@testing-library/react' -const Button = ({onClick, children}) => +const Button = ({ onClick, children }) => ( + +) test('calls onClick prop when clicked', () => { const handleClick = jest.fn() diff --git a/docs/ecosystem-user-event.md b/docs/ecosystem-user-event.md index e99bfafad..c65f63be4 100644 --- a/docs/ecosystem-user-event.md +++ b/docs/ecosystem-user-event.md @@ -4,8 +4,8 @@ title: user-event --- [`user-event`][gh] is a companion library for Testing Library that provides more -advanced simulation of browser interactions than the built-in [`fireEvent`][docs] -method. +advanced simulation of browser interactions than the built-in +[`fireEvent`][docs] method. ``` npm install --save-dev @testing-library/user-event @@ -26,4 +26,5 @@ test('types inside textarea', async () => { - [user-event on GitHub][gh] [gh]: https://github.com/testing-library/user-event -[docs]: https://testing-library.com/docs/dom-testing-library/api-events#fireevent +[docs]: + https://testing-library.com/docs/dom-testing-library/api-events#fireevent diff --git a/docs/example-update-props.md b/docs/example-update-props.md index 26d8388cf..1c48acea5 100644 --- a/docs/example-update-props.md +++ b/docs/example-update-props.md @@ -9,12 +9,12 @@ sidebar_label: Update Props // the basic idea is to simply call `render` again and provide the same container // that your first call created for you. -import React, {useRef} from 'react' -import {render, screen} from '@testing-library/react' +import React, { useRef } from 'react' +import { render, screen } from '@testing-library/react' let idCounter = 1 -const NumberDisplay = ({number}) => { +const NumberDisplay = ({ number }) => { const id = useRef(idCounter++) // to ensure we don't remount a different instance return ( @@ -26,7 +26,7 @@ const NumberDisplay = ({number}) => { } test('calling render with the same component on the same container does not remount', () => { - const {rerender} = render() + const { rerender } = render() expect(screen.getByTestId('number-display')).toHaveTextContent('1') // re-render the same component with different props diff --git a/docs/guide-disappearance.md b/docs/guide-disappearance.md index a3d981268..1dbd1022c 100644 --- a/docs/guide-disappearance.md +++ b/docs/guide-disappearance.md @@ -10,9 +10,9 @@ vice versa. 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. -*The async methods return a Promise, so you must always use `await` or -.then(done) when calling them.* +proceeding. The wait utilities retry until the query passes or times out. _The +async methods return a Promise, so you must always use `await` or .then(done) +when calling them._ ```jsx test('movie title appears', async () => { diff --git a/docs/react-testing-library/cheatsheet.md b/docs/react-testing-library/cheatsheet.md index 1243a0355..16acaba6b 100644 --- a/docs/react-testing-library/cheatsheet.md +++ b/docs/react-testing-library/cheatsheet.md @@ -11,8 +11,8 @@ A short guide to all the exported functions in `React Testing Library` - `unmount` function to unmount the component - `container` reference to the DOM node where the component is mounted - all the queries from `DOM Testing Library`, bound to the document so there - is no need to pass a node as the first argument (usually, you can use - the `screen` import instead) + is no need to pass a node as the first argument (usually, you can use the + `screen` import instead) ```jsx import { render, fireEvent, screen } from '@testing-library/react' From 91ae836403fdbf061dc576e4c7b2b08e2fcac03f Mon Sep 17 00:00:00 2001 From: Sherman Hui Date: Fri, 2 Oct 2020 21:42:03 -0700 Subject: [PATCH 4/4] chore: update README add note to ensure any new docs pages do not include non-url safe characters in the file name or markdown id --- website/README.md | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/website/README.md b/website/README.md index 1e71255dc..36616677c 100755 --- a/website/README.md +++ b/website/README.md @@ -110,7 +110,10 @@ title: This Doc Needs To Be Edited My new content here.. ``` -1. Refer to that doc's ID in an existing sidebar in `website/sidebar.json`: +Note: Ensure the file name and the id value do not include non-url safe +characters i.e. '\*'. + +2. Refer to that doc's ID in an existing sidebar in `website/sidebar.json`: ```javascript // Add newly-created-doc to the Getting Started category of docs @@ -192,7 +195,7 @@ For more information about the navigation bar, click 1. Docusaurus uses React components to build pages. The components are saved as .js files in `website/pages/en`: -1. If you want your page to show up in your navigation header, you will need to +2. If you want your page to show up in your navigation header, you will need to update `website/siteConfig.js` to add to the `headerLinks` element: `website/siteConfig.js`