Rewriting Vue/Jest Tutorial Code

While learning how to set up Jest testing for Vue, I found some helpful , though a little outdated* tutorial code at Digital Ocean

describe('Mounted App', () => {
  const wrapper = mount(App);

  test('is a Vue instance', () => {
    expect(wrapper.isVueInstance()).toBeTruthy()
  })

  it('renders the correct markup', () => {
    expect(wrapper.html()).toContain('What is the sum of the two numbers?')
  })

  // it's also easy to check for the existence of elements
  it('has a button', () => {
    expect(wrapper.contains('button')).toBe(true)
  })
})

What with the blazing fast evolution of, well, everything related to web development — I found myself working with slightly newer versions of Vue and Jest, I think. The result were some confusing error messages until I tracked down the culprits: deprecated properties of the testing objects…

The isVueIntance() method was recently taken out of circulation, so it caused some errors when trying to call the method from the test wrapper. Primarily, this error:

TypeError: wrapper.isVueInstance is not a function

As a Jest and Vue n00b, this threw me off until I found the deprecation warning in the documentation for Vue Test Utils.

After running the wrapper constant through a few console.log outputs, I was able to determine why things weren’t working.

From console.log(wrapper):

  console.log tests/unit/example.spec.js:38
    VueWrapper {
      isDisabled: [Function],
      wrapperElement: HTMLDivElement {},
      __app: {
        _uid: 0,
        _component: { name: 'VTU_ROOT', render: [Function: render] },
        _props: null,
        _container: HTMLDivElement { _vnode: [Object], __vue_app__: [Circular] },
        _context: {
          app: [Circular],
          config: [Object],
          mixins: [Array],
          components: [Object],
          directives: {},
          provides: [Object: null prototype] {},
          optionsCache: [WeakMap],
          propsCache: [WeakMap],
          emitsCache: [WeakMap],
          reload: [Function]
        },
        _instance: {
          uid: 0,
          vnode: [Object],
          type: [Object],
          parent: null,
          appContext: [Object],
          root: [Circular],
          next: null,
          subTree: [Object],
          update: [Function],
          scope: [EffectScope],
          render: [Function: render],
          proxy: {},
          exposed: null,
          exposeProxy: null,
          withProxy: null,
          provides: Object <Complex prototype> {},
          accessCache: [Object: null prototype] {},
          renderCache: [],
          components: null,
          directives: null,
          propsOptions: [Array],
          emitsOptions: null,
          emit: [Function: bound emit$1],
          emitted: null,
          propsDefaults: [Object: null prototype] {},
          inheritAttrs: undefined,
          ctx: {},
          data: {},
          props: {},
          attrs: {},
          slots: {},
          refs: [Object],
          setupState: {},
          setupContext: null,
          suspense: null,
          suspenseId: 0,
          asyncDep: null,
          asyncResolved: false,
          isMounted: true,
          isUnmounted: false,
          isDeactivated: false,
          bc: null,
          c: null,
          bm: null,
          m: null,
          bu: null,
          u: null,
          um: null,
          bum: null,
          da: null,
          a: null,
          rtg: null,
          rtc: null,
          ec: null,
          sp: null
        },
        version: '3.2.20',
        config: [Getter/Setter],
        use: [Function: use],
        mixin: [Function: mixin],
        component: [Function: component],
        directive: [Function: directive],
        mount: [Function],
        unmount: [Function: unmount],
        provide: [Function: provide]
      },
      rootVM: {},
      componentVM: {
        check: [Function: bound check],
        refresh: [Function: bound refresh],
        x1: [Getter/Setter],
        x2: [Getter/Setter],
        guess: [Getter/Setter],
        message: [Getter/Setter],
        hasOwnProperty: [Function]
      },
      __setProps: [Function: setProps]
    }

And console.log(typeof (wrapper)):

  console.log tests/unit/example.spec.js:39
    object

Finally console.log(wrapper.html())

console.log tests/unit/example.spec.js:40
    <div id="app">
      <div>
        <h3>Let us test your arithmetic.</h3>
        <p>What is the sum of the two numbers?</p>
        <div class="inline">
          <p>26 + 85 =</p><input><button>Check Answer</button>
        </div><button>Refresh</button>
        <p></p>
      </div>
    </div>

With the console log output, I was able to kinda sorta infer what the issue was, and by looking up different, non-deprecated methods and matchers re-wrote the tests in a way that worked:

describe('Mounted App', () => {
  const wrapper = mount(App);
  test('The wrapper exists', () => {
    expect(wrapper.find('does-not-exist').exists()).toBe(false)
  })

  it('renders the correct markup', () => {
    const element = wrapper.find('#app p:first-of-type')
    expect(element.text()).toBe('What is the sum of the two numbers?')
  })

  it('has a button', () => {
    const button = wrapper.find('button')
    expect(button.exists()).toBe(true)
  })

})

Not quite as concise as the original author’s examples, but it works (for now)!

*UPDATE–
The original tutorial at Digital Ocean was re-written less than 24 hours after I let them know about the deprecation issue. Check it out: https://www.digitalocean.com/community/tutorials/vuejs-vue-testing — Thanks Parthiv at D.O.!

Comments are closed.