Search code examples
reactjstypescriptjestjsreact-testing-libraryts-jest

How to write unit test case for error validation of checkbox


I have scenario where when the user clicks on the Next button without agreeing the terms i should throw an error saying 'please agree the terms',so i need to write a unit test case for it using Jest and React Testing Library.How can i achieve that.

import Terms from "./Terms";
import "./styles.css";

export default function App() {
  return (
    <div className="App">
      <Terms />
    </div>
  );
}

const { useState } = require("react");

function Terms() {
  const [checked, setChecked] = useState(false);
  const [errorMessage, setErrorMessage] = useState(false);
  const onNext = (e: React.FormEvent) => {
    e.preventDefault();
    if (checked !== true) {
      setErrorMessage(true);
    } else {
      setErrorMessage(false);
    }
  };
  const handleCheckBoxChange = (e: React.FormEvent) => {
    const result = (e.target as HTMLInputElement).checked;
    setChecked(result);
  };

  return (
    <div>
      <h1>Terms</h1>
      <input type="checkbox" value={checked} onChange={handleCheckBoxChange} />
      <label>click to agree the terms</label>
      <br />
      {errorMessage && <p>Please agree the terms before proceeding</p>}
      <button onClick={onNext}>Next</button>
    </div>
  );
}
export default Terms;


Solution

  • Well, first break it down. You want a test that does the following things, one after the other:

    1. renders your Terms component
    2. finds a button labelled "Next"
    3. clicks the button
    4. finds the error text on the screen

    You can use react-testing-library to grab the elements you need, and user-event-testing-library to interact with them.

    Add both libraries as dependencies to your project, and try the following, importing the things you need to get it working:

    it("error shows when terms not agreed", async () => {
      const user = userEvent.setup();
    
      render(<Terms />)
    
      const nextButton = screen.getByRole("button", { name: /next/i });
      await user.click(nextButton);
      
      expect(screen.getByText(/please agree the terms before proceeding/i)).toBeVisible()
    })
    

    You probably want a similar test for your happy case too, where you agree the terms before clicking the button.