我正在使用formik和useDispatch用于表单和提交功能。仅当我注释掉API调用代码时,我才能测试该操作是否在提交时分派。如果我不评论,则会引发错误。
如何调用模拟API调用而不是实际的API?或如何使用redux-mock-store进行 formik +异步API调用?
ForgotPassword.js:
<>
<Typography variant='h6'>Recover Password</Typography>
<Formik
initialValues={{ username: '' }}
onSubmit={(values, { setSubmitting }) => {
dispatch(forgotPassword(values.username)).then(() => {
setSubmitting(false)
})
}}
validationSchema={validations}
>
<Form noValidate>
<Field
name='forgotPassword'
render={formikProps => (
<>
<Field
variant='outlined'
margin='normal'
required
fullWidth
id='username'
label='Username'
name='username'
autoComplete='username'
component={TextField}
autoFocus
/>
<Button type='submit' />
</>
)}
/>
</Form>
</Formik>
</>
ForgotPassword.test.js
import React from 'react'
import ForgotPassword from '../../components/public/ForgotPassword'
import { mount } from 'enzyme'
import { Provider } from 'react-redux'
import configureStore from 'redux-mock-store'
import * as ReactReduxHooks from '../react-redux-hooks'
import thunk from 'redux-thunk'
describe('#ForgotPassword', () => {
let wrapper
const middleWare = [thunk]
const mockStore = configureStore(middleWare)
let store
beforeEach(() => {
const initialState = {
auth: { tempUsername: '' },
}
store = mockStore(initialState)
jest
.spyOn(ReactReduxHooks, 'useSelector')
.mockImplementation(state => store.getState())
jest
.spyOn(ReactReduxHooks, 'useDispatch')
.mockImplementation(() => store.dispatch)
wrapper = mount(
<Provider store={store}>
<ForgotPassword />
</Provider>
)
})
it('expect value changes after simulate change', async () => {
wrapper.find('input').simulate('change', {
persist: () => {},
target: { value: 'jhonny123', name: 'username' },
})
expect(wrapper.find('input').props().value).toBe('jhonny123')
wrapper.find('button').simulate('submit')
await new Promise(resolve => {
setTimeout(() => resolve(), 0)
})
const actions = store.getActions()
console.log(actions)
//when the API call part, is commented out inside the actions, prints the actions nicely
//and if I don't comment out the API call part, throws an error
})
})
调度的动作
export const forgotPassword = username => {
return async dispatch => {
dispatch(setTempUsername(username))
// await Auth.forgotPassword(username)
// .then(() => {
// dispatch(setResettingPassword(true))
// })
// .catch(err => {
// /*dispatch(showError(err.message)*/
// })
dispatch(
showSuccess(
'A verification code has been sent to the email linked to your username.'
)
)
}
}
这是当操作中的API调用部分被注释掉时的console.log
[
{ type: 'auth/setTempUsername', payload: 'jhonny123' },
{
type: 'snackbar/handleSnackbar',
payload: {
verticalPosition: 'bottom',
horizontalPosition: 'center',
message: 'A verification code has been sent to the email linked to your username.',
autoHideDuration: 10000,
messageType: 'success',
isOpen: true
}
}
]
未将api调用注释掉的错误
TypeError: Cannot read property 'clientMetadata' of undefined
407 | return async dispatch => {
408 | dispatch(setTempUsername(username))
> 409 | await Auth.forgotPassword(username)
| ^
410 | .then(() => {
411 | dispatch(setResettingPassword(true))
412 | })
答案 0 :(得分:2)
从2.1.0版本开始,Redux Thunk支持注入自定义参数,您可以将其用于应用程序中使用的api,例如:
<ActionSheet
ref={o => this.ActionSheet = o}
options={[
(
<TouchableOpacity style={styles.actionTextInline} onPress={() => {
# ----- change here -------
this.ActionSheet.hide();
setTimeout(() => this.openReservationModal(), 1000)
# ----- change here -------enter code here
}}>
<Icon name="receipt" size={24} style={{ color: '#737373' }} />
</TouchableOpacity>
), (
<TouchableOpacity style={styles.actionTextInline}>
<Icon name="call" size={24} style={{ color: '#737373' }} />
</TouchableOpacity>
), (
<TouchableOpacity style={styles.actionTextInline} onPress={() => { alert("Hello friends !!") }}>
<Icon name="message" size={24} style={{ color: '#737373' }} />
</TouchableOpacity>
)
]}
cancelButtonIndex={2}
destructiveButtonIndex={-1}
styles={{
body: {
flex: 1,
backgroundColor: '#FFFFFF',
borderRadius: 10,
height: 100
},
cancelButtonBox: {
height: 50,
backgroundColor: '#FFFFFF',
paddingLeft: 16,
paddingTop: 16,
alignItems: 'flex-start'
},
buttonBox: {
height: 50,
backgroundColor: '#FFFFFF',
borderRadius: 10,
paddingLeft: 16,
paddingTop: 16,
alignItems: 'flex-start'
},
}}
/>
然后在您的thunk acion中删除导入Auth并将其从第三个参数中提取出来:
const store = configureStore({
reducer: {
auth: authReducer,
},
middleware: [
getDefaultMiddleware({
thunk: {
extraArgument: storeAuth,
},
}),
],
})
要进行测试,您应该创建模拟存储并将模拟api作为额外参数添加到thunk
return async (dispatch, getState, { storeAuth }) => {
dispatch(setTempUsername(username))
await storeAuth.forgotPassword(username)
.then(() => {
dispatch(setResettingPassword(true))
})