Im using react hooks and using Use State for ponent states. While testing the ponent in jest i see i cant access state value and mock it either.
There are bunches of code which is looking for different values in state. since state is not acccesible i could t cover plete code coverage.
Please help me in writting a test case for below code.
const MyComponent = props => {
const [counterSecond, setCounterSecond] = React.useState(8);
const [counterFirst, setCounterFirst] = React.useState(0);
const handleIncrement = () => {
setCounterSecond(counterSecond + 1);
};
const handleDecrement = () => {
setCounterSecond(counterSecond - 1);
};
React.useEffect(() => {
if (counterSecond === 10) {
setCounterSecond(0);
setCounterFirst(1);
}
if (counterSecond === 3) {
setCounterSecond(1);
setCounterFirst(0);
}
if (counterSecond ===9) {
setCounterSecond(2);
setCounterFirst(1);
}
}, [counterSecond]);
return (
<div>
<div onClick={handleIncrement} >Increment</div>
<div onClick={handleDecrement} >Decrement</div>
</div>
);
};
export default MyComponent;
As you see the code is having useEffect, which looks after for the change in counterSecond value. But the internal conditions will only be covered when the state value matches 8 Or 3 Or 9.
Could you please guide me in writing Jest test case to cover the internal conditions in UserEffect.
1) And how to mock any state value
2) how to check of state value in Jest while using Hooks
Im using react hooks and using Use State for ponent states. While testing the ponent in jest i see i cant access state value and mock it either.
There are bunches of code which is looking for different values in state. since state is not acccesible i could t cover plete code coverage.
Please help me in writting a test case for below code.
const MyComponent = props => {
const [counterSecond, setCounterSecond] = React.useState(8);
const [counterFirst, setCounterFirst] = React.useState(0);
const handleIncrement = () => {
setCounterSecond(counterSecond + 1);
};
const handleDecrement = () => {
setCounterSecond(counterSecond - 1);
};
React.useEffect(() => {
if (counterSecond === 10) {
setCounterSecond(0);
setCounterFirst(1);
}
if (counterSecond === 3) {
setCounterSecond(1);
setCounterFirst(0);
}
if (counterSecond ===9) {
setCounterSecond(2);
setCounterFirst(1);
}
}, [counterSecond]);
return (
<div>
<div onClick={handleIncrement} >Increment</div>
<div onClick={handleDecrement} >Decrement</div>
</div>
);
};
export default MyComponent;
As you see the code is having useEffect, which looks after for the change in counterSecond value. But the internal conditions will only be covered when the state value matches 8 Or 3 Or 9.
Could you please guide me in writing Jest test case to cover the internal conditions in UserEffect.
1) And how to mock any state value
2) how to check of state value in Jest while using Hooks
-
I'm wondering if you ponent really need state at all if it does not use it in
render
– skyboyer Commented Aug 26, 2019 at 17:44 - @skyboyer i want to know how it can be done.. so that i can apply to bigger application. Please suggest – Sumanth madey Commented Aug 26, 2019 at 19:46
1 Answer
Reset to default 2Let's assume your ponent renders counterFirst
and counterSecond
otherwise their existence just doesn't make any sense. Something like
....
return (
<div>
<span test-id="counter">{`${counterFirst}:${counterSecond}`}</span>
<div onClick={handleIncrement} id="inc">Increment</div>
<div onClick={handleDecrement} id="dec">Decrement</div>
</div>
);
Then we would like to test our ponent. I strongly believe we don't need mock or assert against state or any internals. Instead we need to municate through props
and check render's result to check if ponent behaves as we expect.
So testing for initial state may look like:
function getCounter(wrapper) {
return wrapper.find("['test-id'='counter']").text();
}
it('renders 0:8 by default', () => {
const wrapper = mount(<MyComponent />);
expect(getCounter(wrapper)).toEqual('0:8');
});
But what to do with that code in useEffect
? If you have enzyme version recent enough it should just work. I believe. If it does not - check what version you use.
And returning to testing. Up to your code sample counter should react on incremention and decremention in slightly untypical way. Say for inc: 0:8 -> 1:2 -> 1:0 -> 1:1 -> 1:2 -> 1:0
(because for 0:9
and 1:3
there is appropriate logic in useEffect
that causes re-render). So we will test that:
function doInc(wrapper) {
wrapper.find("inc").props().onClick();
}
it('jumps from 0:8 to 1:2 on inc', () => {
const wrapper = mount(<MyComponent />); // 0:8
doInc(wrapper);
expect(getCounter(wrapper)).toEqual('1:2');
});
Actually here logic should create values cycled(1:2 -> 1:0 -> 1:1 -> 1:2 -> 1:0
) so I would test that in single test case. But maybe in your real ponent it does not loop.
You may wonder how could you set up initial state for some particular case? The same way: by calling props
to imitate clicks and other munication.
function doDec(wrapper) {
wrapper.find("dec").props().onClick();
}
it('increments from 0:5 to 0:6', () => {
const wrapper = mount(<MyComponent />); // 0:8
doDec(wrapper); // 0:7
doDec(wrapper); // 0:6
doDec(wrapper); // 0:5
doInc(wrapper);
expect(getCounter(wrapper)).toEqual('0:6');
});
Maybe it's good idea to make some helper function.
But would it be faster to set state directly? Yes, it would be. But that also would make tests non-reliable. Say, your sample code never achieves '0:9'. And that may be an error rather a goal. And we expect testing helps us realize that. By setting state directly we would never know there is an issue.