are there anyone see the problem here? If I put checked in state on change it works. But I don't want to duplicate the checked state data and watch it every single props change.
Parent components gets the latest checked information and put it in own state and if parent isChecked change, FormCheckBox isChecked changes. I think, it works async and when I reach latest line of my test code, parent update does not finish, so I see the stale isChecked.
export default function FormCheckBox(props: IFormCheckBoxProps) {
const { onChange, label, isChecked, error, errorModelLabel = '' } = props
const handleChange = (event: React.ChangeEvent<HTMLInputElement>) => {
onChange(event.currentTarget.checked)
}
const errorMsg = getFormErrorMsg(error, errorModelLabel)
return (
<FormGroup
as={Row}
className={cx('mb-3', { 'is-invalid': errorMsg })}
controlId="catalogDescription"
data-testid="slvy-formcheckbox"
>
<FormLabel column className="d-flex align-items-center justify-content-end fw-bold" sm={2}>
{label}
</FormLabel>
<Col className="d-flex align-items-center" sm={10}>
<input
checked={isChecked}
className={cx('checkbox', { 'is-invalid': errorMsg })}
type="checkbox"
onChange={handleChange}
/>
<Form.Control.Feedback type="invalid">{errorMsg}</Form.Control.Feedback>
</Col>
</FormGroup>
)
}
it('checkbox must use fireEvent.click', async () => {
const handleChange = jest.fn()
props.isChecked = false
props.onChange = handleChange
const { container } = render(<FormCheckBox {...props} />)
const checkbox = container.querySelectorAll("input[type='checkbox']")[0] as HTMLInputElement
fireEvent.click(checkbox)
expect(handleChange).toHaveBeenCalledTimes(1)
expect(checkbox.checked).toBe(true)
})
Since the FormCheckBox is a controlled component, the input’s value is always driven by the React state. So you need a wrapper component to provide this state. In your test case, even though the mock handleChange function is called, we need to update the isChecked state so that the FormCheckBox component will re-render with this new state.
E.g.
index.tsx:
import React from 'react';
export default function FormCheckBox({ onChange, isChecked }) {
const handleChange = (event: React.ChangeEvent<HTMLInputElement>) => {
onChange(event.currentTarget.checked);
};
return <input checked={isChecked} type="checkbox" onChange={handleChange} />;
}
To keep things simple. I removed the irrelevant code.
index.test.tsx:
import { fireEvent, render } from '@testing-library/react';
import React, { useState } from 'react';
import FormCheckBox from './';
describe('73184212', () => {
test('should pass', () => {
const Wrap = () => {
const [isChecked, setIsChecked] = useState(false);
return <FormCheckBox isChecked={isChecked} onChange={() => setIsChecked(!isChecked)} />;
};
const { container } = render(<Wrap />);
const checkbox = container.querySelectorAll("input[type='checkbox']")[0] as HTMLInputElement;
fireEvent.click(checkbox);
expect(checkbox.checked).toBe(true);
});
});
Test result:
PASS stackoverflow/73184212/index.test.tsx (10.998 s)
73184212
✓ should pass (30 ms)
-----------|---------|----------|---------|---------|-------------------
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s
-----------|---------|----------|---------|---------|-------------------
All files | 100 | 100 | 100 | 100 |
index.tsx | 100 | 100 | 100 | 100 |
-----------|---------|----------|---------|---------|-------------------
Test Suites: 1 passed, 1 total
Tests: 1 passed, 1 total
Snapshots: 0 total
Time: 11.607 s
While my response may not directly address the original post, it does provide the answer that I was personally seeking. I was having trouble with the checked state of my checkbox not being registered properly. After doing some digging, I realized that the issue was with my selection method. I was able to successfully solve my issue by using getByRole.
it("check that checkbox gets checked", () => {
render(
<input
type="checkbox"
aria-label="checkbox"
name="checkbox-array"
value="second"
id="second"
/>
);
const checkbox = screen.getByRole("checkbox", { name: "checkbox" });
expect(checkbox).not.toBeChecked();
fireEvent.click(checkbox);
expect(checkbox).toBeChecked();
});
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With