久しぶりに Enzyme
を使った際に、 Shallow Rendering と Full DOM Rendering の挙動の違いで少々ハマった。過去にもつまづいた事例であったため、覚え書きとして書き残す。
コード
Country.tsx
import React from 'react';
interface IProps {
className: string;
greeting: string;
}
class Country extends React.Component<IProps, {}> {
public constructor(props: any) {
super(props);
}
public render() {
return (
<div>
<span className={this.props.className}>{this.props.greeting}</span>
</div>
);
}
}
export default Country;
Country.test.tsx
import { configure, shallow, ShallowWrapper, mount, ReactWrapper } from 'enzyme';
import Adapter from 'enzyme-adapter-react-16';
import React from 'react';
import Country from '../Country';
configure({ adapter: new Adapter() });
const countryShallow: ShallowWrapper = shallow(<Country
className="France"
greeting="Bonjour"
/>);
const countryMount: ReactWrapper = mount(<Country
className="France"
greeting="Bonjour"
/>);
it('Works', () => {
expect(countryShallow.find('.France').render().text()).toBe("Bonjour");
});
it('FAILS', () => {
expect(countryMount.find('.France').render().text()).toBe("Bonjour");
console.log(countryMount.debug());
});
console.log(countryShallow.debug(), "\n");
console.log(countryMount.debug());
コード解説
Country
オブジェクトをレンダリングする際、子ノードにクラス名を指定したく、プロパティ className
を設定した。
再現
Full DOM Rendering したノードを探索するため、リファレンスに沿って Shallow Rendering と同様に find()
を使った。ノードが1つだけ発見されることを期待したが、2つ発見されたためエラーとなった。
● FAILS
Method “html” is meant to be run on 1 node. 2 found instead.
19 |
20 | it('FAILS', () => {
> 21 | expect(countryMount.find('.France').render().text()).toBe("Bonjour");
| ^
22 | console.log(countryMount.debug());
23 | });
24 |
原因
Shallow Rendering は、単純に render()
が返すノードをレンダリングする。他方の Full DOM Rendering では、まず仮想ノードがレンダリングされ、その配下に render()
が返すノードがレンダリングされる。
console.log src/__tests__/App.test.tsx:25
<div>
<span className="France">
Bonjour
</span>
</div>
console.log src/__tests__/App.test.tsx:26
<Country className="France" greeting="Bonjour">
<div>
<span className="France">
Bonjour
</span>
</div>
</Country>
このため、Full DOM Rendering では同じクラス名が2つ存在し find()
が複数のDOM要素を検出するため、後続の render()
の実行に失敗した。
対策
実ノードのみを得たい場合は hostNode()
を用いる。この例では find()
が検出したDOM要素の中から実ノードのみを返すことで結果的に単一ノードが得られ、後続の render()
が正常に実行される。
Country.test.tsx
it('FAILS', () => {
- expect(countryMount.find('.France').render().text()).toBe("Bonjour");
+ expect(countryMount.find('.France').hostNodes().render().text()).toBe("Bonjour");
console.log(countryMount.debug());
});