为什么我的反应测试在 CI-pipeline 中由于 "not wrapped in act()" 而失败,而在本地工作正常?
Why does my react tests fail in CI-pipeline due to "not wrapped in act()", while working fine locally?
我有一个包含 37 个测试的测试套件,这些测试正在测试我的一个观点。在本地,所有测试都顺利通过,但是当我推送我的代码时,测试套件在我们的管道中失败(我们使用的是 GitLab)。
CI中日志的错误输出非常长(数千行,甚至超过了 GitLab 设置的限制)。该错误包括许多“未包含在 act() 中”- 和“不支持对 act() 的嵌套调用”-警告(Moslty 由 I18Next 的 useTranslation()
和 Tooltip
等组件触发 Material-UI).
我的猜测是来自 API 的异步数据(使用 msw 模拟)在调用 act()
完成后触发状态更新,但我不确定如何证明这个,甚至弄清楚哪些测试实际上失败了。
有没有人经历过类似的事情,或者知道是怎么回事?
失败测试示例:
it.each([
[Status.DRAFT, [PAGE_1, PAGE_11, PAGE_2, PAGE_22, PAGE_3]],
[Status.PUBLISHED, [PAGE_1, PAGE_12, PAGE_2, PAGE_21, PAGE_22, PAGE_221]],
])('should be possible to filter nodes by status %s', async (status, expectedVisiblePages) => {
renderComponent();
await waitFor(() => {
expect(screen.queryByRole('progressbar')).not.toBeInTheDocument();
});
userEvent.click(screen.getByLabelText('components.FilterMenu.MenuLabel'));
const overlay = await screen.findByRole('presentation');
await waitFor(() => expect(within(overlay).queryByRole('progressbar')).not.toBeInTheDocument());
userEvent.click(within(overlay).getByText(`SiteStatus.${status}`));
userEvent.keyboard('{Esc}');
const items = await screen.findAllByRole('link');
expect(items).toHaveLength(expectedVisiblePages.length);
expectedVisiblePages.forEach((page) => expect(screen.getByText(page.title)).toBeInTheDocument());
});
更新 1
好的。所以我将范围缩小到这一行:
const items = await screen.findAllByRole('link');
在等待事物出现的过程中似乎发生了很多事情。我相信对 findAllByRole
的调用已经包含在 act()
中,这将确保所有更新都已应用。
更新 2
这似乎是部分由测试超时引起的问题。
我相信在同一测试中对 waitFor(...)
和 find[All]By(...)
的多次调用,除了运行缓慢之外,共同超过了测试的超时(默认为 5000 毫秒)。我尝试通过 运行 测试 --testTimeout 60000
来调整此限制。现在,一些测试正在通过。我仍在与“act()”警告作斗争。这些可能完全是由不同的问题引起的...
漏洞搜寻仍在继续...
这是一个常见问题 ;)
我猜,你在 CI 服务器上看到这个问题是因为环境(less cpu/mem/etc)。
此警告是因为您执行了一些异步操作但没有完成(因为它是异步的)。
您可以在这篇文章中阅读有关此问题的更多信息:https://kentcdodds.com/blog/fix-the-not-wrapped-in-act-warning
最好的解决办法是等待操作完成。例如通过添加加载指示器并等待元素删除。
例如:
it('should show empty table', async () => {
const [render] = createRenderAndStore()
mockResponse([])
const { container } = render(<CrmClientsView />) // - this view do async request in first render
await waitForElementToBeRemoved(screen.queryByRole('test-loading'))
await waitFor(() => expect(container).toHaveTextContent('There is no data'))
})
经过多次尝试,我终于找到了答案。 CI-服务器只有 2 个 CPU 可用,通过 运行 测试 --maxWorkers=2 --maxConcurrent=2
,而不是默认的 --maxWorkers=100% --maxConcurrent=5
,证明可以解决问题。
我有一个包含 37 个测试的测试套件,这些测试正在测试我的一个观点。在本地,所有测试都顺利通过,但是当我推送我的代码时,测试套件在我们的管道中失败(我们使用的是 GitLab)。
CI中日志的错误输出非常长(数千行,甚至超过了 GitLab 设置的限制)。该错误包括许多“未包含在 act() 中”- 和“不支持对 act() 的嵌套调用”-警告(Moslty 由 I18Next 的 useTranslation()
和 Tooltip
等组件触发 Material-UI).
我的猜测是来自 API 的异步数据(使用 msw 模拟)在调用 act()
完成后触发状态更新,但我不确定如何证明这个,甚至弄清楚哪些测试实际上失败了。
有没有人经历过类似的事情,或者知道是怎么回事?
失败测试示例:
it.each([
[Status.DRAFT, [PAGE_1, PAGE_11, PAGE_2, PAGE_22, PAGE_3]],
[Status.PUBLISHED, [PAGE_1, PAGE_12, PAGE_2, PAGE_21, PAGE_22, PAGE_221]],
])('should be possible to filter nodes by status %s', async (status, expectedVisiblePages) => {
renderComponent();
await waitFor(() => {
expect(screen.queryByRole('progressbar')).not.toBeInTheDocument();
});
userEvent.click(screen.getByLabelText('components.FilterMenu.MenuLabel'));
const overlay = await screen.findByRole('presentation');
await waitFor(() => expect(within(overlay).queryByRole('progressbar')).not.toBeInTheDocument());
userEvent.click(within(overlay).getByText(`SiteStatus.${status}`));
userEvent.keyboard('{Esc}');
const items = await screen.findAllByRole('link');
expect(items).toHaveLength(expectedVisiblePages.length);
expectedVisiblePages.forEach((page) => expect(screen.getByText(page.title)).toBeInTheDocument());
});
更新 1
好的。所以我将范围缩小到这一行:
const items = await screen.findAllByRole('link');
在等待事物出现的过程中似乎发生了很多事情。我相信对 findAllByRole
的调用已经包含在 act()
中,这将确保所有更新都已应用。
更新 2
这似乎是部分由测试超时引起的问题。
我相信在同一测试中对 waitFor(...)
和 find[All]By(...)
的多次调用,除了运行缓慢之外,共同超过了测试的超时(默认为 5000 毫秒)。我尝试通过 运行 测试 --testTimeout 60000
来调整此限制。现在,一些测试正在通过。我仍在与“act()”警告作斗争。这些可能完全是由不同的问题引起的...
漏洞搜寻仍在继续...
这是一个常见问题 ;)
我猜,你在 CI 服务器上看到这个问题是因为环境(less cpu/mem/etc)。
此警告是因为您执行了一些异步操作但没有完成(因为它是异步的)。
您可以在这篇文章中阅读有关此问题的更多信息:https://kentcdodds.com/blog/fix-the-not-wrapped-in-act-warning
最好的解决办法是等待操作完成。例如通过添加加载指示器并等待元素删除。
例如:
it('should show empty table', async () => {
const [render] = createRenderAndStore()
mockResponse([])
const { container } = render(<CrmClientsView />) // - this view do async request in first render
await waitForElementToBeRemoved(screen.queryByRole('test-loading'))
await waitFor(() => expect(container).toHaveTextContent('There is no data'))
})
经过多次尝试,我终于找到了答案。 CI-服务器只有 2 个 CPU 可用,通过 运行 测试 --maxWorkers=2 --maxConcurrent=2
,而不是默认的 --maxWorkers=100% --maxConcurrent=5
,证明可以解决问题。