Nesh
Nesh

Reputation: 2541

Test is failing as the object is incorrect in React Testing Library

Component to test -

import { useState } from "react";

const UserForm = ({ onUserAdd }) => {
  const [name, setName] = useState("");
  const [email, setEmail] = useState("");

  const handleSubmit = (e) => {
    e.preventDefault();
    onUserAdd({ name, email });
  };

  return (
    <form onSubmit={handleSubmit}>
      <div>
        <label>Name</label>
        <input value={name} onChange={(e) => setName(e.target.value)} />
      </div>
      <div>
        <label>Email</label>
        <input value={email} onChange={(e) => setEmail(e.target.value)} />
      </div>
      <button onClick={handleSubmit}>Add User</button>
    </form>
  );
};

export default UserForm;

Failing Test Case -

test("it calls onUserAdd when the form is submitted", async () => {
  // BETTER IMPLEMENTATION
  const mock = jest.fn();

  // Render - the component
  render(<UserForm onUserAdd={mock} />);

  // Find 2 inputs (name, email in this case)
  const [nameInput, emailInput] = screen.getAllByRole("textbox");

  // Simulate typing in a name
  await user.click(nameInput);
  await user.keyboard("jane");

  // Simulate typing in a email
  await user.click(emailInput);
  await user.keyboard("[email protected]");

  // Find the submit button
  const button = screen.getByRole("button");

  // Simulate clicking the submit button
  await user.click(button);

  // Assertion - make sure 'onUserAdd' gets called with name/email
  expect(mock).toHaveBeenCalled();
  expect(mock).toHaveBeenCalledWith({ name: "jane", email: "[email protected]" });
});

Error -

- Expected
+ Received

  Object {
-   "email": "[email protected]",
-   "name": "jane",
+   "email": "",
+   "name": "",
  },

Let me know what I am doing wrong here.

Codesandbox Link - https://codesandbox.io/s/morning-microservice-xxh0mw?file=/src/UserForm.test.js

PS - Since I am learning react testing, I used await for every event, let me know if this is a correct approach as well. Thanks.

Upvotes: 0

Views: 348

Answers (1)

Avi
Avi

Reputation: 1407

Generally looks ok but I find CodeSandbox to be really buggy when dealing with react testing library. I replaced your user.clicks and user.keyboards with user.type which I find more human readable and concise to work with and it seems to work:

test("it calls onUserAdd when the form is submitted", async () => {
  const mock = jest.fn();

  // Render - the component
  render(<UserForm onUserAdd={mock} />);

  // Find 2 inputs (name, email in this case)
  const [nameInput, emailInput] = screen.getAllByRole("textbox");

  // Simulate typing in a name
  await user.type(nameInput, "jane"); // <--here-<<

  // Simulate typing in a email
  await user.type(emailInput, "[email protected]"); // <--and here-<<

  // Find the submit button
  const button = screen.getByRole("button");

  // Simulate clicking the submit button
  await user.click(button);

  // Assertion - make sure 'onUserAdd' gets called with name/email
  expect(mock).toHaveBeenCalled();
  expect(mock).toHaveBeenCalledWith({ name: "jane", email: "[email protected]" });
});

And yes, you are correct wo await every user action. Although RTL docs recommend to use the new setup const user = userEvent.setup() instead of calling the API directly

Upvotes: 1

Related Questions