Search code examples
javascriptunit-testingvue.jsjestjsvue-test-utils

vue-test-utils - how to handle $refs?


THE SITUATION

I am trying to shallowMount a component, unsuccessfully.

The component makes use of $refs to read the height of a div. That value is read inside a computed property. Then in the mounted lifecycle I save that value in the store.

The logic itself is simple and works fine. But in the test suite, the mounting of the component breaks, because the $refs key is undefined.

To be clear: I don't intend to test the $refs, I just need to mount the component and move on doing actual unit-testing.

THE COMPONENT

This is the markup:

<div ref="tgmp">

I save the height of the div in a computed property:

computed: {
  barH() {
    return this.$refs.tgmp.clientHeight
  }
}

And then, in the mounted lifecycle, I commit the value in the store:

this.$store.commit('setBarHeight', this.barH)

THE TEST

This is the test. I have omitted irrelevant stuff, like installing the store in the localVue.

beforeEach(() => {
  wrapper = shallowMount(Bar, {
    store,
  })
})

test('is a Vue instance', () => {
  expect(wrapper.isVueInstance()).toBeTruthy()
})

THE ERROR

Error in mounted hook: "TypeError: Cannot read property 'clientHeight' of undefined"

TypeError: Cannot read property 'clientHeight' of undefined

ATTEMPT

I have been trying searching anywhere for a solution, but couldn't find it. I have tried to mock the $refs, but without success:

wrapper = shallowMount(ThePlayerBar, {
  store,
  mocks: {
    $refs: {
      tgmp: {
        clientHeight: 600
      }
    }
  }
})

THE QUESTION

How can I mount a component that makes us of $refs in the mounted lifecycle?


Solution

  • shallowMount is supposed to provide refs, so this.$refs.tgmp should be <div> element in case <div ref="tgmp"> exists in the view on initial render.

    $refs isn't supposed to be mocked because it's internal property and assigned on component initialization. It's computed property that relies on a ref, so it can be mocked if necessary because element height is expected to be 0 in JSDOM:

    jest.spyOn(ThePlayerBar.options.computed, 'barH').mockReturnValue(600);
    

    Or:

      wrapper = shallowMount(Bar, {
        store,
        computed: { barH: () => 600 }
      })