0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

CypressでPiniaのストアのユニットテストを書く

Last updated at Posted at 2024-04-17

Cypresse2eからUIコンポーネントまでの広い範囲を扱えるテスティングフレームワーク。

この記事では、PiniaのストアのユニットテストをCypressを使って行う方法のアイデアを提示する。

はじめに

vue.jsのテンプレートを使用し、Cypressを組み込んでプロジェクトを作成した場合、以下の構成でテストが用意される。

  • ./cypress/フォルダ下にe2eのテスト
  • ./src/components/__tests__/フォルダ下にコンポーネントテスト

ここに、`./stores/下に配置したユニットテストを実行させたいが、

CypressTesting Type-Specific Optionse2ecomponentの設定しか用意されていなく、そのままではストアの設定を加えることはできない。

方法

まず、ストアのフォルダ構成は、以下のようになると想定している。

📁 /
├── src
    ├── components   
    ├── stores
        ├── 各ストアのフォルダ
            ├── index.ts   ここにストアの実装
            └── test.cy.ts ここにユニットテストの実装

ストアの近くにユニットテストを置きたかったのと、フォルダ分けせずstores直下にストアの実装とユニットテストの実装を置くと、フォルダが肥大化していや〜んな感じになるのが好みじゃないため。

こうしなければならないというわけではないです。

設定内容

Cypressのコマンドラインオプションとして、明示的に設定ファイルを渡すことができる。

そこで、package.jsonscript設定を以下のように記述。

-    "test:unit": "cypress run --component",
-    "test:unit:dev": "cypress open --component",
+    "test:c": "cypress run --component",
+    "test:c:dev": "cypress open --component",
+    "test:u": "cypress run --component --config-file cypress.stores.config.ts",

元々あった、コンポーネントテストを実行するためのコマンドtest:unittest:cに変更している。(ccomponentc)

ユニットテスト用の設定ファイルは、以下のように記述した。

import { defineConfig } from 'cypress'

export default defineConfig({
  component: {
    specPattern: 'src/stores/**/*.{cy,spec}.{js,ts,jsx,tsx}',
    devServer: {
      framework: 'vue',
      bundler: 'vite'
    }
  }
})

ユニットテストなのでdevServerはなくてもいいのだけど、必須のためテンプレートでの記述をそのまま採用している。1

テストの記述

あとは、ストアのためのユニットテストを書く。
幸いにして、他のBDDフレームワークとだいたい同じ記法をサポートしてくれている。

たとえば、vueテンプレートでサンプルとして用意されるcounterストアの場合は以下のようになる。

import { setActivePinia, createPinia } from 'pinia'
import { useCounterStore } from '.'

describe('Counter store', () => {
    beforeEach(() => {
        setActivePinia(createPinia())
    })

    it ('increment', () => {
        const store = useCounterStore()
        expect(store.count).to.equal(0)
        store.count++
        expect(store.count).to.equal(1)
        store.count++
        expect(store.count).to.equal(2)
    })

    it ('double increment', () => {
        const store = useCounterStore()
        expect(store.doubleCount).to.equal(0)
        store.count++
        expect(store.doubleCount).to.equal(2)
        store.count++
        expect(store.doubleCount).to.equal(4)
    })
})

Piniaの公式サイトで紹介された内容と比べると、以下の違い程度で済むのも魅力。

-    expect(counter.count).toBe(0)
+    expect(store.count).to.equal(0)

おまけ

Cypressの一番気に入っている点が、descrive > context > itと階層化して書けること。
最近ははやりのjestとかjestとかjestcontextが書けない(書けてもなんか不恰好)ことに不満だったのでよき。2

おまけその2

ユニットテスで、

import { useCounterStore } from '.'

と記述していて、おやっ?と思った人のための補足。

vite.config.tsのエイリアスの解決ルールとして以下のように記述しているため。

export default defineConfig({
  plugins: [
    vue(),
  ],
  resolve: {
    alias: {
+      '@stores/*': fileURLToPath(new URL('./src/stores/**/index.ts', import.meta.url)),
       '@': fileURLToPath(new URL('./src', import.meta.url))
    }
  }
})

コンポーネト側でのインポートで、以下のように手抜きをしたかったから。

import { useCounterStore } from '@/stores/counter'
  1. テスト実行時に裏でサーバが起動してしまうが、トレードオフとして受け入れることにした

  2. contextサポートしてるmocha好きだった。

0
0
0

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
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?