React-hooks-testing-library: act() doesn't seem to be updating state

Created on 1 Aug 2019  路  6Comments  路  Source: testing-library/react-hooks-testing-library

I have a simple 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 }];
}

I have a test that's somewhat passing. When I have a test that updates state, it doesn't seem to work.

The test in question:

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 initial value of false', () => {
        expect(isOpen).toBe(false);
    });

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

Test 1 passes, but when I console.log(isOpen) for test 2, isOpen remains false.

Does it have anything to do with the array destructuring? Is it immutable? Or is it the way I'm using act()?

question

Most helpful comment

Hi @davidgtu,

You cannot destructure the values as it locks in their current value. It's like having

const result = { current: "example" }

const example = result.current
result.current = "something else"

expect(example).toBe(result.current) 

and expecting the values to still be the same.

Try making your test:

describe('useOpenClose', () => {
    const { result } = renderHook(() => useOpenClose());

    test('Should have initial value of false', () => {
        console.log(result.current[0])
    });

    test('Should update value to true', () => {
        act(() => result.current[1].open())
        console.log(result.current[0])
    })
});

It looks a little but nasty when you have an array as the result of your custom hook, but unfortunately it's a symptom of your hook design (which I'm not saying is bad). You could make it a bit more readible by adjusting the hook callback slightly:

describe('useOpenClose', () => {
    const { result } = renderHook(() => {
      const [isOpen, actions] = useOpenClose();
      return { isOpen, ...actions };
    });

    test('Should have initial value of false', () => {
        console.log(result.current.isOpen)
    });

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

All 6 comments

Hi @davidgtu,

You cannot destructure the values as it locks in their current value. It's like having

const result = { current: "example" }

const example = result.current
result.current = "something else"

expect(example).toBe(result.current) 

and expecting the values to still be the same.

Try making your test:

describe('useOpenClose', () => {
    const { result } = renderHook(() => useOpenClose());

    test('Should have initial value of false', () => {
        console.log(result.current[0])
    });

    test('Should update value to true', () => {
        act(() => result.current[1].open())
        console.log(result.current[0])
    })
});

It looks a little but nasty when you have an array as the result of your custom hook, but unfortunately it's a symptom of your hook design (which I'm not saying is bad). You could make it a bit more readible by adjusting the hook callback slightly:

describe('useOpenClose', () => {
    const { result } = renderHook(() => {
      const [isOpen, actions] = useOpenClose();
      return { isOpen, ...actions };
    });

    test('Should have initial value of false', () => {
        console.log(result.current.isOpen)
    });

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

@mpeyper That was incredibly helpful. Thank you so much.

Maybe this is worth to record in the docs as might happen to others (like me just now :sweat_smile:)

Great idea @gillchristian. PRs always welcome ;)

:heavy_check_mark: :tada:

This can be closed now :smirk:

Was this page helpful?
0 / 5 - 0 ratings