Open mfolnovic opened 5 years ago
I'd like to add this also happens with validate
(instead of validationSchema
), e.g.:
const validate = (values) => {
const errors = {};
if (!values.test) {
errors.test = "required";
}
return errors;
};
And I forgot to mention that, even surrounding fireEvent.blur
with act
doesn't help, e.g.:
act(() => {
fireEvent.blue(input);
});
I'm seeing the same issue when using a validation schema.
Warning: An update to Formik inside a test was not wrapped in act(...).
https://github.com/cmelion/react-cra-demo/blob/cfulnecky/formik/src/components/input-form/.test.js
I am having the same issue when trying to change an input value:
fireEvent.change(getByLabelText(/email/i), {target: {value: fakeUsername}});
Obviously, wrapping this in act(() => {})
doesn't do anything to mitigate the problem.
Have you tried this?
await act(async() => {
fireEvent.change(getByLabelText(/email/i), {target: {value: fakeUsername}});
});
@2Steaks Thanks for that snippet. Works for me.
Looks like in https://github.com/jaredpalmer/formik/blob/master/packages/formik/src/Formik.tsx#L534-L553
setValues
and setFieldValue
both use the hook useEventCallback
so you need to wait on the the promise.
const setValues = useEventCallback((values: Values) => {
dispatch({ type: 'SET_VALUES', payload: values });
return validateOnChange
? validateFormWithLowPriority(state.values)
: Promise.resolve();
Including this information in the documentation would be very helpful.
Edit: Wouldn't using wait
utility fix the issue? https://testing-library.com/docs/dom-testing-library/api-async#wait
Running into this while attempting to upgrade from v1 to v2, and having it cause warnings in hundreds of tests. I'd like to avoid having to wrap all of these with async act calls if I can help it... Did anyone find any other workaround? Using @testing-library/react and @testing-library/user-event fwiw.
@pleunv I use the same libraries, and I have written my test like this. I hope this will help.
const onSubmit = jest.fn();
render(<Form onSubmit={onSubmit} />);
// without act()
userEvent.click(screen.getByRole('button', { name: 'foo' });
await waitFor(() => expect(onSubmit).toHaveBeenCalledWith({ /** XXX */ }));
Did anyone was able to fix it using Enzyme?
Does that warning indicate that there is an issue in the website? or is it a warning saying you are doing something wrong in your test?
After numerous attempts this is what worked for me:
import { render, fireEvent, waitFor } from '@testing-library/react'
import userEvent from '@testing-library/user-event'
test('validates the email field', async () => {
const { getByText, getByPlaceholderText } = render(<Form />)
const emailInput = getByPlaceholderText('Email')
userEvent.type(emailInput, 'invalidemail.com')
fireEvent.blur(emailInput)
await waitFor(() => {
expect(getByText(/Please enter a valid email/i)).toBeInTheDocument()
})
})
userEvent.type
to type into the input.act
.await waitFor
block (waitFor
is the new API replacing the previous wait
). Edit: you can also use await findByText()
which is the same thing as await waitFor
with getByText
.
I wanted to add to this for anyone that is still struggling.
I had a beforeEach
render, so I had to wrap that render.
let wrapper: RenderResult
beforeEach(() => {
wrapper = renderWithProviders(<ManualAddressForm {...props} />)
})
@burrack No solutions for enzyme at the moment I don't think. This breaks testing for us so hope it's fixed soon.
This issue was fixed for me by updating formik and testing library packages to the latest versions.
formik@2.2.9
and 👇
Form
Doesn't work with more up to date versions for me:
"@testing-library/jest-dom": "^5.16.5",
"@testing-library/react": "^13.4.0",
"formik": "^2.2.9",
Have you tried this?
await act(async() => { fireEvent.change(getByLabelText(/email/i), {target: {value: fakeUsername}}); });
I think this solution deserves a bit more explanation.
Normally we don't need to wrap fireEvent
calls in act()
, because testing-library takes care of that (I think), but in this case fireEvent.change()
triggers form validation, which is async, so state is only updated when that promises resolves which is probably out of the scope where fireEvent
was expecting state to change.
In this case we need to wrap 2 things in act()
: user action and awaiting promise flush. So I propose the following fix instead:
fireEvent.change(getByLabelText(/email/i), { target: { value: fakeUsername } });
await act(() => Promise.resolve()); // Flush microtasks used by Formik validation
As alternative if you are using delays/timers:
// Flush timers and microtasks used by Formik validation
await act(() => jest.runAllTimersAsync());
Any news or update regarding this error? We are having the same problem using fireEvent.change
it('should submit the form with entered values', async () => {
const alertMock = jest.spyOn(window, 'alert').mockImplementation(() => {})
render(<SignInForm />)
const usernameInput = screen.getByLabelText(/username/i)
const passwordInput = screen.getByLabelText(/password/i)
const submitButton = screen.getByRole('button', { name: /signin/ })
fireEvent.change(usernameInput, { target: { value: 'testuser' } })
fireEvent.change(passwordInput, { target: { value: 'password123' } }
fireEvent.submit(submitButton)
expect(alertMock).toHaveBeenCalledWith(
JSON.stringify(
{
username: 'testuser',
password: 'password123',
branch: 1,
},
null,
2,
),
)
alertMock.mockRestore()
})
For now we have used the following solution from @romulof:
fireEvent.change(getByLabelText(/email/i), { target: { value: fakeUsername } }); await act(() => Promise.resolve()); // Flush microtasks used by Formik validation
Any news or update regarding this error? We are having the same problem using
fireEvent.change
it('should submit the form with entered values', async () => { const alertMock = jest.spyOn(window, 'alert').mockImplementation(() => {}) render(<SignInForm />) const usernameInput = screen.getByLabelText(/username/i) const passwordInput = screen.getByLabelText(/password/i) const submitButton = screen.getByRole('button', { name: /signin/ }) fireEvent.change(usernameInput, { target: { value: 'testuser' } }) fireEvent.change(passwordInput, { target: { value: 'password123' } } fireEvent.submit(submitButton) expect(alertMock).toHaveBeenCalledWith( JSON.stringify( { username: 'testuser', password: 'password123', branch: 1, }, null, 2, ), ) alertMock.mockRestore() })
For now we have used the following solution from @romulof:
fireEvent.change(getByLabelText(/email/i), { target: { value: fakeUsername } }); await act(() => Promise.resolve()); // Flush microtasks used by Formik validation
Formik is essentially unmaintained. Migrate to react-hook-forms.
@tyteen4a03 Where does it say you have to migrate? Is there any collaborator, contributor or maintainer who indicates this?
@tyteen4a03 Where does it say you have to migrate? Is there any collaborator, contributor or maintainer who indicates this?
Nothing, but the huge amount of unresolved issues, unmerged PRs and the frequency of release within the past 12 months are strong indicators.
🐛 Bug report
Current Behavior
I have a test that basically screenshots a form after removing focus from field that is required (while not filling in any value). For validations, I'm using Yup.
During
fireEvent.blur(textField);
, I get warning:I'm also trying to screenshot page after blur, expecting to see validation message. From my experiments, I need to do:
await waitForDomChange({ input })
to get correct screenshot.I've also noticed there's no warning if I don't have
validationSchema
.I assume this is connected to https://github.com/jaredpalmer/formik/issues/1524 ?
Expected behavior
No warning. No need for
waitForDomChange
.Reproducible example
https://codesandbox.io/s/agitated-lalande-5nhh0
Your environment