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();
});
});
waitForElementToBeRemoved
expects the element to be visible first, which is not the OP's case, where the element starts as not visible and must stay like that. – Forehand