Open yasin459 opened 1 year ago
Getting this too with v14.4.3:
My test:
const inputText = wrapper.getByLabelText('my-label');
await event.type(inputText, textString);
expect(inputText.value).toBe(textString)
And the result:
AssertionError: expected 't1t5e rlse tltoenrgs long' to be '15 letters long' // Object.is equality
- Expected
+ Received
- 15 letters long
+ t1t5e rlse tltoenrgs long
Downgrading to v13.5.0 was the only resolution I could find.
I'm getting the same behavior as well (in a project with lots of dependencies). I worked around the issue by refactoring to one call to userEvent.type per character that I want to type.
Getting similar behavior, where it seems to be random how many of the characters in the type()
make it into a text box. Also tried keyboard()
directly with the same result.
You are likely not awaiting your changes with waitFor()
or findBy
. From v14 methods are not synchronous. The test works as intended when awaiting the changes.
I'm getting the same behavior as well (in a project with lots of dependencies). I worked around the issue by refactoring to one call to userEvent.type per character that I want to type.
I was able to get await userEvent.type()
to work correctly after upgrading @testing-library/dom to version 9.3.3 or 8.19.0 (previously my lock file also had version 9.0.1 and 8.13 (don't know which version is actually used, should be 9.33 since version 8 is a dependency of a dependency).
You are likely not awaiting your changes with waitFor() or findBy. From v14 methods are not synchronous. The test works as intended when awaiting the changes.
This was part of the issue, when I awaited the user.type() calls I got an not wrapped in act error, then I removed the await and I didn't get an error but the calls to type just entered one character. Even when I tried to wait 1s after the call to type there was only one character in the inputs.
You are likely not awaiting your changes with
waitFor()
orfindBy
. From v14 methods are not synchronous. The test works as intended when awaiting the changes.
I am using waitFor
, and an await
on the user.type
:
const filenameField = getByLabelText('Filename');
await user.clear(filenameField);
await user.type(filenameField, '.startswithperiod');
await waitFor(() => expect(filenameField).toBeInvalid());
await waitFor(() => expect(filenameField.value).toEqual('.startswithperiod'));
Pretty straightforward, but if you see something wrong there, let me know. In this test, it fails with only part of the string being the filenameField.value, e.g.
Expected: ".startswithperiod"
Received: ".starts"
Same issue here, type is sometimes not being awaited and it randomly fails...
I'm using the following versions:
"@testing-library/angular": "14.3.0",
"@testing-library/dom": "9.3.3",
"@testing-library/jasmine-dom": "1.3.3",
"@testing-library/user-event": "14.4.3",
"karma": "6.4.2",
Example of my code:
await user.type(
document.querySelector('textarea'),
'Test example'
);
await user.click(
getByText(
transloco.instant('action.save_example')
)
);
const [submission] = submitData.calls.mostRecent().args;
expect(submission.text).toBe('Test example');
Error:
Expected 'Test' to be 'Test example'.
In case this helps anyone else, I was running into this issue when using onKeyDown
as an event handler for a textInput. Switching to using onChange
resolved the issue.
it('Renders a text input', async () => {
const Template = () => {
const [value, setValue] = useState('')
// switching from `onKeyDown` to `onChange` here fixed the issue for me
return <TextInput value={value} onChange={(e) => setValue(e.currentTarget.value)} />
}
render(<Template />)
expect(screen.getByRole('textbox')).toBeInTheDocument()
await userEvent.type(screen.getByRole('textbox'), 'text content')
expect(screen.getByRole('textbox')).toHaveValue('text content')
})
You are likely not awaiting your changes with
waitFor()
orfindBy
. From v14 methods are not synchronous. The test works as intended when awaiting the changes.I am using
waitFor
, and anawait
on theuser.type
:const filenameField = getByLabelText('Filename'); await user.clear(filenameField); await user.type(filenameField, '.startswithperiod'); await waitFor(() => expect(filenameField).toBeInvalid()); await waitFor(() => expect(filenameField.value).toEqual('.startswithperiod'));
Pretty straightforward, but if you see something wrong there, let me know. In this test, it fails with only part of the string being the filenameField.value, e.g.
Expected: ".startswithperiod" Received: ".starts"
I'm still with the same issue, the days that the machine runs slower, the tests fails more. Did you find any workaround? I tried with setTimeouts, waitFor.... and none of them worked.
I have tried your example with
it.each(Array(100).fill(null))("ExampleThatFails",
async () => {
const user = userEvent.setup({ delay: null }); // <-- added
render(<ExampleThatFails />);
// replaced every userEvent with user
and that seems to work. Why? I don't know. But maybe it's helpful.
By now I think it is clear this is a real bug. It is not just people forgetting await
. Here is my test that is failing (using vitest):
const { container } = render( <MyComponent /> );
const input = container.querySelector<HTMLInputElement>(
'#inputfield',
);
const user = userEvent.setup();
await user.type(input, '61857600265');
expect(input.value).toBe('61857600265')
Wrapping user.type
in my own act
call removes the warnings and makes my tests deterministic.
Before:
await user.type(textarea, '@');
After:
await act(async () => {
await user.type(textarea, '@');
});
I thought that user.type
would take care of act
for me, however, in this case it doesn't seem to.
Wrapping in act
doesn't fix it for me 🤔. My test fails consistently, though.
+1. None of the suggestions work for me, upgrading to react 18 and v14.5.1
None of the suggestions work for me too. It just says "AssertionError: expected '' to be 't' // Object.is equality"
Trying this
test("Should allow user to enter passwords into the input", async () => {
const user = userEvent.setup();
const { getByRole, getByTestId } = render(
<div>
<label
htmlFor="currentPassword"
className="text-white block mb-2 text-sm font-medium dark:text-white"
>
Current Password
</label>
<input
type="password"
role="textbox"
name="currentPassword"
id="currentPassword"
data-testid="currentPassword"
required
autoFocus
value={""}
onChange={(event) => vi.fn()}
/>
</div>,
);
//also tried getByRole
const currentPasswordInputElement = getByTestId("currentPassword");
await user.type(currentPasswordInputElement, "t");
await waitFor(() =>
expect((currentPasswordInputElement as HTMLInputElement).value).toBe("t"),
);
});
package.json (parts that matter)
"dependencies": {
"next": "^14.0.4",
"react": "^18.2.0",
"react-dom": "^18.2.0",
},
"devDependencies": {
"@testing-library/jest-dom": "^6.1.5",
"@testing-library/react": "^14.1.2",
"@testing-library/user-event": "^14.5.1",
"@types/node": "^20.10.5",
"@types/react": "^18.2.45",
"@types/react-dom": "^18.2.18",
"@vitejs/plugin-react": "^4.2.1",
"jsdom": "^23.0.1",
"typescript": "^5.3.3",
"vitest": "^1.1.0"
}
}
Still broken :(
I await it and it doesnt work for me, neither the other suggestions
setting up userEvent first and using await works for me:
it("should be able to type username", async () => {
const user = userEvent.setup()
render(<App />);
const element = screen.getByLabelText("Username") as HTMLInputElement;
await user.type(element, "Admin");
expect(element.value).toBe("Admin");
});
Same issue here, none of the above hints works for me
I have the same issue when i test component that accepts state from the parent component. When I call user.type() just entered one character and so several times,character by character according to the number of character in the test word.
Same issue, it seems the onChange
events are fired properly simulating the typing but when I check the input.value
it doesn't change.
UPDATE: I found a solution for my scenario. I was replacing the value
property of the input from props on every change, that works on browser, but it seems it causes conflict when testing. I just changed the value
for defaultValue
in the input element and the error was solved.
I've noticed that it types the text letter by letter, and with number input, it does not adds the letters, but each time overrides it (I have a controlled component, could be that the issue?)
So for my test purpose, I will just set single digit number...
my 2 cents
I am experiencing the same issue as @MiroslavPetrik; When typing, my onChange handler is only receiving the most recent character typed, not the additive string.
@MiroslavPetrik @obryckim I've found you'll need to await
the userEvent.type
statement inside of your act
block to see the entire string.
Like @omidmogasemi said, adding this await for user.type did the trick. No need of act():
const user = userEvent.setup();
const input = screen.getByTestId('input-search');
user.click(input);
await user.type(input, 'abc');
expect(input).toHaveValue('abc');
Removing
jest.useFakeTimers();
or adding{delay: null}
to userEvent.setup
.
Makes more, but not all, tests pass. Perhaps that's a hint to what's going on.
Adding await
or act
or any combination of the two doesn't work.
Reproduction example
zip file listed bellow
Prerequisites
please download this project demo and run it using npm install react-testing-library-bug.zip
it has 2 tests: 1- testThatFails 2- testThatWorks
in thre first example, test fails because and can not type into coponent using userEvent.type:
code for failing test:
code for working test:
Expected behavior
expected to pass all tests on v14
Actual behavior
testThatFails fails in v14, but when using v13.5 it works properly testTahtWorks passes on both versions
User-event version
14.1.1(actually all v14 dists act the same)
Environment
Additional context
No response