Skip to content

Commit

Permalink
fix(type): wrap type in the asyncWrapper from DOM Testing Library (#303)
Browse files Browse the repository at this point in the history
BREAKING CHANGE: The DOM Testing Library version 7.9.0 or greater is required
  • Loading branch information
kentcdodds committed Jun 2, 2020
1 parent eb33bdb commit 9fe76b4
Show file tree
Hide file tree
Showing 5 changed files with 137 additions and 56 deletions.
6 changes: 3 additions & 3 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

16 changes: 13 additions & 3 deletions package.json
Expand Up @@ -40,23 +40,33 @@
"@babel/runtime": "^7.10.2"
},
"devDependencies": {
"@testing-library/dom": "^7.8.0",
"@testing-library/dom": "^7.9.0",
"@testing-library/jest-dom": "^5.9.0",
"@testing-library/react": "^10.0.5",
"kcd-scripts": "^6.2.0",
"react": "^16.13.1",
"react-dom": "^16.13.1"
},
"peerDependencies": {
"@testing-library/dom": ">=5"
"@testing-library/dom": ">=7.9.0"
},
"eslintConfig": {
"extends": "./node_modules/kcd-scripts/eslint.js",
"rules": {
"jsx-a11y/click-events-have-key-events": "off",
"jsx-a11y/tabindex-no-positive": "off",
"no-return-assign": "off"
}
},
"overrides": [
{
"files": [
"**/__tests__/**"
],
"rules": {
"no-console": "off"
}
}
]
},
"eslintIgnore": [
"node_modules",
Expand Down
38 changes: 19 additions & 19 deletions src/__tests__/type.js
Expand Up @@ -2,7 +2,7 @@ import React from 'react'
import {render, screen} from '@testing-library/react'
import userEvent from '../../src'

test.each(['input', 'textarea'])('should type text in <%s>', type => {
test.each(['input', 'textarea'])('should type text in <%s>', async type => {
const onChange = jest.fn()
render(
React.createElement(type, {
Expand All @@ -11,30 +11,30 @@ test.each(['input', 'textarea'])('should type text in <%s>', type => {
}),
)
const text = 'Hello, world!'
userEvent.type(screen.getByTestId('input'), text)
await userEvent.type(screen.getByTestId('input'), text)
expect(onChange).toHaveBeenCalledTimes(text.length)
expect(screen.getByTestId('input')).toHaveProperty('value', text)
})

test('should append text one by one', () => {
test('should append text one by one', async () => {
const onChange = jest.fn()
render(<input data-testid="input" onChange={onChange} />)
userEvent.type(screen.getByTestId('input'), 'hello')
userEvent.type(screen.getByTestId('input'), ' world')
await userEvent.type(screen.getByTestId('input'), 'hello')
await userEvent.type(screen.getByTestId('input'), ' world')
expect(onChange).toHaveBeenCalledTimes('hello world'.length)
expect(screen.getByTestId('input')).toHaveProperty('value', 'hello world')
})

test('should append text all at once', () => {
test('should append text all at once', async () => {
const onChange = jest.fn()
render(<input data-testid="input" onChange={onChange} />)
userEvent.type(screen.getByTestId('input'), 'hello', {allAtOnce: true})
userEvent.type(screen.getByTestId('input'), ' world', {allAtOnce: true})
await userEvent.type(screen.getByTestId('input'), 'hello', {allAtOnce: true})
await userEvent.type(screen.getByTestId('input'), ' world', {allAtOnce: true})
expect(onChange).toHaveBeenCalledTimes(2)
expect(screen.getByTestId('input')).toHaveProperty('value', 'hello world')
})

test('should not type when event.preventDefault() is called', () => {
test('should not type when event.preventDefault() is called', async () => {
const onChange = jest.fn()
const onKeydown = jest
.fn()
Expand All @@ -43,15 +43,15 @@ test('should not type when event.preventDefault() is called', () => {
<input data-testid="input" onKeyDown={onKeydown} onChange={onChange} />,
)
const text = 'Hello, world!'
userEvent.type(screen.getByTestId('input'), text)
await userEvent.type(screen.getByTestId('input'), text)
expect(onKeydown).toHaveBeenCalledTimes(text.length)
expect(onChange).toHaveBeenCalledTimes(0)
expect(screen.getByTestId('input')).not.toHaveProperty('value', text)
})

test.each(['input', 'textarea'])(
'should not type when <%s> is disabled',
type => {
async type => {
const onChange = jest.fn()
render(
React.createElement(type, {
Expand All @@ -61,15 +61,15 @@ test.each(['input', 'textarea'])(
}),
)
const text = 'Hello, world!'
userEvent.type(screen.getByTestId('input'), text)
await userEvent.type(screen.getByTestId('input'), text)
expect(onChange).not.toHaveBeenCalled()
expect(screen.getByTestId('input')).toHaveProperty('value', '')
},
)

test.each(['input', 'textarea'])(
'should not type when <%s> is readOnly',
type => {
async type => {
const onChange = jest.fn()
const onKeyDown = jest.fn()
const onKeyPress = jest.fn()
Expand All @@ -85,7 +85,7 @@ test.each(['input', 'textarea'])(
}),
)
const text = 'Hello, world!'
userEvent.type(screen.getByTestId('input'), text)
await userEvent.type(screen.getByTestId('input'), text)
expect(onKeyDown).toHaveBeenCalledTimes(text.length)
expect(onKeyPress).toHaveBeenCalledTimes(text.length)
expect(onKeyUp).toHaveBeenCalledTimes(text.length)
Expand Down Expand Up @@ -154,7 +154,7 @@ test.each(['input', 'textarea'])(

test.each(['input', 'textarea'])(
'should enter text in <%s> up to maxLength if provided',
type => {
async type => {
const onChange = jest.fn()
const onKeyDown = jest.fn()
const onKeyPress = jest.fn()
Expand All @@ -177,7 +177,7 @@ test.each(['input', 'textarea'])(

const inputEl = screen.getByTestId('input')

userEvent.type(inputEl, text)
await userEvent.type(inputEl, text)

expect(inputEl).toHaveProperty('value', slicedText)
expect(onChange).toHaveBeenCalledTimes(slicedText.length)
Expand Down Expand Up @@ -205,7 +205,7 @@ test.each(['input', 'textarea'])(

test.each(['input', 'textarea'])(
'should append text in <%s> up to maxLength if provided',
type => {
async type => {
const onChange = jest.fn()
const onKeyDown = jest.fn()
const onKeyPress = jest.fn()
Expand All @@ -230,8 +230,8 @@ test.each(['input', 'textarea'])(

const inputEl = screen.getByTestId('input')

userEvent.type(inputEl, text1)
userEvent.type(inputEl, text2)
await userEvent.type(inputEl, text1)
await userEvent.type(inputEl, text2)

expect(inputEl).toHaveProperty('value', slicedText)
expect(onChange).toHaveBeenCalledTimes(slicedText.length)
Expand Down
27 changes: 27 additions & 0 deletions src/__tests__/wrapping-in-act-is-unnecessary.js
Expand Up @@ -22,3 +22,30 @@ test('act necessitating side effect', () => {

expect(effectCallback).toHaveBeenCalledTimes(1)
})

test('act necessitating async side effect', async () => {
function TestComponent() {
const [renderMessage, setRenderMessage] = React.useState(false)
function handleChange() {
Promise.resolve().then(() => {
setRenderMessage(true)
})
}
return (
<div>
<input type="text" onChange={handleChange} />
<div>{renderMessage ? 'MESSAGE' : null}</div>
</div>
)
}
render(<TestComponent />)

// https://github.com/testing-library/dom-testing-library/pull/602
// before our fixes in DOM Testing Library, we had to wrap
// this next line in act for this test to pass.
await userEvent.type(screen.getByRole('textbox'), 'a')

expect(await screen.findByText('MESSAGE')).toBeInTheDocument()

expect(console.error).not.toHaveBeenCalled()
})

0 comments on commit 9fe76b4

Please sign in to comment.