1

I've tried almost everything I can think of but I'm unable to correctly mount/shallow mount my vue components for testing correctly. Everytime I console.log the wrapper I get the following print out:

VueWrapper {
  isFunctionalComponent: undefined,
  _emitted: [Object: null prototype] {},
  _emittedByOrder: []
}

This question is similar to this question asked here:

Vue-test-utils wrapper undefined

I'm using Vuetify, Vuex and Vue Router. My test.spec.ts is below:

import { shallowMount, createLocalVue, mount } from "@vue/test-utils"
import Vuex from "vuex"
import Vuetify from "vuetify"
import VueRouter from "vue-router"
import TheExamAnswer from "@/components/common/TheExamAnswer.vue"

describe("TheExamAnswer.vue", () => {
  const localVue = createLocalVue()
  let getters: any
  let store: any
  let vuetify: any
  let router: any

  beforeEach(() => {
    localVue.use(Vuex)
    localVue.use(Vuetify)
    localVue.use(VueRouter)
    getters = {
      getExam: () => true,
    }

    store = new Vuex.Store({
      modules: {
        // Need to add FlightPlanning for name spacing
        FlightPlanning: {
          namespaced: true,
          getters,
        },
      },
    })

    vuetify = new Vuetify()

    router = new VueRouter()
  })

  it("Renders the element if the exam has been submitted", () => {
    const wrapper = mount(TheExamAnswer, { localVue, store, router })
    console.log("This is the HTML", wrapper.html())
    expect(wrapper.text()).toContain("Show Answer")
  })
})

My view component is very simple and the code is below:

<template>
  <div v-if="submitted" class="div">
    <v-btn @click="answerHidden = !answerHidden" class="mb-10"
      >Show Answer</v-btn
    >
    <div v-if="!answerHidden">
      <slot name="questionAnswer"></slot>
    </div>
  </div>
</template>

<script>
export default {
  data: () => {
    return {
      answerHidden: true,
    }
  },
  computed: {
    submitted() {
      const exam = this.$store.getters["FlightPlanning/getExam"]
      return exam.submitted
    },
  },
}
</script>

<style></style>

UPDATED: I've added the suggestion from the answer below however now I"m getting the following message.

 TheExamAnswer.vue
    ✕ Renders the element if the exam has been submitted (49ms)

  ● TheExamAnswer.vue › Renders the element if the exam has been submitted

    expect(received).toContain(expected) // indexOf

    Expected substring: "Show Answer"
    Received string:    ""

      38 |     const wrapper = mount(TheExamAnswer, { localVue, store, router })
      39 |     console.log("This is the HTML", wrapper.html())
    > 40 |     expect(wrapper.text()).toContain("Show Answer")
         |                            ^
      41 |   })
      42 | })
      43 | 

      at Object.it (tests/unit/test.spec.ts:40:28)

  console.error node_modules/vuetify/dist/vuetify.js:43612
    [Vuetify] Multiple instances of Vue detected
    See https://github.com/vuetifyjs/vuetify/issues/4068
    
    If you're seeing "$attrs is readonly", it's caused by this

  console.log tests/unit/test.spec.ts:39
    This is the HTML 

Test Suites: 1 failed, 1 total
Tests:       1 failed, 1 total

As you can see the HTML is blank and therefore I'm presuming that's also the same reason it's failing this test as the received string is "".

SOLUTION -

I figured it out. The error was on my behalf by not looking at the logic of the computed property correctly.

In my test I had:

 getters = {
          getExam: () => true,
        }

In my component I had:

computed: {
    submitted() {
      const exam = this.$store.getters["FlightPlanning/getExam"]
      return exam.submitted
    },

If you look at the logic of the computed property it going to take whats returned from the getter and assign it to the exam variable. Originally I was returning true, because that's what I wanted the submitted() function to return this means when I call exam.submitted I'm calling it on a boolean value which obviously gives me "undefined". The solution was to return exactly what the computed property was designed to deal with, an object i.e. {submitted:true}

Therefore the final test looks like this and is returning valid HTML.

import { shallowMount, createLocalVue, mount } from "@vue/test-utils"
import Vuex from "vuex"
import Vuetify from "vuetify"
import VueRouter from "vue-router"
import TheExamAnswer from "@/components/common/TheExamAnswer.vue"

const localVue = createLocalVue()

localVue.use(Vuex)
localVue.use(Vuetify)
localVue.use(VueRouter)

describe("test.vue", () => {
  let getters: any
  let store: any
  let vuetify: any
  let router: any

  beforeEach(() => {
    getters = {
      getExam: () => {
        return { submitted: true }
      },
    }

    store = new Vuex.Store({
      modules: {
        // Need to add FlightPlanning for name spacing
        FlightPlanning: {
          namespaced: true,
          getters,
        },
      },
    })

    vuetify = new Vuetify()

    router = new VueRouter()
  })

  it("Renders the element if the exam has been submitted", () => {
    const wrapper = mount(TheExamAnswer, { localVue, vuetify, store, router })
    console.log("This is the HTML", wrapper.html())
  })
})

This gives me the result of:

  console.log tests/unit/test.spec.ts:44
    This is the HTML <div><button type="button" class="mb-10 v-btn v-btn--contained theme--light v-size--default"><span class="v-btn__content">Show Answer</span></button>
      <!---->
    </div>

Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   0 total
Time:        5.235s
Ran all test suites.

1 Answer 1

1

The console.log with that weird input for wrapper or elements is normal behaviour. I ran couple tests with your components and everything was working.

it("Renders the element if the exam has been submitted", () => {
  const wrapper = mount(TheExamAnswer, { localVue, store, router });
  expect(wrapper.text()).toContain("Show Answer");
});

If you want to console.log html in your wrapper:

console.log(wrapper.html())

UPDATED: the reason, why wrapper.html() return empty string is v-if="submitted" on your root component. The computed property return undefined, because getter return true, so true.submitted return undefined

Getter in test.spec.ts:

getters = {
  getExam: () => {
    return { submitted: true };
  }
};
Sign up to request clarification or add additional context in comments.

3 Comments

Sorry bud, it's still doesn't seem to be coming to the party. I've updated the question with the latest error. It's returning zero HTML which suggests to me the wrapper is empty.
The problem is probably with store getter. This is the reason, why the html is empty. I will update my example after some tests with working solution.
I wish I had read this update 5 mins ago. I just figured it out as well. I've added it all to the question and marked yours as correct because it's the solution. Thanks so much for your help, without the hint of "The problem is probably with the store getter" I would still be stuck.

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.