我尝试在我的应用中使用redux-form,如何通过redux-form测试handleSubmit?我使用酶,之前我刚刚发现了一些组件,模拟了点击,并检查了调用args,以及触发了多少点击。当我切换到redux-form时,我不太清楚如何编写正确的单元测试并检查handleSubmit。
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)
以前的单元测试。
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()
})
})