Enzyme
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
は、react
とreact-dom
にピア依存関係があります。
現時点では、Enzymeには、React 16.x
、React 15.x
、React 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のドキュメントと例ではmochaとchaiを使用していますが、選択したフレームワークに外挿できるはずです。
Reactコンポーネントをテストするためのカスタムアサーションと便利な関数を使用してenzymeを使用することに興味がある場合は、次の使用を検討できます。
- Mocha / Chaiで
chai-enzyme
を使用する。 - Jasmineで
jasmine-enzyme
を使用する。 - Jestで
jest-enzyme
を使用する。 - should.jsで
should-enzyme
を使用する。 - expectで
expect-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のシャローレンダラーでは呼び出されません。関連する issueuseCallback()
は、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
を使用している組織やプロジェクトは、こちらにリストできます。