Skip to content

Cannot read property 'getters' of undefined #363

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
WangHansen opened this issue Jan 20, 2018 · 9 comments
Closed

Cannot read property 'getters' of undefined #363

WangHansen opened this issue Jan 20, 2018 · 9 comments

Comments

@WangHansen
Copy link

Version

1.0.0-beta.10

Reproduction link

http://jsfiddle.net/m33w0o9p/2/

Steps to reproduce

For jest testing with vuex, if vuex contains both namespaced modules and global actions or states, it doesn't work. It will produce Cannot read property 'getters' of undefined error.

Testing file

import { shallow, createLocalVue } from '@vue/test-utils'
import Vuex from 'vuex'
import App from '@/App'
import auth from '../../../src/store/module/auth'

const localVue = createLocalVue()

localVue.use(Vuex)

describe('App', () => {

  let actions
  let store

  beforeEach(() => {
    actions = {
      toggleDevice: jest.fn()
    }
    store = new Vuex.Store({
      state: {},
      modules: {
      	auth
      },
      actions
    })
  })

  it('should have beforeMount hook', () => {
  	const wrapper = shallow(App, { store, localVue })
  	wrapper.setComputed({tokenExpired: true})
  })
})

App.vue

export default {
  name: 'app',
  beforeMount () {
    this.toggleDevice()
  },
  mounted () {
    this.loadAuth()
  },
  computed: {
    ...mapGetters({
      tokenExpired: 'auth/tokenExpired'
    })
  },
  watch: {
    tokenExpired () {
      if (this.tokenExpired) {
        this.$router.push('/login')
      }
    }
  },
  methods: mapActions({
    toggleDevice: 'toggleDevice',
    loadAuth: 'auth/loadAuth'
  })
}

module/auth.js

const state = () => {
  return {
    tokenExpired: false
  }
}

const getters = {
  tokenExpired: state => state.tokenExpired
}

What is expected?

To pass the test

What is actually happening?

It doesn't compile, just suggesting Cannot read property 'getters' of undefined


I tried to make vuex store exactly like the one in production, it doesn't work.
I tried to combine the getters from the module to the global getters, it doesn't work either.
So I believe it is a bug

@eddyerburgh
Copy link
Member

eddyerburgh commented Jan 20, 2018

Thanks for the bug report 🙂

I tried to create a minimal reproduction with your code, but there were parts I had to guess. I can't reproduce this error using a namespaced module and mapGetters.

Can you create a full reproduction using this JSFiddle as a starting point—https://jsfiddle.net/eddyerburgh/2mzsL00d/4/

@WangHansen
Copy link
Author

Here: https://jsfiddle.net/L5fye9w0/1/
run it and open up the console, you will see the error message

@eddyerburgh
Copy link
Member

You need to pass the store instance—https://jsfiddle.net/eddyerburgh/sghur81m/1/

@WangHansen
Copy link
Author

Sorry, my bad, I use vue-jest and jest, and I can't figure a way out to use them on jsfiddle: https://jsfiddle.net/L5fye9w0/4/
my actual testing code look like this

const localVue = createLocalVue()

localVue.use(Vuex)

describe('App', () => {

  let actions
  let store

  beforeEach(() => {
    actions = {
      toggleDevice: jest.fn()
    }
    store = new Vuex.Store({
      state: {},
      modules: {
      	auth
      },
      actions
    })
  })

  it('should have beforeMount hook', () => {
  	const wrapper = shallow(App, { store, localVue })
  	wrapper.setComputed({tokenExpired: true})
  })
})

@WangHansen
Copy link
Author

I figured out what the problem is, I passed in the fake store with a real module, but in this real module, it calls another getter from the real store, but since I don't have this getter method in the fake store, it gives me the error

@bennettdams
Copy link

I figured out what the problem is, I passed in the fake store with a real module, but in this real module, it calls another getter from the real store, but since I don't have this getter method in the fake store, it gives me the error

@WangHansen I have the same exact issue, what did you do to bypass this?

@alexandreaco
Copy link

@bennettdams You need to provide getters to your test store if you want your component to be able to access their data. You can mock them with jest if you are testing whether or not they are called.

const localVue = createLocalVue()

localVue.use(Vuex)

describe('App', () => {

  let actions
  let store

  beforeEach(() => {
    actions = {
      toggleDevice: jest.fn()
    }
    store = new Vuex.Store({
      modules: {
      	auth: {
          state: {},
          getters: {
            myFunc: jest.fn()
         }
      },
      actions
    })
  })

  it('should have beforeMount hook', () => {
  	const wrapper = shallow(App, { store, localVue })
  	wrapper.setComputed({tokenExpired: true})
  })
})

Alternatively, if you export your getters from your auth module file, you can import that directly into your test and use all of the logic.

import { getters } from '../somepath/modules/auth'
const localVue = createLocalVue()

localVue.use(Vuex)

describe('App', () => {

  let actions
  let store

  beforeEach(() => {
    actions = {
      toggleDevice: jest.fn()
    }
    store = new Vuex.Store({
      modules: {
      	auth: {
          state: {},
          getters
      },
      actions
    })
  })

  it('should have beforeMount hook', () => {
  	const wrapper = shallow(App, { store, localVue })
  	wrapper.setComputed({tokenExpired: true})
  })
})

Be sure to provide all of the initial values to your auth state so your getters are not looking for undefined values :)

@MaheshBodas
Copy link

Just my two cents. I think whats happening here is Test case is trying to create actual store. Obviously creation of Store will have modules and getters defined. It will use store we have defined in our code. In test case I had to explicitly import store and getters

  1. Import module where 'store' is defined
  2. Import module where getters is defined

@spronkets
Copy link

Why are people intentionally mocking app behavior in their own codebase? You shouldn't be mocking your store, you should be mocking 3rd party dependencies that your app relies on. You are intentionally cutting out relevant code to how your codebase works.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

6 participants