Hey, hello, hi thanks for stopping by! Want to learn how to test React UseState with Jest or how to mock useState in jest? Well, look no further. This article covers basic component testing, as well as testing for state. We will create a stateful button component and then write a test for it using Jest and React Testing Library (RTL). We’ll be using a React Typescript project, but don’t worry if Typescript is new to you, this informative article will help fill in the gaps.
Estimated reading time: 9 minutes
Skip to important parts:
- Jump to the Code example of the Component in full
- Jump to more about testing state in RTL
- Code example of Jest Test in full
If you’ve been to this site before, then you know I love a button. Let’s face it what component could be more simple to understand than a button? So, in my usual fashion, we’re going to create a Button Component.
The Button Component
Below is the full code of our Button component.
import React, { useState } from 'react'
interface IButton {
label: string
icon: string
}
const Button: React.FC<IButton> = ({label, icon}) => {
const [state, setState] = useState(false)
return (
<>
<span>{icon}</span>
<button disabled={state} onClick={() => setState(true)}>{label}</button>
</>
)
}
export default Button
If you like building buttons, check out this how to create accessible toggle buttons with Material UI. If building stuff from scratch is more your thing, check out this tutorial on making accessible toggle buttons.
The Button Type Interface
The following code is how we declare data types for the props in a React component. It’s called an interface and it just simply helps us test, and work with our Button component to cut down on errors and confusion.
interface IButton {
label: string
icon: string
}
This interface is saying, hey the label prop and the icon prop are both strings. Now, whenever I use this Button component, if I’m using VSCode, my IDE will yell at me to remind me to add in the label prop and icon prop. It will also tell me that they must be strings.

As you can see in the above image, I’ve imported the Button component to use in my React App. It has a red squiggly line. When I mouse over the Button component watch the magic happen:

We see this modal appear that tells us exactly what information we’re missing. Next I click on the ‘Quick Fix’ then Add missing attributes and voila. We see the label and icon props have been added as empty strings.

Now I know I need to enter in a label and icon prop and they must be strings. I’m smarter than VSCode (sort of) so I know I can remove the curly braces and replace them with double quotes like this:
<Button label="" icon="" />
Want to learn more about Typescript? Check out this post about building with WordPress and Typescript.
The Button Props in our Jest test
The great news is that when we render our Button component inside of our Jest test, we’ll get this same help from Typescript when testing our props.
Let’s take the code below in isolation to see what I mean:
it('tests the button props', () => {
render(<Button />)
})
In VSCode, we get the same red squiggly line under the button component. In our render function in this test, we can add the label and icon and they can be any string we want. In a jest test all we want is to know that our component will behave as expected. Therefore, we mock the prop values to be any string of our choosing.
it('tests the button props', () => {
render(<Button label="poopy" icon="icons" />)
})
As you can see the value in and of itself doesn’t matter. What matters is that we have props and they are strings. Now we can use these mock values to test what we expect our component to behave like.
it('tests the button props', () => {
render(<Button label="poopy" icon="icons" />)
expect(screen.getByRole('button', {name: 'poopy'})).toBeInTheDocument()
})
In the code above, I am grabbing an HTML element with an aria role of button. The button text should say “poopy” because that is the label i’ve given it and if you go back to the Button component you’ll see the label prop is implemented as the button text. This test will pass.
Rewind: Set up our Jest Unit test
Let’s go backwards a bit and start at the beginning. Let’s create our unit test file. In the same directory as our Button Component, we’ll create a corresponding unit test file. My Button component file name is Button.tsx, so my Button jest test will be Button.unit.test.tsx
Below is what the file structure looks like:

Inside the Button.unit.test.tsx file let’s scaffold our test and create a test suite.
Import modules into the Unit test
Before we start our imports let’s run down what we’re doing here. We’re learning how to mock usestate in jest. Starting with our imports, these three imports will pull in all of the code we’ll need to create a unit test.
import React, { useState as useStateMock } from 'react';
The React and useState imports from React will allow us to use react and useState within our component test.
import { render, screen } from '@testing-library/react';
The render and screen modules are utilities we use to run our tests.
import Button from './Button';
Finally, we import the Button component which we need so we can test it.
Create a Test Suite
When testing a React component, we should create a test suite by first adding the describe() function and passing the name or our component as the first parameter. This will prove useful when we are examining our tests that have run as it organizes our test cases.
Below our imports we’ll add a describe block like so:
describe('Button', () => {
})
Next, inside of our describe block we’ll add an it() block. The it() block is where each individual test will be housed. What we are testing should be the first parameter of the it block like this:
describe('Button', () => {
it('tests the button props', () => {
// add test code here
})
})
When I run npm test
in my terminal and my jest test fails, I’ll now be able to see the component and the test that failed like so:

We covered in a previous section how to test button props, so let’s move onto the meat of this post and test the state of our Button component.
Go deeper into Jest and React Testing Library with this getAllByRole example.
Testing State in React
To use jest to mock useState, we’ll need to actually use useState from React. The jest.requireActual() function allows us to return the actual React useState module instead of mocking it out.
At the top of our file under our import statements, we’ll add this code:
jest.mock('react', () => ({
...jest.requireActual('react'),
useState: jest.fn()
}))
const setState = jest.fn()
Next, at the top of our test suite, we’ll add this beforeEach() block. This will run clean up and reset our state before each test runs.
describe('Button', () => {
beforeEach(() => {
useStateMock.mockImplementation((init: any) => [init, setState])
})
As you can see, we’re using useStateMock as an alias which we pulled in at the top of our file when we imported useState. From useState we’re calling mockImplementation().
This function accepts a function that will be used as an implementation of the mock for one call to the mocked function. Okay but what does that mean exactly? We’re writing a function inside the mockImplementation() function (init: any) => [init, setState]). The first parameter of this function is init and we’ll return something that looks a lot like the way we define state in React. Notice how setState is a mock jest function.
What does that actually do? Well, in our tests, mockImplementationOnce is calling the use of useState in our Button component once for each time we use useState in the component.
Another way to say this is when we call mockImplementationOnce and pass the first parameter of the array a value, that value is the state of our component.
Testing the default state
In our second test, let’s test the state of our button when the state is false, or in other words its default state:
it('renders the button not as disabled when state is false', () => {
useStateMock.mockImplementationOnce(() => [false, setState])
render(<Button label="poopy" icon="icons" />)
expect(screen.getByRole('button', {name: 'poopy'})).not.toBeDisabled()
})
We can actually write this test like this below and it will produce the same result because the use of this mockImplementationOnce() function is calling the default state of the component, which is false.
it('renders the button not as disabled when state is false', () => {
useStateMock.mockImplementationOnce((init: any) => [init, setState])
render(<Button label="poopy" icon="icons" />)
expect(screen.getByRole('button', {name: 'poopy'})).not.toBeDisabled()
})
Note that in this test our assertion is testing that the button is not disabled.
Testing the state change
In the next test we’re going to change the first value in the return statement of the mockImplementationOnce() function to true. Then we’ll expect our button to be disabled since the disabled button attribute is tied to this piece of state.
it('renders the button as disabled when state is true', () => {
useStateMock.mockImplementationOnce(() => [true, setState])
render(<Button label="poopy" icon="icons" />)
expect(screen.getByRole('button', {name: 'poopy'})).toBeDisabled()
})
Want to set up React Testing Library in a Vite React project? Look no further, we’ve got you covered.
The Jest Test in full
import React, { useState as useStateMock } from 'react';
import { render, screen } from '@testing-library/react';
import Button from './Button';
// Mock state.
jest.mock('react', () => ({
// Returns the actual module instead of a mock,
// bypassing all checks on whether the module should receive
// a mock implementation or not.
...jest.requireActual('react'),
useState: jest.fn()
}))
const setState = jest.fn()
describe('Button', () => {
beforeEach(() => {
// @ts-ignore
// Accepts a function that will be used as an implementation of the mock for one call to the mocked function.
// Can be chained so that multiple function calls produce different results.
useStateMock.mockImplementation((init: any) => [init, setState])
})
it('tests the button props', () => {
render(<Button label="poopy" icon="icons" />)
expect(screen.getByRole('button', {name: 'poopy'})).toBeInTheDocument()
})
it('renders the button not as disabled when state is false', () => {
// @ts-ignore
useStateMock.mockImplementationOnce((init: any) => [init, setState])
render(<Button label="poopy" icon="icons" />)
expect(screen.getByRole('button', {name: 'poopy'})).not.toBeDisabled()
})
it('renders the button as disabled when state is true', () => {
// @ts-ignore
useStateMock.mockImplementationOnce(() => [true, setState])
render(<Button label="poopy" icon="icons" />)
expect(screen.getByRole('button', {name: 'poopy'})).toBeDisabled(
})
})
Conclusion
That’s it! Hopefully now you have a good understanding of how to test React useState with Jest. We ran through how to test props on a React component. We covered how to actually use React useState in a test with jest.mock and jest.requireActual. And finally you got to see how to use mockImplementationOnce() to dictate the state of your component within your test.