Jest.js 如何等待Assert一个元素永远不会出现在文档中?

pbwdgjma  于 2022-12-08  发布在  Jest
关注(0)|答案(3)|浏览(153)

我想Assert一个元素永远不会出现在我的文档中。我知道我可以做this

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

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

但是在我的例子中,我需要等待,以确保元素不会在延迟后被添加。

u2nhd7ah

u2nhd7ah1#

There are two ways to do this, both involving react-testing-library 's async helper function waitFor.
The first and simpler method is to wait until something else happens in your document before checking that the element doesn't exist:

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();
});

You can use the same strategy with any valid Jest assertion:

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();
});

If there isn't any good assertion you can use to wait for the right time to check an element does not exist, you can instead use waitFor to repeatedly check that an element does not exist over a period of time. If the element ever does exist before the assertion times out, the test will fail. Otherwise, the test will pass.

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());
});

You can adjust the amount of time waitFor will keep checking and how frequently it will check using the timeout and interval options. Do note, though, that since this test waits until waitFor times out for the test to pass, increasing the timeout option will directly increase the time this test takes to pass.
And here is the helper function I wrote to avoid having to repeat the boilerplate:

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

Which is then used like so:

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

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

xwbd5t1u2#

我们使用普通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())
hgtggwj0

hgtggwj03#

下面是一个示例函数,用于异步检查不应显示的元素。它将首先执行同步检查,然后执行时间最短的异步检查,然后等待所需的时间量,然后再次检查(默认为50ms)。
此示例在内部使用"queryByTestId."您可以将其抽象出来,或者只进行修改以适合您所需得测试库选择器类型.
此代码假定使用react测试库。

const notFindByTestId = async (
    container: HTMLElement,
    matcher: Matcher,
    waitTimeMillis: number = 50
) :Promise<void> => {
    function check() {
        const element = queryByTestId(container, matcher);
        if (element) {
            throw new Error(`Found element '${element}' given matcher '${matcher}' that should not be found.`);
        }
    }
    check();
    await wait(0);
    check();
    await wait(waitTimeMillis);
    check();
}

function wait(waitTimeMillis: number): Promise<void> {
    return new Promise(resolve => {
        setTimeout(() => resolve(), waitTimeMillis);
    });
}

相关问题