-
-
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
shallow doesn't work correctly with useState + React.memo #2196
Comments
Try upgrading react and react-dom to latest? |
@ljharb yes |
@MellowoO to clarify - you specified you're on 16.8.0, but there's a number of bugs in the early 16.8 releases. Can you upgrade to the latest react and react-dom, confirm exactly which versions you're on, and what behavior you're seeing? |
yes, of course |
@ljharb |
So, in this case, it seems the use of the useState hook combined with memo may be the issue. If you use a class component and setState, it will work. This is likely a limitation in react’s shallow renderer, which enzyme uses. Since hooks give us no way to hook into them, there’s not really a way for enzyme to react to hook changes. |
@ljharb |
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 |
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
Example Componentconst MyComponent = React.memo((props: { testProp: boolean }) => {
const [myState, setMyState] = useState('')
return <input value={myState} onChange={e => setMyState(e.target.value} />
}) Example Testit('updates', () => {
const wrapper = enzyme.shallow(<MyComponent testProp={true} />
wrapper.simulate('change', { target: { value: 'abc' } })
expect(wrapper.prop('value')).toEqual('abc') // FAIL
}) To recap: our props didn't change, so our component should not re-render. How do we solve this? Change the props! Updated Testit('updates', () => {
const wrapper = enzyme.shallow(<MyComponent testProp={true} />
wrapper.simulate('change', { target: { value: 'abc' } })
wrapper.setProps({ testProp: false })
expect(wrapper.prop('value')).toEqual('abc') // FAIL
}) 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. const props = () => ({ testPropObject: { ...testFixture } })
props() === { ...props() } // false |
Any solution for this test case? |
Maybe just split exports // Component.js
export const Component = (props) => { ... }
export default React.memo(Component)
// Component.test.js
import { Component } from './Component.js'
// Container.js
import Component from './Component.js' |
@frayeralex |
any updates on this issue ?? |
React.memo doesn't work with react react-dom react-test-render same minor version."enzyme": "^3.11.0", // Header.js
import React, { memo, useState } from "react";
const Header = () => {
const [value, setValue] = useState("");
const handleInputChange = (e) => {
setValue(e.target.value.trim());
};
return (
<div>
<input
type="text"
data-test="input"
value={value}
onChange={handleInputChange}
name="todo-input"
/>
</div>
);
};
export default memo(Header); // Header.test.js
it("Header 组件 input 框内容,当用户输入时,会跟随变化", () => {
const wrapper = shallow(<Header />);
wrapper.find("input[data-test='input']").simulate("change", {
target: {
value: "learn jest",
},
});
const userInput = "learn jest";
expect(wrapper.find("input[data-test='input']").prop("value")).toEqual(
userInput
);
}); expect(received).toEqual(expected) // deep equality
Expected: "learn jest"
Received: ""
22 | });
23 | const userInput = "learn jest";
> 24 | expect(wrapper.find("input[data-test='input']").prop("value")).toEqual(
| ^
25 | userInput
26 | );
27 | });
at Object.<anonymous> (src/containers/todo-list/__tests__/unit/Header.test.js:24:66) any updates on this issue ?? But use mount, it works. |
"jest": "^25.1.0", describe('test', () => {
it('success suite', () => {
const Component: React.FC = () => null;
const $el = mount(
<Component>
<div id={'findMe'} />
</Component>
);
expect($el.exists('#findMe')).toBeFalsy(); // passed
});
it('failure suite', () => {
const Component: React.FC = React.memo(() => null);
const $el = mount(
<Component>
<div id={'findMe'} />
</Component>
);
expect($el.exists('#findMe')).toBeFalsy(); // fail
});
}); debug output on failure suite:
|
It would be really nice to have this mentioned along with the couple of other issues mentioned in the introduction page. I spent a frustrating few hours last night without realizing that memo would be the culprit here :| |
@a-b-h-i-97 always happy to get PRs that improve the docs :-) |
Current behavior
Hi all! I try to test my functional component, wrapped by memo.
TestButton.tsx
TestButton.test.tsx
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 makecomponent.update()
it will be passed tooExpected behavior
Test should be passed
Your environment
API
Version
Adapter
The text was updated successfully, but these errors were encountered: