web-dev-qa-db-ja.com

酵素はReact Material-UI v1の変更イベントをシミュレートしていません-コンポーネントを選択してください

そこで、ユニットテストを開始しましたReactコンポーネント。これまでのところ、Material-UIからのSelectコンポーネントに遭遇するまで、すべてのイベントシミュレーションは正常に機能していました。(詳細未満)

プロジェクトはcreate-react-appを使用してブートストラップされ、material-ui-nextを利用しました。

依存関係バージョン

  • 反応:16.2.0
  • リアクトドーム:16.2.0
  • React-Scripts:1.1.1
  • マテリアルUI:1.0.0-beta.35
  • Jest:セットアップに同梱されているもの(22.4.3)
  • 酵素:3.3.0
  • 酵素アダプターReact 16:1.1.1

問題

Material-UIフォームフィールドで構成されるFiltersDesktopという名前の純粋な機能コンポーネントがあります。そのうちの3つはSelectコンポーネントで、その他はmaterial-uiのテキストフィールドと日付ピッカーです。

UIコード

<Collapse in={props.visible} className={'filters-container-desk'}>
  <Grid container classes={{ typeContainer: "filter-container" }} id={'container-desk'}>

    <Grid item lg={2} xl={2}>
      <FormControl fullWidth={true}>
        <InputLabel htmlFor="sources">Sources</InputLabel>
        <Select
          open
          inputProps={{ name: 'sources-desk', id: 'sources-desk' }}
          value={props.filters.source || ''}
          onChange={(event) => props.updateFilter({ source: event.target.value })}
        >
          <MenuItem value=''>
            <em>None</em>
          </MenuItem>
          <MenuItem value={10}>Ten</MenuItem>
          <MenuItem value={20}>Twenty</MenuItem>
          <MenuItem value={30}>Thirty</MenuItem>
        </Select>
      </FormControl>
    </Grid>

    <Grid item lg={2} xl={2}>
    ...
    </Grid>
    ... // More Grid components of similar structure as above
  </Grid>
</Collapse>

テキストフィールドコンポーネントの変更イベントをシミュレートしようとすると、正常に動作します。以下は、テキストフィールドをテストするために私が書いたコードです。

TextFieldのテストコード

const props = {
  updateFilter: jest.fn()
};

test(`updateFilter should get called on simulating text changes in domain`, () => {
  const component = mount(<FiltersDesktop {...this.props} />);
  component.find('#domain-desk').last().simulate('change', { target: { value: 'scoopwhoop.com' } });
  expect(props.updateFilter).toHaveBeenCalled();
});

しかし、同様のものがSelectコンポーネントでは機能しません。ただし、インターフェイスを介して実際に選択フィールドを操作すると、更新関数が呼び出されます。以下は、Selectをテストするために記述したテストコードです。

Selectのテストコード

const props = {
  updateFilter: jest.fn()
};

test(`updateFilter should get called on simulating text changes in sources`, () => {
  const component = mount(<FiltersDesktop {...this.props} />);

  // Did not work
  component.find('#sources-desk').last().simulate('change', { target: { value: 20 } });

  // Did not work
  component.find('Select').first().simulate('change', { taget: { value: 20 } });

  // Did not work
  component.find('#sources-desk').forEach(element => element.simulate('change', { taget: { value: 20 } }))

  expect(props.updateFilter).toHaveBeenCalled();
});

何らかの理由で、findメソッドは常に上記のすべてのケースで1つ以上の要素を返したため、適切なケースでは、first、last、forEachを使用することにしました。

変更イベントのシミュレーション時にSelectコンポーネントでトリガーされない理由を理解してください。

JestとEnzymeのソリューションとテストガイドを実装するために、少なくとも1週間Githubで問題を読んでいるので安心してください。残りのケースは問題なく動作しているので、テスト設定は問題ないと確信しています。

ソースコードを正確に確認する場合は、 here がリポジトリへのリンクです。リポジトリのプルリクエストも歓迎します。リポジトリを使用している場合は、react-materialブランチに切り替えることを忘れないでください。

PS-私は最近React:Pで始めたばかりなので笑わないでください

5
Himanshu Singh

私はあなたのブランチを複製してテストを行いましたが、何か興味深いことに気づきました:シミュレーションメソッドは、ShallowWrapperとReactWrapperで異なる動作をします。つまり、浅い場合とマウントを使用する場合のシミュレーションの動作は異なります。

まず、この質問を見てください: 酵素でレンダーとシャローを使用する場合/ Reactテスト?

この種類のテストに最も適しているのは、このコンポーネントをユニットとしてテストするため、mount()ではなく、shallow()にすることです。

mountを使用したテスト:

test("updateFilter should get called on simulating text changes in sources", () => {
  const component = mount(<FiltersDesktop {...props} />);

  component
    .find(Select)
    .at(0)
    .props()
    .onChange({ target: { value: 20 } });

  expect(props.updateFilter).toHaveBeenCalled();
});

シャローを使用したテスト:

test("updateFilter should get called on simulating text changes in sources", () => {
  const wrapper = shallow(<FiltersDesktop {...props} />);
  wrapper
    .find(Select)
    .at(0)
    .simulate("change", { target: { value: 20 } });

  expect(props.updateFilter).toHaveBeenCalled();
});

ご覧のとおり、shallowを使用した2番目のアプローチでは、変数ラッパーを呼び出しました。これは、コンポーネントではなくコンポーネントへのラッパーであるためです。さらに、mountを使用した最初のアプローチでは、onChangeを呼び出したときにのみテストが機能することがわかります。小道具を介して、直接。

23
Fabio Miranda