admin管理员组

文章数量:1289530

I have a useEffect hook that loads when the ponent is mounted, as so:

useEffect(() => {
   listFiles().then(keys => {
      setKeys(keys)
      console.log(keys)
   }).catch(err => {
        showFail(err.message)
   })
}, [])

I'm trying to test the function with react testing-library, simply using the render function:

beforeEach(() => {
  render(<Dashboard />)
})

However, when I run any test that resolves the promise and sets the state:

jest.mock('../utils/storage', () => ({
    listFiles: jest.fn(() => Promise.resolve([])),
}))

I end up with a weird warning message about using act to to wrap the event:

  Warning: An update to Dashboard inside a test was not wrapped in act(...).

    When testing, code that causes React state updates should be wrapped into act(...):

    act(() => {
      /* fire events that update state */
    });
    /* assert on the output */

    This ensures that you're testing the behavior the user would see in the browser. Learn more at .. 
        in Dashboard

      18 |     useEffect(() => {
      19 |         listFiles().then(keys => {
    > 20 |             setKeys(keys)
         |             ^
      21 |             console.log(keys)
      22 |         }).catch(err => {
      23 |             showFail(err.message)

I have tried wrapping the render in an act, but it doesn't seem to change anything.

Any suggestions as to what I'm doing wrong here? Should I be rendering in some other way?

Thanks in advance!

I have a useEffect hook that loads when the ponent is mounted, as so:

useEffect(() => {
   listFiles().then(keys => {
      setKeys(keys)
      console.log(keys)
   }).catch(err => {
        showFail(err.message)
   })
}, [])

I'm trying to test the function with react testing-library, simply using the render function:

beforeEach(() => {
  render(<Dashboard />)
})

However, when I run any test that resolves the promise and sets the state:

jest.mock('../utils/storage', () => ({
    listFiles: jest.fn(() => Promise.resolve([])),
}))

I end up with a weird warning message about using act to to wrap the event:

  Warning: An update to Dashboard inside a test was not wrapped in act(...).

    When testing, code that causes React state updates should be wrapped into act(...):

    act(() => {
      /* fire events that update state */
    });
    /* assert on the output */

    This ensures that you're testing the behavior the user would see in the browser. Learn more at .. 
        in Dashboard

      18 |     useEffect(() => {
      19 |         listFiles().then(keys => {
    > 20 |             setKeys(keys)
         |             ^
      21 |             console.log(keys)
      22 |         }).catch(err => {
      23 |             showFail(err.message)

I have tried wrapping the render in an act, but it doesn't seem to change anything.

Any suggestions as to what I'm doing wrong here? Should I be rendering in some other way?

Thanks in advance!

Share Improve this question asked May 4, 2020 at 14:46 SamSam 1,3044 gold badges18 silver badges36 bronze badges
Add a ment  | 

2 Answers 2

Reset to default 7

This error usually happens when you try to assert before the ponent has finished updating all state.

Note that inside listFiles you are calling setKeys(keys) and that updates the state.

You should await for the new keys(or files) to show up in the document:

expect(await findByText('some file name or key')).toBeInTheDocument();
// more asserts here

Alternatively, you can waitFor the mock to have been called (although I think the option above is better).

await waitFor(() => expect(listFilesMock).toHaveBeenCalled());
// more asserts here

The methods above should already be wrapped in act for you by the React Testing Library, so you don't need to do it


What is act() from the React docs:

When writing UI tests, tasks like rendering, user events, or data fetching can be considered as “units” of interaction with a user interface. React provides a helper called act() that makes sure all updates related to these “units” have been processed and applied to the DOM before you make any assertions.

The name act es from the Arrange-Act-Assert pattern.


Useful links:

  • Fix act warning by React Testing Library author
  • React Act docs

In my case I wasn't mocking the useEffect async function.

ponent.test.tsx:

test('Working useEffect hook', () => {
  const dbCallMock = jest.fn(() => Promise.resolve())
  render(<Tracks dbCallMock ={dbCallMock} />)
}

ponent.tsx:

export const myComponent = (props: {
  dbCallMock: Function
}) => {
  const [state, setState] = useState<string[]>([])

  const getDbState= () => 
    db.state.toArray().then(gotState => setState(gotState))

  useEffect(
    () => (props.dbCallMock ? props.dbCallMock() : getDbState()),
    []
  )
}

本文标签: javascriptReact testinglibraryTesting a promise that set states in the first useEffect hookStack Overflow