user-event
user-event copied to clipboard
Setting focus gives act() error
@testing-library/reactversion: 14.0.0- Testing Framework and version: Jest 29.5.0
- DOM Environment: jest-environment-jsdom 29.5.0
What you did:
I have a Material UI Autocomplete, and am using a Radix UI AlertDialog to add new options. In my initial implementation, the Enter key didn't work to open the dialog. After fixing that, I wrote a test to verify that Enter behaves as expected. This resulted in a massive error message about state updates not being wrapped in act().
Relevant code is in https://github.com/ysulyma/testing-library-focus-repro/blob/main/tests/repro.test.tsx
What happened:
act-repro% jest
console.error
Warning: An update to ForwardRef(Autocomplete) inside a test was not wrapped in act(...).
When testing, code that causes React state updates should be wrapped into act(...):
act(() => {
/* fire events that update state */
});
/* assert on the output */
This ensures that you're testing the behavior the user would see in the browser. Learn more at https://reactjs.org/link/wrap-tests-with-act
at Autocomplete (/Users/yuri/dev/act-repro/node_modules/@mui/material/node/Autocomplete/Autocomplete.js:381:44)
at DebugComponent (/Users/yuri/dev/act-repro/tests/repro.test.tsx:21:27)
at printWarning (node_modules/react-dom/cjs/react-dom.development.js:86:30)
at error (node_modules/react-dom/cjs/react-dom.development.js:60:7)
at warnIfUpdatesNotWrappedWithActDEV (node_modules/react-dom/cjs/react-dom.development.js:27589:9)
at scheduleUpdateOnFiber (node_modules/react-dom/cjs/react-dom.development.js:25508:5)
at dispatchSetState (node_modules/react-dom/cjs/react-dom.development.js:17527:7)
at handleBlur (node_modules/@mui/base/node/useAutocomplete/useAutocomplete.js:767:5)
at HTMLUnknownElement.callCallback (node_modules/react-dom/cjs/react-dom.development.js:4164:14)
at HTMLUnknownElement.callTheUserObjectsOperation (node_modules/jsdom/lib/jsdom/living/generated/EventListener.js:26:30)
at innerInvokeEventListeners (node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:350:25)
at invokeEventListeners (node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:286:3)
at HTMLUnknownElementImpl._dispatch (node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:233:9)
at HTMLUnknownElementImpl.dispatchEvent (node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:104:17)
at HTMLUnknownElement.dispatchEvent (node_modules/jsdom/lib/jsdom/living/generated/EventTarget.js:241:34)
at Object.invokeGuardedCallbackDev (node_modules/react-dom/cjs/react-dom.development.js:4213:16)
at invokeGuardedCallback (node_modules/react-dom/cjs/react-dom.development.js:4277:31)
at invokeGuardedCallbackAndCatchFirstError (node_modules/react-dom/cjs/react-dom.development.js:4291:25)
at executeDispatch (node_modules/react-dom/cjs/react-dom.development.js:9041:3)
at processDispatchQueueItemsInOrder (node_modules/react-dom/cjs/react-dom.development.js:9073:7)
at processDispatchQueue (node_modules/react-dom/cjs/react-dom.development.js:9086:5)
at dispatchEventsForPlugins (node_modules/react-dom/cjs/react-dom.development.js:9097:3)
at node_modules/react-dom/cjs/react-dom.development.js:9288:12
at batchedUpdates$1 (node_modules/react-dom/cjs/react-dom.development.js:26140:12)
at batchedUpdates (node_modules/react-dom/cjs/react-dom.development.js:3991:12)
at dispatchEventForPluginEventSystem (node_modules/react-dom/cjs/react-dom.development.js:9287:3)
at dispatchEventWithEnableCapturePhaseSelectiveHydrationWithoutDiscreteEventReplay (node_modules/react-dom/cjs/react-dom.development.js:6465:5)
at dispatchEvent (node_modules/react-dom/cjs/react-dom.development.js:6457:5)
at dispatchDiscreteEvent (node_modules/react-dom/cjs/react-dom.development.js:6430:5)
at HTMLDivElement.callTheUserObjectsOperation (node_modules/jsdom/lib/jsdom/living/generated/EventListener.js:26:30)
at innerInvokeEventListeners (node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:350:25)
at invokeEventListeners (node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:286:3)
at HTMLInputElementImpl._dispatch (node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:233:9)
at Object.exports.fireFocusEventWithTargetAdjustment (node_modules/jsdom/lib/jsdom/living/helpers/focusing.js:103:10)
at HTMLButtonElementImpl.focus (node_modules/jsdom/lib/jsdom/living/nodes/HTMLOrSVGElement-impl.js:55:16)
at HTMLButtonElement.focus (node_modules/jsdom/lib/jsdom/living/generated/HTMLElement.js:117:34)
at focus (node_modules/@radix-ui/react-alert-dialog/dist/packages/react/alert-dialog/src/AlertDialog.tsx:133:34)
at Object.ourEventHandler [as current] (node_modules/@radix-ui/primitive/dist/packages/core/primitive/src/primitive.tsx:10:14)
at HTMLDivElement.<anonymous> (node_modules/@radix-ui/react-use-callback-ref/dist/packages/react/use-callback-ref/src/useCallbackRef.tsx:15:44)
at HTMLDivElement.callTheUserObjectsOperation (node_modules/jsdom/lib/jsdom/living/generated/EventListener.js:26:30)
at innerInvokeEventListeners (node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:350:25)
at invokeEventListeners (node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:286:3)
at HTMLDivElementImpl._dispatch (node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:233:9)
at HTMLDivElementImpl.dispatchEvent (node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:104:17)
at HTMLDivElement.dispatchEvent (node_modules/jsdom/lib/jsdom/living/generated/EventTarget.js:241:34)
at dispatchEvent (node_modules/@radix-ui/react-focus-scope/dist/packages/react/focus-scope/src/FocusScope.tsx:112:19)
at commitHookEffectListMount (node_modules/react-dom/cjs/react-dom.development.js:23150:26)
at commitPassiveMountOnFiber (node_modules/react-dom/cjs/react-dom.development.js:24931:11)
at commitPassiveMountEffects_complete (node_modules/react-dom/cjs/react-dom.development.js:24891:9)
at commitPassiveMountEffects_begin (node_modules/react-dom/cjs/react-dom.development.js:24878:7)
at commitPassiveMountEffects (node_modules/react-dom/cjs/react-dom.development.js:24866:3)
at flushPassiveEffectsImpl (node_modules/react-dom/cjs/react-dom.development.js:27039:3)
at flushPassiveEffects (node_modules/react-dom/cjs/react-dom.development.js:26984:14)
at commitRootImpl (node_modules/react-dom/cjs/react-dom.development.js:26935:5)
at commitRoot (node_modules/react-dom/cjs/react-dom.development.js:26682:5)
at performSyncWorkOnRoot (node_modules/react-dom/cjs/react-dom.development.js:26117:3)
at flushSyncCallbacks (node_modules/react-dom/cjs/react-dom.development.js:12042:22)
at flushActQueue (node_modules/react/cjs/react.development.js:2667:24)
at act (node_modules/react/cjs/react.development.js:2582:11)
at node_modules/@testing-library/react/dist/act-compat.js:46:25
at Object.eventWrapper (node_modules/@testing-library/react/dist/pure.js:92:28)
at Object.wrapEvent (node_modules/@testing-library/user-event/dist/cjs/event/wrapEvent.js:8:28)
at Object.dispatchEvent (node_modules/@testing-library/user-event/dist/cjs/event/dispatchEvent.js:47:22)
at Object.dispatchUIEvent (node_modules/@testing-library/user-event/dist/cjs/event/dispatchEvent.js:24:26)
at KeyboardHost.keydown (node_modules/@testing-library/user-event/dist/cjs/system/keyboard.js:65:38)
at keyboardAction (node_modules/@testing-library/user-event/dist/cjs/keyboard/index.js:31:35)
at Object.keyboard (node_modules/@testing-library/user-event/dist/cjs/keyboard/index.js:20:15)
at Object.type (node_modules/@testing-library/user-event/dist/cjs/utility/type.js:26:5)
at Object.asyncWrapper (node_modules/@testing-library/react/dist/pure.js:73:22)
# (several hundred similar lines omitted)
PASS tests/repro.test.tsx
issue reproduction
✓ should open the modal and not explode (321 ms)
Test Suites: 1 passed, 1 total
Tests: 1 passed, 1 total
Snapshots: 0 total
Time: 1.091 s, estimated 3 s
Ran all test suites.
act-repro%
Reproduction:
https://github.com/ysulyma/testing-library-focus-repro
Suggested solution:
Notes:
- it works if I remove the
<AlertDialog.Cancel>(which Radix auto-focuses on open). It also breaks if I remove<AlertDialog.Cancel>but add<AlertDialog onOpenAutoFocus={e => e.currentTarget.focus()}> - it also works if I leave
<AlertDialog.Cancel>as-is but removeawait userEvent.type(input, "Dennis"); - might be related to https://github.com/testing-library/react-testing-library/issues/1051
Moving to user-event for now until we have a repro just using @testing-library/react
@ysulyma Did you ever figure out what the issue was or how to solve it?
Running into this myself and am completely lost
@jd-carroll nope I've been doing
export const knownErrors = {
act: `Warning: An update to %s inside a test was not wrapped in act(...).
When testing, code that causes React state updates should be wrapped into act(...):
act(() => {
/* fire events that update state */
});
/* assert on the output */
This ensures that you're testing the behavior the user would see in the browser. Learn more at https://reactjs.org/link/wrap-tests-with-act%s`,
};
/** Run code with `console.error` silenced. */
export async function withSilencedErrors(
fn: () => unknown,
/** Specific error messages to ignore. */
errors: string[],
) {
const consoleError = console.error;
console.error = (e: Error | string) => {
if (typeof e === "string" && errors.includes(e)) return;
if (e instanceof Error && errors.includes(e.message)) return;
consoleError(e);
};
await fn();
console.error = consoleError;
}
Wow, umm yeah, I can definitely relate to that (feel like I was getting close to something like that).
Fortunately, I was able to solve my issue. Take a look at this thread where I provide a lot more detail: https://github.com/reduxjs/redux-toolkit/issues/4033
Hopefully it is of some value to you / it helps solve your issue.
Sadly we don't have the capacity to debug issues with third-party libraries. I hope you could resolve your issue with @jd-carroll 's hint.
If the issue persists and you can break it down to a minimal reproduction, I'll gladly reopen.