Storyshotsでjest-emotion使おうとして諦めた話

StorybookとStoryshotsでDOM構造のデグレチェックをするようになってから、 一部ライブラリの差分が余計なので無視したかったけど諦めた話です。

環境

  • React
  • Stylus
  • Storybook
  • Storyshots

無視したい差分について

  • [React Select](https://react-select.com/home、CSS in JSを利用しているとクラス名がランダムに設定される

    • それをStoryshotsが差分として検知してエラーになってしまうのを解決したかった
-  className="css-1upmc5x aSelect__field__control aSelect__field__control--is-disabled"
+  className="css-kki4vb aSelect__field__control aSelect__field__control--is-disabled"

他にもidに連番がくっついたようなid名がついてることもあり、それもなにかの拍子で連番が変わってて差分になったりしました。

jest-emotion

React Selectがemotion(JSでCSSを記述するためのライブラリ)を使っているので emotion側を調べてみたらドキュメントがありました。

Emotion / Snapshot Testing

jest-emotionというJest用のプラグインがあるということで試してみましたがだめでした。

Jest Snapshot Serializerの話

jest-emotionの中身を見てみると、Jest Snapshot Serializerをカスタマイズしてました。

Serializerの中身はこのブログにまとまっていて、ざっくりいうと

  • カスタマイズしたSerializerをJestに設定する

    • expect.addSnapshotSerializer を呼ぶ
    • jest.config.js で設定する
// https://github.com/emotion-js/emotion/tree/master/packages/jest-emotion より
// jest.config.js
module.exports = {
  // ... other config
  snapshotSerializers: ['jest-emotion']
}
  • Serializerはtestメソッドとprintメソッドを返すようにする

    • test: Serializerを有効にするかどうか判断する関数
    • print: Snapshotを整形しつつ出力する関数

そして、jest-emotionのtestメソッドでは、受け取ったvalueがReactElementかどうかをチェックしていました

// https://github.com/emotion-js/emotion/blob/master/packages/jest-emotion/src/index.js#L102
  function test(val: *) {
    return (
      val &&
      ((!cache.has(val) &&
        (isReactElement(val) || (DOMElements && isDOMElement(val)))) ||
        isEmotionCssPropEnzymeElement(val) ||
        isEmotionCssPropElementType(val))
    )
  }

isReactElementは以下のようになってます。

// https://github.com/emotion-js/emotion/blob/master/packages/jest-emotion/src/utils.js#L43
export function isReactElement(val: any): boolean {
  return val.$$typeof === Symbol.for('react.test.json')
}

この $$typeof は、React Elementが必須にしているフィールドらしいです。
参考: なぜ Reactではelement.$typeofをチェックしてるのか | colla.me

そしてStorybookで react-test-renderer を利用してレンダリングしていることにより、 上記の $$typeof が付与されなくて、jest-emotionのtestで弾かれててjest-emotionがStoryshotsに使えなさそうでした。

あきらめた

  • 特定の設定でReact Selectをstorybookでレンダリングしないように他の人が対応してくれた
  • Serializerを自作するのが面倒かなと思ってしまった
  • StylusからCSS in JSなフレームワーク・ライブラリに移行したときに再チャレンジしたい

という気持ちです。