2

I created a Vue plugin to activate console.logs if a user sets a property in localStorage. The plugin is a wrapper around console.log(). If the user enters 'localStorage.isLoggingData = true', then the plugin will test if that property exists in local storage and the logData function with run

index.js

import logData from '../plugins/logData

  // I want to console.log this inital data coming into the app
  async init ({ state, commit, dispatch }) {
    try {
      const { data } = await messaging.send(ACTION.READY)
      logData(data)

main.js

import logData from '../plugins/logData

// Use logData to optionally view console.log statements
Vue.use(logData)

logData.js

export default {
  install: function (Vue) {
    Vue.prototype.$logData = function (dataToLog) {
      const isLoggingData = localStorage.getItem('isLoggingData')
      if (isLoggingData) {
        console.log(dataToLog)
      }
    }
  }
}

Currently when we have an application error we route to an error page, when I comment out the 'logData(data)' I am routed to the correct page in my app. Am I not creating the plugin or importing it correctly?

Update

index.spec.js

import logData from '../plugins/logger'
import { createLocalVue, shallowMount } from '@vue/test-utils'
import App from '@src/App'

const localVue = createLocalVue()
localVue.use(Vuex)
localVue.use(logData)

const mocks = {
  _vm: {}
}
mocks._vm.$logData = logData

const wrapper = shallowMount(App, {
  mocks,
  localVue
})

I am now told to mock _vm. Is this the correct way to mock it?

1 Answer 1

1

Your init({ state, commit, dispatch }) function looks like it comes from vuex.
You can't access vue methods from vuex actions directly.

You could directly export your logData function in index.js and import that in vuex:

index.js

import { logData } from '../plugins/logData';

// I want to console.log this inital data coming into the app
async init ({ state, commit, dispatch }) {
  try {
    const { data } = await messaging.send(ACTION.READY);
    logData(data);
    // ...
  } catch(e) { /* ... */ }
}

main.js

import logDataPlugin from '../plugins/logData';

// Use logData to optionally view console.log statements
Vue.use(logDataPlugin);

logData.js

export function logData(dataToLog) {
  const isLoggingData = localStorage.getItem('isLoggingData');
  if (isLoggingData)
    console.log(dataToLog);
}

export default {
  install: function (Vue) {
    Vue.prototype.$logData = logData;
  }
}

If you want to have the method only as a vue plugin and not expose it directly you could pass the vue instance to your vuex action to access $logData:

// in your vuex actions:
const actions = {
  async init ({ state, commit, dispatch }, {vm}) {
    vm.$logData("Hello");
  }
};

// call action from vue component:
export default {
   mounted() {
     // pass reference to vue instance to vuex store
     this.init({vm: this});
   },
   methods: {
     ...mapActions(['init'])
   }
}
Sign up to request clarification or add additional context in comments.

6 Comments

The main question I have now, is why we can't access Vue methods, if written on the prototype, in Vuex actions?
@KevinT. vue and vuex are two different libraries, you can only access methods defined on the Vue.prototype inside vue components. You can however pass your current vue component to the vuex action (my last example), and then use the $logData method you defined on the prototype on that instance
My PR reviewer wants me to call, this._vm.$logData(data) in the init action. I have that working. Now, I don't understand how to access / call this._vm.$logData() in my tests. I also have other tests that are failing now because "Cannot read property '_vm' of undefined. It seems this is not accessible.
@KevinT. I would strongy discourage using this._vm - the underscore before the property name is a convention to signal this a private member. this._vm is nowhere documented in the official vuex documentation, so you should not rely on it to be a reference to the calling vue component - this might change in future vuex versions. I would recommend directly exporting the function like shown in my example above. This will also make testing easier.
@KevinT. If you still want to do it via your vue plugin, you can pass the vue instance as an extra parameter to your vuex action or use one of the work-arounds shown in this github issue. You could also check out vuex-persist which will store all (or part of) your vuex store in localStorage so you don't have to deal directly with it.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.