1

Let's say I have a very basic vue-class-component as shown below:

<template>
    <div>Nothing of interest here</div>
</template>

<script>
    import Vue from 'vue';
    import Component from 'vue-class-component';
    import http from './../modules/http';

    @Component
    export default class Example extends Vue {
        user = null;
        errors = null;

        /**
         * @returns {string}
         */
        getUserId() {
            return this.$route.params.userId;
        }

        fetchUser() {
            this.user = null;
            this.errors = null;

            http.get('/v1/auth/user/' + this.getUserId())
                .then(response => this.user = response.data)
                .catch(e => this.errors = e);
        }
    }
</script>

I want to test the fetchUser() method so I just mock the './../modules/http' dependency and make http.get return a Promise. The problem is that in my assertion I want to check if the URL is being built properly and in order to do so the user ID has to come from an hard-coded variable in the test.

I tried something like this but it doesn't work:

import ExampleInjector from '!!vue-loader?inject!./../../../src/components/Example.vue';

const mockedComponent = ExampleInjector({
    './../modules/http': {
        get: () => new Promise(/* some logic */)
    },
    methods: getUserId: () => 'my_mocked_user_id'
});

Unfortunately it doesn't work and I could not find anything this specific in the Vue docs so the question is, how am I supposed to mock both external dependencies and a class component method?

NOTE: I do not want to mock this.$route.params.userId as the userId could potentially come from somewhere else as well (plus this is just an example). I just want to mock the getUserId method.

2 Answers 2

2

Since I specifically asked about how I could mock Vue class component methods with the inject loader here's the complete solution for the question at hand:

import ExampleInjector from '!!vue-loader?inject!./../../../src/components/Example.vue';

const getComponentWithMockedUserId = (mockedUserId, mockedComponent = null, methods = {}) => {
    if (!mockedComponent) {
        mockedComponent = ExampleInjector();
    }

    return Vue.component('test', {
        extends: mockedComponent,
        methods: {
            getUserId: () => mockedUserId,
            ...methods
        }
    });
};

And then in my test case:

const component = getComponentWithMockedUserId('my_mocked_user_id');

const vm = new Vue(component);

I found this to be very helpful when you need to create a partial mock AND inject some dependencies too.

Sign up to request clarification or add additional context in comments.

Comments

1

The easiest way to do this is to extend the component and override the method:

const Foo = Vue.extend({
  template: `<div>{{iAm}}</div>`,
  created() {
    this.whoAmI();
  },
  methods: {
    whoAmI() {
      this.iAm = 'I am foo';
    }
  },
  data() {
    return {
      iAm: ''
    }
  }
})

Vue.component('bar', {
  extends: Foo,
  methods: {
    whoAmI() {
      this.iAm = 'I am bar';
    }
  }
})

new Vue({
  el: '#app'
})

In this example I'm using the extends property to tell Vue that Bar extends Foo and then I'm overriding the whoAmI method, you can see this is action here: https://jsfiddle.net/pxr34tuz/

I use something similar in one of my open source projects, which you can check out here. All I'm doing in that example is switching off the required property for the props to stop Vue throwing console errors at me.

3 Comments

Can you make your example complete by mocking also external modules like I'm doing in my question with the inject-loader please?
@FrancescoCasula Do you mean when importing single file components?
yes like in the second snippet of code in my question where I'm doing const mockedComponent = ExampleInjector({.... I think it works if you just pass mockedComponent on extends in the Vue.component call. In my case I also had to do const component = Vue.component(/*...*/) and then const vm = new Vue(component); or it wouldn't work, perhaps because there's no mounting in my test.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.