Enzyme

Join the chat at https://gitter.im/enzymejs/enzyme

npm Version License Build Status Coverage Status

Enzymeは、Reactコンポーネントの出力をより簡単にテストできるようにするReact用のJavaScriptテストユーティリティです。出力に基づいて、操作、トラバース、そしてある程度はランタイムのシミュレーションを行うこともできます。

EnzymeのAPIは、DOM操作とトラバースのためのjQueryのAPIを模倣することで、直感的で柔軟なものになるように設計されています。

Enzyme 2.xまたはReact < 16からのアップグレード

EnzymeがReact 16と互換性があるかどうかを確認するためにここに来ましたか?現在Enzyme 2.xを使用していますか?素晴らしい!React 16がサポートされているEnzyme v3に移行するための移行ガイドをご覧ください。

インストール

enzymeを使い始めるには、npm経由でインストールするだけです。使用しているReact(または他のUIコンポーネントライブラリ)のバージョンに対応するアダプターと一緒にenzymeをインストールする必要があります。たとえば、React 16でenzymeを使用している場合は、次を実行できます。

npm i --save-dev enzyme enzyme-adapter-react-16

各アダプターには、追加のピア依存関係があり、それもインストールする必要があります。たとえば、enzyme-adapter-react-16は、reactreact-domにピア依存関係があります。

現時点では、Enzymeには、React 16.xReact 15.xReact 0.14.x、およびReact 0.13.xとの互換性を提供するアダプターがあります。

次のアダプターは、enzymeによって公式に提供されており、Reactとの互換性は次のとおりです。

Enzymeアダプターパッケージ Reactセマンティックバージョン互換性
enzyme-adapter-react-16 ^16.4.0-0
enzyme-adapter-react-16.3 ~16.3.0-0
enzyme-adapter-react-16.2 ~16.2
enzyme-adapter-react-16.1 `~16.0.0-0 \ \ ~16.1`
enzyme-adapter-react-15 ^15.5.0
enzyme-adapter-react-15.4 15.0.0-0 - 15.4.x
enzyme-adapter-react-14 ^0.14.0
enzyme-adapter-react-13 ^0.13.0

最後に、使用するアダプターを使用するようにenzymeを設定する必要があります。これを行うには、トップレベルのconfigure(...) APIを使用できます。

import Enzyme from 'enzyme';
import Adapter from 'enzyme-adapter-react-16';

Enzyme.configure({ adapter: new Adapter() });

サードパーティ製アダプター

コミュニティが、enzymeを他のライブラリで動作させるための追加の(非公式の)アダプターを作成することは可能です。作成したものが以下のリストに含まれていない場合は、このREADMEにPRを作成してリンクを追加してください。既知のサードパーティ製アダプターは次のとおりです。

アダプターパッケージ ライブラリ ステータス
enzyme-adapter-preact-pure preact (安定)
enzyme-adapter-inferno inferno (開発中)

Enzymeテストの実行

Enzymeは、使用するテストランナーまたはアサーションライブラリに関して、独自の意見を持たず、すべての主要なテストランナーおよびアサーションライブラリと互換性があるはずです。 enzymeのドキュメントと例ではmochachaiを使用していますが、選択したフレームワークに外挿できるはずです。

Reactコンポーネントをテストするためのカスタムアサーションと便利な関数を使用してenzymeを使用することに興味がある場合は、次の使用を検討できます。

MochaでのEnzymeの使用

KarmaでのEnzymeの使用

BrowserifyでのEnzymeの使用

SystemJSでのEnzymeの使用

WebpackでのEnzymeの使用

JSDOMでのEnzymeの使用

React NativeでのEnzymeの使用

JestでのEnzymeの使用

LabでのEnzymeの使用

TapeとAVAでのEnzymeの使用

基本的な使い方

シャローレンダリング

import React from 'react';
import { expect } from 'chai';
import { shallow } from 'enzyme';
import sinon from 'sinon';

import MyComponent from './MyComponent';
import Foo from './Foo';

describe('<MyComponent />', () => {
  it('renders three <Foo /> components', () => {
    const wrapper = shallow(<MyComponent />);
    expect(wrapper.find(Foo)).to.have.lengthOf(3);
  });

  it('renders an `.icon-star`', () => {
    const wrapper = shallow(<MyComponent />);
    expect(wrapper.find('.icon-star')).to.have.lengthOf(1);
  });

  it('renders children when passed in', () => {
    const wrapper = shallow((
      <MyComponent>
        <div className="unique" />
      </MyComponent>
    ));
    expect(wrapper.contains(<div className="unique" />)).to.equal(true);
  });

  it('simulates click events', () => {
    const onButtonClick = sinon.spy();
    const wrapper = shallow(<Foo onButtonClick={onButtonClick} />);
    wrapper.find('button').simulate('click');
    expect(onButtonClick).to.have.property('callCount', 1);
  });
});

APIドキュメント全文を読む

フルDOMレンダリング

import React from 'react';
import sinon from 'sinon';
import { expect } from 'chai';
import { mount } from 'enzyme';

import Foo from './Foo';

describe('<Foo />', () => {
  it('allows us to set props', () => {
    const wrapper = mount(<Foo bar="baz" />);
    expect(wrapper.props().bar).to.equal('baz');
    wrapper.setProps({ bar: 'foo' });
    expect(wrapper.props().bar).to.equal('foo');
  });

  it('simulates click events', () => {
    const onButtonClick = sinon.spy();
    const wrapper = mount((
      <Foo onButtonClick={onButtonClick} />
    ));
    wrapper.find('button').simulate('click');
    expect(onButtonClick).to.have.property('callCount', 1);
  });

  it('calls componentDidMount', () => {
    sinon.spy(Foo.prototype, 'componentDidMount');
    const wrapper = mount(<Foo />);
    expect(Foo.prototype.componentDidMount).to.have.property('callCount', 1);
    Foo.prototype.componentDidMount.restore();
  });
});

APIドキュメント全文を読む

静的レンダリングされたマークアップ

import React from 'react';
import { expect } from 'chai';
import { render } from 'enzyme';

import Foo from './Foo';

describe('<Foo />', () => {
  it('renders three `.foo-bar`s', () => {
    const wrapper = render(<Foo />);
    expect(wrapper.find('.foo-bar')).to.have.lengthOf(3);
  });

  it('renders the title', () => {
    const wrapper = render(<Foo title="unique" />);
    expect(wrapper.text()).to.contain('unique');
  });
});

APIドキュメント全文を読む

React Hooksのサポート

Enzymeは、Reactのシャローレンダラーの上流の問題により、.shallow()にいくつかの制限がありますが、react hooksをサポートしています。

  • useEffect()useLayoutEffect()は、Reactのシャローレンダラーでは呼び出されません。関連する issue

  • useCallback()は、Reactのシャローレンダラーでコールバックをメモ化しません。関連する issue

ReactTestUtils.act() ラップ

React 16.8+と.mount()を使用している場合、Enzymeは.simulate().setProps().setContext().invoke()などのAPIをReactTestUtils.act()でラップするため、手動でラップする必要はありません。

.act()でハンドラーをトリガーし、アサートするための一般的なパターンは次のとおりです。

const wrapper = mount(<SomeComponent />);
act(() => wrapper.prop('handler')());
wrapper.update();
expect(/* ... */);

Enzyme内部では、返される値の等価性が壊れてしまうため、.prop()(または.props())の結果を.act()でラップすることはできません。ただし、.invoke()を使用してコードを簡略化できます。

const wrapper = mount(<SomeComponent />);
wrapper.invoke('handler')();
expect(/* ... */);

今後の展望

Enzymeの今後

貢献

貢献者ガイドを参照してください。

活用事例

enzymeを使用している組織やプロジェクトは、こちらにリストできます。

ライセンス

MIT