0

i'm trying to implement a test on vuex getter but it's giving me cannot read property weather of undefined and i couldn't understand what is "weather" here i have not declared any weather variable anywhere here still don't know what jest is referring to weather. please help me figure it out. here's the error it's throwing me.i can provide more code if needed

> weather-app@0.1.0 test C:\Users\guest1\Projects\Vue Cli\wheather-app
> jest

 PASS  src/test/navbar_test/navbar.test.js (27.728s)
 PASS  src/test/app_test/App.test.js (34.842s)
 FAIL  src/test/weather_test/weatherTemp.test.js (35.418s)
  ● Console

    console.error node_modules/vue/dist/vue.runtime.common.dev.js:621
      [Vue warn]: Error in render: "TypeError: Cannot read property 'weather' of undefined"

      found in

      ---> <Anonymous>
             <Root>
    console.error node_modules/vue/dist/vue.runtime.common.dev.js:1884
      TypeError: Cannot read property 'weather' of undefined
          at Proxy.render (C:\Users\guest1\Projects\Vue Cli\wheather-app\src\components\weather\weatherTemp.vue:29:357)
          at VueComponent.Vue._render (C:\Users\guest1\Projects\Vue Cli\wheather-app\node_modules\vue\dist\vue.runtime.common.dev.js:3532:22)
          at VueComponent.updateComponent (C:\Users\guest1\Projects\Vue Cli\wheather-app\node_modules\vue\dist\vue.runtime.common.dev.js:4048:21)
          at Watcher.get (C:\Users\guest1\Projects\Vue Cli\wheather-app\node_modules\vue\dist\vue.runtime.common.dev.js:4459:25)
          at new Watcher (C:\Users\guest1\Projects\Vue Cli\wheather-app\node_modules\vue\dist\vue.runtime.common.dev.js:4448:12)
          at mountComponent (C:\Users\guest1\Projects\Vue Cli\wheather-app\node_modules\vue\dist\vue.runtime.common.dev.js:4055:3)
          at VueComponent.Object.<anonymous>.Vue.$mount (C:\Users\guest1\Projects\Vue Cli\wheather-app\node_modules\vue\dist\vue.runtime.common.dev.js:8386:10)
          at init (C:\Users\guest1\Projects\Vue Cli\wheather-app\node_modules\vue\dist\vue.runtime.common.dev.js:3112:13)
          at createComponent (C:\Users\guest1\Projects\Vue Cli\wheather-app\node_modules\vue\dist\vue.runtime.common.dev.js:5952:9)
          at createElm (C:\Users\guest1\Projects\Vue Cli\wheather-app\node_modules\vue\dist\vue.runtime.common.dev.js:5899:9)
          at VueComponent.patch [as __patch__] (C:\Users\guest1\Projects\Vue Cli\wheather-app\node_modules\vue\dist\vue.runtime.common.dev.js:6449:7)
          at VueComponent.Vue._update (C:\Users\guest1\Projects\Vue Cli\wheather-app\node_modules\vue\dist\vue.runtime.common.dev.js:3927:19)
          at VueComponent.updateComponent (C:\Users\guest1\Projects\Vue Cli\wheather-app\node_modules\vue\dist\vue.runtime.common.dev.js:4048:10)
          at Watcher.get (C:\Users\guest1\Projects\Vue Cli\wheather-app\node_modules\vue\dist\vue.runtime.common.dev.js:4459:25)
          at new Watcher (C:\Users\guest1\Projects\Vue Cli\wheather-app\node_modules\vue\dist\vue.runtime.common.dev.js:4448:12)
          at mountComponent (C:\Users\guest1\Projects\Vue Cli\wheather-app\node_modules\vue\dist\vue.runtime.common.dev.js:4055:3)
          at VueComponent.Object.<anonymous>.Vue.$mount (C:\Users\guest1\Projects\Vue Cli\wheather-app\node_modules\vue\dist\vue.runtime.common.dev.js:8386:10)
          at mount (C:\Users\guest1\Projects\Vue Cli\wheather-app\node_modules\@vue\test-utils\dist\vue-test-utils.js:8649:21)
          at shallowMount (C:\Users\guest1\Projects\Vue Cli\wheather-app\node_modules\@vue\test-utils\dist\vue-test-utils.js:8677:10)
          at Object.it (C:\Users\guest1\Projects\Vue Cli\wheather-app\src\test\weather_test\weatherTemp.test.js:24:21)
          at Object.asyncJestTest (C:\Users\guest1\Projects\Vue Cli\wheather-app\node_modules\jest-jasmine2\build\jasmineAsyncInstall.js:102:37)
          at resolve (C:\Users\guest1\Projects\Vue Cli\wheather-app\node_modules\jest-jasmine2\build\queueRunner.js:43:12)
          at new Promise (<anonymous>)
          at mapper (C:\Users\guest1\Projects\Vue Cli\wheather-app\node_modules\jest-jasmine2\build\queueRunner.js:26:19)
          at promise.then (C:\Users\guest1\Projects\Vue Cli\wheather-app\node_modules\jest-jasmine2\build\queueRunner.js:73:41)
          at process._tickCallback (internal/process/next_tick.js:68:7)

  ● Getters.vue › Renders "store.getters.clicks" in h1

    TypeError: Cannot read property 'weather' of undefined

      27 |   align-items: flex-end;
      28 |   width: 100%;
    > 29 |   height: auto;
         |                                    ^
      30 | }
      31 |
      32 | .weather-quote {

      at Proxy.render (src/components/weather/weatherTemp.vue:29:357)
      at VueComponent.Vue._render (node_modules/vue/dist/vue.runtime.common.dev.js:3532:22)
      at VueComponent.updateComponent (node_modules/vue/dist/vue.runtime.common.dev.js:4048:21)
      at Watcher.get (node_modules/vue/dist/vue.runtime.common.dev.js:4459:25)
      at new Watcher (node_modules/vue/dist/vue.runtime.common.dev.js:4448:12)
      at mountComponent (node_modules/vue/dist/vue.runtime.common.dev.js:4055:3)
      at VueComponent.Object.<anonymous>.Vue.$mount (node_modules/vue/dist/vue.runtime.common.dev.js:8386:10)
      at init (node_modules/vue/dist/vue.runtime.common.dev.js:3112:13)
      at createComponent (node_modules/vue/dist/vue.runtime.common.dev.js:5952:9)
      at createElm (node_modules/vue/dist/vue.runtime.common.dev.js:5899:9)
      at VueComponent.patch [as __patch__] (node_modules/vue/dist/vue.runtime.common.dev.js:6449:7)
      at VueComponent.Vue._update (node_modules/vue/dist/vue.runtime.common.dev.js:3927:19)
      at VueComponent.updateComponent (node_modules/vue/dist/vue.runtime.common.dev.js:4048:10)
      at Watcher.get (node_modules/vue/dist/vue.runtime.common.dev.js:4459:25)
      at new Watcher (node_modules/vue/dist/vue.runtime.common.dev.js:4448:12)
      at mountComponent (node_modules/vue/dist/vue.runtime.common.dev.js:4055:3)
      at VueComponent.Object.<anonymous>.Vue.$mount (node_modules/vue/dist/vue.runtime.common.dev.js:8386:10)
      at mount (node_modules/@vue/test-utils/dist/vue-test-utils.js:8649:21)
      at shallowMount (node_modules/@vue/test-utils/dist/vue-test-utils.js:8677:10)
      at Object.it (src/test/weather_test/weatherTemp.test.js:24:21)

Test Suites: 1 failed, 2 passed, 3 total
Tests:       1 failed, 4 passed, 5 total
Snapshots:   0 total
Time:        63.368s
Ran all test suites.
npm ERR! Test failed.  See above for more details.

here's my test file

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

window.alert = jest.fn();
const localVue = createLocalVue();
localVue.use(Vuex);

describe("Getters.vue", () => {
  let getters;
  let store;

  beforeEach(() => {
    getters = {
      getTemperature: () => 2
    };

    store = new Vuex.Store({
      getters
    });
  });

  it('Renders "store.getters.clicks" in h1', () => {
    const wrapper = shallowMount(weatherTemperature, { store, localVue });
    const temp = wrapper.findAll(".weather-degree");
    expect(temp.text()).toBe(getters.getTemperature().toString());
  });
});

my store

import Vue from "vue";
import Vuex from "vuex";
Vue.use(Vuex);
export const store = new Vuex.Store({
  state: {
    coords: {},
    burgerClicked: false,
    temperature: 0,
    locationAllowed: false
  },
  getters: {
    getCoords(state) {
      return state.coords;
    },
    getBurgerClicked(state) {
      return state.burgerClicked;
    },
    getTemperature(state) {
      return state.temperature;
    }
  },
  mutations: {
    setCoords(state, value) {
      state.coords = value;
    },
    setBurgerClick(state, value) {
      state.burgerClicked = value;
    },
    setTemperature(state, value) {
      state.temperature = value.toFixed(0);
    },

    convertToCelsius(state) {
      var tempInCelsius = ((state.temperature - 32) * 5) / 9;
      state.temperature = tempInCelsius.toFixed(0);
    },
    convertToFarenheit(state) {
      var tempInFarenheit = state.temperature * (9 / 5) + 32;
      state.temperature = tempInFarenheit.toFixed(0);
    }
  },
  actions: {
    setCoords(context, value) {
      context.commit("setCoords", value);
    },
    setBurgerClick(context, value) {
      context.commit("setBurgerClick", value);
    },
    setTemperature(context, value) {
      context.commit("setTemperature", value);
    },
    convertToFarenheit(context) {
      context.commit("convertToFarenheit");
    },
    convertToCelsius(context) {
      context.commit("convertToCelsius");
    }
  }
});

my Weathertemp component

   <template>
      <div class="weather-temp">
        <h1 class="weather-degree">{{getTemperature}}&#176;</h1>
        <div class="weather-quote">
          <h1 class="weather-quote-1">
            <b>{{data.weather[0].main}}</b>
          </h1>
        </div>
      </div>
    </template>
    <script>
    import { mapGetters } from "vuex";
    export default {
      props: ["data"],
      computed: {
        ...mapGetters(["getTemperature"])
      }
    };
    </script>
    

main component where setTemperature is being called

<template>
  <div class="main" v-if="weatherData.main">
    <Weather :data="weatherData" />
    <SideMenu :data="weatherData"/>
  </div>
</template>

<script>
import Weather from "./weather/weather";
import SideMenu from "./sidemenu/sideMenu";
import {mapActions, mapGetters } from "vuex";
export default {
  name: "Main",
  components: {
    Weather,
    SideMenu
  },
  data() {
    return {
      weatherData: {}
    };
  },
  methods: {
    ...mapActions(["setTemperature"])
  },
  created() {
    fetch(
      `https://api.openweathermap.org/data/2.5/weather?lat=${this.getCoords.coords.latitude}&lon=${this.getCoords.coords.longitude}&units=metric&APPID=${process.env.VUE_APP_APPID}`
    )
      .then(response => {
        return response.json();
      })
      .then(data => {
        console.log(data);
        
        this.weatherData = data;
        this.setTemperature(data.main.temp);
      });
  },
  computed: {
    ...mapGetters(["getCoords"])
  }
};
Nimantha
  • 6,405
  • 6
  • 28
  • 69
Naveen Kashyap
  • 372
  • 1
  • 9
  • Show the code for the component and store. It sounds like you are trying to access a nested property somewhere in the component and it is erroring because that isn't being provided to the component or loaded into the initial state of the store. – Alexander Staroselsky Nov 19 '19 at 20:06
  • i have added my store and weatherTemp component and where temperature value is being set. i have something in my mind that might be causing it getTemperature value is set on a fetch call but it's default value is 0 so vue-test-utils is calling fetch too and the weather property is in response that i after calling fetch. it should just call the getter – Naveen Kashyap Nov 20 '19 at 11:59
  • here's the git repository but i have deleted this test https://github.com/naveenkash/vue-weather but it's the same – Naveen Kashyap Nov 20 '19 at 12:06
  • i followed exact it said in the documentation https://vue-test-utils.vuejs.org/guides/using-with-vuex.html – Naveen Kashyap Nov 20 '19 at 12:16

1 Answers1

1

The issue is that you are trying to access a property of a completely undefined value, in this case the prop data. Either use something like v-if to only render/access that value when data is defined and has length:

<template>
  <div class="weather-temp">
    <h1 class="weather-degree">{{ getTemperature }}&#176;</h1>
    <div class="weather-quote">
      <h1 class="weather-quote-1">
        <b v-if="data && data.length">{{ data.weather[0].main }}</b>
      </h1>
    </div>
  </div>
</template>
<script>
import { mapGetters } from "vuex";
export default {
  props: ["data"],
  computed: {
    ...mapGetters(["getTemperature"])
  }
};
</script>

I'd recommend this approach no matter what because you may have moments when data has not fully resolved and you could encounter this same error in production, that is unless you are only rendering Weathertemp in the parent conditionally. Otherwise, you would need to pass prop data using propsData to the test:

it('Renders "store.getters.clicks" in h1', () => {
  const propsData = { data: [{ weather: { main: 42 } }] };
  const wrapper = shallowMount(weatherTemperature, { store, localVue, propsData });
  const temp = wrapper.findAll(".weather-degree");
  expect(temp.text()).toBe(getters.getTemperature().toString());
});
Dharman
  • 30,962
  • 25
  • 85
  • 135
Alexander Staroselsky
  • 37,209
  • 15
  • 79
  • 91
  • so the prop data is not there when i run my test and that is giving the error. if i have any prop in any component that i'm testing i have to pass it as propData? – Naveen Kashyap Nov 20 '19 at 16:09
  • In general it is not required to pass props to the mounted test component, but with you implementation it probably is because your component doesn’t attempt to do any kind of null or length checks before trying to access a nested property. It’s not just a test issue, if prop data is undefined going into the weather component in production it would have the same error because the lack of conditional rendering or fallback/default logic for that property you are trying to access. – Alexander Staroselsky Nov 20 '19 at 16:14
  • i have added a check in the parent component of weathertemp. render only when data is fetched and response is added in local state ans pass it down as prop – Naveen Kashyap Nov 20 '19 at 16:24
  • but if it's not required then why it's throwing that error – Naveen Kashyap Nov 20 '19 at 16:25
  • Let me rephrase, it in your situation without any refactoring of the component, you need to pass `propsData` to this shallow mounted component because other prop `data` is undefined. It's not different than in the browser developer console executing `undefined[0].weather[0].main`, it will give you the same exact error. That's basically what's happening in your test because `data` is undefined`. In your actual application this may not be happening because you are passing props to the component, you need to replicate that with your test. – Alexander Staroselsky Nov 20 '19 at 16:33