Vue and Vuetify unit test, <v-btn> with :to property renders as <router-link> instead of <a>

This is the relevant part of my template:

<v-flex xs12 sm6 paren>
    <v-btn class="btn-edit"
        color="blue"
        :to="{ name: 'category-edit', params: { category_id: category.id }}">
        Editar
    </v-btn>
</v-flex>

This :to property may have something to do with the problem, described at the end.

And here’s my MyComponent.spec.js:

import { mount, createLocalVue } from '@vue/test-utils';
import VueRouter from 'vue-router';
import Vuetify from 'vuetify';
import CategoryIndex from '../../../src/components/CategoryIndex.vue';
import axios from 'axios';

describe('CategoryIndex', function () {
    let wrp;

    const routes = [
        { path: '/categories', name: 'categories' },
        { path: '/categories/new', name: 'category-new' },
        { path: '/categories/:category_id/edit', name: 'category-edit' }
    ];

    const router = new VueRouter({ routes });

    beforeEach(() => {

        const localVue = createLocalVue();
        localVue.use(VueRouter);
        localVue.use(Vuetify);

        wrp = mount(CategoryIndex, {
            localVue: localVue,
            router,
        });
    });

    it('has a mounted hook', () => {
        expect(typeof CategoryIndex.mounted).toBe('function');
    });

    //
    // NOTE: Here's the problem!
    //
    it.only('edit button routes to correct place with right parameters', () => {
        let elem = wrp.find('.paren');
        console.log(elem.html()); // See below how this is rendered.
    });
});

The rendered output for that element on the unit tests is:

<div class="flex xs12 sm6 paren">
    <router-link class="btn-edit btn btn--router blue" data-ripple="true">
        <div class="btn__content">
        Editar
        </div>
    </router-link>
</div>

As you see, what was <v-btn> in the template becomes <router-link>. It is of extreme importance to note that this misrendering only happens in the unit tests. Everything renders as expected on a real browser.

Moreover, other Vuetify components are compiled to HTML tags just fine, like <v-flex> that get rendered to <div> with some css classes.

If, in the template, I use <router-link>, then it gets rendered to <a href="..."> in the unit tests.

I am using jsdom and jest with jest-vue to compile single file components for the tests.

1 Like

You should see if you can post this on the projects very active github issues page. you may get quicker answers for that specific project.

I have found the problem.

The way I am setting up my test in the opening post is correct.

In my spec test file (like showed in my opening post), I am doing that localVue.use(Vuetify). It looks like hat is the correct way to do it. However, I was accidentally doing Vue.use(Vuetify) in my jest-setup.js file and that was the problem. As soon as I removed it, then it worked.

So, in short, you don’t tell the global Vue to use Vuetify, in the same way it is not recommended to tell the global Vue to use VueRouter. It seems we’d better use localVue for both.

4 Likes

Thanks for responding back with your solution, we definitely appreciate it here.

1 Like

Just a side note: you do not need to install jsdom when you use Jest.js as in this situation.

An other thing: if you write Vue.use(Vuetify) you are going against the recommended way: localVue.use(Vuetify) where localVue = createLocalVue()