StoryBookでビジュアルリグレッションテストしたいときの構成。
前のはURL単位にテストファイルを作っていたのですが、一括で全URL対象にした方が楽。
storyshotsを使うかscreencapを使うか。
両方やってみてscreencapを使うようにしたのでその辺の話。
StoryShots
GitHubのReadmeを見れば導入はそのままでOK。
で、実際に使う時に設定したこと。
除外したいstoryの指定
実際のコンポーネントを考えると、ずっとアニメーションしてるものの場合、同じスクリーンショットとるとか不可能なので、テストを外したい。Readmeにも書いてあるけどその場合は↓。
import initStoryshots from '@storybook/addon-storyshots'; initStoryshots({ storyKindRegex:/^((?!.*?DontTest).)*$/ });
スナップショット取る前にちょっと待機させたい場合
開いた瞬間アニメーションしてるやつが落ち着くまで待機させたい場合。
import initStoryshots from '@storybook/addon-storyshots' import { imageSnapshot } from '@storybook/addon-storyshots-puppeteer' const beforeScreenshot = (page, { context: { kind, story }, url }) => { return new Promise( (resolve) => setTimeout(() => { resolve() }, 1000) // waitのミリ秒 ) } initStoryshots({ suite: 'Image', storyKindRegex: /^(?!.*?nvis).*$/, test: imageSnapshot({ storybookUrl: 'http://localhost:9009', beforeScreenshot, }), })
で、見逃してるだけのような気もするのですが、story毎に待機時間を決められないように思うので、待機時間つけちゃうと全部遅くなっちゃう。。。
あと、除外する名前の正規表現ってURLのところになってると思うのですが、どうにも上手くいかない。名称の見方がなんか違うっぽい。どう書けばいいんだろうか。正規表現的に色々試してみたのですが、どうもやりたい事が出来ない。
StoryCap
で、StoryShotsの代わりにこれを使うようにした。スターの数だと圧倒的にStoryShotsなんだけど、
こっちの方が望む結果にすぐたどり着いたので。導入もすごく楽。
動き的にHTMLの変化を監視して、画面のアニメーションが落ち着くのを待ってからスクリーンショットを撮ってるぽい。賢い。
もちろんずっとアニメーションしてるコンポーネントは↑のWaitのタイムアウトでエラーになるけど。
で、そういうコンポーネントを除外したい場合は↓の感じで実行コマンドに渡す。
storycap http://localhost:9009 -e "**/DontTest/**"
ルールとしてstorybookに表示されるサブディレクトリの階層で、DontTestとか階層を作って、テスト除外したい奴はそこに配置する感じ。ちょっとカッコ悪いけど、urlをminimatchしてるのかな?
ディレクトリ階層で切り分けないとうまくいかなかった。
ただし、StoryCapはスクリーンショットを撮るだけでテストまでは入ってないので、
そこは自分で書いておかないとダメ。ロードマップ見ると将来的には対応してくれるようす。
テストは↓の感じで書けばよいのではないかと。
const fs = require('fs') function getFiles(dir, files_) { files_ = files_ || [] const files = fs.readdirSync(dir) for (const i in files) { const name = dir + '/' + files[i] if (fs.statSync(name).isDirectory()) { getFiles(name, files_) } else { files_.push(name) } } return files_ } const files = getFiles('storycapで画像が出来るディレクトリ') describe.each(files)('ビジュアルテスト', (filepath) => { test(`file: ${filepath}`, () => { const data = fs.readFileSync(filepath) expect(data).toMatchImageSnapshot({ customSnapshotsDir: 'テスト用のスナップショット周りが出来るディレクトリ', failureThreshold: 0.10, failureThresholdType: 'percent', }) }) })