Search code examples
reactjstypescriptreact-hooksreact-testing-libraryreact-hooks-testing-library

Assert that a function changes a stateful value


So, here is a simplified version of my code.

This is my custom hook.

export const useStep = () => {
  const [step, setStep] = useState<Steps>("sending");

  const changeStep = (newStep: Steps) => setStep(newStep);

  return { step, changeStep };
}

This is my test file

const { result } = renderHook(() => useStep());

const { step, changeStep, resetStep } = result.current;

...

it("should change step value when `changeStep` is called", async () => {
  expect(step).toBe("sending");

  changeStep("verifying");

  await waitFor(() => expect(step).toBe("verifying"));
})

I've already tried many things, but none of them seems to work. step value stays as 'sending'


Solution

  • There is an example in the doc, see Updates.

    NOTE: There's a gotcha with updates. renderHook mutates the value of current when updates happen so you cannot destructure its values as the assignment will make a copy locking into the value at that time.

    So the correct way is:

    index.ts:

    import { useState } from 'react';
    
    type Steps = 'sending' | 'verifying';
    
    export const useStep = () => {
      const [step, setStep] = useState<Steps>('sending');
    
      const changeStep = (newStep: Steps) => setStep(newStep);
    
      return { step, changeStep };
    };
    

    index.test.ts:

    import { renderHook, act } from '@testing-library/react-hooks';
    import { useStep } from '.';
    
    describe('72209087', () => {
      it('should change step value when `changeStep` is called', async () => {
        const { result } = renderHook(useStep);
        expect(result.current.step).toBe('sending');
        act(() => {
          result.current.changeStep('verifying');
        });
        expect(result.current.step).toBe('verifying');
      });
    });
    

    Test result:

     PASS  stackoverflow/72209087/index.test.ts (25.293 s)
      72209087
        ✓ should change step value when `changeStep` is called (17 ms)
    
    Test Suites: 1 passed, 1 total
    Tests:       1 passed, 1 total
    Snapshots:   0 total
    Time:        28.622 s