web-dev-qa-db-ja.com

マテリアルUI +酵素テストコンポーネント

ReactにJestでテストしようとしているコンポーネントがありますが、残念ながらテストはパスしません。

コンポーネントコード:

import React, {Component} from 'react';
import ProductItem from '../ProductItem/ProductItem';
import AppBar from "@material-ui/core/es/AppBar/AppBar";
import Tabs from "@material-ui/core/es/Tabs/Tabs";
import Tab from "@material-ui/core/es/Tab/Tab";
import {connect} from 'react-redux';


class ProductsTabsWidget extends Component {

    state = {
        value: 0
    }

    renderTabs = () => {
        return this.props.tabs.map((item, index) => {
            return item.products.length > 0 ? (<Tab key={index} label={item.title}/>) : false;
        })
    }

    handleChange = (event, value) => {
        this.setState({value});
    };


    renderConentActiveTab = () => {
        if (this.props.tabs[this.state.value]) {
            return this.props.tabs[this.state.value].products.map((productIndex) => {
                return (<ProductItem key={productIndex} {...this.props.products[productIndex]} />);
            });
        }
    }

    render() {
        let tabs = null;
        let content = null;
        if (this.props.tabs) {
            tabs = this.renderTabs();
            content = this.renderConentActiveTab();
        }
        return (
            <div>
                <AppBar position="static" color="default">
                    <Tabs
                        value={this.state.value}
                        onChange={this.handleChange}
                        indicatorColor="primary"
                        textColor="primary"
                        centered
                        scrollButtons="auto"
                    >
                        {tabs}
                    </Tabs>
                </AppBar>
                <div className="productWidget">
                    <div className="wrapper">
                        {content}
                    </div>
                </div>
            </div>
        )
    }
}

const mapStateToProps = state => {
    return {
        products: state.product.products,
    }
}

export default connect(mapStateToProps)(ProductsTabsWidget);

このコンポーネントの適切なテストを作成しようとしましたが、コードは以下のとおりです。

import React from 'react';

import {configure, shallow} from 'enzyme';
import Adapter from 'enzyme-adapter-react-16';
import ProductsTabsWidget from "./ProductsTabsWidget";


configure({adapter: new Adapter()});

describe('ProductsTabsWidget - component', () => {
    let wrapper;


    beforeEach(() => {
        wrapper = shallow(<ProductsTabsWidget/>);
    });

    it('renders with minimum props without exploding', () => {
        wrapper.setProps({
            tabs: [],
            products:[]
        });
        expect(wrapper).toHaveLength(1);
    });
})

しかし、テストを実行しているときにエラーが発生します:

Test suite failed to run

    F:\PRACA\reactiveShop\node_modules\@material-ui\core\es\AppBar\AppBar.js:1
    ({"Object.<anonymous>":function(module,exports,require,__dirname,__filename,global,jest){import _extends from "@babel/runtime/helpers/builtin/extends";
                                                                                             ^^^^^^

    SyntaxError: Unexpected token import

      at new Script (vm.js:51:7)
      at Object.<anonymous> (src/components/product/ProductsTabsWidget/ProductsTabsWidget.js:3:15)

shallowmountrenderでテストしてみましたが、役に立ちませんでした。私は何が欠けていますか?

私のアプリケーションはcreate-react-appで作成されます。

10
DevQuayle

@material-uiを使用しているときは、何か違うものです。

@material-uiの組み込みAPIを使用する必要があります。 createMountcreateShallowcreateRenderなど、酵素のshallowmount、およびrenderを使用するため。

これらのAPIはenzymeの上に構築されるため、@material-uiをテストするためにenzymeを直接使用することはできません。


@ material-uiを使用したShallowレンダリングの例

import { createShallow } from '@material-ui/core/test-utils';

describe('<MyComponent />', () => {
  let shallow;

  before(() => {
    shallow = createShallow(); 
  });

  it('should work', () => {
    const wrapper = shallow(<MyComponent />);
  });
});

リファレンス: @ material-uiの公式ドキュメント

9
Ritwick Dey

以下は、_create-react-app_および_@material-ui_の観点からより完全な回答を提供するための謙虚な試みです。

_1._ srcフォルダーに_setupTests.js_を直接作成し、次のコードを貼り付けます。

_import { configure } from "enzyme";
import Adapter from "enzyme-adapter-react-16";

configure({ adapter: new Adapter() });
_

_2._以下は、_material-ui_コンポーネントを使用するリアクティブステートレスコンポーネントです。

_import React from "react";
import TextField from "@material-ui/core/TextField";

const SearchField = props => (
   <TextField InputProps={{ disableUnderline: true }} fullWidth
              placeholder={props.placeholder}
              onChange={props.onChange}
   />
);

export default SearchField;
_

上記のコンポーネントでは、コンポーネントは親コンポーネントがplaceholderおよびonChange()イベントハンドラーのプロパティを渡すことを期待していることに注意してください。

_3._上記のコンポーネントのテストケースに来ると、_material-ui_が示唆する方法で、または_pure enzyme_スタイルで書くことができます。両方とも機能します。

_Pure Enzyme_スタイル

_import React from "react";
import { mount } from "enzyme";
import TextField from "@material-ui/core/TextField";
import SearchField from "../SearchField";
describe("SearchField Enzyme mount() ", () => {
  const fieldProps = {
    placeholder: "A placeholder",
    onChange: jest.fn()
  };
  const Composition = props => {
    return <SearchField {...fieldProps} />;
  };

  it("renders a <TextField/> component with expected props", () => {
    const wrapper = mount(<Composition />);
    expect(wrapper.childAt(0).props().placeholder).toEqual("A placeholder");
    expect(wrapper.childAt(0).props().onChange).toBeDefined();
  });
  it("should trigger onChange on <SearchField/> on key press", () => {
    const wrapper = mount(<Composition />);
    wrapper.find("input").simulate("change");
    expect(fieldProps.onChange).toHaveBeenCalled();
  });
  it("should render <TextField />", () => {
    const wrapper = mount(<Composition />);
    expect(wrapper.find(TextField)).toHaveLength(1);
    expect(wrapper.find(TextField).props().InputProps.disableUnderline).toBe(
      true
    );
  });
});
_

_Material UI_スタイル

_import React from "react";
import { createMount } from "@material-ui/core/test-utils";
import TextField from "@material-ui/core/TextField";
import SearchField from "../SearchField";
describe("SearchField", () => {
  let mount;
  const fieldProps = {
    placeholder: "A placeholder",
    onChange: jest.fn()
  };
  beforeEach(() => {
    mount = createMount();
  });

  afterEach(() => {
    mount.cleanUp();
  });

  it("renders a <TextField/> component with expected props", () => {
    const wrapper = mount(<SearchField {...fieldProps} />);
    expect(wrapper.props().placeholder).toEqual("A placeholder");
    expect(wrapper.props().onChange).toBeDefined();
  });
  it("should trigger onChange on <SearchField/> on key press", () => {
    const wrapper = mount(<SearchField {...fieldProps} />);
    wrapper.find("input").simulate("change");
    expect(fieldProps.onChange).toHaveBeenCalled();
  });
});
_

_5._取得しているエラーは、babelがファイルを処理する機会を得ていないという事実によるものです。 _create-react-app_は、_yarn run test_ではなく_jest your/test/file.js_のようなテストを実行することを期待しています。後者を使用する場合、babelemployedにはなりません。

jestを使用してファイルを実行する場合は、_jest.config.js_ファイルを作成するか、_package.json_ファイルにjestを構成して_babel-jest_を使用する必要があります+ _other babel dependencies_は、jestがテストを実行する前にコードを変換します。

_@material-ui_を初めて使用しようとしたとき、昨日と同じボートに乗って、より完全な答えを得るためにここに来ました。

3
Firefly

このような何かが私のために働いた:

import {createMount} from '@material-ui/core/test-utils';

const WrappedComponent = () => 
    <MUIThemeStuffEtc>
        <MyComponent />
    </MUIThemeStuffEtc>

const render = createMount();
const wrapper = render(<WrappedComponent />);

const state = wrapper.find(MyComponent).instance().wrappedInstance.state
0
rekarnar