Mario Cardinal

"The real voyage of discovery consists, not in seeking new landscapes, but in having new eyes" – Marcel Proust


Leave a comment

Mounting (with the Cypress Component Testing Tool) a Vue component requiring Vuetify

I’m writing this post to make sure that a recipe on mounting (with the Cypress Component Testing Tool) a Vue component requiring the Vuetify framework is documented somewhere on the web. Thus, with the help of Google search, those who will have the same goal in the future will find the right answer easily.

Cypress is a front-end test automation framework built for the modern web. It is a very powerful tool that enables developers to write End-to-End as well as Rest APIs tests entirely in JavaScript, directly accessing everything within the browser. At To-Do Studio, we use Cypress with success.

In the last year, Cypress added the ability to automate testing of Vue or React components. Besides the automation, what is very interesting is that with a little ingenuity we can also use Cypress to obtain a playground to visualize the rendering of the components. I saw not only the ability to automate but also an opportunity to replace Storybook for component visualization.

However, the challenge when you want to use the Cypress component testing tool with Vue is that some frameworks such as Vuetify require a global vuetify object on the Vue instance as well as all components to be wrapped in the VApp component, otherwise it triggers warnings in the simplest cases and doesn’t work at all in more complex situations.

Unfortunately, the documented way on mounting a Vue component does not work with Vuetify.

While waiting for a more elegant solution from Cypress and Vuetify here is what we use as a workaround:


// Spec File with VBtn as component: xxx.spec.ts
import { mount } from '@cypress/vue';
import { VApp, VBtn } from 'vuetify/lib';
import vuetify from '../plugins/vuetify';
import i18n from '../plugins/i18n';

describe('Cypress CT with Vuetify', () => {
  it('playground', { viewportWidth: 360, viewportHeight: 667 }, () => {
    mount({
      vuetify,
      render: h => h(VApp,
        [
          h(VBtn, { props: { color: 'primary', height: '40', width: '250' } },
            [
              'Button Title',
            ]),
        ],
      ),
    }, { extensions: { plugins: [vuetify, i18n] } });
  });
});

and here is the Vuetify plugin:


// Vuetify plugin: ../plugins/vuetify.ts
import Vue from 'vue';
import Vuetify, {
  VApp, VBtn,
} from 'vuetify/lib';
import 'roboto-fontface/css/roboto/roboto-fontface.css';

Vue.use(Vuetify, {
  components: {
    VApp,
    VAppBar,
  },
});

export default new Vuetify({
  icons: {
    iconfont: 'mdiSvg',
  },
  customProperties: true,
  // add theme...
  // add breakpoint...
});

To give you a glimpse of how we use it in real life scenario at To-Do Studio, here is a sample of a real spec file:


import { mount } from '@cypress/vue';
import { VApp } from 'vuetify/lib';
import vuetify from '../plugins/vuetify';
import i18n from '../plugins/i18n';
import THeader from './THeader.vue';

describe('THeader', () => {
  it('playground', { viewportWidth: 360, viewportHeight: 667 }, () => {
    const user = null;
    const studioId = '00000000-0000-0000-0000-000000000000';
    const activeStudios = [ ];

    mount({
      vuetify,
      render: h => h(VApp,
        [h(THeader, {
          props: { routeName: 'studio-tips', studioId: studioId, activeStudios: activeStudios, user: user },
        })]),
    }, { extensions: { plugins: [vuetify, i18n] } });
  });
});