Pathee engineering blog

世界をしなやかに変えるエンジニアたちのブログ

styled-componentsで作ったコンポーネントをjest + enzymeでテストする時は dive() を使う

Pathee エンジニアの keisei1092 です。

styled-componentsで作ったコンポーネントをはさんだコンポーネントをテストする時のやり方に若干戸惑いました。

次のように Wrapper というstyled-componentsで定義されたコンポーネントに囲まれた Test コンポーネントがあるとします。

import React from 'react';
import { pure } from 'recompose';
import styled from 'styled-components';

const Wrapper = styled.div`
  display: flex;
  align-items: center;
`; // ... 何かスタイルを定義

export type Props = {
  title: string;
};

export const Test = ({ title }: Props) => (
  <Wrapper>
    <h1>{title}</h1>
  </Wrapper>
);

export default pure(Test);

このとき、 props.title に渡した値が正しくレンダリングされることをテストしたいとします。あまり深く考えず次のようなテストコードを書いてみます。

import React from 'react';
import { shallow } from 'enzyme';

import Test, { Props } from '@app/components/Test';

describe('<Test>', () => {
  let props: Props;

  beforeEach(() => {
    props = {
      title: 'title'
    };
  });

  describe('rendering', () => {
    it('should render title', () => {
      const wrapper = shallow(<Test {...props} />);

      const h1 = wrapper.find('h1');
      expect(h1.text()).toEqual(props.title);
    });
  });
});

これを実行すると

Method “text” is meant to be run on 1 node. 0 found instead.

とエラーが出てテストにfailします。

shallowで <Test />レンダリングしているところをデバッグしてみます。

console.log test/components/CollectionRegister/SRHeader/test.spec.tsx:20
    <Component title="title" />

Wrapperレンダリングされていることはわかります( Component という表示で Wrapper と実際の名前は出ていない)が、その先の <h1> 以降がレンダリングされていないようです。ここで、enzymeの dive() を使います。

describe('rendering', () => {
  it('should render title', () => {
    const wrapper = shallow(<Test {...props} />);

    const h1 = wrapper.dive().find('h1'); // changed
    expect(h1.text()).toEqual(props.title);
  });
});

これを実行してみます。

PASS  test/components/test.spec.tsx
  <Test>
    rendering
      ✓ should render title (18ms)

Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   0 total
Time:        2.945s, estimated 3s
Ran all test suites matching /test\/components\/test.spec.tsx/i.
✨  Done in 4.01s.

無事テストがパスしました。

ちなみに先ほどのコンポーネントconsole.log(wrapper.dive().debug());デバッグすると次のように出力されます。

console.log test/components/test.spec.tsx:20
  <styled.div>
    <h1>
      title
    </h1>
    &gt;
  </styled.div>

<Test />レンダリングしているコンポーネントが正しく出力されています。

styled-components jest enzyme test などで検索しましたが英語のページばかりで日本語のページが見つけられなかったので逆引きとして使えるように書いてみました。
英語の習熟の大事さをひしひしと感じます。