enzyme: shallow doesn't work correctly with useState + React.memo
Current behavior
Hi all! I try to test my functional component, wrapped by memo.
TestButton.tsx
function TestButton () {
const [open, setOpen] = useState(false)
const toggle = () => setOpen(!open)
return (
<button
className={open && 'Active'}
onClick={toggle}>
test
</button>
)
}
export default memo(TestButton)
TestButton.test.tsx
import React from 'react'
import { shallow } from 'enzyme';
import TestButton from './TestButton';
describe('Test', () => {
it('after click, button should has Active className ', () => {
let component = shallow(<TestButton />)
component.find("button").prop('onClick')()
expect(component.find("button").hasClass('Active')).toBeTruthy()
})
})
I expect, that test will pass, but it fails and i can not understand why.
If I will remove memo wrapper it passed.
Or if I wrap testing component with mount
and after click make component.update()
it will be passed too
Expected behavior
Test should be passed
Your environment
API
- shallow
- mount
- render
Version
library | version |
---|---|
enzyme | 3.1.0 |
react | 16.8.0 |
react-dom | 16.8.0 |
react-test-renderer | |
adapter (below) |
Adapter
- enzyme-adapter-react-16
- enzyme-adapter-react-16.3
- enzyme-adapter-react-16.2
- enzyme-adapter-react-16.1
- enzyme-adapter-react-15
- enzyme-adapter-react-15.4
- enzyme-adapter-react-14
- enzyme-adapter-react-13
- enzyme-adapter-react-helper
- others ( )
About this issue
- Original URL
- State: open
- Created 5 years ago
- Reactions: 10
- Comments: 18 (5 by maintainers)
Any solution for this test case?
Maybe just split exports then you can avoid “React.memo()” versions in your tests
@frayeralex code should not depend on writing tests
I had a similar issue you’re facing. I’m shallow rendering a component with memoized components on the inside, and was not seeing the updates in the
wrapper.debug()
output. The problem seems pretty obvious once I figured it out.React.memo
is checking your props for equality before re-rendering (that’s great, that’s why we’re using memo!). If the props don’t change, the component won’t update.Example Component
Example Test
To recap: our props didn’t change, so our component should not re-render.
How do we solve this? Change the props!
Updated Test
This technique may not work for everyone; for example, if you’re relying on your props to be a certain primitive value, you might not be able to change it. In my case, I set the same prop values, but re-created the prop objects so that a strict equality check on prop objects would equate to false.
I’ll keep this open, to track it.
Not sure if related but memo doesn’t seem to work with mount.
When I use enzyme to test it:
If I use it without memo than it’s all good
React: 16.9.0 React-DOM: 16.9.0 Enzyme: 3.10.0 enzyme-adapter-react-16: 1.14.0
@ljharb Unfortunately, upgrate to latest version didn’t help. Same behavior
yes, of course