LoginSignup
5
1

More than 5 years have passed since last update.

Enzymeでfindを使った際に、仮想ノードと実ノードが検出される場合の対策

Last updated at Posted at 2019-01-19

久しぶりに 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());
});
5
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
1