Reactjs 单元测试重复表单handleSubmit
我尝试在我的应用程序中使用redux表单,如何通过redux表单测试handleSubmit?我使用酶,之前我只是找到一些成分,模拟点击,检查调用参数,以及点击触发的次数。当我切换到redux表单时,我不太清楚如何编写正确的单元测试和检查handleSubmitReactjs 单元测试重复表单handleSubmit,reactjs,unit-testing,redux,redux-form,enzyme,Reactjs,Unit Testing,Redux,Redux Form,Enzyme,我尝试在我的应用程序中使用redux表单,如何通过redux表单测试handleSubmit?我使用酶,之前我只是找到一些成分,模拟点击,检查调用参数,以及点击触发的次数。当我切换到redux表单时,我不太清楚如何编写正确的单元测试和检查handleSubmit export const validate = device => { const errors = {} if (device.name && device.name.length > co
export const validate = device => {
const errors = {}
if (device.name && device.name.length > constants.defaultMaxTextFieldLength) {
errors.name = <FormattedMessage id={tooLongErrorMessage} />
}
if (!device.name)
errors.name = <FormattedMessage id={emptyErrorMessage} />
return errors
}
export class EditDevice extends Component {
static propTypes = {...}
update = device => {
device.miConfiguration.isMiEnabled = device.miConfiguration.miConfigurationType !== MiConfigurationTypes.AccessPointOnly
this.props.update(device).then(({success, ...error}) => {
if (!success)
throw new SubmissionError(error)
this.returnToList()
})}
returnToList = () => this.props.history.push({pathname: '/devices', state: {initialSkip: this.props.skip}})
render = () => {
let {isLoadingInProgress, handleSubmit, initialValues: {deviceType} = {}, change} = this.props
const actions = [
<Button
name='cancel'
onClick={this.returnToList}
>
<FormattedMessage id='common.cancel' />
</Button>,
<Button
name='save'
onClick={handleSubmit(this.update)}
color='primary'
style={{marginLeft: 20}}
>
<FormattedMessage id='common.save' />
</Button>]
return (
<Page title={<FormattedMessage id='devices.deviceInfo' />} actions={actions} footer={actions}>
<form onSubmit={handleSubmit(this.update)}>
{isLoadingInProgress && <LinearProgress mode='indeterminate'/>}
<Grid container>
<Grid item xs={12} sm={6} md={4} >
<Field
component={renderTextField}
name='name'
label={<FormattedMessage id='name' />}
/>
</Grid>
....
</Grid>
</form>
</Page>
)
}
}
export const mapStateToProps = (state, {match: {params: {deviceId}}}) => {
let initialValues = deviceId && state.entities.devices[deviceId]
return {
initialValues,
deviceId,
isLoadingInProgress: state.devices.isLoadingInProgress,
skip: state.devices.skip,
form: `device-${deviceId}`,
}
}
export const mapDispatchToProps = (dispatch, {match: {params: {deviceId}}}) => ({
init: () => dispatch(DeviceActions.get(deviceId)),
update: device => dispatch(DeviceActions.createOrUpdate(device)),
})
export default compose(
connect(mapStateToProps, mapDispatchToProps),
reduxForm({validate, enableReinitialize: true, keepDirtyOnReinitialize: true}),
)(EditDevice)
export const validate=device=>{
常量错误={}
if(device.name&&device.name.length>constants.defaultMaxTextFieldLength){
错误。名称=
}
如果(!device.name)
错误。名称=
返回错误
}
导出类EditDevice扩展组件{
静态propTypes={…}
更新=设备=>{
device.miConfiguration.isMiEnabled=device.miConfiguration.miConfigurationType!==MiConfigurationTypes.AccessPointOnly
this.props.update(设备)。然后({success,…error})=>{
如果(!成功)
抛出新提交错误(错误)
这个返回列表()
})}
returnToList=()=>this.props.history.push({pathname:'/devices',state:{initialSkip:this.props.skip})
渲染=()=>{
让{IsLoadingProgress,handleSubmit,initialValues:{deviceType}={},change}=this.props
常量动作=[
,
]
返回(
{IsLoadingProgress&&}
....
)
}
}
export const mapStateToProps=(状态,{match:{params:{deviceId}})=>{
让initialValues=deviceId&&state.entities.devices[deviceId]
返回{
初始值,
设备ID,
IsLoadingProgress:state.devices.IsLoadingProgress,
跳过:state.devices.skip,
格式:`device-${deviceId}`,
}
}
export const mapDispatchToProps=(调度,{match:{params:{deviceId}}})=>({
init:()=>dispatch(DeviceActions.get(deviceId)),
更新:设备=>dispatch(DeviceActions.createOrUpdate(设备)),
})
导出默认组合(
连接(mapStateToProps、mapDispatchToProps),
reduxForm({validate,enableReinitialize:true,keepDirtyOnReinitialize:true}),
)(编辑设备)
先前的单元测试
describe('EditDevice', () => {
let init, handleSubmit, page, push
beforeEach(() => page = shallow(<EditDevice
handleSubmit={handleSubmit = sinon.spy()}
deviceId={deviceId}
history={{push: push = sinon.spy()}}
skip={skip}
/>))
......
it('should call push back to list on successful response', async () => {
let update = sinon.stub().resolves({success: true})
page.setProps({update})
page.find(Field).findWhere(x => x.props().name === 'name').simulate('change', {}, 'good name')
await page.find(Page).props().footer.find(x => x.props.name === saveButtonName).props.onClick()
push.calledOnce.should.be.true
push.calledWith({pathname: '/devices', state: {initialSkip: skip}}).should.be.true
})
describe('mapStateToProps', () => {
const deviceId = 123
const device = {}
const isEnabled = true
const isLoadingInProgress = {}
let props
let skip = {}
beforeEach(() => props = mapStateToProps({devices: {isLoadingInProgress, skip}, entities: {devices: {[deviceId]: device}}}, {match: {params: {deviceId}}}))
it('should pass deviceId, form, isLoadingInProgress and skip from state', () => {
props.deviceId.should.be.equal(deviceId)
props.isLoadingInProgress.should.be.equal(isLoadingInProgress)
props.skip.should.be.equal(skip)
props.form.should.be.equal(`device-${deviceId}`)
})
})
describe('mapDispatchToProps', () => {
const response = {}
const deviceId = 123
let props
beforeEach(() => props = mapDispatchToProps(x=> x, {match: {params: {deviceId}}}))
it('init should call get from DeviceActions', () => {
sinon.stub(DeviceActions, 'get').returns(response)
props.init(deviceId).should.be.equal(response)
DeviceActions.get.calledOnce.should.be.true
DeviceActions.get.args[0][0].should.be.equal(deviceId)
DeviceActions.get.restore()
})
it('update should call createOrUpdate from DeviceActions', () => {
const device = {}
sinon.stub(DeviceActions, 'createOrUpdate').returns(response)
props.update(device).should.be.equal(response)
DeviceActions.createOrUpdate.calledOnce.should.be.true
DeviceActions.createOrUpdate.args[0][0].should.be.equal(device)
DeviceActions.createOrUpdate.restore()
})
})
description('EditDevice',()=>{
让init、handleSubmit、page、push
之前(()=>page=shallow())
......
它('should call push back to list on successful response',async()=>{
让update=sinon.stub().resolves({success:true})
page.setProps({update})
page.find(Field).findWhere(x=>x.props().name==='name').simulate('change',{},'good name'))
等待page.find(page.props().footer.find(x=>x.props.name===saveButtonName.props.onClick())
push.calledOnce.should.be.true
push.calledWith({pathname:'/devices',state:{initialSkip:skip}}).should.be.true
})
描述('MapStateTrops',()=>{
常量设备ID=123
常量设备={}
常数isEnabled=true
常量IsLoadingProgress={}
让道具
让我们跳过={}
beforeach(()=>props=mapstatetops({devices:{isloadingprogress,skip},实体:{devices:{[deviceId]:device}}},{match:{params:{deviceId}}}))
它('应该传递deviceId、form、IsLoadingProgress和skip from state',()=>{
props.deviceId.should.be.equal(deviceId)
props.isloadingprogress.should.be.equal(isloadingprogress)
道具.跳过.应该.相等(跳过)
props.form.should.be.equal(`device-${deviceId}`)
})
})
描述('mapDispatchToProps',()=>{
常量响应={}
常量设备ID=123
让道具
beforeach(()=>props=mapDispatchToProps(x=>x,{match:{params:{deviceId}}}))
它('init应该调用从DeviceActions获取',()=>{
sinon.stub(DeviceActions,'get')。返回(响应)
props.init(deviceId).should.be.equal(响应)
DeviceActions.get.calledOnce.should.be.true
DeviceActions.get.args[0][0]。应为.be.equal(deviceId)
DeviceActions.get.restore()
})
它('更新应调用createOrUpdate from DeviceActions',()=>{
常量设备={}
sinon.stub(DeviceActions,'createOrUpdate')。返回(响应)
道具更新(设备).should.be.equal(响应)
DeviceActions.createOrUpdate.calledOnce.should.be.true
DeviceActions.createOrUpdate.args[0][0]。应.be.equal(设备)
DeviceActions.createOrUpdate.restore()
})
})