2017-04-09 3 views
1

React 및 material UI를 사용하여 구성 요소를 구축했습니다. 나는 React와 Redux를 사용하고있다.TextField 재질 UI 요소를 테스트하는 방법 React Jest?

index.jsx은 다음과 같습니다 InputSearch은 다음과 같습니다

import React from 'react'; 
import { render } from 'react-dom'; 
import { Provider } from 'react-redux'; 
import MuiThemeProvider from 'material-ui/styles/MuiThemeProvider'; 
import configureStore from '../store/configureStore'; 
import Routes from '../routes/routes'; 
import '../styles/main.less'; 

const store = configureStore(); 
render(
    <Provider store={store}> 
    <MuiThemeProvider> 
     <Routes /> 
    </MuiThemeProvider> 
    </Provider>, 
    document.getElementById('app'), 
); 

내 구성 요소 : I는 단위 테스트를 구축하는 에어 비앤비 효소와 농담을 사용하고

import React, { PropTypes, Component } from 'react'; 
import TextField from 'material-ui/TextField'; 

class InputSearch extends Component { 
    ... 

    render() { 
    return (
     ... 
     <TextField 
     defaultValue={this.props.keyword} 
     ref={(input) => { this.input = input; }} 
     autoFocus 
     hintText='Type a keyword' 
     errorText={this.state.errorText} 
     floatingLabelText='Search for keyword' 
     style={styles.textField} 
     /> 
    ); 
    } 
} 

InputSearch.propTypes = { 
    keyword: PropTypes.string.isRequired, 
    resetSearch: PropTypes.func.isRequired, 
    searchBooks: PropTypes.func.isRequired, 
    toggleResultsOpacity: PropTypes.func.isRequired, 
    firstSearch: PropTypes.bool.isRequired, 
}; 

export default InputSearch; 

. InputSearch 구성 요소에 내 테스트는 다음과 같습니다

import React from 'react'; 
import { shallow, mount } from 'enzyme'; 
import MuiThemeProvider from 'material-ui/styles/MuiThemeProvider'; 
import TextField from 'material-ui/TextField'; 
import InputSearch from '../components/InputSearch/InputSearch'; 

const resetSearchMock = jest.fn(); 
const searchBooksMock = jest.fn(); 
const toggleResultsOpacityMock = jest.fn(); 

const setup =() => { 
    const props = { 
    keyword: '', 
    resetSearch: resetSearchMock, 
    searchBooks: searchBooksMock, 
    toggleResultsOpacity: toggleResultsOpacityMock, 
    firstSearch: true, 
    }; 

    const wrapper = shallow(<MuiThemeProvider><InputSearch {...props} /></MuiThemeProvider>); 

    return { 
    props, 
    wrapper, 
    }; 
}; 

describe('Initial test',() => { 
    test('Shows error message when input search is empty.',() => { 
    const { wrapper, props } = setup(); 
    expect(wrapper.find(TextField).getValue()).toEqual(''); 
    }); 
} 

을 그러나, 나는 다음과 같은 오류를 받고 있어요 :

TypeError: wrapper.find(...).getValue is not a function

사람이 나를을 확인하는 올바른 방법으로 달성 할 수 있도록 할 수 있습니다 소재의 값은 TextField입니까?

답변

0

저는 모카 (mocha), 효소 (enzyme) 및 차이 (chai)를 사용하여 며칠 동안 테스트를 작성했습니다. material-ui 테스트 문제는 inturn react 구성 요소이므로 일반 html 요소를 테스트 할 때 테스트 할 수 없습니다.

당신은 당신이 생각하는 것입니다되는 TestField이 value 소품을 가지고 있음을 알 수 있습니다, 당신을위한 모든 요소를 ​​출력합니다

console.log(wrapper.find('TextField').debug()); 

이 같은 전체 구성 요소를 인쇄하여 어떤 속성 변화를 찾을 수 있습니다

describe('Initial test',() => { 
    test('Shows error message when input search is empty.',() => { 
    const { wrapper, props } = setup(); 
    expect(wrapper.find(TextField).props().value).to.equal(''); 
    }); 
} 
prop 그래서 코드는 다음과 같이 갈 것 TextField

의 값을 결정 무엇 때문에 확인

이것은 TextField 구성 요소를 테스트 한 방법입니다.

희망 사항을 찾으십시오.

+0

안녕하세요 @ Farhaan Bukhsh, 좋은 팁 "디버그"기능입니다. 그러나 내 TextField 구성 요소에는 "value"속성이 없으며 "defaultValue"속성 만 있습니다. 새 값을 전달하는 "변경"이벤트를 어떻게 시뮬레이트하고 테스트 할 수 있습니까? –

+0

이봐, 당신이 가지고있는''prop''이라면''value''를''defaultValue''로 대체 할 수 있습니다. 또한''material-ui ''를 업데이트 할 것을 제안합니다. 이제는 "변화"이벤트를 "시뮬레이션"하는 것이 매우 간단합니다. '대상 : { 값 : "Farhaan" }})'',''Farhaan''을 넣을 것입니다. ''TextField''에서 값을 쉽게 확인할 수 있습니다. –

1

효소 shallow은 한 레벨 만 렌더링하므로, 귀하의 경우에는 MuiThemeProviderInputSearch 만 렌더링됩니다. Jest 스냅 샷 기능을 사용하여 wrapper 내부에 무엇이 렌더링되었는지 확인할 수 있습니다.

expect(wrapper.('InputSearch').dive().find(TextField).getValue()).toEqual(''); 

하거나 MuiThemeProvider과 구성 요소를 포장하고 직접 InputSearch 렌더링 그나마 : 당신은 구성 요소의 내용을 렌더링하는 효소를 강제로 dive를 사용할 수 있습니다. 스타일 소품 만 추가하면됩니다. 현재 InputSearch이 최상위 구성 요소이며 Enzyme은 그 내용을 렌더링합니다.

const setup =() => { 
    const props = { 
    keyword: '', 
    resetSearch: resetSearchMock, 
    searchBooks: searchBooksMock, 
    toggleResultsOpacity: toggleResultsOpacityMock, 
    firstSearch: true, 
    styles: {textfield: {fontSize:10}} 
    }; 

    const wrapper = shallow(<InputSearch {...props} />); 

    return { 
    props, 
    wrapper, 
    }; 
}; 
+0

안녕하세요 @ Andreas Köberle, 답변 해 주셔서 감사합니다. 나는 "얕은"렌더링이 오직 한 단계의 깊이를 가지고 있다는 것을 알았지 만, 효소 "마운트"를 사용해 보았는데 작동하지 않습니다. 나는 "다이빙"으로 당신의 제안을 시도했지만 이것이 해결되지 않았습니다. 나는 또한 "MuiThemeProvider"제거 노력했지만 너무 작동하지 않습니다. Material ui와 TextField를 가진 샘플을 코드해볼 수 있습니까? 당신의 도움을 주셔서 감사합니다. –

+0

좋아, 그래서 효소 워드 프로세서에서'getValue'를 찾을 수 없습니다. 어쩌면 당신은'prop ('value')'를 대신 찾고있을 것인가? –

+0

안녕하세요 @ Andreas Köberle, "getValue"는 "TextField"구성 요소 값을 가져 오는 메서드로 작성된 재료 UI입니다. –

1

더 좋은 해결책이 있다면 제발 저에게 대답하십시오. 몇 가지 시도를 한 후에, 중요한 UI 구성 요소를 테스트하는 방법을 알아 냈습니다. 기본적으로, 우리는 효소 발견을 통해 재료 UI 컴포넌트 내부의 고유 HTML 요소 (입력, 버튼 등)를 찾아야합니다. @Andreas Köberle이 언급 한 바와 같이, "얕게", 오직 한 단계 깊은 검색 만한다는 것을 깨달았습니다. DOM 트리에서 깊은 검색을 강제하려면 효소 "마운트"를 사용해야합니다. http://airbnb.io/enzyme/docs/api/ReactWrapper/mount.html

다음은 새로운 테스트 코드입니다.

import React from 'react'; 
import { shallow, mount } from 'enzyme'; 
import getMuiTheme from 'material-ui/styles/getMuiTheme'; 
import { search } from '../sagas/search'; 
import TextField from 'material-ui/TextField'; 
import RaisedButton from 'material-ui/RaisedButton'; 
import Toggle from 'material-ui/Toggle'; 
import InputSearch from '../components/InputSearch/InputSearch'; 


const resetSearchMock = jest.fn(); 
const searchBooksMock = jest.fn(); 
const toggleResultsOpacityMock = jest.fn(); 
const muiTheme = getMuiTheme(); 
const props = { 
    keyword: '', 
    resetSearch: resetSearchMock, 
    searchBooks: searchBooksMock, 
    toggleResultsOpacity: toggleResultsOpacityMock, 
    firstSearch: true, 
}; 

const setup =() => { 
    const wrapper = mount(
    <InputSearch {...props} />, 
    { 
     context: {muiTheme}, 
     childContextTypes: {muiTheme: React.PropTypes.object} 
    } 
); 

    return { 
    props, 
    wrapper, 
    }; 
}; 

const { wrapper } = setup(); 
const textFieldMUI = wrapper.find(TextField); 
const toggleAuthor = wrapper.find(Toggle).find('input#author'); 
const toggleTitle = wrapper.find(Toggle).find('input#title'); 
const button = wrapper.find(RaisedButton).find('button'); 

describe ('Initial test, validate fields',() => { 
    test('TextField component should exists.',() => { 
    expect(textFieldMUI).toBeDefined(); 
    }); 

    test('Shows an error message when input search is empty and the search button is clicked.',() => { 
    const { props } = setup(); 
    props.keyword = ''; 

    const wrapper = mount(
     <InputSearch {...props} />, 
     { 
     context: {muiTheme}, 
     childContextTypes: {muiTheme: React.PropTypes.object} 
     } 
    ); 

    button.simulate('click'); 
    expect(textFieldMUI.props().errorText).toEqual('This field is required'); 
    }); 

    test('Shows an error message when both "author" and "title" toggles are off and the search button is clicked.',() => { 
    toggleTitle.simulate('click'); 
    button.simulate('click'); 
    expect(textFieldMUI.props().errorText).toEqual('Select at least one filter (Title or Author)'); 
    }); 

});