如何等待断言元素从未出现在文档中?

How to wait to assert an element never appears in the document?

我想断言某个元素从未出现在我的文档中。我知道我可以做到 :

import '@testing-library/jest-dom/extend-expect'

it('does not contain element', async () => {
    const { queryByText } = await render(<MyComponent />);
    expect(queryByText('submit')).not.toBeInTheDocument();
});

但就我而言,我需要等待以确保元素不会在延迟后添加。我怎样才能做到这一点?

有两种方法可以做到这一点,都涉及 react-testing-library 的异步辅助函数 waitFor

第一个也是更简单的方法是等到文档中发生其他事情后再检查该元素是否不存在:

import '@testing-library/jest-dom/extend-expect'

it('does not contain element', async () => {
    const { getByText, queryByText } = await render(<MyComponent />);

    await waitFor(() => expect(getByText('something_else')).toBeInTheDocument());

    expect(queryByText('submit')).not.toBeInTheDocument();
});

您可以对任何有效的 Jest 断言使用相同的策略:

import '@testing-library/jest-dom/extend-expect'
import myFunc from './myFunc'

it('does not contain element', async () => {
    const { getByText, queryByText } = await render(<MyComponent />);

    await waitFor(() => expect(myFunc).toBeCalled());

    expect(queryByText('submit')).not.toBeInTheDocument();
});

如果没有任何好的断言可以用来等待正确的时间来检查元素是否不存在,您可以改为使用 waitFor 来重复检查元素是否不存在一段的时间。如果元素在断言超时之前确实存在,则测试将失败。否则,测试将通过。

import '@testing-library/jest-dom/extend-expect'

it('does not contain element', async () => {
    const { getByText } = await render(<MyComponent />);

    await expect(async () => {
        await waitFor(
            () => expect(getByText('submit')).toBeInTheDocument();
        );
    }).rejects.toEqual(expect.anything());
});

您可以调整 waitFor 持续检查的时间以及使用 the timeout and interval options 检查的频率。但请注意,由于此测试会等到 waitFor 超时才能通过测试,因此增加 timeout 选项将直接增加此测试通过的时间。

这是我为避免重复样板而编写的辅助函数:

export async function expectNever(callable: () => unknown): Promise<void> {
    await expect(() => waitFor(callable)).rejects.toEqual(expect.anything());
}

然后像这样使用:

it('does not contain element', async () => {
  const { getByText } = await render(<MyComponent />);

  await expectNever(() => {
    expect(getByText('submit')).toBeInTheDocument();
  });
});

我们使用普通 JavaScript 并且@Nathan 的 expectNever 函数抛出错误:

Error: expect(received).rejects.toEqual()
Matcher error: received value must be a promise

我修改了它,使其看起来和感觉更像 waitFor,这很有效:

const waitForNeverToHappen = async (callable) => {
    await expect(waitFor(callable)).rejects.toEqual(expect.anything())
}
    
await waitForNeverToHappen(() => expect(screen.getByText('submit')).toBeInTheDocument())