Home > Software engineering >  Alter useMemo when write input in react testing library
Alter useMemo when write input in react testing library

Time:12-09

I'm trying to do a test, in which when changing the input, I have to read the useMemo and change the disabled of my button, the userEvent is not making this change, has anyone gone through this?

I'm going to put part of my source code here, where the component and the test script are.

<>
  <input
    data-testid="ipt-email"
    value={form.email}
    onChange={(e) => {
      setForm({ ...form, email: e.target.value });
    }}
  />
  <button data-testid="submit-sendUser" disabled={isDisabled}>
    OK
  </button>
</>

This is my hook

const isDisabled = useMemo(() => {
  const { email } = form;
    
  if (!email.length) return true
  
  return false;
}, [form]);

Right after that is my unit test, where I write to the input and wait for the state to change

import userEvent from "@testing-library/user-event";

it("Should enable button when form is valid", async () => {
  const wrapper = render(<MyComponent />);

  const getEmail = wrapper.getByTestId("ipt-name");

  await userEvent.type(getEmail, '[email protected]');

  const getBtnSubmit = wrapper.getByTestId("submit-sendUser");

  console.log(wrapper.container.innerHTML);

  expect(getBtnSubmit).not.toBeDisabled();
});

I can't make the input change reflect in the button hook

CodePudding user response:

The combination of fireEvents and forced move to the "next frame" worked for me

const tick = () => {
  return new Promise((resolve) => {
    setTimeout(resolve, 0);
  });
};

// async test
fireEvent.change(getEmail, {target: {value: '[email protected]'}})
await tick();
expect(getBtnSubmit).not.toBeDisabled();

CodePudding user response:

Need to wait for changes to occur after the action

 await waitFor(() => expect(getBtnSubmit).not.toBeDisabled())

moving code inside the handler applied to useEffect, but I feel its better to handle the validation inside the handler.

Hope it helps

CodePudding user response:

In your constant getEmail you get a component with a data-testid='ipt-name' instead of 'ipt-email'. The code below works for me :

my test :

import { render, screen, waitFor } from '@testing-library/react';
import App from './App';
import userEvent from '@testing-library/user-event';

it("Should enable button when form is valid", async () => {
  render(<App />);

  expect(screen.getByTestId("submit-sendUser")).toBeDisabled();

  const getEmail = screen.getByTestId("ipt-email");

  userEvent.type(getEmail, '[email protected]');

  await waitFor(() => expect(screen.getByTestId("submit-sendUser")).not.toBeDisabled());
});

my component :

import React, { useMemo, useState } from "react";

export const App = () => {
  const [form, setForm] = useState({ email: '' });

  const isDisabled = useMemo(() => {
    const { email } = form;

    if (!email || !email.length) return true;

    return false;
  }, [form]);

  return (
    <div>
      <input
        data-testid="ipt-email"
        value={form.email}
        onChange={(e) => {
          setForm({ ...form, email: e.target.value });
        }}
      />
      <button data-testid="submit-sendUser" disabled={isDisabled}>
        OK
      </button>
    </div>
  );
};

export default App;
  • Related