enzyme: element.focus() not setting document.activeElement
Current behavior
After explicitly calling .focus()
on DOM Node under test document.activeElement
switches from <body>
to null
Expected behavior
After explicitly calling .focus()
on DOM Node under testdocument.activeElement
switches to DOM Node under test
Your environment
NOTE: this was working with testEnvironment: 'jest-environment-jsdom-fourteen',
API
- shallow
- mount
- render
Version
library | version |
---|---|
jest | 25.1 |
enzyme | 3.11.0 |
react | 16.12 |
react-dom | 16.12 |
jsdom | 15.2 |
adapter (below) |
Adapter
- enzyme-adapter-react-16
- enzyme-adapter-react-16.3
- enzyme-adapter-react-16.2
- enzyme-adapter-react-16.1
- enzyme-adapter-react-15
- enzyme-adapter-react-15.4
- enzyme-adapter-react-14
- enzyme-adapter-react-13
- enzyme-adapter-react-helper
- others ( )
About this issue
- Original URL
- State: closed
- Created 4 years ago
- Comments: 15 (6 by maintainers)
@ljharb thanks for the response, I think you’re right but
enzyme
API plays a role in this issue as well. to fix a failing testdocument.activeElement === inputDOMNode
thx to https://github.com/ant-design/ant-design/pull/21185is to add
{ attachTo: document.body }
In case it can help someone, this is what I did in our project:
In Jest setup file:
Then I created a custom wrapper for mounting, using Enzyme mount, like so:
Usage:
This approach works very well, and we are using it with around 4k of tests, without any issues. The only drawback with this is that you can have only one mounting per test, so be aware of it.
I am happy to provide more details should you need it.
For now, I’ve build myself a simple function like this:
However it would be very nice to have that built-in in the Enzyme library. (Honestly, I think I wrote something similar to it for the 3rd time already, each time in a different project.)
Thread necromancy but I thiiink this might be an issue in enzyme after all.
Doing a bit of investigation, I think jsdom has gotten stricter and more in-line with what browsers do between v14 and v16 that Jest v25 uses. I think jsdom is in the right here - it matches browser behaviour, and that enzyme will need to mount elements slightly differently if it wants to have
document.activeElement
be set.Consider the following JSBin: https://jsbin.com/tuqonikavu/edit?js,console,output
It shows that in a browser:
.focus()
on is attached to the body element (present on the page? not sure of the right term for this)Looking at the react adaptor it looks like the element that you create to mount an element onto by default is
global.document.createElement('div');
which isn’t attached to the body element.That sounds like the current enzyme behaviour using jsdom v16 given the “default” behaviour and @vire’s workaround using
attachTo
matches the behaviour of browsers.To get this working out-the-box I think Enzyme will want to mount attach content somewhere under the
document.body
instead of on an unattached div.JSDOM is in full control of how
.focus()
works; enzyme (or jest) has nothing to do with it.The implication is that this changed in JSDOM v15; I’d suggest investigating their changelog.
Yeah, I know this. But I’m sure we could have a separate package that everybody using both enzyme and jest could use. (Nowadays it seems like 90% of community is using jest; ignoring that would be ignoring that community.)
Should I file such feature requests against other repository (or create my own)? Or should I file it here?
I mean, we could have such helpers living at https://github.com/enzymejs/enzyme/tree/master/packages/enzyme-jest-helpers , for example. I could help developing that a bit.
Yep that’ll solve the issue in userland. However I get the feeling that this is going to trip a lot of folks up.
Personally, the team I’m on has written several tests that help ensure accessibility - that focus is moved to a particular element at a given element at a point in time, and I did not expect these to require modifications after a jsdom update. I expected that when I mounted elements that they’d be mounted within the body of a document and thus focus changing would work like when I have visible elements within a browser - do my manual checking with elements attached to a body I would have thought my automated tests would work in the same way by default.
I think we want to encourage people to write tests around focus management, and making it so they have to add
attachTo
and then clean up after themselves will disincentive people from doing that. I wonder if it possible to change Enzyme’s default behaviour (i.e. it should attach elements onto the body) to make writing these tests as lean as possible.Low-effort userland solution:
This is subtly buggy - if the expect check fails then then
ele
is never unmounted and we won’t be working off a clean slate for future tests, which may lead to cascading failures in unrelated tests which will be hard to debug. This is a footgun waiting to happen IMO.Bulletproof userland solution:
This fixes the “expect failures will cause leakages into other tests” problem but it is a lot more boilerplate. I’d wager most people won’t be aware of this subtlety and go for the lower-effort solution mentioned above
Ideal end state, this currently does not work because mount does not attach things to the body by default:
thank you for this! just had the very same issue.
That enzyme can be used to work around a jsdom issue doesn’t change the source of the issue 😃