enzyme: enzyme@3: wrapper is not updated even if there was a new render
Hi. Just faced this after updating to v3.
Given the following deps:
├─ enzyme-adapter-react-16@1.0.0
├─ enzyme@3.0.0
├─ react-dom@16.0.0
├─ react-test-renderer@16.0.0
└─ react@16.0.0
And the HOC:
import React, { Component } from 'react'
const testHOC = (Target) => class TestClass extends Component {
constructor (...args) {
super(...args)
this.state = {}
this.onTest = this.onTest.bind(this)
}
onTest () {
this.setState({
foo: true
})
}
render () {
console.log(this.state)
return (
<Target {...this.props} {...this.state} onTest={this.onTest} />
)
}
}
export default testHOC
And the test:
import React from 'react'
import { mount } from 'enzyme'
import testHOC from './testHOC'
describe('testHOC', () => {
it('should work', () => {
const Target = () => null
const EnhancedTarget = testHOC(Target)
const wrapper = mount(
<EnhancedTarget />
)
wrapper.find(Target).prop('onTest')()
console.log(
wrapper.debug()
)
})
})
I see:
console.log testHOC.js:18
{ foo: true }
console.log testHOC.spec.js:15
<TestClass>
<Target onTest={[Function]} />
</TestClass>
So the was a new render, but wrapper just didn’t react to it. Works fine with v2.
Please correct me if I was wrong all this time and test should be written in another way.
About this issue
- Original URL
- State: closed
- Created 7 years ago
- Reactions: 49
- Comments: 48 (16 by maintainers)
Wrappers are immutable in enzyme 3; this is in the migration docs.
Try
wrapper.update()
after invoking your function.Hi,
In case this helps anyone, I was also struggling with this issue, specifically where a component was asynchronously fetching data in
componentDidMount
. The data was being retrieved from a stub function that returnsPromise.resolve(data)
. A tip I picked up from http://engineering.pivotal.io/post/react-integration-tests-with-enzyme sent me in the right direction. I simply needed to defer mywrapper.update()
till after the promise resolves, which is easy to predict in the case ofPromise.resolve(...)
.Versions:
I had a similar issue with wrapper not being updated and I think there might be a confusion regarding usage of
wrapper.update()
.@ljharb wrote that it is immutable and example http://airbnb.io/enzyme/docs/api/ShallowWrapper/update.html shows its usage in non-immutable way.
👎 Anyway, for my case the following did not work for me:
👍 But, the following did work as expected:
Should http://airbnb.io/enzyme/docs/api/ShallowWrapper/update.html example be corrected?
I had a similar issue. I fixed it by the following replacement:
The
.update()
method must be called on the root wrapper, not on a child wrapper. The method mutates the root wrapper but doesn’t mutate any child wrapper so I have to find the button again.I’m also experiencing the same behaviour with the same deps on some of my component tests (non-HOC) where the state updates, but the wrapper does not, even after calling
.update()
.Placing console.log’s in the component under tests render method show’s things rendering correctly during the test, I just can’t seem to assert properly after an
.update()
,.debug()
outputs the initial component..state()
shows the correct state after an.update()
This seems to still be an issue in enzyme-adapter-react-16@1.1.0 wrapper.update() does not work. Yet console logs in the source code show that state is being updated. .html() shows the correct structure. I can point you to a repo with the failing test if that helps.
Same issue. I can confirm that render is running appropriately, and I can even get the updated values from
wrapper.state
, butwrapper.update
doesn’t reflect the re-rendered component.I did some heave debugging for https://github.com/WordPress/gutenberg/pull/2813 and it looks like we are having the same kind of issues that are reported in this thread and here.
I tried to add recommended
wrapper.update();
call after the click event is simulated, but it didn’t help. It’s quite interesting scenario because the part of the component that depends on the component’s state (https://github.com/WordPress/gutenberg/blob/ad316ab1f8cfe60aeeb45ff27d45336bfb214c3c/editor/inserter/menu.js#L384) gets properly updated, but the other part (https://github.com/WordPress/gutenberg/blob/ad316ab1f8cfe60aeeb45ff27d45336bfb214c3c/editor/inserter/menu.js#L366) which also is conditionally rendered based on the components’ state doesn’t show up in the output ofwrapper.debug()
call. When I debugged it turned out that React component does everything properly behind the scenes. It looks like Enzyme gets out of sync.We have encountered a similar issue (please let me know if If got yours wrong) and created a codesandbox to demo/reproduce. The test is in
enzyme.spec.js
and you have to click on thetests
tab at the bottom.Consider the following small component:
Whenever I click the span, the
data-clicked
prop should change. Here is a test that fails, but imo should work:However, if you re-query the span after clicking it, it works.
I wonder if that is intended behavior? We often run into troubles due to that. Thank you. 😃
Same problem here. setState is inside the method I am trying to test. So when calling the method from the test and even when I do a
wrapper.update
the state of the component isn’t updated. I have tried both with mount and shallowtest.js
panel.js
This is hopefully fixed in
enzyme-adapter-react-16@1.0.1
. Please upgrade and let us know if it does not fix your issue. Thanks!This appears to remain an issue in
enzyme-adapter-react-15@1.0.5
. Will the fix be backported for earlier versions of React/Adapters?Is this supposed to be fixed?
I have this code:
results:
FWIW I was having the same issue. The I added the
done
parameter to theit
function and called it at the end, and that fixed my problem.it('does something', done => { .... done()})
I found something that works. Add these middle two lines.
Tried all suggestions here and didn’t work. At the end updating to
"enzyme-adapter-react-16": "^1.3.1"
worked.Confirmed what @gziolo said. The component is updated properly.
.html()
returns the right structure. But theReactWrapper
itself is out of sync.See the API docs.
@Finesse yes, that’s part of v3 - you always have to re-find from the root.
@jneander and @diablouma I don’t think
wrapper.update()
is broken inenzyme-adapter-react-15@1.0.5
. I’m running1.0.5
now and it works for me.I spent some time (hours) debugging a similar issue this afternoon. In my case, the issue was that I was doing this:
And expecting
simulate
to be synchronous. It wasn’t. I had anawait
inside my event handler and when execution hit thatawait
it surrendered execution from the event handler back to the test briefly. NOTE that I am not sayingawait
did not wait successfully. It did, from the perspective of the event handler. However, from the perspective of the test itself, it didn’t. I’m not sure what the technical term for that is, but you can imagine that they are two separate async processes running at the same time and control briefly switched from the event handler process to the test process.You can test this the old school way by putting a ton of
console.log('before such and such')
statements all throughout your test and your event handler and see what order they are printed when the test executes.The issue is that events in JS do not return promises. So there is no way to do the equivalent of this:
However, event handlers can return promises. So the solution, in my case, was to call the event handler directly, rather than use
simulate
. Example, wherehandleSubmit()
is my event handler:I got this idea from the owner of the enzyme repo in this comment: https://github.com/airbnb/enzyme/issues/1054#issuecomment-318811871
He says:
Hope that helps someone save some time. (Also, I hope I’m on the right track here)
@ljharb I created issue #1400
Thanks for looking into this.