无法读取未定义的 属性 'querySelector' - Vue 测试实用程序

Cannot read property 'querySelector' of undefined - Vue test utils

我正在测试 Vuetify 导航抽屉组件,因为我必须稍微更改它并且我遇到了非常奇怪的问题。另外我补充说我使用 TypeScript

TypeError: Cannot read property 'querySelector' of undefined

  28 | 
  29 |   private setBorderWidth(): void {
> 30 |     const border = this.drawer.$el.querySelector(
     | ^
  31 |       ".v-navigation-drawer__border"
  32 |     );
  33 | 

  at VueComponent.setBorderWidth (src/components/Navigation/NavigationDrawer.vue:30:1)
  at VueComponent.mounted (src/components/Navigation/NavigationDrawer.vue:90:1)
  at invokeWithErrorHandling (node_modules/vue/dist/vue.runtime.common.dev.js:1850:57)
  at callHook (node_modules/vue/dist/vue.runtime.common.dev.js:4207:7)
  at Object.insert (node_modules/vue/dist/vue.runtime.common.dev.js:3133:7)
  at invokeInsertHook (node_modules/vue/dist/vue.runtime.common.dev.js:6326:28)
  at VueComponent.patch [as __patch__] (node_modules/vue/dist/vue.runtime.common.dev.js:6543:5)
  at VueComponent.Vue._update (node_modules/vue/dist/vue.runtime.common.dev.js:3933:19)
  at VueComponent.updateComponent (node_modules/vue/dist/vue.runtime.common.dev.js:4054:10)
  at Watcher.get (node_modules/vue/dist/vue.runtime.common.dev.js:4465:25)
  at new Watcher (node_modules/vue/dist/vue.runtime.common.dev.js:4454:12)
  at mountComponent (node_modules/vue/dist/vue.runtime.common.dev.js:4061:3)
  at VueComponent.Object.<anonymous>.Vue.$mount (node_modules/vue/dist/vue.runtime.common.dev.js:8392:10)
  at mount (node_modules/@vue/test-utils/dist/vue-test-utils.js:13855:21)
  at shallowMount (node_modules/@vue/test-utils/dist/vue-test-utils.js:13881:10)
  at Object.<anonymous> (tests/unit/components/Navigation/NavigationDrawer.spec.ts:20:21)

任何建议我的测试代码有什么问题我愿意接受所有建议

import { shallowMount, createLocalVue } from "@vue/test-utils";
import Vuetify from "vuetify";
import NavigationDrawer from "@/components/Navigation/NavigationDrawer.vue";

const localVue = createLocalVue();

describe("NavigationDrawer.vue", () => {
  let vuetify: any;

  beforeEach(() => {
    vuetify = new Vuetify();
  });

  test("Render props correctly when passed", () => {
    const props = {
      width: 300,
      visible: true
    };

    const wrapper = shallowMount(NavigationDrawer, {
      localVue,
      vuetify,
      propsData: props,
    });

    expect(wrapper.props()).toStrictEqual(props);
    expect(wrapper.vm.$data.navigation.show).toBeTruthy();
  });
});

导航抽屉组件我添加了调整此抽屉大小的可能性

<template>
  <v-navigation-drawer
    ref="drawer"
    v-bind="$attrs"
    :width="navigation.width"
    v-model="navigation.visible"
  >
    <slot></slot>
  </v-navigation-drawer>
</template>

<script lang="ts">
import { Component, Vue, Prop, Ref } from "vue-property-decorator";

@Component
export default class NavigationDrawer extends Vue {
  @Prop({ required: true, type: [Number], default: 256 })
  private width!: number;
  @Prop({ required: true, type: Boolean, default: true })
  private visible!: boolean;

  @Ref("drawer") private drawer!: any;

  private navigation = {
    show: this.visible,
    width: this.width,
  };

  private setBorderWidth(): void {
    const border = this.drawer.$el.querySelector(
      ".v-navigation-drawer__border"
    );

    border.style.width = "5px";
    border.style.cursor = "col-resize";
  }

  private setEvents(): void {
    const minSize = 5;
    const el: HTMLElement = this.drawer.$el;

    const border = el.querySelector(
      ".v-navigation-drawer__border"
    )! as HTMLElement;
    const direction: string = el.classList.contains(
      "v-navigation-drawer--right"
    )
      ? "right"
      : "left";

    function resize(e: MouseEvent) {
      let clientX: number =
        direction === "right"
          ? document.body.scrollWidth - e.clientX
          : e.clientX;

      if (clientX <= 5) {
        clientX = 5;
      }

      el.style.width = `${clientX}px`;
    }

    border.addEventListener(
      "mousedown",
      (e: MouseEvent) => {
        if (e.offsetX < minSize) {
          el.style.transition = "initial";
          document.body.style.userSelect = "none";
          document.addEventListener("mousemove", resize, false);
        }
      },
      false
    );

    document.addEventListener(
      "mouseup",
      () => {
        el.style.transition = "";
        this.navigation.width = Number(el.style.width.replace("px", ""));
        document.body.style.cursor = "";
        document.body.style.userSelect = "";
        document.removeEventListener("mousemove", resize, false);
      },
      false
    );
  }

  private mounted() {
    this.setBorderWidth();
    this.setEvents();
  }
}
</script>

shallowMount换成mount应该就可以了

请记住,需要安装 vuetify 组件才能访问它们。

编辑:

您的 v-model 指令值似乎无效。 我想应该是 navigation.show 而不是 navigation.visible

编辑 2: 试试打电话 localVue.use(Vuetify) 就在 const localVue = createLocalVue()

之后

它可能导致 检测到多个 Vue 实例。那么我建议这样做:

...
import Vue from 'vue'
import Vuetify from 'vuetify'
... 

Vue.use(Vuetify);

...

const wrapper = mount(NavigationDrawer, {
  vuetify,
  propsData: props,
});

编辑 3(添加了我的代码):

import { createLocalVue, mount } from "@vue/test-utils";

import Vuetify from "vuetify";
import NavigationDrawer from "@/components/NavigationDrawer.vue";

const localVue = createLocalVue()
localVue.use(Vuetify)

describe("NavigationDrawer.vue", () => {
  let vuetify: any;

  beforeEach(() => {
    vuetify = new Vuetify();
  });

  test("Render props correctly when passed", () => {
    const props = {
      width: 300,
      visible: true
    };

    const wrapper = mount(NavigationDrawer, {
      localVue,
      vuetify,
      propsData: props,
    });

    expect(wrapper.props()).toStrictEqual(props);
    expect(wrapper.vm.$data.navigation.show).toBeTruthy();
  });
});
import { createLocalVue, mount } from "@vue/test-utils";
import Vue from 'vue'
import Vuetify from "vuetify";
import NavigationDrawer from "@/components/NavigationDrawer.vue";

Vue.use(Vuetify)

describe("NavigationDrawer.vue", () => {
  let vuetify: any;

  beforeEach(() => {
    vuetify = new Vuetify();
  });

  test("Render props correctly when passed", () => {
    const props = {
      width: 300,
      visible: true
    };

    const wrapper = mount(NavigationDrawer, {
      vuetify,
      propsData: props,
    });

    expect(wrapper.props()).toStrictEqual(props);
    expect(wrapper.vm.$data.navigation.show).toBeTruthy();
  });
});