如何等待断言元素永远不会出现在文档中?

Nat*_*hur 15 reactjs jestjs react-testing-library

我想断言某个元素永远不会出现在我的文档中。我知道我可以做到这一点

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

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

但就我而言,我需要等待以确保延迟后不会添加该元素。我怎样才能实现这个目标?

Nat*_*hur 21

有两种方法可以做到这一点,都涉及react-testing-library's async helper function 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();
});
Run Code Online (Sandbox Code Playgroud)

您可以对任何有效的 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();
});
Run Code Online (Sandbox Code Playgroud)

如果没有任何好的断言可以用来等待正确的时间来检查某个元素是否不存在,那么您可以使用它来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());
});
Run Code Online (Sandbox Code Playgroud)

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

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

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

然后像这样使用:

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

  await expectNever(() => {
    expect(getByText('submit')).toBeInTheDocument();
  });
});
Run Code Online (Sandbox Code Playgroud)


小智 7

我们使用纯 JavaScript,@Nathan 的 ExpectNever 函数会抛出错误:

Error: expect(received).rejects.toEqual()
Matcher error: received value must be a promise
Run Code Online (Sandbox Code Playgroud)

我将其修改为看起来和感觉更像 waitFor 并且这有效:

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