React 单元测试无法使用 Async Act 找到元素

问题描述 投票:0回答:1

我正在我的 React 应用程序中使用 Jest 和 RTL 测试用户点击交互。组件状态通过交互(即单击事件)进行更新。

我的组件有一个组合框,单击它时,应该打开列表框并显示选项。

test.only('option should open when clicked', async () => {
  // Arrange
  const props = {
    searchProcessing: false,
    setSearchProcessing: () => {},
    setFilterInfo: () => {},
    setData: () => {},
    sortBy: {
      FieldName: 'state',
      Direction: 'ASC',
    },
    pageNumber: 1,
    pageSize: 10,
  };

  // Act
  await act(async () => {
    await render(<Component{...props} />);
    const combobox = await screen.findByRole('combobox', { owns: 'select-state' });
    fireEvent.click(combobox);
  });
  const options = within(screen.getByRole('listbox')).getAllByRole('option');
  screen.debug(options);

  // Assert
  expect(options).toHaveLength(2);
});

当我运行上面的代码时,它抛出一个错误

  Unable to find role="combobox"

    Ignored nodes: comments, script, style
    <body>
      <div />
    </body>

            await act(async () => {
      23 |     await render(<Component {...props} />);
    > 24 |     combobox = await screen.findByRole('combobox', { owns: 'select-state' });
         |                             ^
      25 |   });

当我将

fireEvent
放入
waitFor
异步方法中,插入
act
时,就像下面的代码片段一样,它正在工作。

await waitFor(() => {
  fireEvent.click(screen.getByRole('combobox', { owns: 'select-state' }));
});
console.log
    <a
      aria-label="AK"
      aria-selected="false"
      class="dropdown-item"
      href="#"
      id="select-state-item-0"
      role="option"
    >
      AK
    </a>

      at logDOM (node_modules/@testing-library/dom/dist/pretty-dom.js:94:13)
          at Array.forEach (<anonymous>)

  console.log
    <a
      aria-label="AK2"
      aria-selected="false"
      class="dropdown-item"
      href="#"
      id="select-state-item-1"
      role="option"
    >
      AK2
    </a>

      at logDOM (node_modules/@testing-library/dom/dist/pretty-dom.js:94:13)
          at Array.forEach (<anonymous>)

 PASS  src/App/Main/Component.test.js (11.508 s)
  √ state option should open when clicked (454 ms)

Test Suites: 1 passed, 1 total                                                                                                                                                                                         
Tests:       1 passed, 1 total                                                                                                                                                                                         
Snapshots:   0 total
Time:        16.5 s

但是根据这里提到的 linting 规则:

no-wait-for-side-effects
这是一个不好的做法。

__

我应该错过什么?为什么我的

render
findByRole
承诺不在
act
函数中等待实际的组件 DOM。但相同的代码通过了
waitFor

在此感谢您的任何帮助。预先感谢。

reactjs unit-testing jestjs react-testing-library testing-library
1个回答
0
投票

经过多次尝试和错误,我找到了两种可能的解决方案。

解决方案1##

将第二个动作/事件包装在另一个动作中

    await act(async () => {
    await render(<Component {...props} />);
  });
   await act(async () => {
     fireEvent.click(await screen.findByRole('combobox', { owns: 'select-state' }));
   });

解决方案2

RTL 正在证明另一个实用程序 userEvent。您可以使用它代替 fireEvent,如下所示。

  const user = userEvent.setup();
await user.click(await screen.findByRole('combobox', { owns: 'select-state' }));

希望有帮助。谢谢。

© www.soinside.com 2019 - 2024. All rights reserved.