Re-thinking approach to async event handling
See original GitHub issueSee https://github.com/testing-library/dom-testing-library/pull/616#issuecomment-643711133
We’ve been discussing some differences in Testing Library behavior with asyncronous renders and data fetching. The official Vue Test Utils docs (which Vue Testing Library uses) recommend awaiting its events so the library could internally wait for Vue to finish rendering. However, User Event is used with some libraries like React and Angular that don’t have async renders like this. This causes potential race conditions with the UI when awaiting things like fireEvent or userEvent.
I’m starting to feel that perhaps this test example shouldn’t rely on the race condition being fixed. For example in a real world app, if a web app loads very quickly its loader may not be displayed (perhaps it’s already cached or the website has a threshold to prevent it from loading). A real human manually testing a website wouldn’t give up after not seeing the loader, they would just continue as long as the page changed and they would wait for a loader if they saw one. As a result, I don’t think waitForElement
is the right function to make sure a loader disappears, especially since frameworks like React may batch updates when async functions are mocked. What matters here is that the element isn’t displayed, so .not.toBeInTheDocument()
is more accurate and reliable.
I think that instead of trying to get User Event to run the original code without modifications, we should update waitForElement’s error message for initial null elements to explain that the element may have already been removed and give alternatives like using Jest DOM’s .not.toBeInTheDocument()
instead, and potentially document other common issues. Then we’ll be able to make User Event functionality async, which makes it more consistent both with real user behavior and some frameworks like Vue and Svelte which already deal with async renders in tests. It’s also worth noting that because userEvent isn’t async, its APIs are harder to wrap for async Vue tests and users have to learn more implementation details of Vue as a result (see https://github.com/testing-library/vue-testing-library/pull/182).
Issue Analytics
- State:
- Created 3 years ago
- Reactions:10
- Comments:23 (15 by maintainers)
Top GitHub Comments
I seem to be running into this exact use-case now while attempting to upgrade to v14, in which all tests that verify an intermediate (loading) state now fail. I also don’t really have a way to control the network mocking. Is there any documented approach to work around this? The only ways out I see right now is to either stop testing intermediate states (I’d rather not, they need to be verified) or to switch these tests back to fireEvent.
I think this is a good opportunity to make things async 👍 the loading state testing methods just needs to be documented is all.