Giorgio Martini
Giorgio Martini

Reputation: 139

Input not updating on react testing library, thus test failing, however it does update on the actual app

I want to test that when i type a value in an input(inputA), anoter input(inputB) gets updated with a value.

inputA accepts a postal code e.g: "10999", after inputB shows a location: "Berlin"

This works on the actual app, i type in inputA, and inputB gets updated.

When ome types on inputA, an action is dispatched and then inputB gets a new value from the redux state.

This is my test code, any ideas why it doesnt updates the input with placeholder of "Ort" on the test, but it does on the actual app?

import { render, withIntl, withStore, configureStore, withState } from "test-utils-react-testing-library";
import { screen, fireEvent, withHistory, withRoute, within } from "@testing-library/react";
import configureMockStore from 'redux-mock-store';

import ProfileForm from "./ProfileForm";
import PersonalDetails from "../PersonalDetails/PersonalDetails";

const STATE = {
  locations: { locations: {} },
  streets: { streets: {} },
  password: {}
};

const mockStore = configureMockStore();
const STORE = mockStore({
  streets: {
    isFetching: false,
  },
  locations: {
    locations: {
      isFetching: false,
    },
  },
  user: {
    session: {
      impersonated_access_token: "",
    },
    updateError: "error",
  },
});

const props = {
  id: "user1",
  user: { email: "[email protected]" },
  locations: {},
  onSubmit: jest.fn(),
};
  
beforeEach(jest.resetAllMocks);

describe("ProfileForm", () => {
    describe("on personal details change", () => {
      it("auto selects only location when postalcode becomes selected", () => {
        const locations = { electricity: { [PLZ_1]: [LOCATION_OBJ_1] } };
        const user = { postalcode: null };

        render(<ProfileForm {...props} user={user} locations={locations} />, [...decorators, withStore(STORE)]);
        
        const input = screen.getByPlaceholderText("PLZ");
        fireEvent.change(input, { target: { value: "10999" } })
        
        screen.debug(screen.getByPlaceholderText("PLZ"))
        screen.debug(screen.getByPlaceholderText("Ort"))

        expect(screen.getByPlaceholderText("Ort")).toHaveValue("Berlin");
      });

});

Upvotes: 3

Views: 14842

Answers (3)

Lars Johan
Lars Johan

Reputation: 364

I've encountered a similar proplem and found that changes in the microtask queue aren't always flushed, so the changes are not applied/rendered until the test is finished running. What worked for me, was to call jest.useFakeTimers() at the beginning of your testcase, and then await act(async () => { jest.runOnlyPendingTimers() }); after the call to fireEvent.<some-event>(...)

In your case:

it("auto selects only location when postalcode becomes selected", async () => {
  jest.useFakeTimers();
  const locations = { electricity: { [PLZ_1]: [LOCATION_OBJ_1] } };
  const user = { postalcode: null };

  render(<ProfileForm {...props} user={user} locations={locations} />, [...decorators, withStore(STORE)]);
        
  const input = screen.getByPlaceholderText("PLZ");
  fireEvent.change(input, { target: { value: "10999" } })
  await act(async () => {
    jest.runOnlyPendingTimers();
  });      
  screen.debug(screen.getByPlaceholderText("PLZ"))
  screen.debug(screen.getByPlaceholderText("Ort"))
  expect(screen.getByPlaceholderText("Ort")).toHaveValue("Berlin");

});

Upvotes: 4

Vlad R
Vlad R

Reputation: 2624

Tried, but get this error: Warning: Can't perform a React state update on an unmounted component. This is a no-op, but it indicates a memory leak in your application. To fix, cancel all subscriptions and asynchronous tasks in a useEffect cleanup function. No idea where that comes from :(

Try to use findBy instead of getBy.

https://testing-library.com/docs/dom-testing-library/api-queries#findby

import { screen, waitFor } from "@testing-library/react";

const inputNode = await screen.findByPlaceholderText("Ort");
// or with timeout:  await screen.findByPlaceholderText("Ort", { timeout: 4000 });
await waitFor(() => expect(inputNode).toHaveValue("Berlin"));

Upvotes: 0

Vlad R
Vlad R

Reputation: 2624

I guess your input hasn't been updated yet.

Try to use waitfor: https://testing-library.com/docs/dom-testing-library/api-async#waitfor

import { waitFor } from "@testing-library/react";

const inputNode = screen. getByPlaceholderText("Ort");
//  keep in mind that you need to make your test async like this
//  it("auto selects only location when postalcode becomes selected", async () => {
await waitFor(() => expect(inputNode).toHaveValue("Berlin"));

If it won't work, try to add timeout:

await waitFor(() => expect(inputNode).toHaveValue("Berlin"), { timeout: 4000 });

Upvotes: 6

Related Questions