Reactのバージョンを16に上げるのに伴いEnzymeのバージョンを3にしたら、一部のテストが壊れた。
調べたところ、v3からshallow
の挙動が変わったことが原因だった。
https://github.com/airbnb/enzyme/blob/master/docs/guides/migration-from-2-to-3.md#lifecycle-methods
v2では、明示的に呼び出さない限りcomponentDidMount
やcomponentDidUpdate
は実行されないが、v3ではshallow
すると明示しなくても実行される。
v2の挙動
2.9.1
で、挙動を確認してみる。
まず、テストの対象となるFoo
コンポーネントを作成した。
import React from 'react'; export default class Foo extends React.Component { constructor() { super(); this.count = 0; this.history = []; } componentWillMount() { this.count = this.count + 1; this.history.push('componentWillMount'); } componentDidMount() { this.count = this.count + 1; this.history.push('componentDidMount'); } render() { this.count = this.count + 1; this.history.push('render'); return <div>foo</div>; } }
各メソッドが呼ばれる度にcount
が増え、呼ばれたメソッドの名前がhistory
に追加されていく。
そのテストコードが以下。
import assert from 'assert'; import React from 'react'; import {shallow} from 'enzyme'; import Foo from '../Foo'; describe('Foo', () => { it('Lifecycle', () => { const wrapper = shallow(<Foo />); assert(wrapper.instance().count === 2); assert(wrapper.instance().history.length === 2); assert(wrapper.instance().history[0] === 'componentWillMount'); assert(wrapper.instance().history[1] === 'render'); wrapper.instance().componentDidMount(); assert(wrapper.instance().count === 3); assert(wrapper.instance().history[2] === 'componentDidMount'); }); });
shallow
した段階では、メソッドが2回呼ばれている。
まずcomponentWillMount
、そしてrender
。
componentDidMount
は、明示的に呼び出さない限り実行されない。
v3の挙動
続いて、3.2.0
での挙動を見てみる。
ちなみにv3からは、アダプターの設定が必要になる。
// テストのための設定ファイル import Enzyme from 'enzyme'; import Adapter from 'enzyme-adapter-react-15'; Enzyme.configure({adapter: new Adapter()});
v3で先程のテストを実行すると失敗する。
次のように書き換えることで、パスするようになる。
describe('Foo', () => { it('Lifecycle', () => { const wrapper = shallow(<Foo />); assert(wrapper.instance().count === 3); assert(wrapper.instance().history.length === 3); assert(wrapper.instance().history[0] === 'componentWillMount'); assert(wrapper.instance().history[1] === 'render'); assert(wrapper.instance().history[2] === 'componentDidMount'); wrapper.instance().componentDidMount(); assert(wrapper.instance().count === 4); assert(wrapper.instance().history[3] === 'componentDidMount'); }); });
shallow
の時点でcomponentDidMount
が呼びされており、wrapper.instance().componentDidMount();
とするとさらにもう一度呼ばれていることが分かる。
対策
v2と同じ挙動にしたい場合、shallow
を次のように書けばいい。
const wrapper = shallow(<Foo />, {disableLifecycleMethods: true});
テスト全体に適用させたい場合は、テストの設定ファイルなどに{disableLifecycleMethods: true}
を書けばいい。
つまり、こうなる。
Enzyme.configure({adapter: new Adapter(), disableLifecycleMethods: true});