How do I re-render a component in Jest?
Asked Answered
H

2

5

I have a beforeEach() that renders my app:

describe('...', () => {
  beforeEach(() => {
    render(<App />);
  });
  ...
});

I am currently going through a config change in my app. config was previously a boolean value in localStorage and now it has a more appropriate value like prod and dev. My app checks the old boolean values when it first loads and it changes them to their respective non-boolean value - here's the mapping:

true -> prod
false -> dev

I am trying to write tests for this transformation in Jest. The idea behind the first test is to set the localStorage item, re-render the app, and check the the localStorage item has been updated correctly:

it('should show dev config when using old boolean value', () => {
  const toggle = screen.getByTestId('toggle');
  expect(toggle).toBeChecked();
  localStorage.setItem('config', false);

  // re-render app and check localStorage
  render(<App />);
  const toggle2 = screen.getByTestId('toggle');

  expect(toggle2).not.toBeChecked();
  expect(localStorage.getItem('config')).toEqual('dev');
});

However, this test throws an error presumably because the app is now rendered twice instead of once:

TestingLibraryElementError: Found multiple elements by: [data-id="toggle"]

How do I re-render the app so that it isn't duplicated in the test environment?

Humility answered 1/2, 2022 at 2:11 Comment(1)
Similar question for enzyme #30614954Scrawny
T
10

If you are using @testing-library/react you can use the rerender method that is returned from the initial render. You can use this method to call render again and provide the same container that your first call created (you can even pass new props).

Docs: https://testing-library.com/docs/example-update-props/

Example:

it('should add the fixed width class if position is fixed', () => {
  const {rerender} = render(<PageNavigation position="fixed-left" fixedWidth="test-123" />);

  const list = screen.getByTestId('page-navigation'); // Or however you're selecting

  expect(list).toHaveClass('test-123');

  rerender(<PageNavigation position="fixed-right" fixedWidth="test-456" />);

  // Sanity check to ensure the first class was removed
  expect(list).not.toHaveClass('test-123');

  expect(list).toHaveClass('test-456');
});
Traumatism answered 31/1, 2023 at 15:2 Comment(0)
C
2

I think the error means that jest cannot access a dom node with [data-id=toggle]

because it founds more than one node with same attribute.

Instead, use matcher "getAllByTestId('toggle') instead of "getByTestId('toggle).

This will return an array of nodes with attribute [data-id=toggle] you can access them same way like arrays.

it('should show dev config when using old boolean value', () => {
  **let toggles = screen.getAllByTestId('toggle');**
  expect(toggles[0]).toBeChecked();
  localStorage.setItem('config', false);

. . . .

For rerendering a react component in unit test, check this https://testing-library.com/docs/react-testing-library/api/#rerender

    it('should show dev config when using old boolean value', () => {
  const {rerender} = render(<App />) 
  let toggles = screen.getAllByTestId('toggle');
  expect(toggles[0]).toBeChecked();
  localStorage.setItem('config', false);

  // re-render app and check localStorage
  rerender(<App />);
  toggles = screen.getAllByTestId('toggle');

  expect(toggles[1]).not.toBeChecked();
  expect(localStorage.getItem('config')).toEqual('dev');
});
Comminate answered 3/5, 2023 at 13:48 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.