testing-library / react-hooks-testing-library

šŸ Simple and complete React hooks testing utilities that encourage good testing practices.
https://react-hooks-testing-library.com
MIT License
5.25k stars 230 forks source link

Why does the UI not update when calling a hook method? #933

Closed JamesBrightman-pp closed 1 year ago

JamesBrightman-pp commented 1 year ago

I have written a simple component and test file which aims to test the hook and the UI. It uses the useCounter hook example from the docs.

TextComp.tsx

import React, { FC, useCallback, useState } from 'react';

export const TestComp: FC = () => {
  const { count } = useCounter();

  return <p>{`COUNT: ${count}`}</p>;
};

export const useCounter = () => {
  const [count, setCount] = useState(0);
  const increment = useCallback(() => setCount((x) => x + 1), []);
  return { count, increment };
};

TestComp.spec.tsx

import { TestComp, useCounter } from './TestComp';
import { act, render, renderHook, screen } from '@testing-library/react';

it('should render successfully', () => {
  const { asFragment } = render(<TestComp />);

  expect(asFragment()).toMatchSnapshot();
});

it('should have init value of 0', () => {
  render(<TestComp />);

  expect(screen.getByText('COUNT: 0')).toBeInTheDocument();
});

it('should increment via hook', () => {
  const { result } = renderHook(() => useCounter());
  expect(result.current.count).toBe(0);

  act(() => {
    result.current.increment();
  });

  expect(result.current.count).toBe(1);
});

it('should update ui from hook', async () => {
  render(<TestComp />);
  const { result } = renderHook(() => useCounter());

  await act(() => {
    result.current.increment();
  });

  expect(result.current.count).toBe(1);
  await expect(screen.getByText('COUNT: 1')).toBeInTheDocument();
});

The test file has 4 tests.

  1. The component renders properly and matches a snapshot āœ…
  2. The UI of the component shows the string "COUNT: 0" (0 is the default value for the useCounter hook) āœ…
  3. The hook can be tested and the increment function is working correctly āœ…
  4. The UI reflects the hooks value changing - I would expect it to now say "COUNT: 1" after running the increment function āŒ

All of these tests pass except 4. Where I expect to see "COUNT: 1" I actually see "COUNT: 0". Why is this?

Error message dump: image

Is this due to a race condition / async operation? Am I using the library completely wrong? I want to be able to test that the hook functionality properly updates the UI, but I am seeing what looks like an out of date Ui version. Thanks for the help.

joshuaellis commented 1 year ago

Because each hook call is it's own instance e.g. calling the hook outside the component will not affect the component's hook, that would create wild UI behaviour for users. Hooks are meant for sharing logic across codebases. Maybe take a look at this ā€“ https://beta.reactjs.org/learn#using-hooks