This is a test in order to check value of input sets appropriately to state of component.
describe('RegistrationForm component', () => {
const mockStore = configureStore();
let wrapper;
let store;
beforeEach(() => {
const initialState = { type: LOGIN_USER }; // LOGIN_USER is imported ...
store = mockStore(initialState);
const props = { store }
wrapper = mount(<RegistrationForm {...props} />);
console.log("beforeEach done", wrapper.state()) // ********* CONSOLE PRINT
});
it('should has firstName', () => {
wrapper.find('[name="firstName"]').find('input').simulate('change',
{
target: { value: 'BBBBB', name: 'firstName' }
}
);
//wrapper = wrapper.update();
console.log("test->state: ", wrapper.state()); // ********* CONSOLE PRINT
expect(wrapper.state().user.firstName).toBe('BBBBB');
});
});
Here there is two calls to state() function of wrapper which both of them output {} as result. Also I put three console.log(this.state) in component, one in last line of constructor and two in first and last line of handleChange to ensure simulate runs as expected. Since I set firstName to AAAAA in constructor. It shows constructor done -> AAAAA, handleChange1 -> AAAAA and handleChange2 -> BBBBB. So it seems wrapper could connect to component but state() could not get its state. I checked wrapper.instance().state as well.
"enzyme": "^3.6.0",
"enzyme-adapter-react-16": "^1.5.0",
"react": "^16.5.2",
"react-dom": "^16.5.2",
"jest": "^23.6.0",
What's your component code? (Note that "simulate" doesn't actually simulate anything, it just calls a prop function)
You should also replace the commented line with wrapper.update();
Here is component code.
class RegistrationForm extends Component {
constructor() {
super()
this.state = { user: {firstName: 'AAAAA'}}; // other fields of user omitted
console.log('constructor done->', this.state);
}
// some other code here
handleChange(event) {
console.log('handleChange1 -> ', this.state); // shows handleChange1 -> AAAAA after running simulate
let { user } = this.state;
user[event.target.name] = event.target.value;
this.setState({ user });
console.log('handleChange2 -> ', this.state); // shows handleChange2 -> BBBBB after running simulate
}
// some other code here
render() {
return (
// some other code
<ValidatorForm>
<TextValidator
name='firstName'
onChange={this.handleChange}
// some other props
>
<TextValidator/>
<ValidatorForm/>
);
}
}
1) Why state() in the test does not get expected result(it output {} as component state)?
2) Why getting state right after mount outputs {} instead of component state?
3) Calling wrapper.update() after simulate does special work? (I am confused, in some examples in order to simulate they do that and some other they do not and get right behaviour.)
@ljharb Thanks
PS:
TextValidator is here
I think you have a bug in your code, btw - this.setState(user); should be this.setState({ user });
That was a typo in here(Currently I have not actual code at home and I rewrite it in github editor). I can double check that tomorrow but consider that console.log('handleChange2 -> ', this.state); output right thing(i.e BBBBB which sets from test).
I attached the actual code of both component and test. Also I attached the screenshot of test result. In the screenshot we have five state print. Three of them from inside component(constructor + 2*handleChange) which they have right value. But others which prints from test with wrapper.state() does not have value...
I Also uncomment wrapper = wrapper.update() and change it to wrapper.update() but it does not change anything...
What is status of this issue? Is someone working on it?
@bonjefir the one that was filed 4 days ago, that got its last update from you on a friday while it's sunday night right now? yes, someone's probably going to look into it, but you'll need to have some patience.
I just hit the same problem, and came across this issue.
After some poking around I discovered the cause: The component is wrapped with connect from react-redux, so the root node of the wrapper isn't actually the component in question, but rather a Connect instance -- which quietly returns empty state.
So my question is then... any good workaround to actually get at the wrapped instance's state?
@ronen with mount, you should be able to traverse to the child and retrieve it directly; with shallow, you'd need to .dive() to it first.
@ljharb what do you mean by traversing to the child? Could you elaborate?
I'm also having issues accessing the component state (wrapped inside component).
@sensui7 if you could share the results of wrapper.debug(), i can show you.
Here is the result of wrapper.debug() for my testing component.
It's being wrapped with connect, so do I need a way to access it somehow through
wrapper.instance()?
<Connect(Test) store={{...}}><Test store={{...}} dispatch={[Function]}><div /></Test></Connect(Test)>
EDIT: I guess I could simply export the unwrapped component for testing purposes.
@sensui7 you do not want to export the unwrapped component; you want to use wrapper.dive(), which will give you a wrapper on the inner Test component.
Here's the dive() documentation for anyone interested. This is so useful! I'd been pulling out the semi-secret WrappedComponent prior to this. 🤦♂️
No one seems understand what is the problem
even though shallow+dive() or mount gives a
state a expected {}, but in the Foo, this.state = {email:'', password:'',...}



@gogogous88 i definitely understand the problem - in your case, however, it's that you shouldn't be accessing instance.state, you should be accessing wrapper.state() - ie, wrapper.find(LoginPersonal).state().
@bonjefir there's a number of issues here:
simulatesetState could be async, so you can't rely on the values of this.state being set immediately after calling itI apologize it took so long to respond to your original issue, especially given my comment above.
Can you update all enzyme things to the latest, and confirm if you still have the problem? If so, I'll happily reopen this.
@gogogous88 i definitely understand the problem - in your case, however, it's that you shouldn't be accessing
instance.state, you should be accessingwrapper.state()- ie,wrapper.find(LoginPersonal).state().
really fast, Appreciate.
i got the problem and here is the right one to me

the quoted "LoginPersonal" give me the wrapper, and the unquoted I believe give me the instance
@gogogous88 you're incorrect; they both only ever give you an enzyme wrapper. However, that suggests that the LoginPersonal you're finding for is not actually the same one being found when you find by name. Finding by reference is far more reliable than finding by name, and in either case do NOT do .instance().state, always only do .state().
Most helpful comment
really fast, Appreciate.
i got the problem and here is the right one to me
the quoted "LoginPersonal" give me the wrapper, and the unquoted I believe give me the instance