无法读取未定义的 属性 '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();
});
});
我正在测试 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();
});
});