)
+}
+
+export default HiddenMessage
+
+// __tests__/hidden-message.js
+// these imports are something you'd normally configure Jest to import for you
+// automatically. Learn more in the setup docs: https://testing-library.com/docs/react-testing-library/setup#cleanup
+import '@testing-library/react/cleanup-after-each'
+import '@testing-library/jest-dom/extend-expect'
+// NOTE: jest-dom adds handy assertions to Jest and is recommended, but not required
- // Act
- fireEvent.click(getByText(/load greeting/i))
+import React from 'react'
+import {render, fireEvent} from '@testing-library/react'
+import HiddenMessage from '../hidden-message'
- // Let's wait until our mocked `get` request promise resolves and
- // the component calls setState and re-renders.
- // getByTestId throws an error if it cannot find an element with the given ID
- // and waitForElement will wait until the callback doesn't throw an error
- const greetingTextNode = await waitForElement(() =>
- getByTestId('greeting-text'),
+test('shows the children when the checkbox is checked', () => {
+ const testMessage = 'Test Message'
+ const {queryByText, getByLabelText, getByText} = render(
+ {testMessage},
)
- // Assert
- expect(axiosMock.get).toHaveBeenCalledTimes(1)
- expect(axiosMock.get).toHaveBeenCalledWith(url)
- expect(getByTestId('greeting-text')).toHaveTextContent('hello there')
- expect(getByTestId('ok-button')).toHaveAttribute('disabled')
- // snapshots work great with regular DOM nodes!
- expect(container.firstChild).toMatchSnapshot()
- // you can also get a `DocumentFragment`, which is useful if you want to compare nodes across renders
- expect(asFragment()).toMatchSnapshot()
+ // query* functions will return the element or null if it cannot be found
+ // get* functions will return the element or throw an error if it cannot be found
+ expect(queryByText(testMessage)).toBeNull()
+
+ // the queries can accept a regex to make your selectors more resilient to content tweaks and changes.
+ fireEvent.click(getByLabelText(/show/i))
+
+ // .toBeInTheDocument() is an assertion that comes from jest-dom
+ // otherwise you could use .toBeDefined()
+ expect(getByText(testMessage)).toBeInTheDocument()
})
```
-## Installation
-
-This module is distributed via [npm][npm] which is bundled with [node][node] and
-should be installed as one of your project's `devDependencies`:
+### Complex Example
-```
-npm install --save-dev @testing-library/react
-```
+```jsx
+// login.js
+import React from 'react'
-This library has `peerDependencies` listings for `react` and `react-dom`.
+function Login() {
+ const [state, setState] = React.useReducer((s, a) => ({...s, ...a}), {
+ resolved: false,
+ loading: false,
+ error: null,
+ })
+
+ function handleSubmit(event) {
+ event.preventDefault()
+ const {usernameInput, passwordInput} = event.target.elements
+
+ setState({loading: true, resolved: false, error: null})
+
+ window
+ .fetch('/api/login', {
+ method: 'POST',
+ headers: {'Content-Type': 'application/json'},
+ body: JSON.stringify({
+ username: usernameInput.value,
+ password: passwordInput.value,
+ }),
+ })
+ .then(r => r.json())
+ .then(
+ user => {
+ setState({loading: false, resolved: true, error: null})
+ window.localStorage.setItem('token', user.token)
+ },
+ error => {
+ setState({loading: false, resolved: false, error: error.message})
+ },
+ )
+ }
+
+ return (
+
+
+ {state.error ?
{state.error.message}
: null}
+ {state.success ? (
+
Congrats! You're signed in!
+ ) : null}
+
+ )
+}
-You may also be interested in installing `jest-dom` so you can use
-[the custom jest matchers](https://github.com/gnapse/jest-dom#readme).
+export default Login
-> [**Docs**](https://testing-library.com/docs/react-testing-library/intro)
+// __tests__/login.js
+// again, these first two imports are something you'd normally handle in
+// your testing framework configuration rather than importing them in every file.
+import '@testing-library/react/cleanup-after-each'
+import '@testing-library/jest-dom/extend-expect'
+import React from 'react'
+import {render, fireEvent} from '@testing-library/react'
+import Login from '../login'
+
+test('allows the user to login successfully', async () => {
+ // mock out window.fetch for the test
+ const fakeUserResponse = {token: 'fake_user_token'}
+ jest.spyOn(window, 'fetch').mockImplementationOnce(() => {
+ return Promise.resolve({
+ json: () => Promise.resolve(fakeUserResponse),
+ })
+ })
+
+ const {getByLabelText, getByText, findByRole} = render()
+
+ // fill out the form
+ fireEvent.change(getByLabelText(/username/i), {target: {value: 'chuck'}})
+ fireEvent.change(getBylabelText(/password/i), {target: {value: 'norris'}})
+
+ fireEvent.click(getByText(/submit/i))
+
+ // just like a manual tester, we'll instruct our test to wait for the alert
+ // to show up before continuing with our assertions.
+ const alert = await findByRole('alert')
+
+ // .toHaveTextContent() comes from jest-dom's assertions
+ // otherwise you could use expect(alert.textContent).toMatch(/congrats/i)
+ // but jest-dom will give you better error messages which is why it's recommended
+ expect(alert).toHaveTextContent(/congrats/i)
+ expect(window.localStorage.getItem('token')).toEqual(fakeUserReponse.token)
+})
+```
-## Examples
+### More Examples
> We're in the process of moving examples to the
> [docs site](https://testing-library.com/docs/example-codesandbox)
You'll find runnable examples of testing with different libraries in
-[the `examples` directory](https://github.com/testing-library/react-testing-library/blob/master/examples).
+[the `react-testing-library-examples` codesandbox](https://codesandbox.io/s/github/kentcdodds/react-testing-library-examples).
Some included are:
-- [`react-redux`](https://github.com/testing-library/react-testing-library/blob/master/examples/__tests__/react-redux.js)
-- [`react-router`](https://github.com/testing-library/react-testing-library/blob/master/examples/__tests__/react-router.js)
-- [`react-context`](https://github.com/testing-library/react-testing-library/blob/master/examples/__tests__/react-context.js)
+- [`react-redux`](https://codesandbox.io/s/github/kentcdodds/react-testing-library-examples/tree/master/?fontsize=14&module=%2Fsrc%2F__tests__%2Freact-redux.js&previewwindow=tests)
+- [`react-router`](https://codesandbox.io/s/github/kentcdodds/react-testing-library-examples/tree/master/?fontsize=14&module=%2Fsrc%2F__tests__%2Freact-router.js&previewwindow=tests)
+- [`react-context`](https://codesandbox.io/s/github/kentcdodds/react-testing-library-examples/tree/master/?fontsize=14&module=%2Fsrc%2F__tests__%2Freact-context.js&previewwindow=tests)
You can also find react-testing-library examples at
[react-testing-examples.com](https://react-testing-examples.com/jest-rtl/).
@@ -181,14 +288,10 @@ You can also find react-testing-library examples at
If you are interested in testing a custom hook, check out
[react-hooks-testing-library][react-hooks-testing-library].
-## Other Solutions
-
-In preparing this project,
-[I tweeted about it](https://twitter.com/kentcdodds/status/974278185540964352)
-and [Sune Simonsen](https://github.com/sunesimonsen)
-[took up the challenge](https://twitter.com/sunesimonsen/status/974784783908818944).
-We had different ideas of what to include in the library, so I decided to create
-this one instead.
+> NOTE it is not recommended to test single-use custom hooks in isolation from
+> the components where it's being used. It's better to test the component that's
+> using the hook rather than the hook itself. The react-hooks-testing-library is
+> intended to be used for reusable hooks/libraries.
## Guiding Principles
@@ -213,19 +316,6 @@ principles:
At the end of the day, what we want is for this library to be pretty
light-weight, simple, and understandable.
-## Contributors
-
-Thanks goes to these people ([emoji key][emojis]):
-
-
-
-
-
-
-
-This project follows the [all-contributors][all-contributors] specification.
-Contributions of any kind welcome!
-
## Docs
[**Read The Docs**](https://testing-library.com/react) |
@@ -258,14 +348,129 @@ instead of filing an issue on GitHub.
- [Reactiflux on Discord][reactiflux]
- [Stack Overflow][stackoverflow]
+## Contributors
+
+Thanks goes to these people ([emoji key][emojis]):
+
+
+
+
+
+
+
+This project follows the [all-contributors][all-contributors] specification.
+Contributions of any kind welcome!
+
## LICENSE
MIT
-
-
[npm]: https://www.npmjs.com/
diff --git a/examples/.eslintrc.js b/examples/.eslintrc.js
deleted file mode 100644
index 67ff778c..00000000
--- a/examples/.eslintrc.js
+++ /dev/null
@@ -1,15 +0,0 @@
-module.exports = {
- // we have to do this so our tests can reference 'react-testing-library'
- overrides: [
- {
- files: ['**/__tests__/**'],
- settings: {
- 'import/resolver': {
- jest: {
- jestConfigFile: require.resolve('./jest.config.js'),
- },
- },
- },
- },
- ],
-}
diff --git a/examples/README.md b/examples/README.md
deleted file mode 100644
index 44e36304..00000000
--- a/examples/README.md
+++ /dev/null
@@ -1,31 +0,0 @@
-# Examples
-
-Here we have some examples for you to know how to not only use
-`react-testing-library` but also in general how to test common scenarios that
-pop up with React. Check out the `__tests__` directory for the different
-examples.
-
-## Setup
-
-The examples have a unique jest/eslint set up so the test files will resemble
-how they might appear in your project. (You'll see in the tests that we can
-`import {render} from 'react-testing-library'`).
-
-## Contribute
-
-We're always happy to accept contributions to the examples. Can't have too many
-of these as there are TONs of different ways to test React. Examples of testing
-components that use different and common libraries is always welcome. Try to
-keep examples simple enough for people to understand the main thing we're trying
-to demonstrate from the example.
-
-Please follow the guidelines found in [CONTRIBUTING.md][contributing] to set up
-the project.
-
-To run the tests, you can run `npm test examples`, or if you're working on a
-specific example, you can run `npm test name-of-your-file`. This will put you
-into Jest's interactive watch mode with a filter based on the name you provided.
-
-[contributing]:
- https://github.com/testing-library/react-testing-library/blob/master/CONTRIBUTING.md
-[jest-dom]: https://github.com/gnapse/jest-dom
diff --git a/examples/__tests__/input-event.js b/examples/__tests__/input-event.js
deleted file mode 100644
index 0e1c5305..00000000
--- a/examples/__tests__/input-event.js
+++ /dev/null
@@ -1,65 +0,0 @@
-import React from 'react'
-import {render, fireEvent, cleanup} from 'react-testing-library'
-
-class CostInput extends React.Component {
- state = {
- value: '',
- }
-
- removeDollarSign = value => (value[0] === '$' ? value.slice(1) : value)
- getReturnValue = value => (value === '' ? '' : `$${value}`)
- handleChange = ev => {
- ev.preventDefault()
- const inputtedValue = ev.currentTarget.value
- const noDollarSign = this.removeDollarSign(inputtedValue)
- if (isNaN(noDollarSign)) return
- this.setState({value: this.getReturnValue(noDollarSign)})
- }
-
- render() {
- return (
-
- )
- }
-}
-
-const setup = () => {
- const utils = render()
- const input = utils.getByLabelText('cost-input')
- return {
- input,
- ...utils,
- }
-}
-
-afterEach(cleanup)
-
-test('It should keep a $ in front of the input', () => {
- const {input} = setup()
- fireEvent.change(input, {target: {value: '23'}})
- expect(input.value).toBe('$23')
-})
-test('It should allow a $ to be in the input when the value is changed', () => {
- const {input} = setup()
- fireEvent.change(input, {target: {value: '$23.0'}})
- expect(input.value).toBe('$23.0')
-})
-
-test('It should not allow letters to be inputted', () => {
- const {input} = setup()
- expect(input.value).toBe('') // empty before
- fireEvent.change(input, {target: {value: 'Good Day'}})
- expect(input.value).toBe('') //empty after
-})
-
-test('It should allow the $ to be deleted', () => {
- const {input} = setup()
- fireEvent.change(input, {target: {value: '23'}})
- expect(input.value).toBe('$23') // need to make a change so React registers "" as a change
- fireEvent.change(input, {target: {value: ''}})
- expect(input.value).toBe('')
-})
diff --git a/examples/__tests__/mock.react-transition-group.js b/examples/__tests__/mock.react-transition-group.js
deleted file mode 100644
index 83894534..00000000
--- a/examples/__tests__/mock.react-transition-group.js
+++ /dev/null
@@ -1,49 +0,0 @@
-import React from 'react'
-import {CSSTransition} from 'react-transition-group'
-import {render, fireEvent, cleanup} from 'react-testing-library'
-
-function Fade({children, ...props}) {
- return (
-
- {children}
-
- )
-}
-
-class HiddenMessage extends React.Component {
- state = {show: this.props.initialShow || false}
- toggle = () => {
- this.setState(({show}) => ({show: !show}))
- }
- render() {
- return (
-
-
-
-
Hello world
-
-
- )
- }
-}
-
-afterEach(cleanup)
-
-jest.mock('react-transition-group', () => {
- const FakeTransition = jest.fn(({children}) => children)
- const FakeCSSTransition = jest.fn(props =>
- props.in ? {props.children} : null,
- )
- return {CSSTransition: FakeCSSTransition, Transition: FakeTransition}
-})
-
-test('you can mock things with jest.mock', () => {
- const {getByText, queryByText} = render()
- expect(getByText('Hello world')).toBeTruthy() // we just care it exists
- // hide the message
- fireEvent.click(getByText('Toggle'))
- // in the real world, the CSSTransition component would take some time
- // before finishing the animation which would actually hide the message.
- // So we've mocked it out for our tests to make it happen instantly
- expect(queryByText('Hello World')).toBeNull() // we just care it doesn't exist
-})
diff --git a/examples/__tests__/reach-router.js b/examples/__tests__/reach-router.js
deleted file mode 100644
index 61aae97d..00000000
--- a/examples/__tests__/reach-router.js
+++ /dev/null
@@ -1,70 +0,0 @@
-import React from 'react'
-import {render, cleanup} from 'react-testing-library'
-import {
- Router,
- Link,
- createHistory,
- createMemorySource,
- LocationProvider,
-} from '@reach/router'
-import 'jest-dom/extend-expect'
-
-const About = () =>
You are on the about page
-const Home = () =>
You are home
-const NoMatch = () =>
No match
-
-function App() {
- return (
-
- Home
- About
-
-
-
-
-
-
- )
-}
-
-// Ok, so here's what your tests might look like
-
-afterEach(cleanup)
-
-// this is a handy function that I would utilize for any component
-// that relies on the router being in context
-function renderWithRouter(
- ui,
- {route = '/', history = createHistory(createMemorySource(route))} = {},
-) {
- return {
- ...render({ui}),
- // adding `history` to the returned utilities to allow us
- // to reference it in our tests (just try to avoid using
- // this to test implementation details).
- history,
- }
-}
-
-test('full app rendering/navigating', async () => {
- const {
- container,
- history: {navigate},
- } = renderWithRouter()
- const appContainer = container
- // normally I'd use a data-testid, but just wanted to show this is also possible
- expect(appContainer.innerHTML).toMatch('You are home')
-
- // with reach-router we don't need to simulate a click event, we can just transition
- // to the page using the navigate function returned from the history object.
- await navigate('/about')
- expect(container.innerHTML).toMatch('You are on the about page')
-})
-
-test('landing on a bad page', () => {
- const {container} = renderWithRouter(, {
- route: '/something-that-does-not-match',
- })
- // normally I'd use a data-testid, but just wanted to show this is also possible
- expect(container.innerHTML).toMatch('No match')
-})
diff --git a/examples/__tests__/react-context.js b/examples/__tests__/react-context.js
deleted file mode 100644
index b87c61c9..00000000
--- a/examples/__tests__/react-context.js
+++ /dev/null
@@ -1,58 +0,0 @@
-import React from 'react'
-import {render, cleanup} from 'react-testing-library'
-import 'jest-dom/extend-expect'
-import {NameContext, NameProvider, NameConsumer} from '../react-context'
-
-afterEach(cleanup)
-
-/**
- * Test default values by rendering a context consumer without a
- * matching provider
- */
-test('NameConsumer shows default value', () => {
- const {getByText} = render()
- expect(getByText(/^My Name Is:/)).toHaveTextContent('My Name Is: Unknown')
-})
-
-/**
- * To test a component tree that uses a context consumer but not the provider,
- * wrap the tree with a matching provider
- */
-test('NameConsumer shows value from provider', () => {
- const tree = (
-
-
-
- )
- const {getByText} = render(tree)
- expect(getByText(/^My Name Is:/)).toHaveTextContent('My Name Is: C3P0')
-})
-
-/**
- * To test a component that provides a context value, render a matching
- * consumer as the child
- */
-test('NameProvider composes full name from first, last', () => {
- const tree = (
-
-
- {value => Received: {value}}
-
-
- )
- const {getByText} = render(tree)
- expect(getByText(/^Received:/).textContent).toBe('Received: Boba Fett')
-})
-
-/**
- * A tree containing both a provider and consumer can be rendered normally
- */
-test('NameProvider/Consumer shows name of character', () => {
- const tree = (
-
-
-
- )
- const {getByText} = render(tree)
- expect(getByText(/^My Name Is:/).textContent).toBe('My Name Is: Leia Organa')
-})
diff --git a/examples/__tests__/react-intl.js b/examples/__tests__/react-intl.js
deleted file mode 100644
index 48fe0e0f..00000000
--- a/examples/__tests__/react-intl.js
+++ /dev/null
@@ -1,45 +0,0 @@
-import React from 'react'
-import 'jest-dom/extend-expect'
-import {render, cleanup, getByTestId} from 'react-testing-library'
-import {IntlProvider, FormattedDate} from 'react-intl'
-import IntlPolyfill from 'intl'
-import 'intl/locale-data/jsonp/pt'
-
-const setupTests = () => {
- // Test enviroment run as server enviroment and should have polyfill to locale
- // https://formatjs.io/guides/runtime-environments/#server
- if (global.Intl) {
- Intl.NumberFormat = IntlPolyfill.NumberFormat
- Intl.DateTimeFormat = IntlPolyfill.DateTimeFormat
- } else {
- global.Intl = require('intl')
- }
-}
-
-const FormatDateView = () => {
- return (
-
- )
- }
-}
-
-// normally this would be:
-// export default connect(state => ({count: state.count}))(Counter)
-// but for this test we'll give it a variable name
-// because we're doing this all in one file
-const ConnectedCounter = connect(state => ({count: state.count}))(Counter)
-
-// app.js
-function reducer(state = {count: 0}, action) {
- switch (action.type) {
- case 'INCREMENT':
- return {
- count: state.count + 1,
- }
- case 'DECREMENT':
- return {
- count: state.count - 1,
- }
- default:
- return state
- }
-}
-
-// normally here you'd do:
-// const store = createStore(reducer)
-// ReactDOM.render(
-//
-//
-// ,
-// document.getElementById('root'),
-// )
-// but for this test we'll umm... not do that :)
-
-// Now here's what your test will look like:
-
-afterEach(cleanup)
-
-// this is a handy function that I normally make available for all my tests
-// that deal with connected components.
-// you can provide initialState or the entire store that the ui is rendered with
-function renderWithRedux(
- ui,
- {initialState, store = createStore(reducer, initialState)} = {},
-) {
- return {
- ...render({ui}),
- // adding `store` to the returned utilities to allow us
- // to reference it in our tests (just try to avoid using
- // this to test implementation details).
- store,
- }
-}
-
-test('can render with redux with defaults', () => {
- const {getByTestId, getByText} = renderWithRedux()
- fireEvent.click(getByText('+'))
- expect(getByTestId('count-value').textContent).toBe('1')
-})
-
-test('can render with redux with custom initial state', () => {
- const {getByTestId, getByText} = renderWithRedux(, {
- initialState: {count: 3},
- })
- fireEvent.click(getByText('-'))
- expect(getByTestId('count-value').textContent).toBe('2')
-})
-
-test('can render with redux with custom store', () => {
- // this is a silly store that can never be changed
- const store = createStore(() => ({count: 1000}))
- const {getByTestId, getByText} = renderWithRedux(, {
- store,
- })
- fireEvent.click(getByText('+'))
- expect(getByTestId('count-value').textContent).toBe('1000')
- fireEvent.click(getByText('-'))
- expect(getByTestId('count-value').textContent).toBe('1000')
-})
diff --git a/examples/__tests__/react-router.js b/examples/__tests__/react-router.js
deleted file mode 100644
index 02f4c7d2..00000000
--- a/examples/__tests__/react-router.js
+++ /dev/null
@@ -1,71 +0,0 @@
-import React from 'react'
-import {withRouter} from 'react-router'
-import {Link, Route, Router, Switch} from 'react-router-dom'
-import {createMemoryHistory} from 'history'
-import {render, fireEvent, cleanup} from 'react-testing-library'
-
-const About = () =>
- )
-}
-
-// Ok, so here's what your tests might look like
-
-afterEach(cleanup)
-
-// this is a handy function that I would utilize for any component
-// that relies on the router being in context
-function renderWithRouter(
- ui,
- {route = '/', history = createMemoryHistory({initialEntries: [route]})} = {},
-) {
- return {
- ...render({ui}),
- // adding `history` to the returned utilities to allow us
- // to reference it in our tests (just try to avoid using
- // this to test implementation details).
- history,
- }
-}
-
-test('full app rendering/navigating', () => {
- const {container, getByText} = renderWithRouter()
- // normally I'd use a data-testid, but just wanted to show this is also possible
- expect(container.innerHTML).toMatch('You are home')
- const leftClick = {button: 0}
- fireEvent.click(getByText(/about/i), leftClick)
- // normally I'd use a data-testid, but just wanted to show this is also possible
- expect(container.innerHTML).toMatch('You are on the about page')
-})
-
-test('landing on a bad page', () => {
- const {container} = renderWithRouter(, {
- route: '/something-that-does-not-match',
- })
- // normally I'd use a data-testid, but just wanted to show this is also possible
- expect(container.innerHTML).toMatch('No match')
-})
-
-test('rendering a component that uses withRouter', () => {
- const route = '/some-route'
- const {getByTestId} = renderWithRouter(, {route})
- expect(getByTestId('location-display').textContent).toBe(route)
-})
diff --git a/examples/__tests__/shallow.react-transition-group.js b/examples/__tests__/shallow.react-transition-group.js
deleted file mode 100644
index fe7ddead..00000000
--- a/examples/__tests__/shallow.react-transition-group.js
+++ /dev/null
@@ -1,51 +0,0 @@
-import React from 'react'
-import {CSSTransition} from 'react-transition-group'
-import {render, fireEvent, cleanup} from 'react-testing-library'
-
-function Fade({children, ...props}) {
- return (
-
- {children}
-
- )
-}
-
-class HiddenMessage extends React.Component {
- state = {show: this.props.initialShow || false}
- toggle = () => {
- this.setState(({show}) => ({show: !show}))
- }
- render() {
- return (
-
-
-
-
Hello world
-
-
- )
- }
-}
-
-afterEach(cleanup)
-
-jest.mock('react-transition-group', () => {
- const FakeCSSTransition = jest.fn(() => null)
- return {CSSTransition: FakeCSSTransition}
-})
-
-test('you can mock things with jest.mock', () => {
- const {getByText} = render()
- const context = expect.any(Object)
- const children = expect.any(Object)
- const defaultProps = {children, timeout: 1000, className: 'fade'}
- expect(CSSTransition).toHaveBeenCalledWith(
- {in: true, ...defaultProps},
- context,
- )
- fireEvent.click(getByText(/toggle/i))
- expect(CSSTransition).toHaveBeenCalledWith(
- {in: true, ...defaultProps},
- expect.any(Object),
- )
-})
diff --git a/examples/__tests__/update-props.js b/examples/__tests__/update-props.js
deleted file mode 100644
index c245b9ff..00000000
--- a/examples/__tests__/update-props.js
+++ /dev/null
@@ -1,33 +0,0 @@
-// This is an example of how to update the props of a rendered component.
-// the basic idea is to simply call `render` again and provide the same container
-// that your first call created for you.
-
-import React from 'react'
-import {render, cleanup} from 'react-testing-library'
-
-let idCounter = 1
-
-class NumberDisplay extends React.Component {
- id = idCounter++ // to ensure we don't remount a different instance
- render() {
- return (
-
- {this.props.number}
- {this.id}
-
- )
- }
-}
-
-afterEach(cleanup)
-
-test('calling render with the same component on the same container does not remount', () => {
- const {getByTestId, rerender} = render()
- expect(getByTestId('number-display').textContent).toBe('1')
-
- // re-render the same component with different props
- rerender()
- expect(getByTestId('number-display').textContent).toBe('2')
-
- expect(getByTestId('instance-id').textContent).toBe('1')
-})
diff --git a/examples/jest.config.js b/examples/jest.config.js
deleted file mode 100644
index 8dc4330d..00000000
--- a/examples/jest.config.js
+++ /dev/null
@@ -1,11 +0,0 @@
-const jestConfig = require('kcd-scripts/jest')
-
-module.exports = Object.assign(jestConfig, {
- rootDir: __dirname,
- roots: [__dirname],
- displayName: 'example',
- moduleNameMapper: {
- // this is just here so our examples look like they would in a real project
- 'react-testing-library': require.resolve('../src'),
- },
-})
diff --git a/examples/react-context.js b/examples/react-context.js
deleted file mode 100644
index 4ec24f6c..00000000
--- a/examples/react-context.js
+++ /dev/null
@@ -1,18 +0,0 @@
-import React from 'react'
-
-const NameContext = React.createContext('Unknown')
-
-const NameProvider = ({children, first, last}) => {
- const fullName = `${first} ${last}`
- return (
- {children}
- )
-}
-
-const NameConsumer = () => (
-
- {value =>
From 54d060be1e485004a69ed88ddc135df58f0d9ef1 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jo=C3=A3o=20Fernandes?=
Date: Mon, 5 Aug 2019 16:06:41 +0200
Subject: [PATCH 026/298] docs: Document known issue with React 16.8 (#423)
* docs: Document known issue with React 16.8
These warnings will be common among users with React 16.8. By adding
this to the README we can address a common concern until React 16.9
becomes common.
* Update README.md
Co-authored-by: Kent C. Dodds
---
README.md | 32 ++++++++++++++++++++++++++++++++
1 file changed, 32 insertions(+)
diff --git a/README.md b/README.md
index ac962d1b..e8a1342f 100644
--- a/README.md
+++ b/README.md
@@ -56,6 +56,7 @@ practices.
- [The problem](#the-problem)
- [This solution](#this-solution)
- [Installation](#installation)
+ - [Suppressing unnecessary warnings on React DOM 16.8](#suppressing-unnecessary-warnings-on-react-dom-168)
- [Examples](#examples)
- [Basic Example](#basic-example)
- [Complex Example](#complex-example)
@@ -108,6 +109,37 @@ use [the custom jest matchers](https://github.com/testing-library/jest-dom).
> [**Docs**](https://testing-library.com/react)
+### Suppressing unnecessary warnings on React DOM 16.8
+
+There is a known compatibility issue with React DOM 16.8 where you will see the
+following warning:
+
+```
+Warning: An update to ComponentName inside a test was not wrapped in act(...).
+```
+
+If you cannot upgrade to React DOM 16.9, you may suppress the warnings by adding
+the following snippet to your test configuration
+([learn more](https://github.com/testing-library/react-testing-library/issues/281)):
+
+```js
+// this is just a little hack to silence a warning that we'll get until we
+// upgrade to 16.9: https://github.com/facebook/react/pull/14853
+const originalError = console.error
+beforeAll(() => {
+ console.error = (...args) => {
+ if (/Warning.*not wrapped in act/.test(args[0])) {
+ return
+ }
+ originalError.call(console, ...args)
+ }
+})
+
+afterAll(() => {
+ console.error = originalError
+})
+```
+
## Examples
### Basic Example
From 3ef5361bd792d1c51c9a7d4cd6c73c41df441963 Mon Sep 17 00:00:00 2001
From: "allcontributors[bot]"
<46447321+allcontributors[bot]@users.noreply.github.com>
Date: Mon, 5 Aug 2019 08:23:49 -0600
Subject: [PATCH 027/298] docs: add JSFernandes as a contributor (#424)
* docs: update README.md
* docs: update .all-contributorsrc
Co-authored-by: null <46447321+allcontributors[bot]@users.noreply.github.com>
---
.all-contributorsrc | 9 +++++++++
README.md | 3 ++-
2 files changed, 11 insertions(+), 1 deletion(-)
diff --git a/.all-contributorsrc b/.all-contributorsrc
index dc1342d7..56f8ab9f 100644
--- a/.all-contributorsrc
+++ b/.all-contributorsrc
@@ -847,6 +847,15 @@
"contributions": [
"doc"
]
+ },
+ {
+ "login": "JSFernandes",
+ "name": "JoΓ£o Fernandes",
+ "avatar_url": "https://avatars1.githubusercontent.com/u/1075053?v=4",
+ "profile": "https://joaofernandes.me/",
+ "contributions": [
+ "doc"
+ ]
}
],
"contributorsPerLine": 7,
diff --git a/README.md b/README.md
index e8a1342f..af475f90 100644
--- a/README.md
+++ b/README.md
@@ -29,7 +29,7 @@ practices.
[![version][version-badge]][package] [![downloads][downloads-badge]][npmtrends]
[![MIT License][license-badge]][license]
-[](#contributors)
+[](#contributors)
[![PRs Welcome][prs-badge]][prs] [![Code of Conduct][coc-badge]][coc]
[![Join the community on Spectrum][spectrum-badge]][spectrum]
@@ -499,6 +499,7 @@ Thanks goes to these people ([emoji key][emojis]):
')
+})
diff --git a/src/__tests__/auto-cleanup.js b/src/__tests__/auto-cleanup.js
new file mode 100644
index 00000000..1d0a7954
--- /dev/null
+++ b/src/__tests__/auto-cleanup.js
@@ -0,0 +1,13 @@
+import React from 'react'
+import {render} from '../'
+
+// This just verifies that by importing RTL in an
+// environment which supports afterEach (like jest)
+// we'll get automatic cleanup between tests.
+test('first', () => {
+ render(
hi
)
+})
+
+test('second', () => {
+ expect(document.body.innerHTML).toEqual('')
+})
diff --git a/src/index.js b/src/index.js
index 4565074b..f6e1c1ef 100644
--- a/src/index.js
+++ b/src/index.js
@@ -142,6 +142,16 @@ fireEvent.select = (node, init) => {
fireEvent.keyUp(node, init)
}
+// if we're running in a test runner that supports afterEach
+// then we'll automatically run cleanup afterEach test
+// this ensures that tests run in isolation from each other
+if (typeof afterEach === 'function' && !process.env.RTL_SKIP_CLEANUP) {
+ afterEach(async () => {
+ await asyncAct(async () => {})
+ cleanup()
+ })
+}
+
// just re-export everything from dom-testing-library
export * from '@testing-library/dom'
export {render, cleanup, fireEvent, act}
diff --git a/tests/setup-env.js b/tests/setup-env.js
index d1d6d891..264828a9 100644
--- a/tests/setup-env.js
+++ b/tests/setup-env.js
@@ -1,6 +1 @@
import '@testing-library/jest-dom/extend-expect'
-
-afterEach(() => {
- // have to do a dynamic import so we don't mess up jest mocking for old-act.js
- require('../src').cleanup()
-})
From f8a88e779ceb65720d5d60a5166c96df1026db12 Mon Sep 17 00:00:00 2001
From: "Kent C. Dodds"
Date: Fri, 9 Aug 2019 12:20:07 -0600
Subject: [PATCH 035/298] Update src/__tests__/auto-cleanup-skip.js
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Co-Authored-By: AdriΓ Fontcuberta
---
src/__tests__/auto-cleanup-skip.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/__tests__/auto-cleanup-skip.js b/src/__tests__/auto-cleanup-skip.js
index 4e58d6c5..c52d741b 100644
--- a/src/__tests__/auto-cleanup-skip.js
+++ b/src/__tests__/auto-cleanup-skip.js
@@ -8,7 +8,7 @@ beforeAll(() => {
})
// This one verifies that if RTL_SKIP_CLEANUP is set
-// that we DON'T auto-wire up the afterEach for folks
+// then we DON'T auto-wire up the afterEach for folks
test('first', () => {
render(
hi
)
})
From e2d25724dc5b0f9b29655a75c8a58ae24780a307 Mon Sep 17 00:00:00 2001
From: "Kent C. Dodds"
Date: Thu, 8 Aug 2019 15:50:51 -0600
Subject: [PATCH 036/298] feat(cleanup): automatically cleanup if afterEach is
detected
You can disable this with the RTL_SKIP_CLEANUP environment variable if
you so choose, but it's recommended to have cleanup work this way.
Closes #428
BREAKING CHANGE: If your tests were not isolated before (and you referenced the same component between tests) then this change will break your tests. You should [keep your tests isolated](https://kentcdodds.com/blog/test-isolation-with-react), but if you're unable/unwilling to do that right away, then you can either run your tests with the environment variable `RTL_SKIP_AUTO_CLEANUP` set to `true` or import `@testing-library/react/pure` instead of `@testing-library/react`.
---
package.json | 3 +-
pure.js | 2 +
src/__tests__/auto-cleanup-skip.js | 4 +-
src/index.js | 159 ++---------------------------
src/pure.js | 153 +++++++++++++++++++++++++++
5 files changed, 165 insertions(+), 156 deletions(-)
create mode 100644 pure.js
create mode 100644 src/pure.js
diff --git a/package.json b/package.json
index b326a1a6..d27b209a 100644
--- a/package.json
+++ b/package.json
@@ -24,7 +24,8 @@
"files": [
"dist",
"typings",
- "cleanup-after-each.js"
+ "cleanup-after-each.js",
+ "pure.js"
],
"keywords": [
"testing",
diff --git a/pure.js b/pure.js
new file mode 100644
index 00000000..75dc0452
--- /dev/null
+++ b/pure.js
@@ -0,0 +1,2 @@
+// makes it so people can import from '@testing-library/react/pure'
+module.exports = require('./dist/pure')
diff --git a/src/__tests__/auto-cleanup-skip.js b/src/__tests__/auto-cleanup-skip.js
index c52d741b..e5ef35ae 100644
--- a/src/__tests__/auto-cleanup-skip.js
+++ b/src/__tests__/auto-cleanup-skip.js
@@ -2,12 +2,12 @@ import React from 'react'
let render
beforeAll(() => {
- process.env.RTL_SKIP_CLEANUP = 'true'
+ process.env.RTL_SKIP_AUTO_CLEANUP = 'true'
const rtl = require('../')
render = rtl.render
})
-// This one verifies that if RTL_SKIP_CLEANUP is set
+// This one verifies that if RTL_SKIP_AUTO_CLEANUP is set
// then we DON'T auto-wire up the afterEach for folks
test('first', () => {
render(
hi
)
diff --git a/src/index.js b/src/index.js
index f6e1c1ef..5e05b725 100644
--- a/src/index.js
+++ b/src/index.js
@@ -1,163 +1,16 @@
-import React from 'react'
-import ReactDOM from 'react-dom'
-import {
- getQueriesForElement,
- prettyDOM,
- fireEvent as dtlFireEvent,
- configure as configureDTL,
-} from '@testing-library/dom'
-import act, {asyncAct} from './act-compat'
-
-configureDTL({
- asyncWrapper: async cb => {
- let result
- await asyncAct(async () => {
- result = await cb()
- })
- return result
- },
-})
-
-const mountedContainers = new Set()
-
-function render(
- ui,
- {
- container,
- baseElement = container,
- queries,
- hydrate = false,
- wrapper: WrapperComponent,
- } = {},
-) {
- if (!baseElement) {
- // default to document.body instead of documentElement to avoid output of potentially-large
- // head elements (such as JSS style blocks) in debug output
- baseElement = document.body
- }
- if (!container) {
- container = baseElement.appendChild(document.createElement('div'))
- }
-
- // we'll add it to the mounted containers regardless of whether it's actually
- // added to document.body so the cleanup method works regardless of whether
- // they're passing us a custom container or not.
- mountedContainers.add(container)
-
- const wrapUiIfNeeded = innerElement =>
- WrapperComponent
- ? React.createElement(WrapperComponent, null, innerElement)
- : innerElement
-
- act(() => {
- if (hydrate) {
- ReactDOM.hydrate(wrapUiIfNeeded(ui), container)
- } else {
- ReactDOM.render(wrapUiIfNeeded(ui), container)
- }
- })
-
- return {
- container,
- baseElement,
- // eslint-disable-next-line no-console
- debug: (el = baseElement) => console.log(prettyDOM(el)),
- unmount: () => ReactDOM.unmountComponentAtNode(container),
- rerender: rerenderUi => {
- render(wrapUiIfNeeded(rerenderUi), {container, baseElement})
- // Intentionally do not return anything to avoid unnecessarily complicating the API.
- // folks can use all the same utilities we return in the first place that are bound to the container
- },
- asFragment: () => {
- /* istanbul ignore if (jsdom limitation) */
- if (typeof document.createRange === 'function') {
- return document
- .createRange()
- .createContextualFragment(container.innerHTML)
- }
-
- const template = document.createElement('template')
- template.innerHTML = container.innerHTML
- return template.content
- },
- ...getQueriesForElement(baseElement, queries),
- }
-}
-
-function cleanup() {
- mountedContainers.forEach(cleanupAtContainer)
-}
-
-// maybe one day we'll expose this (perhaps even as a utility returned by render).
-// but let's wait until someone asks for it.
-function cleanupAtContainer(container) {
- ReactDOM.unmountComponentAtNode(container)
- if (container.parentNode === document.body) {
- document.body.removeChild(container)
- }
- mountedContainers.delete(container)
-}
-
-// react-testing-library's version of fireEvent will call
-// dom-testing-library's version of fireEvent wrapped inside
-// an "act" call so that after all event callbacks have been
-// been called, the resulting useEffect callbacks will also
-// be called.
-function fireEvent(...args) {
- let returnValue
- act(() => {
- returnValue = dtlFireEvent(...args)
- })
- return returnValue
-}
-
-Object.keys(dtlFireEvent).forEach(key => {
- fireEvent[key] = (...args) => {
- let returnValue
- act(() => {
- returnValue = dtlFireEvent[key](...args)
- })
- return returnValue
- }
-})
-
-// React event system tracks native mouseOver/mouseOut events for
-// running onMouseEnter/onMouseLeave handlers
-// @link https://github.com/facebook/react/blob/b87aabdfe1b7461e7331abb3601d9e6bb27544bc/packages/react-dom/src/events/EnterLeaveEventPlugin.js#L24-L31
-fireEvent.mouseEnter = fireEvent.mouseOver
-fireEvent.mouseLeave = fireEvent.mouseOut
-
-fireEvent.select = (node, init) => {
- // React tracks this event only on focused inputs
- node.focus()
-
- // React creates this event when one of the following native events happens
- // - contextMenu
- // - mouseUp
- // - dragEnd
- // - keyUp
- // - keyDown
- // so we can use any here
- // @link https://github.com/facebook/react/blob/b87aabdfe1b7461e7331abb3601d9e6bb27544bc/packages/react-dom/src/events/SelectEventPlugin.js#L203-L224
- fireEvent.keyUp(node, init)
-}
+import {asyncAct} from './act-compat'
+import {cleanup} from './pure'
// if we're running in a test runner that supports afterEach
// then we'll automatically run cleanup afterEach test
// this ensures that tests run in isolation from each other
-if (typeof afterEach === 'function' && !process.env.RTL_SKIP_CLEANUP) {
+// if you don't like this then either import the `pure` module
+// or set the RTL_SKIP_AUTO_CLEANUP env variable to 'true'.
+if (typeof afterEach === 'function' && !process.env.RTL_SKIP_AUTO_CLEANUP) {
afterEach(async () => {
await asyncAct(async () => {})
cleanup()
})
}
-// just re-export everything from dom-testing-library
-export * from '@testing-library/dom'
-export {render, cleanup, fireEvent, act}
-
-// NOTE: we're not going to export asyncAct because that's our own compatibility
-// thing for people using react-dom@16.8.0. Anyone else doesn't need it and
-// people should just upgrade anyway.
-
-/* eslint func-name-matching:0 */
+export * from './pure'
diff --git a/src/pure.js b/src/pure.js
new file mode 100644
index 00000000..4565074b
--- /dev/null
+++ b/src/pure.js
@@ -0,0 +1,153 @@
+import React from 'react'
+import ReactDOM from 'react-dom'
+import {
+ getQueriesForElement,
+ prettyDOM,
+ fireEvent as dtlFireEvent,
+ configure as configureDTL,
+} from '@testing-library/dom'
+import act, {asyncAct} from './act-compat'
+
+configureDTL({
+ asyncWrapper: async cb => {
+ let result
+ await asyncAct(async () => {
+ result = await cb()
+ })
+ return result
+ },
+})
+
+const mountedContainers = new Set()
+
+function render(
+ ui,
+ {
+ container,
+ baseElement = container,
+ queries,
+ hydrate = false,
+ wrapper: WrapperComponent,
+ } = {},
+) {
+ if (!baseElement) {
+ // default to document.body instead of documentElement to avoid output of potentially-large
+ // head elements (such as JSS style blocks) in debug output
+ baseElement = document.body
+ }
+ if (!container) {
+ container = baseElement.appendChild(document.createElement('div'))
+ }
+
+ // we'll add it to the mounted containers regardless of whether it's actually
+ // added to document.body so the cleanup method works regardless of whether
+ // they're passing us a custom container or not.
+ mountedContainers.add(container)
+
+ const wrapUiIfNeeded = innerElement =>
+ WrapperComponent
+ ? React.createElement(WrapperComponent, null, innerElement)
+ : innerElement
+
+ act(() => {
+ if (hydrate) {
+ ReactDOM.hydrate(wrapUiIfNeeded(ui), container)
+ } else {
+ ReactDOM.render(wrapUiIfNeeded(ui), container)
+ }
+ })
+
+ return {
+ container,
+ baseElement,
+ // eslint-disable-next-line no-console
+ debug: (el = baseElement) => console.log(prettyDOM(el)),
+ unmount: () => ReactDOM.unmountComponentAtNode(container),
+ rerender: rerenderUi => {
+ render(wrapUiIfNeeded(rerenderUi), {container, baseElement})
+ // Intentionally do not return anything to avoid unnecessarily complicating the API.
+ // folks can use all the same utilities we return in the first place that are bound to the container
+ },
+ asFragment: () => {
+ /* istanbul ignore if (jsdom limitation) */
+ if (typeof document.createRange === 'function') {
+ return document
+ .createRange()
+ .createContextualFragment(container.innerHTML)
+ }
+
+ const template = document.createElement('template')
+ template.innerHTML = container.innerHTML
+ return template.content
+ },
+ ...getQueriesForElement(baseElement, queries),
+ }
+}
+
+function cleanup() {
+ mountedContainers.forEach(cleanupAtContainer)
+}
+
+// maybe one day we'll expose this (perhaps even as a utility returned by render).
+// but let's wait until someone asks for it.
+function cleanupAtContainer(container) {
+ ReactDOM.unmountComponentAtNode(container)
+ if (container.parentNode === document.body) {
+ document.body.removeChild(container)
+ }
+ mountedContainers.delete(container)
+}
+
+// react-testing-library's version of fireEvent will call
+// dom-testing-library's version of fireEvent wrapped inside
+// an "act" call so that after all event callbacks have been
+// been called, the resulting useEffect callbacks will also
+// be called.
+function fireEvent(...args) {
+ let returnValue
+ act(() => {
+ returnValue = dtlFireEvent(...args)
+ })
+ return returnValue
+}
+
+Object.keys(dtlFireEvent).forEach(key => {
+ fireEvent[key] = (...args) => {
+ let returnValue
+ act(() => {
+ returnValue = dtlFireEvent[key](...args)
+ })
+ return returnValue
+ }
+})
+
+// React event system tracks native mouseOver/mouseOut events for
+// running onMouseEnter/onMouseLeave handlers
+// @link https://github.com/facebook/react/blob/b87aabdfe1b7461e7331abb3601d9e6bb27544bc/packages/react-dom/src/events/EnterLeaveEventPlugin.js#L24-L31
+fireEvent.mouseEnter = fireEvent.mouseOver
+fireEvent.mouseLeave = fireEvent.mouseOut
+
+fireEvent.select = (node, init) => {
+ // React tracks this event only on focused inputs
+ node.focus()
+
+ // React creates this event when one of the following native events happens
+ // - contextMenu
+ // - mouseUp
+ // - dragEnd
+ // - keyUp
+ // - keyDown
+ // so we can use any here
+ // @link https://github.com/facebook/react/blob/b87aabdfe1b7461e7331abb3601d9e6bb27544bc/packages/react-dom/src/events/SelectEventPlugin.js#L203-L224
+ fireEvent.keyUp(node, init)
+}
+
+// just re-export everything from dom-testing-library
+export * from '@testing-library/dom'
+export {render, cleanup, fireEvent, act}
+
+// NOTE: we're not going to export asyncAct because that's our own compatibility
+// thing for people using react-dom@16.8.0. Anyone else doesn't need it and
+// people should just upgrade anyway.
+
+/* eslint func-name-matching:0 */
From 1dd65446fb4f67364966e4b856f1ae729af72dc9 Mon Sep 17 00:00:00 2001
From: "Kent C. Dodds"
Date: Fri, 9 Aug 2019 13:45:48 -0600
Subject: [PATCH 037/298] feat(deps): update @testing-library/dom to 6.0.0
BREAKING CHANGE: If you were using `debugDOM` before, use `prettyDOM` instead. Note that `debugDOM` is different from `debug` which you get back from `render`. That is unchanged.
---
package.json | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/package.json b/package.json
index d27b209a..84e734d3 100644
--- a/package.json
+++ b/package.json
@@ -43,12 +43,12 @@
"license": "MIT",
"dependencies": {
"@babel/runtime": "^7.5.5",
- "@testing-library/dom": "^5.6.1"
+ "@testing-library/dom": "^6.0.0"
},
"devDependencies": {
"@reach/router": "^1.2.1",
"@testing-library/jest-dom": "^4.0.0",
- "@types/react": "^16.8.25",
+ "@types/react": "^16.9.1",
"@types/react-dom": "^16.8.5",
"kcd-scripts": "^1.5.2",
"react": "^16.9.0",
From 0b83ca5720b40ab1731e0c1ed924833d8728eeea Mon Sep 17 00:00:00 2001
From: "Kent C. Dodds"
Date: Fri, 9 Aug 2019 14:12:57 -0600
Subject: [PATCH 038/298] fix(cleanup-after-each): remove cleanup-after-each
file. (#433)
This is automatic now, so there is no reason to have it
Closes #433
---
cleanup-after-each.js | 3 ---
package.json | 1 -
src/__tests__/cleanup-after-each.js | 32 -----------------------------
src/cleanup-async.js | 10 ---------
4 files changed, 46 deletions(-)
delete mode 100644 cleanup-after-each.js
delete mode 100644 src/__tests__/cleanup-after-each.js
delete mode 100644 src/cleanup-async.js
diff --git a/cleanup-after-each.js b/cleanup-after-each.js
deleted file mode 100644
index 9bbba5ce..00000000
--- a/cleanup-after-each.js
+++ /dev/null
@@ -1,3 +0,0 @@
-afterEach(() => {
- return require('./dist/cleanup-async')()
-})
diff --git a/package.json b/package.json
index 84e734d3..78b89545 100644
--- a/package.json
+++ b/package.json
@@ -24,7 +24,6 @@
"files": [
"dist",
"typings",
- "cleanup-after-each.js",
"pure.js"
],
"keywords": [
diff --git a/src/__tests__/cleanup-after-each.js b/src/__tests__/cleanup-after-each.js
deleted file mode 100644
index 3f7e139b..00000000
--- a/src/__tests__/cleanup-after-each.js
+++ /dev/null
@@ -1,32 +0,0 @@
-import React from 'react'
-import {render} from '../'
-import cleanupAsync from '../cleanup-async'
-
-afterEach(() => {
- return cleanupAsync()
-})
-
-const log = []
-let ctr = 0
-
-function App() {
- async function somethingAsync() {
- await null
- log.push(ctr++)
- }
- React.useEffect(() => {
- somethingAsync()
- }, [])
- return 123
-}
-
-test('does not leave any hanging microtasks: part 1', () => {
- render()
- expect(document.body.textContent).toBe('123')
- expect(log).toEqual([])
-})
-
-test('does not leave any hanging microtasks: part 2', () => {
- expect(log).toEqual([0])
- expect(document.body.innerHTML).toBe('')
-})
diff --git a/src/cleanup-async.js b/src/cleanup-async.js
deleted file mode 100644
index 0031db56..00000000
--- a/src/cleanup-async.js
+++ /dev/null
@@ -1,10 +0,0 @@
-// This file is for use by the top-level export
-// @testing-library/react/cleanup-after-each
-// It is not meant to be used directly
-
-module.exports = async function cleanupAsync() {
- const {asyncAct} = require('./act-compat')
- const {cleanup} = require('./index')
- await asyncAct(async () => {})
- cleanup()
-}
From 8277b06c199cacb0e81597aa506151de7a71b439 Mon Sep 17 00:00:00 2001
From: "Kent C. Dodds"
Date: Fri, 9 Aug 2019 14:35:16 -0600
Subject: [PATCH 039/298] fix: restore cleanup-after-each and include a
deprecation warning
ref: #433
---
cleanup-after-each.js | 4 ++++
package.json | 1 +
2 files changed, 5 insertions(+)
create mode 100644 cleanup-after-each.js
diff --git a/cleanup-after-each.js b/cleanup-after-each.js
new file mode 100644
index 00000000..ace739eb
--- /dev/null
+++ b/cleanup-after-each.js
@@ -0,0 +1,4 @@
+console.warn(
+ 'The module `@testing-library/react/cleanup-after-each` has been deprecated and no longer does anything (it is not needed). You no longer need to import this module and can safely remove any import or configuration which imports this module',
+)
+/* eslint no-console:0 */
diff --git a/package.json b/package.json
index 78b89545..84e734d3 100644
--- a/package.json
+++ b/package.json
@@ -24,6 +24,7 @@
"files": [
"dist",
"typings",
+ "cleanup-after-each.js",
"pure.js"
],
"keywords": [
From f4b813e60390501e5db825e1270cc0294fa440b7 Mon Sep 17 00:00:00 2001
From: "Kent C. Dodds"
Date: Sat, 10 Aug 2019 11:36:08 -0600
Subject: [PATCH 040/298] feat: add dont-cleanup-after-each.js (#435)
This is just a simple file that sets the RTL_SKIP_AUTO_CLEANUP environment variable so that RTL doesn't setup automatic cleanup. This makes it easier for folks who don't want to write their tests in an isolated way. It's totally not recommended, but it will hopefully reduce pain while people migrate from one testing style to another.
---
dont-cleanup-after-each.js | 1 +
package.json | 1 +
2 files changed, 2 insertions(+)
create mode 100644 dont-cleanup-after-each.js
diff --git a/dont-cleanup-after-each.js b/dont-cleanup-after-each.js
new file mode 100644
index 00000000..083a8188
--- /dev/null
+++ b/dont-cleanup-after-each.js
@@ -0,0 +1 @@
+process.env.RTL_SKIP_AUTO_CLEANUP = true
diff --git a/package.json b/package.json
index 84e734d3..279e065e 100644
--- a/package.json
+++ b/package.json
@@ -25,6 +25,7 @@
"dist",
"typings",
"cleanup-after-each.js",
+ "dont-cleanup-after-each.js",
"pure.js"
],
"keywords": [
From b5584ebb301f1a0c2cf09236528d1a79656d5e6e Mon Sep 17 00:00:00 2001
From: Sebastian Silbermann
Date: Tue, 13 Aug 2019 01:41:16 +0200
Subject: [PATCH 041/298] fix(TS): act type (#438)
* fix(types): Use act types from react-dom
* Fix unary not extending binary
---
package.json | 3 ++-
typings/index.d.ts | 5 ++++-
2 files changed, 6 insertions(+), 2 deletions(-)
diff --git a/package.json b/package.json
index 279e065e..ff29c1af 100644
--- a/package.json
+++ b/package.json
@@ -44,7 +44,8 @@
"license": "MIT",
"dependencies": {
"@babel/runtime": "^7.5.5",
- "@testing-library/dom": "^6.0.0"
+ "@testing-library/dom": "^6.0.0",
+ "@types/react-dom": "*"
},
"devDependencies": {
"@reach/router": "^1.2.1",
diff --git a/typings/index.d.ts b/typings/index.d.ts
index ddc5512a..ab4528e2 100644
--- a/typings/index.d.ts
+++ b/typings/index.d.ts
@@ -1,4 +1,5 @@
import {queries, Queries, BoundFunction} from '@testing-library/dom'
+import {act as reactAct} from 'react-dom/test-utils'
export * from '@testing-library/dom'
@@ -43,4 +44,6 @@ export function cleanup(): void
* If that's not available (older version of react) then it
* simply calls the given callback immediately
*/
-export function act(callback: () => void): void
+export const act: typeof reactAct extends undefined
+ ? (callback: () => void) => void
+ : typeof reactAct
From 29aad25c7576670bbbe5096fd39bda7c282e702e Mon Sep 17 00:00:00 2001
From: Alex Krolick
Date: Thu, 15 Aug 2019 12:21:48 -0700
Subject: [PATCH 042/298] fix(typescript): move typings to DefinitelyTyped
(#437)
You should not need to make any changes to upgrade to this version. We're just doing this to improve TypeScript maintenance.
Co-authored-by: Kent C. Dodds
---
CONTRIBUTING.md | 35 +++------------------------------
package.json | 6 +-----
typings/index.d.ts | 49 ----------------------------------------------
3 files changed, 4 insertions(+), 86 deletions(-)
delete mode 100644 typings/index.d.ts
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 7cc35e72..de766c7a 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -26,45 +26,16 @@ series [How to Contribute to an Open Source Project on GitHub][egghead]
> can make all of your pull request branches based on this `master` branch.
> Whenever you want to update your version of `master`, do a regular `git pull`.
-## Add yourself as a contributor
-
-This project follows the [all contributors][all-contributors] specification. To
-add yourself to the table of contributors on the `README.md`, please use the
-automated script as part of your PR:
-
-```console
-npm run add-contributor
-```
-
-Follow the prompt and commit `.all-contributorsrc` and `README.md` in the PR. If
-you've already added yourself to the list and are making a new type of
-contribution, you can run it again and select the added contribution type.
-
## Committing and Pushing changes
Please make sure to run the tests before you commit your changes. You can run
`npm run test:update` which will update any snapshots that need updating. Make
sure to include those changes (if they exist) in your commit.
-### opt into git hooks
-
-There are git hooks set up with this project that are automatically installed
-when you install dependencies. They're really handy, but are turned off by
-default (so as to not hinder new contributors). You can opt into these by
-creating a file called `.opt-in` at the root of the project and putting this
-inside:
-
-```
-pre-commit
-```
-
-### Add typings
+### Update Typings
-If your PR introduced some changes in the API, you are more than welcome to
-modify the Typescript type definition to reflect those changes. Just modify the
-`/typings/index.d.ts` file accordingly. If you have never seen Typescript
-definitions before, you can read more about it in its
-[documentation pages](https://www.typescriptlang.org/docs/handbook/declaration-files/introduction.html)
+The TypeScript type definitions are in the
+[DefinitelyTyped repo](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/testing-library__react)
## Help needed
diff --git a/package.json b/package.json
index ff29c1af..56aa7346 100644
--- a/package.json
+++ b/package.json
@@ -4,7 +4,6 @@
"description": "Simple and complete React DOM testing utilities that encourage good testing practices.",
"main": "dist/index.js",
"module": "dist/@testing-library/react.esm.js",
- "typings": "typings/index.d.ts",
"engines": {
"node": ">=8"
},
@@ -23,7 +22,6 @@
},
"files": [
"dist",
- "typings",
"cleanup-after-each.js",
"dont-cleanup-after-each.js",
"pure.js"
@@ -45,13 +43,11 @@
"dependencies": {
"@babel/runtime": "^7.5.5",
"@testing-library/dom": "^6.0.0",
- "@types/react-dom": "*"
+ "@types/testing-library__react": "^9.1.0"
},
"devDependencies": {
"@reach/router": "^1.2.1",
"@testing-library/jest-dom": "^4.0.0",
- "@types/react": "^16.9.1",
- "@types/react-dom": "^16.8.5",
"kcd-scripts": "^1.5.2",
"react": "^16.9.0",
"react-dom": "^16.9.0"
diff --git a/typings/index.d.ts b/typings/index.d.ts
deleted file mode 100644
index ab4528e2..00000000
--- a/typings/index.d.ts
+++ /dev/null
@@ -1,49 +0,0 @@
-import {queries, Queries, BoundFunction} from '@testing-library/dom'
-import {act as reactAct} from 'react-dom/test-utils'
-
-export * from '@testing-library/dom'
-
-export type RenderResult = {
- container: HTMLElement
- baseElement: HTMLElement
- debug: (baseElement?: HTMLElement | DocumentFragment) => void
- rerender: (ui: React.ReactElement) => void
- unmount: () => boolean
- asFragment: () => DocumentFragment
-} & {[P in keyof Q]: BoundFunction}
-
-export interface RenderOptions {
- container?: HTMLElement
- baseElement?: HTMLElement
- hydrate?: boolean
- queries?: Q
- wrapper?: React.ComponentType
-}
-
-type Omit = Pick>
-
-/**
- * Render into a container which is appended to document.body. It should be used with cleanup.
- */
-export function render(
- ui: React.ReactElement,
- options?: Omit,
-): RenderResult
-export function render(
- ui: React.ReactElement,
- options: RenderOptions,
-): RenderResult
-
-/**
- * Unmounts React trees that were mounted with render.
- */
-export function cleanup(): void
-
-/**
- * Simply calls ReactDOMTestUtils.act(cb)
- * If that's not available (older version of react) then it
- * simply calls the given callback immediately
- */
-export const act: typeof reactAct extends undefined
- ? (callback: () => void) => void
- : typeof reactAct
From a4fa8413bbab8b08518994e96322622fc0008f72 Mon Sep 17 00:00:00 2001
From: "allcontributors[bot]"
<46447321+allcontributors[bot]@users.noreply.github.com>
Date: Thu, 15 Aug 2019 13:23:07 -0600
Subject: [PATCH 043/298] docs: add nickmccurdy as a contributor (#444)
* docs: update README.md
* docs: update .all-contributorsrc
Co-authored-by: null <46447321+allcontributors[bot]@users.noreply.github.com>
---
.all-contributorsrc | 9 +++++++++
README.md | 3 ++-
2 files changed, 11 insertions(+), 1 deletion(-)
diff --git a/.all-contributorsrc b/.all-contributorsrc
index 24dbb2ee..03ea3c9a 100644
--- a/.all-contributorsrc
+++ b/.all-contributorsrc
@@ -865,6 +865,15 @@
"contributions": [
"review"
]
+ },
+ {
+ "login": "nickmccurdy",
+ "name": "Nick McCurdy",
+ "avatar_url": "https://avatars0.githubusercontent.com/u/927220?v=4",
+ "profile": "https://nickmccurdy.com/",
+ "contributions": [
+ "review"
+ ]
}
],
"contributorsPerLine": 7,
diff --git a/README.md b/README.md
index 8008d6b7..81424e6f 100644
--- a/README.md
+++ b/README.md
@@ -29,7 +29,7 @@ practices.
[![version][version-badge]][package] [![downloads][downloads-badge]][npmtrends]
[![MIT License][license-badge]][license]
-[](#contributors)
+[](#contributors)
[![PRs Welcome][prs-badge]][prs] [![Code of Conduct][coc-badge]][coc]
[![Join the community on Spectrum][spectrum-badge]][spectrum]
@@ -501,6 +501,7 @@ Thanks goes to these people ([emoji key][emojis]):
@@ -85,7 +85,7 @@ your team down.
## This solution
-The `react-testing-library` is a very lightweight solution for testing React
+The `React Testing Library` is a very lightweight solution for testing React
components. It provides light utility functions on top of `react-dom` and
`react-dom/test-utils`, in a way that encourages better testing practices. Its
primary guiding principle is:
@@ -312,18 +312,18 @@ Some included are:
- [`react-router`](https://codesandbox.io/s/github/kentcdodds/react-testing-library-examples/tree/master/?fontsize=14&module=%2Fsrc%2F__tests__%2Freact-router.js&previewwindow=tests)
- [`react-context`](https://codesandbox.io/s/github/kentcdodds/react-testing-library-examples/tree/master/?fontsize=14&module=%2Fsrc%2F__tests__%2Freact-context.js&previewwindow=tests)
-You can also find react-testing-library examples at
+You can also find React Testing Library examples at
[react-testing-examples.com](https://react-testing-examples.com/jest-rtl/).
## Hooks
If you are interested in testing a custom hook, check out
-[react-hooks-testing-library][react-hooks-testing-library].
+[React Hooks Testing Library][react-hooks-testing-library].
> NOTE it is not recommended to test single-use custom hooks in isolation from
> the components where it's being used. It's better to test the component that's
-> using the hook rather than the hook itself. The react-hooks-testing-library is
-> intended to be used for reusable hooks/libraries.
+> using the hook rather than the hook itself. The `React Hooks Testing Library`
+> is intended to be used for reusable hooks/libraries.
## Guiding Principles
@@ -351,7 +351,7 @@ light-weight, simple, and understandable.
## Docs
[**Read The Docs**](https://testing-library.com/react) |
-[Edit the docs](https://github.com/alexkrolick/testing-library-docs)
+[Edit the docs](https://github.com/testing-library/testing-library-docs)
## Issues
@@ -556,6 +556,6 @@ Contributions of any kind welcome!
[good-first-issue]: https://github.com/testing-library/react-testing-library/issues?utf8=β&q=is%3Aissue+is%3Aopen+sort%3Areactions-%2B1-desc+label%3A"good+first+issue"+
[reactiflux]: https://www.reactiflux.com/
[stackoverflow]: https://stackoverflow.com/questions/tagged/react-testing-library
-[react-hooks-testing-library]: https://github.com/mpeyper/react-hooks-testing-library
+[react-hooks-testing-library]: https://github.com/testing-library/react-hooks-testing-library
From c4ba755e42938018ec67dbc716037cfafca15e03 Mon Sep 17 00:00:00 2001
From: "allcontributors[bot]"
<46447321+allcontributors[bot]@users.noreply.github.com>
Date: Sat, 17 Aug 2019 14:02:15 -0600
Subject: [PATCH 054/298] docs: add afontcu as a contributor (#458)
* docs: update README.md
* docs: update .all-contributorsrc
---
.all-contributorsrc | 3 ++-
README.md | 2 +-
2 files changed, 3 insertions(+), 2 deletions(-)
diff --git a/.all-contributorsrc b/.all-contributorsrc
index 5ae31ec3..71618a32 100644
--- a/.all-contributorsrc
+++ b/.all-contributorsrc
@@ -891,7 +891,8 @@
"avatar_url": "https://avatars0.githubusercontent.com/u/9197791?v=4",
"profile": "https://afontcu.dev",
"contributions": [
- "review"
+ "review",
+ "doc"
]
},
{
diff --git a/README.md b/README.md
index 5810a414..57171e77 100644
--- a/README.md
+++ b/README.md
@@ -505,7 +505,7 @@ Thanks goes to these people ([emoji key][emojis]):
[![version][version-badge]][package] [![downloads][downloads-badge]][npmtrends]
[![MIT License][license-badge]][license]
-[](#contributors)
+[](#contributors)
[![PRs Welcome][prs-badge]][prs] [![Code of Conduct][coc-badge]][coc]
[![Join the community on Spectrum][spectrum-badge]][spectrum]
@@ -511,6 +511,9 @@ Thanks goes to these people ([emoji key][emojis]):