-
Notifications
You must be signed in to change notification settings - Fork 474
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
waitForElementToBeRemoved
can time out even when the element has been removed from the document
#1204
Comments
This might only be happening with |
It doesn't look like this bug report has enough info for one of us to reproduce it. Please provide a CodeSandbox (https://react.new), or a link to a repository on GitHub. Here are some tips for providing a minimal example: https://stackoverflow.com/help/mcve |
Since I suspect a race condition, that makes it difficult to reproduce a real world example. However, the problem can be forced by simply calling const parent = document.createElement("div");
const child = document.createElement("div");
parent.appendChild(child)
await waitForElementToBeRemoved(child); Here's that code running in an actual test:
|
Hello everyone, we have this in CI too, and this is not reproducible locally on developer machines. It happens randomly in CI but always on the same few tests. Not sure what I can provide to further reproduce... |
I just noticed by looking at https://testing-library.com/docs/guide-disappearance/#waiting-for-disappearance that Maybe that's related? EDIT: Yeah, the code's definitely not doing the same thing depending on whether a callback is passed or an element directly. Will implement this, give CI a few days (we usually reproduce once or twice a day) and report here. |
Hey guys, been running fine for one day. 🤞 |
I ran into this because I figured that the first of these is preferable when I already have the element from a previous query:
Turns out that might not be true if the provided element has a parent. I've put a reproduction together [codesandbox]. I took the MUI Alert Dialog demo and wrote a simple test for it:
The test suite consists of two nearly identical tests - the difference is in how we assert that the dialog is no longer in the document:
To simulate the behavior of the element being removed from the document prior to the invocation of The first test is timing out because MUI's dialog renders its element with |
Had the same issue this week. I "fixed" it by increasing the timeout. This seems to us more like a workaround, but at least we can continue for now. await waitForElementToBeRemoved(() => screen.queryByRole('dialog', { name: 'MyDialog' }), { timeout: 30000 }); |
I'm experiencing the same and it happens when these 2 conditions are met:
If the element is a Here's the code I'm using: it's basically a helper we use at the beginning of our test to wait for the loader to be removed: export const waitForLoaderToBeRemoved = async () => {
try {
const loader = await screen.findByTestId('my-loader');
await waitForElementToBeRemoved(loader);
} catch (e: any) {
if (e.message.includes('already removed')) {
// sometimes the loader has already been removed when we try to check for it!
return;
}
throw e;
}
}; |
I fixed my above code by adding export const waitForLoaderToBeRemoved = async () => {
try {
const loader = await screen.findByTestId('my-loader');
if(!document.contains(loader)) return
await waitForElementToBeRemoved(loader);
} catch (e: any) {
if (e.message.includes('already removed')) {
// sometimes the loader has already been removed when we try to check for it!
return;
}
throw e;
}
}; |
Increase test timeout to hopefully resolve issue where `waitForElementToBeRemoved` times out: testing-library/dom-testing-library#1204
Re-query for the dialog element instead of reusing the prior element as suggested in testing-library/dom-testing-library#1204 (comment)
Re-query for the dialog element instead of reusing the prior element as suggested in testing-library/dom-testing-library#1204 (comment)
Having the same problem, for now I will use this instead:
|
It helps if you can control response time. I'm using msw and the delay method set explicitly to 1500 ms. Strange thing is my test for a loading spinner fails at waitForElementToBeRemoved at around 1490 ms if I set the timeout for it. I set it to 1600 to be safe. It is working for me both ways, getting the spinner element first or using the callback method as long as I explicitly add the timeout. const spinner = await screen.findByLabelText(/loading/i);
expect(spinner).toBeInTheDocument();
await waitForElementToBeRemoved(spinner, {
timeout: 1600,
}); |
run into problem with Placing const button = screen.getByRole('button', {
name: /test-topic-name/i
});
expect(button).toBeInTheDocument()
const topicCloseButton = within(button).getByTestId('CloseIcon') as HTMLButtonElement;
await waitForElementToBeRemoved(() => screen.queryByRole('button', {
name: /test-topic-name/i
}))
await userEventHandler.click(topicCloseButton) vs Placing const button = screen.getByRole('button', {
name: /test-topic-name/i
});
expect(button).toBeInTheDocument()
const topicCloseButton = within(button).getByTestId('CloseIcon') as HTMLButtonElement;
await waitForElementToBeRemoved(() => screen.queryByRole('button', {
name: /test-topic-name/i
}))
await userEventHandler.click(topicCloseButton) also tested various different ways: await userEventHandler.click(topicCloseButton)
await waitForElementToBeRemoved(button) await waitForElementToBeRemoved(button)
await userEventHandler.click(topicCloseButton) workarounds that work instead: const button = screen.getByRole('button', {
name: /test-topic-name/i
});
expect(button).toBeInTheDocument()
const topicCloseButton = within(button).getByTestId('CloseIcon') as HTMLButtonElement;
await userEventHandler.click(topicCloseButton)
expect(button).not.toBeInTheDocument() await waitFor(() => {
expect(screen.queryByRole('button', {
name: /test-topic-name/i
})).not.toBeInTheDocument()
}) FYI: |
@renhyl you'll need to get the element before triggering the action that removes it and just pass it to waitForElementToBeRemoved. |
Sorry @MatanBobi , I am unsure what you are trying to point out, please take a careful look, my example demonstrates just that.
|
@renhyl Can you please share a reproduction link so we'll be able to investigate this? it's hard to investigate with code snippets. |
@testing-library/dom
version: 8.11.2Relevant code or config:
What you did:
Executed test
What happened:
Test fails with error
Timed out in waitForElementToBeRemoved.
Reproduction:
Not sure how to dependably repro it, but when it occurs it seems to occur deterministically.
Problem description:
parent.contains(element)
always returnstrue
.document.contains(element)
anddocument.contains(parent)
both return false.parent
has been removed from the document, butdom-testing-library
doesn't check against that.parent
is of typeHTMLDivElement
. I would have expected it to beHTMLHtmlElement
because of thiswhile
loop. Could it be that we have a race condition in which the element gets removed from the document prior to (or even during!) the execution of thewhile
loop?Suggested solution:
Just check if
document.contains(element)
rather than capturing theparent
in the first place (of course, I assume there is a reason for not taking this simple approach).The text was updated successfully, but these errors were encountered: