Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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?

like image 399
FrancescoMussi Avatar asked Apr 15 '20 07:04

FrancescoMussi


People also ask

How do you use refs at Vue?

Referencing DOM Elements in Vue # Vue can store references to DOM elements in a property called $ref . The first thing we have to do, is add a ref attribute to the element we want to reference in our Javascript. The value of the ref attribute will be the name of it within the $ref property.

Are refs reactive Vue?

$refs...are not reactive. However, I have used such refs in templates and they are indeed reactive, and even in methods, computed props, and watchers (as long as you access it after being mounted). Several third party vue libraries e.g. this one also provides features that use/depend on the reactivity of refs.

What is VUE test utils?

Vue Test Utils is the official unit testing utility library for Vue. js. This is the documentation for Vue Test Utils v1, which targets Vue 2 and earlier.

Why is ref undefined Vue?

$refs is undefined when the element with the ref attribute is not visable at the moment you use the this. $refs object. This costs me some time to figure out. It has a button that opens a div that contains an input field with a ref attribute.


1 Answers

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 }
  })
like image 70
Estus Flask Avatar answered Sep 28 '22 07:09

Estus Flask