VueScrollTo を使っているコンポーネントのテストを書くときに躓いたので、その時の対応をまとめました。
その時の状況
Vueコンポーネントのテストを書きはじめたところでした。
とりあえず最低限のテストを書きます。
componentをmountして、htmlを出力してみます。
import { mount } from "@vue/test-utils";
import Complete from "@/views/Complete.vue";
const $store = {
state: {
answer: {
type: "hoge",
},
},
};
describe("Complete.vue", () => {
let wrapper;
beforeEach(() => {
wrapper = mount(Complete, {
global: {
mocks: {
$store,
},
},
});
});
it("ページが表示される", async () => {
console.log(wrapper.html());
});
});
このテストを実行したところ、失敗してしまいました。
FAIL tests/unit/Complete/template.spec.js
Complete.vue
✕ ページが表示される (49 ms)
● Complete.vue › ページが表示される
TypeError: Cannot read property 'created' of undefined
14 |
15 | beforeEach(() => {
> 16 | wrapper = mount(Complete, {
| ^
17 | global: {
18 | mocks: {
19 | $store,
at invokeDirectiveHook (node_modules/@vue/runtime-core/dist/runtime-core.cjs.js:2922:33)
at mountElement (node_modules/@vue/runtime-core/dist/runtime-core.cjs.js:3814:17)
at processElement (node_modules/@vue/runtime-core/dist/runtime-core.cjs.js:3793:13)
at patch (node_modules/@vue/runtime-core/dist/runtime-core.cjs.js:3713:21)
at mountChildren (node_modules/@vue/runtime-core/dist/runtime-core.cjs.js:3888:13)
at mountElement (node_modules/@vue/runtime-core/dist/runtime-core.cjs.js:3811:17)
at processElement (node_modules/@vue/runtime-core/dist/runtime-core.cjs.js:3793:13)
at patch (node_modules/@vue/runtime-core/dist/runtime-core.cjs.js:3713:21)
at mountChildren (node_modules/@vue/runtime-core/dist/runtime-core.cjs.js:3888:13)
at mountElement (node_modules/@vue/runtime-core/dist/runtime-core.cjs.js:3811:17)
at processElement (node_modules/@vue/runtime-core/dist/runtime-core.cjs.js:3793:13)
at patch (node_modules/@vue/runtime-core/dist/runtime-core.cjs.js:3713:21)
at mountChildren (node_modules/@vue/runtime-core/dist/runtime-core.cjs.js:3888:13)
at mountElement (node_modules/@vue/runtime-core/dist/runtime-core.cjs.js:3811:17)
at processElement (node_modules/@vue/runtime-core/dist/runtime-core.cjs.js:3793:13)
at patch (node_modules/@vue/runtime-core/dist/runtime-core.cjs.js:3713:21)
at mountChildren (node_modules/@vue/runtime-core/dist/runtime-core.cjs.js:3888:13)
at mountElement (node_modules/@vue/runtime-core/dist/runtime-core.cjs.js:3811:17)
at processElement (node_modules/@vue/runtime-core/dist/runtime-core.cjs.js:3793:13)
at patch (node_modules/@vue/runtime-core/dist/runtime-core.cjs.js:3713:21)
at componentEffect (node_modules/@vue/runtime-core/dist/runtime-core.cjs.js:4204:21)
at reactiveEffect (node_modules/@vue/reactivity/dist/reactivity.cjs.js:46:24)
at Object.effect (node_modules/@vue/reactivity/dist/reactivity.cjs.js:21:9)
at setupRenderEffect (node_modules/@vue/runtime-core/dist/runtime-core.cjs.js:4169:38)
at mountComponent (node_modules/@vue/runtime-core/dist/runtime-core.cjs.js:4128:9)
at processComponent (node_modules/@vue/runtime-core/dist/runtime-core.cjs.js:4088:17)
at patch (node_modules/@vue/runtime-core/dist/runtime-core.cjs.js:3716:21)
at componentEffect (node_modules/@vue/runtime-core/dist/runtime-core.cjs.js:4204:21)
at reactiveEffect (node_modules/@vue/reactivity/dist/reactivity.cjs.js:46:24)
at Object.effect (node_modules/@vue/reactivity/dist/reactivity.cjs.js:21:9)
at setupRenderEffect (node_modules/@vue/runtime-core/dist/runtime-core.cjs.js:4169:38)
at mountComponent (node_modules/@vue/runtime-core/dist/runtime-core.cjs.js:4128:9)
at processComponent (node_modules/@vue/runtime-core/dist/runtime-core.cjs.js:4088:17)
at patch (node_modules/@vue/runtime-core/dist/runtime-core.cjs.js:3716:21)
at render (node_modules/@vue/runtime-core/dist/runtime-core.cjs.js:4789:13)
at mount (node_modules/@vue/runtime-core/dist/runtime-core.cjs.js:3054:25)
at Object.app.mount (node_modules/@vue/runtime-dom/dist/runtime-dom.cjs.js:1232:23)
at mount (node_modules/@vue/test-utils/dist/vue-test-utils.cjs.js:2335:18)
at Object.<anonymous> (tests/unit/Complete/template.spec.js:16:15)
● Complete.vue › ページが表示される
TypeError: Cannot read property 'html' of undefined
23 | });
24 | it("ページが表示される", async () => {
> 25 | console.log(wrapper.html());
| ^
26 | });
27 | });
28 |
at Object.<anonymous> (tests/unit/Complete/template.spec.js:25:25)
console.warn
[Vue warn]: Failed to resolve directive: scroll-to
at <Complete ref="VTU_COMPONENT" >
at <VTUROOT>
60 | src="/uploads/images/thanks01.jpg"
61 | />
> 62 | <img
| ^
63 | src="/uploads/images/thanks02.jpg"
64 | />
65 | <img
at warn (node_modules/@vue/runtime-core/dist/runtime-core.cjs.js:40:17)
at resolveAsset (node_modules/@vue/runtime-core/dist/runtime-core.cjs.js:5133:13)
at Object.resolveDirective (node_modules/@vue/runtime-core/dist/runtime-core.cjs.js:5104:12)
at Proxy.render (src/views/Complete.vue:62:38)
at renderComponentRoot (node_modules/@vue/runtime-core/dist/runtime-core.cjs.js:729:44)
at componentEffect (node_modules/@vue/runtime-core/dist/runtime-core.cjs.js:4186:53)
at reactiveEffect (node_modules/@vue/reactivity/dist/reactivity.cjs.js:46:24)
Test Suites: 1 failed, 1 total
Tests: 1 failed, 1 total
Snapshots: 0 total
Time: 3.4 s
Ran all test suites matching /\/Users\/okada\/src\/front\/tests\/unit\/Complete\/template.spec.js/i with tests matching "Complete\.vue".
しかし、エラーメッセージが謎です…
TypeError: Cannot read property 'created' of undefined
Complete.vue
では、created
使ってないんだけどな
やったこと
問題箇所の特定
エラーメッセージからは読み解けないため、Complete.vue
の中身を変えて問題の箇所を特定しました。具体的には、Complete.vue
の中から怪しそうなところを消して実行→通ったらその場所が問題なので、更に狭い範囲を消して実行、を繰り返し、以下の場所に問題があることがわかりました。
<div class="present-area-btn">
<ul>
<li>
<a href="#" v-scroll-to="'#present-area'">
<img
src="/uploads/images/button.png"
/>
</a>
</li>
<li>
<a href="#" v-scroll-to="'#other-area'">
<img src="/uploads/images/other.png" />
</a>
</li>
</ul>
</div>
v-scroll-to
とありますね。
v-scroll-to
は、vue-scrolltoというパッケージのもののようです。
以下のページによると、いい感じにスクロールしてくれるパッケージだそうです。
src/main.jsを確認すると、確かに使っていました。
app
.use(router)
.use(store)
.use(VueAxios, axios)
.use(VueScrollTo, {
offset: -100,
})
そして、テスト失敗時のメッセージをもう一度よく見ると、warnも出ていました
[Vue warn]: Failed to resolve directive: scroll-to
scroll-to
というdirective
が解決できないと言っていました。
対応内容と結果
ということで、mount
時にdirective
を渡してみました。
directives: {
scrollTo: VueScrollTo,
},
テスト全文
import { mount } from "@vue/test-utils";
import VueScrollTo from "vue-scrollto";
import Complete from "@/views/Complete.vue";
const $store = {
state: {
answer: {
type: "hoge",
},
},
};
describe("Complete.vue", () => {
let wrapper;
beforeEach(() => {
wrapper = mount(Complete, {
global: {
mocks: {
$store,
},
directives: {
scrollTo: VueScrollTo,
},
},
});
});
it("ページが表示される", async () => {
console.log(wrapper.html());
});
});
結果:成功しました 🎉
PASS tests/unit/Complete/template.spec.js
Complete.vue
✓ ページが表示される (68 ms)
console.log
<div class="host"><div class="comp-top-area"><img src="/uploads/images/thanks_mv.png"> …
at Object.<anonymous> (tests/unit/Complete/template.spec.js:29:13)
Test Suites: 1 passed, 1 total
Tests: 1 passed, 1 total
Snapshots: 0 total
Time: 4.814 s
Ran all test suites matching /\/Users\/okada\/src\/front\/tests\/unit\/Complete\/template.spec.js/i with tests matching "Complete\.vue".
補足
github検索すると、Vue.use(VueScrollTo)
でやってる人が多そうでした。Vue.useはVue2の書き方なので、それをVue3の書き方にすればよかっただけなのかもしれない…?(試してない)
import VueScrollTo from "vue-scrollto”;
import { createApp } from "vue”;
const app = createApp({});
app.use(VueScrollTo, {
offset: -100,
});