首页 > 解决方案 > Vue Test Utils - 无法正确挂载/浅挂载组件,包装器未定义

问题描述

我已经尝试了几乎所有我能想到的东西,但我无法正确安装/浅安装我的 vue 组件以进行正确测试。每次我 console.log 包装器时,我都会得到以下打印输出:

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

这个问题类似于这里提出的这个问题:

Vue-test-utils 包装器未定义

我正在使用 Vuetify、Vuex 和 Vue 路由器。我的 test.spec.ts 如下:

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")
  })
})

我的视图组件非常简单,代码如下:

<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>

更新:我已经从下面的答案中添加了建议,但是现在我收到了以下消息。

 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

如您所见,HTML 是空白的,因此我假设这也是它未能通过此测试的原因,因为接收到的字符串是“”。

解决方案 -

我想到了。该错误代表我没有正确查看计算属性的逻辑。

在我的测试中,我有:

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

在我的组件中,我有:

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

如果您查看计算属性的逻辑,它将获取从 getter 返回的内容并将其分配给考试变量。最初我返回的是 true,因为这就是我希望 submit() 函数返回的意思,这意味着当我调用exam.submitted 时,我在一个布尔值上调用它,这显然给了我“未定义”。解决方案是准确返回计算属性旨在处理的内容,即一个对象,即 {submitted:true}

因此最终的测试看起来像这样并且返回了有效的 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())
  })
})

这给了我以下结果:

  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.

标签: vue.jsvue-test-utils

解决方案


带有用于包装器或元素的奇怪输入的 console.log 是正常行为。我对您的组件进行了几次测试,一切正常。

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

如果你想在你的包装器中 console.log html:

console.log(wrapper.html())

更新:原因,为什么wrapper.html()返回空字符串v-if="submitted"在你的根组件上。计算属性返回undefined,因为getter返回true,所以true.submitted返回undefined

吸气剂test.spec.ts

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

推荐阅读