LoginSignup
1

More than 1 year has passed since last update.

VueScrollToはdirectivesで渡す

Posted at

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使ってないんだけどな :thinking:

やったこと

問題箇所の特定

エラーメッセージからは読み解けないため、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も出ていました :sweat_drops:

    [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,
});

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
What you can do with signing up
1