React state not being updated in Jest while working in the application
When I click the button it increments the value by the amount written in the input, it works when I do that in the app but when I try to use Jest and first fireEvent.change()
the value of an input to 10 and then fireEvent.click()
on the button it doesnt increment it and the value stays at 0
.
Here is the error that Im getting:
expect(received).toBe(expected) // Object.is equality
Expected: 10
Received: 0
33 | fireEvent.click(btnPlus);
34 |
> 35 | expect(parseInt(val.textContent)).toBe(10);
| ^
36 | });
37 | });
38 |
Here is the test file:
import React from 'react';
import Counter from './Counter';
import { render, fireEvent } from '@testing-library/react';
describe('Counter works', () => {
let comp;
let inp;
let btnPlus;
let val;
beforeAll(() => {
comp = render(<Counter />);
inp = comp.getByTestId('inp');
btnPlus = comp.getByTestId('btn-+');
val = comp.getByTestId('counter-value');
});
it('Counter exists', () => {
expect(comp).toBeTruthy();
});
it('Input works', () => {
expect(inp.value).toBe('');
fireEvent.change(inp, {
target: {
value: 10,
},
});
expect(parseInt(inp.value)).toBe(10);
fireEvent.click(btnPlus);
expect(parseInt(val.textContent)).toBe(10);
});
});
The general Counter file:
const Counter = () => {
const [state, setState] = useState({
count: 0,
inpText: '',
});
const setNum = (num) => {
setState((prev) => {
return {
...prev,
count: prev.count + num,
};
});
};
const setInp = (e) => {
setState((prev) => {
return {
...prev,
inpText: e?.target.value,
};
});
};
return (
<>
<h1
data-testid='counter-value'
style={{
color: 'white',
position: 'absolute',
top: '45%',
left: '50%',
transform: 'translate(-50%,-60%)',
}}>
{state.count}
</h1>
<div id='flex'>
<Button setNum={setNum} plus='+' num={parseInt(state.inpText)} />
<input data-testid='inp' value={state.inpText} onChange={setInp} />
<Button setNum={setNum} plus='-' num={-parseInt(state.inpText)} />
</div>
</>
);
};
And the Button:
const Button = (props) => {
return (
<button
data-testid={`btn-${props.plus}`}
onClick={() => {
props.setNum(props.num);
}}>
{props.plus}
</button>
);
};
Solution 1:
I would suggest avoiding initial component setup in beforeAll
/beforeEach
functions. Each test case should run in isolation and not be affected by operations executed in other tests.
Instead, create a helper function with that logic and call it on every test.
import React from 'react';
import Counter from './Counter';
import { render, fireEvent } from '@testing-library/react';
describe('Counter works', () => {
let comp;
let inp;
let btnPlus;
let val;
const renderComponent = () => {
comp = render(<Counter />);
inp = comp.getByTestId('inp');
btnPlus = comp.getByTestId('btn-+');
val = comp.getByTestId('counter-value');
}
it('Counter exists', () => {
renderComponent();
expect(comp).toBeTruthy();
});
it('Input works', () => {
renderComponent();
expect(inp.value).toBe('');
fireEvent.change(inp, { target: { value: 10 } });
expect(inp.value).toBe('10');
fireEvent.click(btnPlus);
expect(val.textContent).toBe('10');
});
});