ふわふわにっき

日々の学習記録などを書いていきます

Vue router + TypeScript環境にて、Cypressでコンポーネントテストを書く ~自作サービスで大変だったところその3~

こんにちは。フィヨルドブートキャンプ(以下FBC)卒業生のふわ(@fuwa-syugyo)です。

先日リリースさせていただいた自作サービスで、大変だったところを振り返るシリーズ第3弾です。

前回はE2Eテストについての記事でしたが、今回はCypressでのコンポーネントテストについてです。

環境

Cypress 12.11.0

TypeScript 4.9.5

Vue 3.2.47 (Composition API)

Vue-router 4.1.6

Vite 4.1.2

リポジトリこちら

コンポーネントテストにCypressを選定した理由

当初はViteとの相性が良いVitestや、一般的なJavaScriptのテストフレームワークであるJest、Vue向けの公式単体テストライブラリであるvue-test-utilsも候補に入れていました。

しかし、自作サービスではVue router及びTypeScriptを使用していました。これらといずれも相性が悪く、Cypress以外は難しそうという理由で選びました。

例をいくつか挙げると、vue-test-utilsではvue-test-utilsをTypeScriptで使う際のコード例で使われているcreateLocalVue()Vue3では使われなくなっているようで、設定方法がわからなくなってしまいました。

Vitestについてはvue routerを使用する際のドキュメントを発見することができず、マウントができずに断念しました。

大変だったところ

コンポーネントのマウント

コンポーネントのマウントができず、Cypressのコンポーネントテスト画面に何も表示されない状態が続いていました。

結論から述べると、routerの設定が間違っていたことが原因でした。(またしても凡ミスです…)

  • src/router/index.ts
export const routeSettings: RouteRecordRaw[] = [
  {
    path: '/',
    name: 'home',
    component: HomeView
  },
//略
]

const router = createRouter({
  history: createWebHistory(import.meta.env.BASE_URL),
  routes: routeSettings
})

export default router
  • cypress/support/component.ts(該当箇所は3行目)
import { mount } from 'cypress/vue'
import { createMemoryHistory, createRouter, createWebHistory } from 'vue-router'
import { routeSettings as routes }  from '../../src/router' // ここがimport { router } になっていた

Cypress.Commands.add('mount', (component, options = {}) => {
  // Setup options object
  options.global = options.global || {}
  options.global.plugins = options.global.plugins || []

  // create router if one is not provided
  if (!options.router) {
    options.router = createRouter({
      routes: routes,
      history: createMemoryHistory(),
    })
  }
//以下略

cypress/support/component.ts

  if (!options.router) {
    options.router = createRouter({
      routes: routes,
      history: createMemoryHistory(),
    })
  }

にて、routes:routeSettingsを指定する必要がありましたが、routerを指定してしまっていました。

(わかりにくくなってしまっていますが、3行目でroutesという名前としてrouteSettingsをimportしています)

それぞれの変数の型を調べてみればわかることだったので反省しました。

また余談になりますが、routerのhistoryの違いについて学びました。(こちらに記載があります)

  • createMemoryHistory

Node環境とサーバーサイドレンダリングに適している。(本アプリケーションはSPAだが、テストではこちらが適していると考えた)

  • createWebHistory

ブラウザ環境に適している。こちらが一般的なモード。

ページネーション用CSSライブラリが表示されなかった

ページネーション用CSSライブラリとしてvue-awesome-paginateを使用していましたが、Cypressのコンポーネントテスト時にのみページネーション部分がマウントされず、表示されないという問題が発生していました。

Cypressの楽曲検索画面のコンポーネントテスト。赤枠部分に通常はページネーションが表示されている

コンソールに [Vue warn]: Failed to resolve component: vue-awesome-paginate If this is a native custom element, make sure to exclude it from component resolution via compilerOptions.isCustomElement. at <RecordingSearch ref="VTU_COMPONENT" > at <VTUROOT> という警告が出ていたため、当初はvue-awesome-paginateをカスタム要素として扱えば解決するかもしれないと考えました。

しかし、こちらを試みましたが解決しませんでした。

どうすれば良いのかわからなくなってしまったのでメンターの方に伺ったところ、「Vueのmain.tsプラグインとしてvue-awesome-paginate を追加しているので、Cypress 側の component.ts でも同じようにプラグインとして追加する必要があります」という返答をいただきました。

こちらのドキュメントに従いcypress/support/component.tsoptions.global.plugins.push(VueAwesomePaginate) を追加し、無事にコンポーネントテストでページネーションが表示されるようになりました。

今回の件について、そもそもvue-awesome-paginateはカスタム要素ではないというところには早く気づくべきでした。エラーメッセージを読むことは大切だと思いますが、そのエラーがなぜ起きているのか?というのをもう少し視野を広くして考えられたら良かったのかなと思います。

まとめ

E2Eテストは比較的スムーズに書くことができましたが、コンポーネントテストでは苦戦しました。

今回のテストの件に限らず、自作サービスでは凡ミスや少し考えればわかることが原因ということも多かったです。これらに早く気がつくには使っている技術の知識量や慣れが必要なのかなと実感しました。

自作サービスではTypeScriptやCypressなど、初めて使う技術をいくつか選定しました。いずれもキャッチアップに苦労しましたが、新しいことを学ぶのは面白かったですし、これから実務となればこういったことはたくさんあるとあるでしょうし良い経験になりました。

これにてCypress編は終了です。もし機会がありましたら次回は使用したAPIについて書こうかなと思います。

お読みいただきありがとうございました!