mercredi 27 novembre 2019

Testing Vuetify (Vue.js) - Multiple calls on mount throw error

I am currently experiencing a behaviour when testing my Vue Application (specifically when vuetify is included). I am using Jest as Test Runner but experienced the same behaviour with mocha.

The first thing to notice is that the problem only occurs with mount from the @vue/test-utils and not shallowMount. Also it only occurs if you use mount twice (I guess the reason is the pollution of the Vue Object but more on that later).

Now my component is manly just a wrapper around a basic v-data-table with the property value bound to its items and some custom slots for checkboxes instead of text.

Now the problem. First this is what the first variant of my test looks like (it's basically how it's recommended by vuetify. take a look here. As the test itsself doesn't really matter I'll just expect true to be true here

import Vue from 'vue';
import Vuetify from 'vuetify';
import { mount, createLocalVue, shallowMount } from '@vue/test-utils';

import  PermissionTable from '@/components/PermissionTable.vue';
import { expect } from 'chai';

const localVue = createLocalVue();

// Vue.use is not in the example but leaving it will cause the error that 
// the data table is not registered
Vue.use(Vuetify);

describe('Permissiontable.vue', () => {
  let vuetify;
  let tableItems;

  beforeEach(() => {
    tableItems = [];
    vuetify = new Vuetify();
  });


  it('will test the first thing', async () => {
    const wrapper = mount(PermissionTable, {
      localVue,
      vuetify,
      propsData: {
        value: tableItems
      }
    });

    expect(true).to.be(true);
  });


  it('will test the second thing', async () => {
    const wrapper = mount(PermissionTable, {
      localVue,
      vuetify,
      propsData: {
        value: tableItems
      }
    });

    expect(true).to.be(true);
  });
});

Now as already commented without using Vue.use(Vuetify) I'll get the error that the component v-data-table is not registered. With it I'm left with the following behaviour

  1. Test the first thing runs as expected and succeeds
  2. The the second thing fails the following Error

Type Error: Cannot read property '$scopedSlots' of undefined

and fails at mount(....). To make the behaviour even weirder, if I debug and stop at this line, run the mount manually in the debug console it fails as well on the first time with the same error. If I run it again it works.

Now I am sure that functions behave the same way if they get the same input. So the Input to the mount must be altered by the first call. My guess is that the Vue class gets polluted somehow. So if I look at the documentation for localVue this utility is made to prevent pollution of the global Vue class. So I altered my code to

import Vue from 'vue';
import Vuetify from 'vuetify';
import { mount, createLocalVue, shallowMount } from '@vue/test-utils';

import  PermissionTable from '@/components/PermissionTable.vue';
import { expect } from 'chai';

describe('Permissiontable.vue', () => {
  let vuetify;
  let tableItems;
  let localVue;

  beforeEach(() => {
    tableItems = [];
    localVue = createLocalVue();
    vuetify = new Vuetify();
    localVue.use(vuetify);
  });


  it('will test the first thing', async () => {
    const wrapper = mount(PermissionTable, {
      localVue,
      vuetify,
      propsData: {
        value: tableItems
      }
    });

    expect(true).to.be(true);
  });


  it('will test the second thing', async () => {
    const wrapper = mount(PermissionTable, {
      localVue,
      vuetify,
      propsData: {
        value: tableItems
      }
    });

    expect(true).to.be(true);
  });
});

So I create a new Instance of localVue and vuetify for every test. and make localVue use vuetify. Now this brings me back to the error

[Vue warn]: Unknown custom element: - did you register the component correctly? For recursive components, make sure to provide the "name" option.

I also experimented with various alterations of injecting vuetify (instantiated) or Vuetify. using the global Vue.use etc. At the end I'm always left with one of those two behaviours.

Now the workouround seems to be to write each test in a single file which works but I think is really bad practice and I want to understand what exactly happens here.

Aucun commentaire:

Enregistrer un commentaire