-
Notifications
You must be signed in to change notification settings - Fork 249
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
Performance issues with userEvent.type()
#577
Comments
I don't think there is much to gain optimizing the test utility code for performance. If you put in the work and optimize some part of the code, a PR will be welcome. |
I don't think the scale of the problem is as low as you make it to be. If you do ten For context, in a perfect world I would expect |
Don't get me wrong. I see that you can't type a book in 5sec default timeout.
What |
If this is still a performance issue for anyone, a reproducible example app or performance test using User Event 13 would be helpful. |
@nickmccurdy Not sure if I misunderstood you, but the example given in the opening comment still yields the same results with |
Hi, 😄 After switching from
We want to use IMO This issue should be addressed. |
As mentioned before |
I think this issue should be reopened. I get that performance of tests is not hyper-critical, but when tests are timing out literally due to a single call to |
If you can provide a reproduction, we'll look into it. |
@ph-fritsche is it reasonable to wait for 5s for typing |
@AlonMiz Depends. el.addEventListener('keydown', () => {
const t0 = (new Date()).getTime()
while((new Date()).getTime() < t0 + 5000) true
}) And all of a sudden it's reasonable for a single So if you think there is a problem, please help to reproduce the issue. I'm sure there are some things inside I'm pretty sure that there is nothing that allows to optimize in the magnitude that you are suggesting. This is simply because I know the code and it is not that slow in any environment I examined. So if you guys think this issue should be addressed, please address it! |
i agree with giving a reproducible example. |
@AlonMiz The initial issue report states something between If there is another issue with some environment, I don't know. But reports about |
- Use userEvent.paste instead of userEvent.type - Ref.: <testing-library/user-event#577>
Locally this is running for me at 30-50 ms per character. In our test runner? Forget about it. This feature is simply working badly and any attempts to say it isn't that bad is just some lost-in-the-sauce denial. |
@mnbroatch Thanks for your feedback. Have you tried turning it off and on again? Your detailed information about the environment will certainly allow us reproduce the problem and fix it for you. We'll be working day and night on this. |
Here is an example with MUI's Autocomplete that takes about 1 second to type "united states" in the input: https://codesandbox.io/s/aged-glitter-dq5coo. But with a basic input it takes about 120 ms: https://codesandbox.io/s/gracious-tereshkova-0qvx0z. So I guess the timing mostly depends on what's happening when a character is typed. |
We at Sentry recently started to profile our tests in CI and we have noticed the same thing. I would just like to emphasize what @sigmike said. While userEvent.type is definitely slower than using keypress, the reality is that it likely plays a much smaller role than you may think. For example, if you are rerendering the entire tree of the component on each keypress or running some long running function on each user input, then the performance issue will be exacerbated by using .type - as a developer that is something you should know about and is imo of the best features of userEvent library. I would still always recommend using .type and investigating what (in your application code) makes it slow. |
I came across this issue after upgrading from userevent 13.2.1 to 14 - multiple tests started timing out on CI. I noticed that I prepared a simple repro repo with branches
On the real project the slowdown is similar, but the numbers are greater - from ~40ms to ~140ms. On CI it takes 600ms on userevent14 (I didn't measure 13 there). Should I open a new issue? |
@Asvarox The measurements are inaccurate regarding what exactly is measured here. See these examples on Codesandbox: Now what looks like a much slower API turns out to not look like it if we don't allow the browser to pick up another macrotask (scheduled by codesandbox or user code or a plugin or the browser itself because e.g. the real mouse moved): If you want to accurately measure the performance, we'll have to isolate it and set up a docker container that runs just the userEvent API in a headless browser or node task. |
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
Has anyone tried a mix of 'paste' and 'type' so that we get the speed of pasting with the events of typing. Something along these lines: export const fastUserType = async (element, text) => {
element.focus();
userEvent.paste(text.slice(0, text.length - 1));
await userEvent.type(element, text.slice(-1));
}; This way we only ever type a single character, which hopefully won't take too long. |
Why is this issue closed? |
Typing with user-event appears to have been slow for a long time [1]. AddReview tests a large combination of separately tested components. There is little harm in using paste instead of typing assuming the lower level components are tested well. [1] testing-library/user-event#577
We're still encountering the performance issue with import { fireEvent } from "@testing-library/react";
userEventType(element, "text");
function userEventType(
element: Document | Element | Window | Node,
input: string,
) {
fireEvent.click(element);
input.split("").forEach((char, i) => {
const value = input.slice(0, i + 1);
fireEvent.keyDown(element, { key: char });
fireEvent.keyPress(element, { key: char });
fireEvent.input(element, { target: { value } });
fireEvent.keyUp(element, { key: char });
});
} |
I certainly don't mean this as any disrespect to the purpose of So far I've found that different configurations can lead to significantly different timing outcomes, and those timings start to seem (almost exponentially) inadequate as instances increase. I'd certainly like to get weigh-in from Jest's own contributors on the matter if some of its major dependents want to redefine what are acceptable for those defaults, but also... As much as
I'm not contesting that Consider the following (Typescript) example, and play with any of the values:
import React from 'react'
import {
render,
fireEvent,
configure as rtlConfigure,
} from '@testing-library/react'
import userEvent, {
Options as UserEventOptions,
} from '@testing-library/user-event'
jest.setTimeout(60000)
rtlConfigure({ defaultHidden: true })
const FIELDS = 10
const CHARS = 1000
const SESSION_CONFIG: UserEventOptions = { skipClick: true }
const fields = Array.from({ length: FIELDS }).map((_, i) => (
<input type="text" key={i} aria-label={`fake${i}`} />
))
const chars = 'a'.repeat(CHARS)
const MyTest = () => <div>{fields}</div>
describe('MyTest', () => {
test('userEvent', async () => {
const session = userEvent.setup(SESSION_CONFIG)
const { getByRole } = render(<MyTest />)
for (let i = 0; i < fields.length; i++) {
await session.type(getByRole('textbox', { name: `fake${i}` }), chars)
}
})
test('fireEvent', async () => {
const { getByRole } = render(<MyTest />)
for (let i = 0; i < fields.length; i++) {
fireEvent.input(getByRole('textbox', { name: `fake${i}` }), {
target: { value: chars },
})
}
})
}) |
@testing-library/user-event
version: 12.6.0@testing-library/react
version 11.2.1jsdom
version 16.4.0Relevant code or config:
Problem description:
Running the above test suite with
yarn test --no-cache
logs the following values on my machine:The results are fairly consistent between reruns (plus-minus a few ms).
The performance difference is starker with longer strings: replacing the input text with
const text = "2001:db8:ac10:fd01::20".repeat(100);
, the results are as follows:I understand that some of this difference stems from the letter-by-letter nature of
type()
which is crucial for certain test scenarios. For the time being however,type()
is too slow for many of the tests we run and we've had to opt forpaste()
instead.I haven't profiled
type()
's internals so I don't know what the source of the performance penalty is.The text was updated successfully, but these errors were encountered: