【问题标题】:while testing onSubmit I want to Mock API call instead of making actual API call在测试 onSubmit 时,我想模拟 API 调用而不是进行实际的 API 调用
【发布时间】:2019-12-03 02:48:04
【问题描述】:

我将 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 |       })

【问题讨论】:

    标签: reactjs redux jestjs formik redux-mock-store


    【解决方案1】:

    从 2.1.0 开始,Redux Thunk 支持注入自定义参数,您可以将其用于您在应用中使用的 api,例如:

    const store = configureStore({
      reducer: {
        auth: authReducer,
      },
      middleware: [
        getDefaultMiddleware({
          thunk: {
            extraArgument: storeAuth,
          },
        }),
      ],
    })
    

    然后在您的 thunk 动作中删除 import Auth 并从第三个参数中提取它:

    return async (dispatch, getState, { storeAuth }) => {
               dispatch(setTempUsername(username))
             await storeAuth.forgotPassword(username)
                 .then(() => {
                   dispatch(setResettingPassword(true))
                 })
    

    要对其进行测试,您应该创建模拟存储并将模拟 api 作为额外参数添加到 thunk

    const storeAuth = {
        forgotPassword: jest.fn(() => Promise.resolve({ data: {} })),
      }
    
      const middleWare = [thunk.withExtraArgument(storeAuth)]
      const mockStore = configureStore(middleWare)
    

    【讨论】:

    • 现在我的存储设置看起来像这样}), ], }) ``` 但我不明白你要我如何传递一个 mockApi。你能给我看一个 mockApi 的 sn-p 吗?
    • 好吧,我想出了如何传递一个模拟函数,更新答案,我会接受它。谢谢@Gilad
    猜你喜欢
    • 2018-08-06
    • 1970-01-01
    • 1970-01-01
    • 2019-07-10
    • 2020-12-01
    • 2021-09-05
    • 2020-05-17
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多