web-dev-qa-db-ja.com

componentDidUpdate()をテストする方法は?

これは実装例です:

export class Person extends Component {
  componentDidMount() {
    const { onLoadProfile, onLoadPolicy, person } = this.props
    onLoadProfile(person.profile.uri)
    onLoadPolicy(person.policy.uri)
  }

  componentDidUpdate(prevProps) {
    const { onLoadProfile, onLoadPolicy, person } = this.props
    const prevPerson = prevProps.person.uri
    const curPerson = person.uri

    // If person has changed, update Person component
    if (prevPerson !== curPerson) {
      onLoadProfile(person.profile.uri)
      onLoadPolicy(person.policy.uri)
    }
  }
}

componentDidMount()で、次のようにテストできました。

describe('<Person />', () => {
  let props
  let mountedPerson
  const mockLoadProfile = jest.fn()
  const mockLoadPolicy = jest.fn()

  const person = () => {
    if (!mountedPerson) {
      mountedPerson = mount(<Person {...props} />)
    } 
    return mountedPerson
  }

  beforeEach(() => {
    props = {
      onLoadProfile = mockLoadProfile,
      onLoadPolicy = mockLoadPolicy
    }
    mountedPerson = undefined
  })

  afterEach(() => {
    mockLoadProfile.mockClear()
    mockLoadPolicy.mockClear()
  })

  describe('componentDidMount', () => {
    it('loads profile', () => {
      person().instance().componentDidMount()
      expect(mockLoadProfile).toBeCalled()
    })

    it('loads policy', () => {
      person().instance().componentDidMount()
      expect(mockLoadPolicy).toBeCalled()
    })
  })
})

componentDidUpdate()では、コンポーネントが必要に応じて更新されるかどうかを確認するために、コンポーネントがrender()を2回試行する必要がありますが、その逆も同様です。

ReactでcomponentDidUpdate()メソッドをテストする正しいアプローチは何ですか?

PS .: jestenzymeおよびReact 15を使用しています。

別のアプローチを使用していますが、アイデアをコピーできます。小道具を変更する必要があります。私はsetProps()関数を使用しました:

describe('componentDidUpdate', () => {
    it('loads profile', () => { 
        const wrapper = shallow(<Person  {...props} />) as any;
        wrapper.setProps({ person: { uri: "something_different" } });
        expect(wrapper.instance().props.onLoadProfile).toBeCalled();
    })
})

カバレッジテストページのピンクは、テストの実行後にcomponentDidUpdateで消えていることがわかります。

26
Bonomi

受け入れられた答えは、上記のケースをテストする最も簡単な方法ですが、次のようにコンポーネントからcomponentDidUpdateロジックを抽出するソリューションと考えることもできます。

// Component definition
export class Person extends Component {
  componentDidUpdate(prevProps) {
    this.props.handleComponentDidUpdate(prevProps, this.currentProps)
  }
  // Rest of component
}

// Component functions/handlers testing
describe('Person component props', () => {
  describe('handleComponentDidUpdate', () => {
    it('loads profile & policy if person changes', () => {
      const onLoadPolicy = jest.fn()
      const onLoadProfile = jest.fn()
      const prevProps = {
        person: { uri: 'some-person-uri-old' },
        policy: { uri: 'some-policy-uri' },
        profile: { uri: 'some-profile-uri' },
        onLoadPolicy,
        onLoadProfile
      }
      const props = {
        person: { uri: 'some-person-uri-new' }, // person uri changes
        policy: { uri: 'some-policy-uri' },
        profile: { uri: 'some-profile-uri' },
        onLoadPolicy,
        onLoadProfile
      }

      handleComponentDidUpdate(prevProps, props)

      expect(onLoadPolicy).toHaveBeenCalled()
      expect(onLoadProfile).toHaveBeenCalled()
    })
  })
})

このように、コンポーネントは、アプリケーションロジックをより簡単にテストできる関数/ハンドラーに抽出できるのと同じくらい愚かである可能性があります。この方法により、テストをより機能に集中させることができ(テストしやすくなります)、コンポーネントに重点を置くことができなくなります(テストが難しくなります)。

Personコンポーネントの使用に関しては、handleComponentDidUpdateを含む必要な小道具を提供するだけです。

それでもコンポーネントをテストする必要がある場合は、次の簡単なテストを実行できます(このテストでは、上記の関数/ハンドラーテストとは異なり、アプリのロジック(人、プロファイル、ポリシーなど)は気にしません)。

// Component testing
describe('<Person/>', () => {
  it('should call handleComponentDidUpdate on prop change', () => {
    const handleComponentDidUpdate = jest.fn()
    const prevProps = {
      someProp: 'some-prop-prev',
      handleComponentDidUpdate
    }
    const newprops = {
      someProp: 'some-prop-new',
      handleComponentDidUpdate
    }

    const wrapper = shallow(<Person { ...prevProps } />)
    wrapper.setProps(newprops)

    expect(handleComponentDidUpdate).toHaveBeenCalledWith(prevProps, newProps)
  })
})
1
Imran Ariffin