-
-
Notifications
You must be signed in to change notification settings - Fork 2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
mount/shallow does not rerender when props change or apply new props on update #1229
Comments
I have the same issue, but this seems to also occur when updating state internally in the Component. |
Workaround for now is to use |
@adrienDog as noted in the issue description and reproduction code, |
@adrienDog it's recommended to use immutable data with react. In your example you're pushing data into the array, so it's reference continues the same and for the component receiving let thing
const onClick = () => {
things = [...things, things.length]
} So this way |
@adrienDog probably you'll need to pass the new props anyway, that's the correct way. In the first example the wrapper is updating the component with the old props. |
I got the same issue here when update state internally. When I log out the props, state, and rendered components, only rendered components are different depending on if I call setProps in advance or not. Any thoughts on this? |
@marchaos @adrienDog calling |
|
I am update enzyme-adapter-react-16 to 1.1.0. Run result is OK.I think that is enzyme bug,but fix 1.1.0. |
Same here. forceUpdate not working for |
I'm seeing this, or something very similar too. Using enzyme 3.1.0, react 16.2.0, enzyme-adapter-react-16 1.0.4, and |
Well, it does send the new props, but in an unexpected order. We have a menu component that has child menu items. The menu items can be visible, and have internal state for the visibility, classes, etc. that gets set based on the When I
We found similar out-of-sequence state/prop updates with React 16, around callbacks to (btw, the conclusion that the child components are getting the new props at some point is based on what |
@notnownikki React 16 itself makes all of that ordering unreliable; the point is to allow async rendering. |
@ljharb so I've been finding out over the past couple of weeks :) |
What seemed to work for me was adding a
let wrapper;
beforeEach(() => {
wrapper = mount(
<MemoryRouter>
<App />
</MemoryRouter>,
);
wrapper.unmount();
});
describe('routing paths work as expected', () => {
it('root page should render SearchTicket component', () => {
wrapper.setProps({ initialEntries: ['/'] });
console.log(wrapper.props());
expect(wrapper.find(DetailTicket)).toHaveLength(0); // works
expect(wrapper.find(SearchTicket)).toHaveLength(1);
});
it('detail page should render DetailTicket component', () => {
wrapper.setProps({ initialEntries: ['/detail/05'] });
console.log(wrapper.props());
expect(wrapper.find(SearchTicket)).toHaveLength(0); // works
expect(wrapper.find(DetailTicket)).toHaveLength(1);
});
}); |
This is surprising to me...if one of my tests calls method Instead, it seems that's only true if I call |
@ialexryan it can, if your spies are set up correctly - one common mistake is using arrow functions in class fields, which prevents those functions from being spied upon properly in tests. |
No matter which order you set state, change state value, update, or force update, child components never get the props right wrapper.instance().state.isLoadingCategories = false;
wrapper.setState({ isLoadingCategories: false });
wrapper.instance().forceUpdate();
wrapper.update();
//false as expected
expect(wrapper.state('isLoadingCategories')).toEqual(false);
//category field isLoading prop derives from wrapper isLoadingCategories state, but its props is aways true (initial)
expect(categoryField.props().isLoading).toEqual(false); Its a shallow wrapper, by the way |
This is an issue in react 15 adapter as well. I did not require the // my-component.js
class MyComponent extends Component {
// ...
handleUpdate = () => this.setState({test: 'updated'});
render() {
return (
<div>
<OtherComponent
onUpdate={this.handleUpdate}
test={this.state.test}
/>
{/* ... */}
</div>
);
}
}
// my-component.spec.js
rootElement.childAt(0).props().onUpdate();
// used to work in v2, but fails on v3 without the `.update()` call
expect(rootElement.childAt(0).props().test).to.equal('updated'); Mentioning myself I don't loose this issue, and I already did once: @Gopikrishna19 |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This was an intentional design choice in v3. I'm going to close this; please file new issues for actionable concerns. |
@ljharb As this is an intentional design choice, is there a migration path or explanation on how to do what folks on this thread want? I'm happy to change my tests but based on the thread, I still have no idea what to change it to. |
@EricSchultz generally, you need to always re-find from the root to get updates, and you may need to use |
Refind still does not work. |
@shaundavin13 please file a new issue if you’re having trouble. |
Why should we open a new issue if this is still not solved? |
@DorianWScout24 because that ensures it gets the issue template filled out, and it avoids pinging all the people on this thread with a potentially different problem, and it helps the maintainers (hi) properly triage, categorize, and pay attention to the fact that there’s a problem. This issue was asking about something that’s not a bug, but rather a design choice for v3, so in this thread there’s nothing to fix. |
Did a new issue ever get filed? I reckon I'm too nooberish to properly file it but this issue persists for me and haven't found any solution here. (Edit: OH WAIT, yes I did, see below.) |
Nope, but it looks like while |
I've discovered the solution for me, hope to help others but they may have another issue: const wrapper = mount(<InputArea/>)
const input = wrapper.find('input')
input.simulate('change', {target: { value: 'Foo' } })
expect(input.props().value).to.equal('Foo') // fails with value: '' will not work as I was trying to check a found child of the wrapper which is immutable. Per this thread: #1221 (comment) You have to find the child again to get the new instance with the new props. This works instead: const wrapper = mount(<InputArea/>)
const input = wrapper.find('input')
input.simulate('change', {target: { value: 'Foo' } })
expect(wrapper.state('text')).to.equal('Foo')
// need to re-find the input cause the original is immutable in Enzyme V3
const refoundInput = wrapper.find('input')
expect(refoundInput.props().value).to.equal('Foo') // passes with value: 'Foo' @ljharb for some reason I didn't understand what you meant in this thread earlier, but the linked comment is more clear about immutability/re-finding, thanks! |
From the tests I've been doing, it seems that you have to first |
The order of when you get find/get the thing matters!!!! |
I had to use a timeout to get the Provider to update:
|
Worked for me, but it is kind bad need to use setTimeout just because have redux |
With Enzyme v2 you could mount/shallow render a component with some props and if those props changed then the component would be updated appropriately. With v3 even when you explicitly call
.update()
it fails to apply the updated version of the props.Two example tests are shown below; the first would work in v2, but v3 requires explicitly calling
.setProps
to force it to update. Is this expected behaviour in v3? I assume it's a consequence of the new adapters, but I couldn't see anywhere in the migration guide that it was mentioned.Package versions
[email protected]
[email protected]
[email protected]
[email protected]
The text was updated successfully, but these errors were encountered: