Set state when testing functional component with useState() hook
Solution 1:
When using state from hooks, your test must ignore implementation details like state in order to properly test it. You can still make sure the component passes the correct state into its children.
You can find a great example in this blog post written by Kent C. Dodds.
Here's an excerpt from it with a code example.
Test that relies on state implementation details -
test('setOpenIndex sets the open index state properly', () => {
const wrapper = mount(<Accordion items={[]} />)
expect(wrapper.state('openIndex')).toBe(0)
wrapper.instance().setOpenIndex(1)
expect(wrapper.state('openIndex')).toBe(1)
})
Test that does not rely on state implementation details -
test('counter increments the count', () => {
const {container} = render(<Counter />)
const button = container.firstChild
expect(button.textContent).toBe('0')
fireEvent.click(button)
expect(button.textContent).toBe('1')
})
Solution 2:
This is the way that I found to do it, I'm not saying this is right or wrong. In my case, a block of code was dependent on state being set to a particular value. I will keep my opinions about testing in React to myself.
In your test file: Adjust your import for the react library
import * as React from 'react'
Then in your test spy on useState and mock its implementation
const stateSetter = jest.fn()
jest
.spyOn(React, 'useState')
//Simulate that mode state value was set to 'new mode value'
.mockImplementation(stateValue => [stateValue='new mode value', stateSetter])
Please be aware that mocking useState this will way apply to all instances where useState is called for your test, so if you have more than one state value that you are looking at, they will all be set to 'new mode value'. Someone else may be able to help you sort that out. Hope it helps.
Solution 3:
At top of test file, can be defined first as:
import { useState } from 'react';
jest.mock('react', () => ({
...jest.requireActual('react'),
useState: jest.fn()
}));
const useStateMock: jest.Mock<typeof useState> = useState as never;
After that at each test can be used with different value which is wanted to be tested:
const setValue = jest.fn();
useStateMock
.mockImplementation(() => ['value', setValue]);