amimaro
amimaro

Reputation: 303

Calling getter at another computed property is not a function on testing

I have been trying to mock a getter function but this function is also called by another computed property and it is returning as an undefined function.

This is a breadcrumb component which changes accordingly to the routing path. The first test passes normally because the component is not supposed to render. But the second test tries to get the user data with a getter using his username.

My doubt is about the mock getter. Isn't it supposed to return the mock object defined at beforeEach?

Thanks in advance!

Here is the test spec:

import {
  shallowMount,
  createLocalVue
} from '@vue/test-utils'
import Breadcrumb from '@/components/Breadcrumb.vue'
import Vuex from 'vuex'
import VueRouter from 'vue-router'

const localVue = createLocalVue()

localVue.use(Vuex)
localVue.use(VueRouter)
const router = new VueRouter()

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

  beforeEach(() => {
    store = new Vuex.Store({
      getters: {
        getUserByUsername: (path) => ({
          name: {
            first: 'FirstName',
            last: 'LastName'
          }
        })
      }
    })
  })

  it('renders home page breadcrumb', () => {
    const wrapper = shallowMount(Breadcrumb, { store, router, localVue })
    const component = wrapper.find('.breadcrumb')
    expect(component.text()).toBe('')
  })
  it('renders users page breadcrumb', () => {
    router.push('/users')
    const wrapper = shallowMount(Breadcrumb, { store, router, localVue })
    const component = wrapper.find('.breadcrumb')
    expect(component.text()).toBe('')
  })
})

The first test passes but the second returns:

TypeError: this.getUserByUsername is not a function

  41 |       crumbs.push(this.users)
  42 |       for (const path of paths) {
> 43 |         const user = this.getUserByUsername(path)
     | ^
  44 |         if (user) {
  45 |           crumbs.push({
  46 |             label: `${user.name.first} ${user.name.last}`,

And this is the computed functions of the component:

  computed: {
    ...mapGetters(['getUserByUsername']),
    breadcrumbs () {
      const crumbs = []
      const routePath = this.$route.path
      if (routePath === '/' || routePath === '/404') return []
      const paths = routePath.split('/')
      delete paths[0]
      crumbs.push(this.home)
      crumbs.push(this.users)
      for (const path of paths) {
        const user = this.getUserByUsername(path)
        if (user) {
          crumbs.push({
            label: `${user.name.first} ${user.name.last}`,
            path: `/${path}`
          })
        }
      }

      return crumbs
    }
  }

Upvotes: 1

Views: 1734

Answers (1)

skirtle
skirtle

Reputation: 29132

I suspect you need to change this:

getUserByUsername: (path) => ({

to:

getUserByUsername: () => (path) => ({

Judging by the error message and component code it would seem that the real version of getUserByUsername is returning a function so the mock version needs to do the same. Take a look at the original getUserByUsername to confirm.

Recall that the outer function for a getter isn't something that you explicitly invoke. It's used behind the scenes when you access the property and is passed the state as its first argument.

Upvotes: 5

Related Questions