はじめに
nuxtjs/storybook
+storybook/addon-interactions
の導入で少しハマったので記事にしました。
大した内容ではないですが、あまり同じ構成の情報が見つからなかったためいつか誰かのためになれば幸いです。
導入に当たっては下記の記事を大変参考にさせていただきました。下記の記事で触れていない内容について記載します。
https://zenn.dev/azukiazusa/articles/storybook-interaction-testing
やったこと
バージョンを揃える
nuxt/storybook
の4.3.1
ではアドオンのバージョンは6.4.22
になっています。
storybook/addon-interactions
をインストールする時はバージョン指定することになります。
npm install -D storybook/addon-interactions@6.4.22
下記のライブラリに関しては、対応時の最新版で動作しています。
@storybook/jest
: 0.0.10
@storybook/test-runner
: 0.0.8
@storybook/testing-library
: 0.0.11
ステップ実行を有効にする
ステップを有効にするためにはStorybookのmain.js
に下記を設定する必要があります。
module.exports = {
features: {
interactionsDebugger: true,
},
};
nuxt/storybook
ではこれをnuxt.config.ts
で指定することが出来なかったため、ejectでStorybookの設定ファイルを外出しする必要があります。
npx nuxt storybook eject
.storybook
フォルダが生成されるので、その中のmain.js
にfeaturesおよびinteractionsDebuggerを設定してください。
withinではなくscreenを使う
こちらは環境要因もあるかもしれませんが、NuxtのユニバーサルモードではStorybook上でF5リロードするとcanvasから要素を取得することが出来ませんでした。
import { within } from '@storybook/testing-library'
...
Default.play = async ({ canvasElement }) = {
const canvas = within(canvasElement)
const textbox = await canvas.findByRole('textbox')
}
上記では下記のエラーでテストが失敗してしまいました。
Unable to find role="textbox"
Ignored nodes: comments, <script />, <style />
<div
id="root"
/>
Ignored nodes: comments, <script />, <style />
<div
id="root"
/>
下記のようにwithinではなくscreenから要素を取得することで解決しました。
import { screen } from '@storybook/testing-library'
...
Default.play = async () = {
const textbox = await screen.findByRole('textbox')
}
ただし、READMEにはWhile you can technically use screen, it's recommended to use within(canvasElement). Besides giving you a better error message when a DOM element can't be found, it will also ensure your play function is compatible with Storybook Docs.
とあるのでなるべくwithinで対応出来るように注視していきたいと思います。
アイコンボタンを取得する
今回のプロジェクトではUIフレームワークにVuetifyを使っており、マテリアルアイコンのみを使ったボタンもあります。
そういったボタンはtext等で要素の取得が出来ないため、aria-label
を適用することで見つけられるようになります。
<template>
<v-btn icon aria-label="close">
<v-icon size="18px">mdi-close</v-icon>
</v-btn>
</template>
...
...
Default.play = async () = {
const closeButton = await screen.findByRole('button', { hidden: true, name: /close/i })
...
}
おわりに
Nuxt3も控えているのでもっと安定するかと思いますが、現状でもこれだけの対応でStorybookを活用してテストを書いていくことが出来ます。
より良い方法等あれば教えていただけると嬉しいです。
また何かあれば追記していきたいと思います。