vue-test-utils: How to test logic within mounted() lifecycle hook (with vuex)?
Asked Answered
C

3

18

I'm trying to write a unit test for the logic within Vue's mounted() lifecycle hook, but not having much luck. The problem seems to be that mounted() never gets called when the component is mounted using vue-test-utils mount. Here's the Vue component I'm trying to test:

<template>
  <div></div>
</template>

<script>   
export default {
  name: 'MyComponent',
  mounted () {
    this.$store.dispatch('logout')
  }
}
</script>

And the test itself:

import { mount, createLocalVue } from '@vue/test-utils'
import Vuex from 'vuex'
import MyComponent from '@/components/MyComponent'

const localVue = createLocalVue()

localVue.use(Vuex)

describe('MyComponent.vue', () => {
  let store
  let actions

  beforeEach(() => {
    actions = {
      logout: jest.fn().mockName('logout')
    }
    store = new Vuex.Store({
      state: {},
      actions
    })
  })

  it('calls store "logout" action', () => {
    mount(MyComponent, { localVue, store })
    expect(actions.logout).toHaveBeenCalled()
  })
})

However, this fails with expect(logout).toHaveBeenCalled() asserting false.

If I call the mocked store action directly with actions.logout() the test passes, and I have other tests which also call store actions on things like a button press, and those pass as well, so the problem definitely appears to be with the mounted() lifecycle hook.

Any thoughts?

(vue 2.5.4 and vue-test-utils 1.0.0-beta-.15)

Custodian answered 10/5, 2018 at 17:49 Comment(2)
Just tested your code with the specified versions and it works.Telesis
Try to use 1.0.0-beta.16, it's released todayDelaunay
C
8

Not sure how it's any different, but I abstracted the store mock to another file and everything seems to work now.

mocks.js

export const storeMock = Object.freeze({
  state: {},
  actions: {
    logout: jest.fn().mockName('logout')
  },
})

test.spec.js

import { shallowMount, createLocalVue } from '@vue/test-utils'
import Vuex from 'vuex'
import { storeMock } from './mocks.js' 
import MyComponent from '@/components/MyComponent'

const localVue = createLocalVue()

localVue.use(Vuex)

describe('MyComponent.vue', () => {
  let options

  beforeEach(() => {
    jest.clearAllMocks()
    const store = new Vuex.Store(storeMock)
    options = { store, localVue }
  })

  it('calls store "logout" action', () => {
    shallowMount(MyComponent, options)
    expect(storeMock.actions.logout).toHaveBeenCalled()
  })
})
Custodian answered 10/7, 2018 at 16:18 Comment(0)
D
1

Without abstracting the store mock to another file, and slightly different approach without beforeEach (ruined my tests for some reason).

import { createLocalVue, shallowMount } from "@vue/test-utils";
import Vuex from "vuex";
import MyComponent from "@/components/MyComponent.vue";

describe("MyComponent", () => {
  const localVue = createLocalVue();
  localVue.use(Vuex);

  const actions = {
    logout: jest.fn()
  };
  const store = new Vuex.Store({ actions });

  const wrapper = shallowMount(MyComponent, {
    localVue,
    store
  });

  it('calls store "logout" action', () => {
    expect(actions.logout).toHaveBeenCalled();
  });
});
Devinne answered 7/4, 2021 at 14:13 Comment(0)
Z
0

Try creating the store instance after executing mount

  //No
const store = new Vuex.Store({ actions });

  const wrapper = shallowMount(MyComponent, {
    localVue,
    store
  });


//Yes
  const wrapper = shallowMount(MyComponent, {
    localVue,
    store
  });

const store = new Vuex.Store({ actions });
Zoster answered 9/7, 2024 at 20:53 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.