Add docs for vue-test-utils

Description

It looks like our current docs are quite out of date in the way they describe our preferred approach to testing Vue components.

  • There's no recommendation for using Vue test utils
  • There's references to the outdated createComponent helpers
    • https://gitlab.com/gitlab-org/gitlab/blob/bf89381eded5e2540250da1d41ed108e1f9b1a92/doc/development/testing_guide/frontend_testing.md#L1128
    • https://gitlab.com/gitlab-org/gitlab/blob/c7662f789a540c23e801266798f6f1aa5dff588c/doc/development/fe_guide/vue.md#L185

So what is our preferred approach?

Here's some good examples:

  • https://gitlab.com/gitlab-org/gitlab/blob/d5e214ec913b2187eb5cbc0a7fc40595b23314cf/spec/frontend/vue_mr_widget/components/states/mr_widget_commits_header_spec.js#L30
  • https://gitlab.com/gitlab-org/gitlab/blob/89c9357521a46d23ea62a8fc7ca9c8dac9ca9c37/ee/spec/frontend/vue_mr_widget/components/approvals/approvals_footer_spec.js#L33

1. Use @vue/test-utils

We prefer using shallowMount because the unit tests are isolated and faster. We must pass sync: false to the shallowMount or mount call because sync mode is going away and has some flakiness around it.

2. In Karma there's some extra things needed

For one, all new specs need to be written in Jest, but for any preexisting Karma specs using @vue/test-utils, it's important that the calls to mount and shallowMount have some extra decorations, otherwise it causes unrelated non-deterministic errors.

What do you mean... extra decorations?

In Karma land... this will cause unrelated errors because @vue/test-utils leaves behinds some artifacts 😞

import { shallowMount } from '@vue/test-utils';
import Foo from '~/foo';

describe('foo', () => {
  let wrapper;

  const createComponent = (props = {}) => {
    // Bad :(
    wrapper = shallowMount(Foo, { 
      propsData: props
    });
  };

  // ...
});

For some reason, adding a localVue, extending the component, and sync: false are known to prevent these non-deterministic errors.

import { shallowMount, createLocalVue } from '@vue/test-utils';
import Foo from '~/foo';

describe('foo', () => {
  let wrapper;

  // Note that only one call to createLocalVue is needed per spec
  const localVue = createLocalVue();
  const createComponent = (props = {}) => {
    // Good :)
    wrapper = shallowMount(localVue.extend(Foo), { 
      propsData: props,
      sync: false,
      localVue,
    });
  };

  // ...
});
Edited Dec 10, 2019 by Chad Woolley
Assignee Loading
Time tracking Loading