Hi, I'm currently trying to test if an element is focused. I tried something like the following:
const wrapper = mount('<MyComponent />'); // Suppose this has an input inside.
const input = wrapper.find('input');
expect(input.is(':focus')).toBe(true);
With this code, I'm getting the following error:
TypeError: Enzyme received a complex CSS selector (':focus') that it does not currently support.
So I have two questions now:
1) Are the complex selectors something that may happen in the near future?
2) Is there another way to test if something is focused?
Thank you!
What version of enzyme are you using? You shouldn't get that error with 2.3.0 (see https://github.com/airbnb/enzyme/pull/217) but psuedo-class queries like that aren't supported as far as I know. If you register an onFocus handler that updates a state value you can assert on that. Maybe @lelandrichardson can clarify is there's a better way to do this right now.
I was using 2.2.0 and now 2.3.0. Like you said, in 2.3.0 I don't see the error.
Regarding the other option, I'd rather avoid modifying the state just for testing concerns. Thanks anyway for the suggestion :)
Any news about this?
I've been thinking that maybe it is something to be tested from an E2E perspective. Because to get the focused element you can do document.activeElement.
Anyway, I'd like to hear your opinion about whether it makes sense or not to implement the :focus selector feature and also see if anyone else has tested if an element is focused.
Thanks!
Regarding the other option, I'd rather avoid modifying the state just for testing concerns. Thanks anyway for the suggestion :)
I know its a matter of opinion, but it's worth nothing that the React team does recommend using controlled components for form elements: https://facebook.github.io/react/docs/forms.html, so the advantages extend beyond just being easier to test.
Anyway, I'd like to hear your opinion about whether it makes sense or not to implement the :focus selector feature and also see if anyone else has tested if an element is focused.
From what I can tell it would be rather difficult to implement. We'd have to rely on document.activeElement being accurate in the DOM environment (usually jsdom), unless there's another good way to query focused state. Supporting :focus also implies we support :hover and :active which would have their own challenges.
I think ideally we'd support these, but I need to think about it more. Ultimately I think it's a low/medium priority given that controlled components are easy to use, recommended, and easy to test.
Ultimately I think it's a low/medium priority given that controlled components are easy to use, recommended, and easy to test.
I've got a different use case where explicitly checking focus would be useful. I'm trying to test where focus ends up after some UI interaction happens and components re-render. That is, if you press a button, and then the UI re-renders so that button disappears and is replaced with something else, I want to assert what's focused afterward.
By default, I think there is _no_ focus in that situation, but I'm trying to improve the user experience for a keyboard or screen reader user by placing the focus somewhere reasonable that shows the results of the interaction, rather than forcing them to scrub through the entire page to find where they left off. Right now, it sounds like I can't use enzyme to write a test for this.
I think you have to use a full browser environment for that, and you couldn't really leverage a testing framework.
Duplicate of #703
I got it to work in enzyme using jsdom enzyme and mocha.
it('focuses the element on mount', () => {
const wrapper = mount(<Element id="foo" />);
const elem = wrapper.find('#foo');
const focusedElement = document.activeElement;
expect(elem.matchesElement(focusedElement)).to.equal(true, 'The element was not focused');
});
I got this to work by abstracting the focus() method that I was testing.
Let's say I wanted to focus on an input on mounting...
componentDidMount() {
this.someRef.focus();
}
Writing the test for the input having focus was not happening for me. Even using @romidane 's method.
...
So instead I write this helper method on my component Class:
focusInput = (obj) => {
obj.focus();
}
And then in my componentDidMount ...
componentDidMount() {
this.focusInput(this.someRef);
}
Now my test is nice and simple:
it(' Mounts with the first input having focus.', () => {
const mockObj = { focus: jest.fn() };
container.focusInput(mockObj);
expect(mockObj.focus).toHaveBeenCalled();
});
Nice approach @gl2748. Do you have any idea of how can I simulate a focus after render? I have a chat input with an emoji button, and I want to hide the emojis picker everytime I focus the text input again :'( Enzyme's simulate('focus') not working here.
You can use document.activeElement this returns currently focussed element
https://developer.mozilla.org/en-US/docs/Web/API/DocumentOrShadowRoot/activeElement
Most helpful comment
I got it to work in enzyme using jsdom enzyme and mocha.