user1486133
user1486133

Reputation: 1487

Jest + Enzyme testing if an element was focused to

I want to test if an element is focused to when the component updated.

  componentDidUpdate() {
    this.button.focus();
  }

I have a render function which gets the component(s)

  function render(args) {
    const component = shallow(<MyComponent {...args} />);

    return {
      component,
      button: () => component.find("button"),
    };
  }

My assertion is as follows

describe("When component did update", () => {
  it("Should focus to the button", () => {
    const { component, button } = render(args);
    expect(button().focus).toHaveBeenCalled();
  });
});

With just this I get the error

Matcher error: received value must be a mock or spy function

So I thought I needed to add a mock of focus which I've now done in my beforeEach, and test that instead, which removes the error but my test asserts 0 calls instead of 1 call:

describe("When component did update", () => {
  it("Should focus to the button", () => {
    const { component, button } = render(defaultArgs);
    expect(backButtonElement.focus).toHaveBeenCalled();
  });
});

So I must be missing something else

Upvotes: 4

Views: 9735

Answers (2)

VnoitKumar
VnoitKumar

Reputation: 1426

This worked for me

const wrapper = mount(<MyComponent />);

const input = wrapper.find('input');

expect(input).toHaveFocus();

Upvotes: 5

otorrillas
otorrillas

Reputation: 4773

The reason your test asserts 0 calls instead of the expected 1 call is because componentDidUpdate does not trigger when the component mounts, only on subsequent updates. You need to trigger an update.

describe("When component did update", () => {
  it("Should focus to the button", () => {
    const { component, button } = render(defaultArgs);
    /* 
       setting some random props to force an update,
       ideally you should simulate a real update/user behaviour 
       when you want the focus triggered
    */
    component.setProps({ forceUpdate: true });
    component.update();

    expect(backButtonElement.focus).toHaveBeenCalled();
  });
});

However, in order to avoid testing internal implementation details, I would suggest to assert the expected side-effects that the user should perceive. So, rather than checking if a function was called or not, checking that the button is focused when certain conditions occur:

describe("When component did update", () => {
  it("Should focus to the button", () => {
    const { component, button } = render(defaultArgs);

    // trigger an update, ideally via user interaction
    // e.g.
    // component.simulate('click')

    // check which element is focused in the document
    const focusedElement = document.activeElement;

    expect(button().node.matchesElement(focusedElement)).toBe(true);
  });
});

Upvotes: 0

Related Questions