-
Notifications
You must be signed in to change notification settings - Fork 470
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
waitFor + getByRole causing severe delays #820
Comments
The issue is that |
Thanks for the quick reply Nick, does that not suggest that any What do you think the best short term resolution for this? |
I'm guessing |
For reference the Would you like me to document some of this? Feels like a sufficiently frustrating morning that I don't want others to go through! |
A higher interval might cause less loops. Even if it doesn't make this specific test run shorter, a longer interval could allow other tests to run in parallel more effectively. Can you try this out? Alternatively, we could dynamically adjust the interval by default based on how long it takes each time. I'm not sure if that's worth the effort though. |
Setting an interval of 750 still caused 2 iterations to fail (~450ms), then the fetch promise resolves. There's one more failure (output still not rendered to the screen), finally it passes. Setting an interval underneath the I guess it works, but you keep having to up this arbitrary interval to "match" however long the waitFor will take as the complexity grows. That doesn't feel great to me. |
Yea, I was thinking maybe |
The problem is when the knowledge has been propogated differently; https://kentcdodds.com/blog/common-mistakes-with-react-testing-library#using-the-wrong-query There's absolutely nothing in the docs about the downsides of I would love to get an action on how best proceed with this, do we:
etc. |
1 would be cool to experiment with but as I said previously, I'm not sure how difficult to implement and useful it would be, so it may not be worth it. I'm fine with either 2 or 3. @kentcdodds @eps1lon What do you think about an asyncronous version of |
One question to make sure I understand. What is your test waiting on that takes more than a single 50ms interval? Most/All tests using this utility should mock out any async code so it resolves on the next tick or two of the event loop 🤔 |
Just noticed the screenshot, sorry about that. Looks like it's getting mocked by MSW, so I wouldn't expect this to take longer than a few milliseconds. Something is up there. The In this situation, there's something especially fishy going on. I think we'd need a reproduction to dive any deeper though. |
@kentcdodds yer to confirm MSW is registering is ~1ms so it's very fast. It's the Reproduction will take some time, is it not clear that exceeding the |
If you want to optimize tests for performance go through these steps until you're satisfied. They're ordered by their confidence impact (lower impact, higher ranked) then perf impact (higher impact, higher ranked).
Not using |
@eps1lon great walkthrough 👍 though I think I'd prefer to try another query before testIDs. I think it makes sense to add this to the docs. |
Definitely! It was easier to say since "use another query" might not be that helpful. If you're really blocked by perf problems I would just suggest a quick escape hatch and revisit it once the test breaks on unrelated changes (though that might be even harder to judge). It's just really hard to give actionable advise that people can apply to different scenarios. I think the most generic advise is to re-evaluate your And to give an optimistic outlook: The |
I would definitely try item 3 from @eps1lon's checklist for this particular case - the visibility calculation is expensive in large DOM trees
|
Thanks for the input here everyone. I think some docs here would go a long way. @herecydev once you've tried and had success with one of these recommendations, would you mind working on improvement the documentation to help others who may face this in the future? |
To touch on another potential optimization point: In Material-UI we set the default value to The other part is that CI can be a little bit slower (since it already takes a couple of minutes). However, for local development you want snappy feedback so every millisecond counts. That might be worth documenting. Though we shouldn't integrate that into the library since we don't know whether people have CI or if every commit passes through it. |
Thanks Sebastian, to address these;
I just want to stress this is nothing to do with timers. Everything is mocked. We're using MSW here, but the |
ie Puppeteer, Cypress How big is the DOM tree being queried in this test? |
I was seeing similar performance issues in one of my tests as well. My app is using Material UI and I was seeing about 6 seconds per query with I agree that a small performance cost is worth the confidence, but it becomes unusable when that cost is about 6 seconds. I definitely agree in having some documentation updates to give visibility into this tradeoff. |
Why are you using
We're using mocha + karma with chrome headless and browserstack. Bundling the full test suite with webpack and running is as fast as running it with JSDOM. So there's a breakpoint where mocha + karma becomes faster if you get bundle time low enough. We don't have as severe problems with JSDOM so I suspect that this might be a real time saver for you. However, I don't think it's appropriate for local development where you just run a subset of the tests.
6 full seconds for each call of |
We are having similar performance issues with I know that both of these durations are a bit long anyways due to the DOM we are testing, but the point here is that relative to each other, In the end I had to give the selectors a container scope like I'm really not sure what the reason is and perhaps it should really be mentioned in the documentations. |
@eps1lon sorry I can't be of much help now, this issue was quite painful and we move over to using cypress where this isn't a problem for us, as well as providing a suite of other benefits. |
@shan-du Please share a reproducible example. Otherwise we can't help you with this problem. |
I wonder if it has something to do with the MutationObserver optimizations in waitFor hogging too much of the thread for the more expensive getByRole DOM traversal |
Here's a reproducible example. It's not quite as bad as my original project (about 5 seconds per getByRole call in the example instead of 6 seconds), but still shows that there's a huge performance issue. Hopefully this is helpful in debugging the issue! https://github.com/meastes/get-by-role-example
|
React Testing Library can be slow and some tests time out on CI. It's a tradeoff between testing by user interaction/accessibility and speed. This optimizes the performance in places that I consider reasonable by - Replacing `getByRole` with `getByText` - Replacing `userEvent.type` with `userEvent.paste` testing-library/dom-testing-library#552 (comment) testing-library/dom-testing-library#820 testing-library/user-event#577
Looking for some opinions. Is the |
I've already started replacing |
@cmacdonnacha, @mmnoo I gave a talk to explain what's happening in |
@MatanBobi Love what you're doing with this library. But want to apologize in advance for possibly coming off as to harsh. Here's the video summary:
|
@frankandrobot, you're not, and we're 100% open for criticism.
|
We've used vitetest before
While it does help test boot up, if the problem is Jsdom, it doesn't provide speed ups to slow queries.
As for happy Dom, it's too incomplete to use in production. I really wish you guys would stop recommending it 😜
On Nov 6, 2023 11:01 AM, Matan Borenkraout ***@***.***> wrote:
@frankandrobot<https://github.com/frankandrobot>, you're not, and we're 100% open for criticism.
I'm not saying it is what it is, we are trying to workaround those, having said that, the major bottleneck here is usually JSDOM.
Regarding your specific question:
1. If you don't care about visibility check for example, you can use hidden<https://testing-library.com/docs/queries/byrole#hidden> for example to avoid that check and get a tiny speedup. The rest is probably too related to the role selection and we can't remove it.
2. I think that not using ByRole misses a bit of the accessibility checks and misses the point of our guiding principle.
3. I highly recommend trying vitest instead of jest and also happy-dom instead of jsdom for some quick wins :)
Feel free to ask more questions, I'll do my best to help.
—
Reply to this email directly, view it on GitHub<#820 (comment)>, or unsubscribe<https://github.com/notifications/unsubscribe-auth/AAGAGMNJ4OATI5N6BVALD2DYDEJXFAVCNFSM4TUQYKQKU5DIOJSWCZC7NNSXTN2JONZXKZKDN5WW2ZLOOQ5TCNZZGU2DSOJZGU2A>.
You are receiving this because you were mentioned.Message ID: ***@***.***>
|
I have used |
Yes. I'm not saying it's not usable. But it's by no means a complete replacement.
To give an example, in my code base, in about a dozen test files. We're only able to migrate two to happy Dom.
That's too low to be a useful replacement.
On Nov 6, 2023 11:10 AM, Matan Borenkraout ***@***.***> wrote:
I have used vitest and happy-dom for production use as a replacement to jest + jsdom or else I wouldn't have recommended it. I can understand why some cases are still not supported, but you can definitely migrate some tests and run them side by side.
—
Reply to this email directly, view it on GitHub<#820 (comment)>, or unsubscribe<https://github.com/notifications/unsubscribe-auth/AAGAGMPRM7DF4BVNBJGNZC3YDEKXTAVCNFSM4TUQYKQKU5DIOJSWCZC7NNSXTN2JONZXKZKDN5WW2ZLOOQ5TCNZZGU2TCOJYG4YA>.
You are receiving this because you were mentioned.Message ID: ***@***.***>
|
what is the workaround ? |
|
how to migrate from jsdom to a real browser ? we are using jest + testing library is there an environment for this ? |
This is out of scope for this discussion. Migrating from Jest+JSDOM to Playwright is not trivial. I'd suggest looking up Playwright's Getting Started docs to get a feeling how testing works in Playwright vs. Jest. In Playwright you wouldn't need |
is there a faster jsdom ? |
@eps1lon Have you considered replace dom-testing-library/src/queries/role.ts Lines 266 to 281 in 56543d5
It will allow us to skip some expensive |
You can try |
Hey! I want to share my experience here as I've been struggling with a few slow tests that were consistently timing out. In my case, the slow tests were the result of using I tried migrating to I tried using the The only thing that worked for me was to replace I am not sure if there is a particular issue with tables, but I would advise to stay away from accessible queries when working with them... |
i don't think we want to do that because then the single element matchers wouldn't throw if there was more than one element |
We've been exploring a possible workaround. Here's some context:
But of course there are caveats:
Notes:
The code: type GetByRoleFullOpts = Parameters<typeof original.getByRole>;
type GetByRoleOpts = GetByRoleFullOpts[1] & { nameType?: "inferred" | "aria-label" }
export const getByRole = (role: GetByRoleFullOpts[0], opts: GetByRoleOpts): GetByRoleReturn => {
const { name, nameType, ...restOpts } = opts ?? {};
if (name && typeof name !== "function") {
const getter = nameType === "inferred" ? original.getByText : original.getByLabelText;
const foundElement = getter(name, restOpts);
const elements = within(foundElement.parentElement ?? document.documentElement).getAllByRole(role, restOpts);
const match = elements.find((elem) => elem === foundElement);
expect(match).toBeDefined();
return foundElement;
} else {
return original.getByRole(role, opts);
}; |
I've profiled issues with this in our codebase locally, and 90% of the speed issues are coming from checking to see if the element's subtree is "accessible", meaning if it's potentially visible to the user. The problem is it recursively checks every element, and worse, runs a There's a new API for that now checkVisibility, but that's probably not going to help much in node. It's probably prudent to add an escape hatch here to skip this check. something like Honestly, I think even having this check to begin with is a bit pedantic given the nature of these tests. If it was my project, I would default to not even checking that unless someone had it on |
Thanks @benlesh for the investigation. |
Last I checked For us |
For record keeping, I did submit a PR: #1331 I'll explore other options for our needs. These tests are honestly slower than just running Playwright or Cypress tests at this point. |
@hwride you might want to check again. |
That is what we recommend for high confidence testing. For lower confidence testing, disabling the inaccessible check via
Keep in mind that the slowness is mostly not coming from the implementation but the environment. Switching to Node.js implementations of the DOM (e.g. JSDOM) are just slower than browsers and less feature complete. Both of these statements apply especially to CSS in Node.js which is why the library is perceived to be slow. |
@testing-library/dom
version: 7.26.6node
version: 14.3.0Relevant code or config:
What you did:
Running this test causes the fetch request promise to resolve a lot longer than usual (around 1.5 - 2s). I initially investigated this by wrapping
console.time
around the request.I also had an additional test which looks very similar to the above, but instead of using
getByRole
it was usinggetByText
to search for some text. That test took a fraction of the time:What happened:
After changing
getByRole
togetByText
or inserting agetByText
query before thegetByRole
it resolved much faster. My working theory is thatgetByRole
is so expensive that it was monopolising thewaitFor
loop and takes a long time to relinquish control to the pending promise that needs to resolve.The text was updated successfully, but these errors were encountered: