Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using act doesn't update state?

I have a custom hook like so:

import { useState } from 'react';

export default function useOpenClose(initial = false) {
    const [isOpen, setOpen] = useState(initial);

    const open = () => { setOpen(true); }
    const close = () => { setOpen(false); }

    return [isOpen, { open, close } ];
}

and as for my tests I have something like this:

import { renderHook, act } from '@testing-library/react-hooks';
import useOpenClose from './useOpenClose';

describe('useOpenClose', () => {
    const { result: { current } } = renderHook(() => useOpenClose());
    const [isOpen, { open, close }] = current;

    test('Should have an open function', () => {
        expect(open).toBeInstanceOf(Function)
    });

    test('Should have an open function', () => {
        expect(close).toBeInstanceOf(Function)
    });

    test('Should have initial value of false', () => {
        expect(isOpen).toBe(false);
    });

    test('Should update value to true', () => {
        act(() => open());
        console.log(isOpen)
    })
});

Where the test "'Should update value to true'", when I log isOpen, it stays false. I'm not exactly sure why it's not updating unless act isn't doing what it's doing?

like image 307
nyphur Avatar asked Oct 23 '25 14:10

nyphur


1 Answers

From the doc 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.

E.g.

useOpenClose.ts:

import { useState } from 'react';

export default function useOpenClose(initial = false) {
  const [isOpen, setOpen] = useState(initial);

  const open = () => {
    setOpen(true);
  };
  const close = () => {
    setOpen(false);
  };

  return [isOpen, { open, close }] as const;
}

useOpenClose.test.ts:

import { act, renderHook } from '@testing-library/react-hooks';
import useOpenClose from './useOpenClose';

describe('useOpenClose', () => {
  test('should pass', () => {
    const { result } = renderHook(() => useOpenClose());
    // Don't destructure `result`.
    expect(result.current[1].open).toBeInstanceOf(Function);
    expect(result.current[1].close).toBeInstanceOf(Function);
    expect(result.current[0]).toBe(false);
    act(() => result.current[1].open());
    console.log(result.current[0]);
  });
});

Test result:

 PASS  examples/57315042/useOpenClose.test.ts (13.635 s)
  useOpenClose
    ✓ should pass (45 ms)

  console.log
    true

      at Object.<anonymous> (examples/57315042/useOpenClose.test.ts:12:13)

-----------------|---------|----------|---------|---------|-------------------
File             | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s 
-----------------|---------|----------|---------|---------|-------------------
All files        |    87.5 |      100 |   66.67 |    87.5 |                   
 useOpenClose.ts |    87.5 |      100 |   66.67 |    87.5 | 10                
-----------------|---------|----------|---------|---------|-------------------
Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   0 total
Time:        15.588 s
like image 109
slideshowp2 Avatar answered Oct 25 '25 07:10

slideshowp2



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!