I testing Vuetify navigation drawer component because I must change it a little bit and I have very weird problem. Additionally I add that I use 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)
any suggestions whats is wrong bellow my test code I am open to all advicess
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();
});
});
Navigation drawer component I added possibility to resize this drawer
<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>
Replace shallowMount
with mount
and it should be ok.
Remember that vuetify components needs to be mounted to to access them.
EDIT:
It seems that you have invalid v-model
directive value.
I suppose it should be navigation.show
instead of navigation.visible
EDIT 2:
Try calling
localVue.use(Vuetify)
just right after const localVue = createLocalVue()
It could result in Multiple instances of Vue detected. Then i would suggest to do it like so:
...
import Vue from 'vue'
import Vuetify from 'vuetify'
...
Vue.use(Vuetify);
...
const wrapper = mount(NavigationDrawer, {
vuetify,
propsData: props,
});
EDIT 3 (Added my code):
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();
});
});