kenju's blog

About Programming, Mathematics, Security and Blockchain

Enzyme First Impession as React.js Components Testing Tool

tl;dr

  • 擬似DOM環境を必要としない、ミニマルなShallow Renderingテストが広く使われているが、Shallow Renderingを使うくらいならJestのSnapshot Testingの方がコスパが良い
  • Full DOM Rendering 環境では、JSDOMを用いた疑似ブラウザ環境を前提としており、比較的本番環境に近い動作環境でテストできる

Shallow Rendering/Full DOM Rendering の違い

Shallow Rendering の限界

まず、Shallow Rendering は

  • 特定のコンポーネントしか描画しない
  • 複数のコンポーネントを跨いだイベント操作などには関与しない(興味もない)
  • したがって、スペックが手軽になるぶん、テストできる範囲も限られる

という特徴があります。なので、APIやあらゆるサンプルコードを見ても

  • props で渡したデータが特定のDOM構造で描画されている
  • 単体のイベント操作によって特定の表示内容が変化している
  • state を手動で変化した時に表示内容が変化している

といったことしかテストできません。なので、カバレッジは上がりますが、

  • 限られている時間的リソースは、エディターなどの重要なコンポーネント周りのテストに注ぎたい
  • 頻繁にデザインが変わりうる場面において、statelessなコンポーネントのDOM構造などを細かくテストしても意味がない

「他の箇所の変更によって他のコンポーネントの表示内容にデグレがない」ことを保証したいのだったら、細かくmatcherなどを使ってShallow Rendering した結果をテストするより、JestのSnapshot Testing を使った方が効率的な気がしています。

Shallow Rendering の実装概要

EnzymeのShallow Rendering は、React本体の TestUtils モジュールが提供するAPIのラッパーにすぎません。

facebook.github.io

shallow() で生成したコンポーネントは、内部的には shallow:: node -> ShallowWrapper クラスのインスタンスとして扱われます。

Enzyme APIには、この ShallowWrapper のインスタンスに対するもの、DOM Elementに対するものが混在しているので、注意が必要です。

dive() について

Shallow Rendering は dive() というメソッドを提供しています。これは、一旦Shallow RenderしたコンポーネントのDOM Treeを辿って行って、子のReact Componentをmanipulateできるようにするためのヘルパーメソッドです。

このメソッドを使うと、例えば以下のようなコンポーネントの時、wrapper = shallow(EditorContainer); const editorWrapper = wrapper.dive().dive(); のように使うことができます。

render() {
  return(
    <Container>
     ...
    <div>
      <SomeComponent/>
    </div>
    ...
  </Container>
)};

しかし、dive() メソッドは内部的には Shallow Rendered されたコンポーネントを生み出しているにすぎない ので、疑似ブラウザ環境でこのコンポーネントを動かした時と全く挙動は異なるわけです。

ブラウザ環境と同じ KeyboardEvent をテストしたい、と行った時にはこの方法では限界があるので、そこは注意が必要です。 その場合、Full DOM Renderingを使うことになるでしょう。