Vanessa Böhner
Vanessa Böhner

Reputation: 61

Mock $root with vue-test-utils and JEST

My component has the following computed code:

textButton() {
    const key = this.$root.feature.name === //...
    // ...
},

Right now I'm trying desperately to mock "root" in my test, but I just don't know how. Any tips?

Upvotes: 3

Views: 5456

Answers (5)

mikazuki
mikazuki

Reputation: 171

For people having the same problem in Vue 3 and Vue Test Utils v2:

I recommend wrapping $root accesses with component computed variables. So, replace this:

methods: {
    textButton() {
        const key = this.$root.feature.name === //...
        // ...
    },
}

with this:

computed: {
    feature() {
        return this.$root.feature;
    }
},
methods: {
    textButton() {
        const key = this.feature.name === //...
        // ...
    },
}

And then, in test implementation, mock this computed variable before mounting:

import { shallowMount } from '@vue/test-utils';
import MyComponent from '<path here>';

MyComponent.computed.feature = jest.fn(() => { name: 'random feature name' });
const wrapper = shallowMount(MyComponent);

...

This way you won't need to mock $root anymore.

Upvotes: 0

Erick Wilder
Erick Wilder

Reputation: 121

You may use a Vue Plugin inside the test to inject the mock data into localVue so that your components can access it.

import {createLocalVue, shallow} from '@vue/test-utils';

const localVue = createLocalVue();

localVue.use((Vue) => {
  Vue.prototype.feature = {
    name: 'Fake news!'
  };
});

let wrapper = shallow(Component, {
  localVue
});

I had the same issues a while ago and I came to the conclusion that accessing this.$root may be a sign that you have to further improve the way you communicate with components. Consider using the plugin structure to define globally available properties and methods not only inside the test for example. Mixins might be helpful as well.

Upvotes: 3

awho
awho

Reputation: 441

Solution from https://github.com/vuejs/vue-test-utils/issues/481#issuecomment-423716430:

You can set $root on the vm directly:

wrapper.vm.$root = { loading: true }
wrapper.vm.$forceUpdate()

Or you can pass in a parent component with the parentComponent mounting option. In VTU, the paren will be the $root:

const Parent = {
  data() {
    return {
      loading: "asdas"
    }
  }
}
const wrapper = shallowMount(TestComponent, {
  parentComponent: Parent
})

Upvotes: 5

lmiller1990
lmiller1990

Reputation: 945

There are two ways to accomplish this with vue-test-utils.

One way, as mentioned above, is using the mocks mounting option.

const wrapper = shallowMount(Foo, {
  mocks: {
    $root: { 
      feature: { 
        name: "Some Val" 
      }
    }
  }
})

But in your case, you probably want to use the computed mouting option, which is a bit cleaner than a deep object in mocks.

const wrapper = shallowMount(Foo, {
  computed: {
    textButton: () => "Some Value"
  }
})

Hopefully this helps!

If you are interested I am compiling a collection of simple guides on how to test Vue components here. It's under development, but feel free to ask make an issue if you need help with other related things to testing Vue components.

Upvotes: 4

JoWinchester
JoWinchester

Reputation: 437

Vue test utils provides you with the ability to inject mocks when you mount (or shallow mount) your component.

const $root = 'some test value or jasmine spy'

let wrapper = shallow(ComponentToTest, {
  mocks: { $root }
})

That should then be easily testable. Hope that helps

Upvotes: 5

Related Questions