使用大理石图运行测试时,不执行ajax请求

时间:2018-10-17 21:11:32

标签: reactjs testing redux rxjs redux-observable

我使用rxjs v6和redux-observable v1

我有史诗般的向服务器发送请求,并尝试像doc中那样测试史诗。当我在发送请求之前运行测试史诗时,会发出3个动作,它会在测试结果上看到,但是当史诗来到ajax调用测试完成时。为了模拟请求,我使用nock lib。

史诗:

import { ofType } from 'redux-observable'
import { of, merge, from } from 'rxjs'
import {
  switchMap,
  catchError
} from 'rxjs/operators'

import { apiRequest, handleAsyncError$ } from '../../async/lib'
import { actions as asyncActions } from '../../async'
import { LOADING_TYPES } from '../../async/constants'
import { actions as authActions } from '../reducer'

const setSignInLoading = (status) => of(asyncActions.setLoading({ type: LOADING_TYPES.signIn, status }))

const emitSignInPending = () => merge(
  setSignInLoading(true),
  of(authActions.signInPending())
)

const emitSignInSuccess = (payload) => merge(
  setSignInLoading(false),
  of(authActions.signInSuccess(payload))
)

const emitSignInFailed = (payload) => merge(
  setSignInLoading(false),
  handleAsyncError$({
    action: authActions.signInFailure,
    payload
  })
)

// --------- ajax call -----------
const startSignIn = (payload) => apiRequest({
  path: '/auth/signin/manager',
  method: 'post',
  body: payload
})

const mapSignInAction$ = ({ payload }) => merge(
  // --------- emit 3 actions -----------
  emitSignInPending(),
  // --------- finish test -----------
  startSignIn(payload)
    .pipe(
      switchMap((emitSignInSuccess)),
      catchError(emitSignInFailed)
    )
)

const signInEpic = action$ =>
  action$
    .pipe(
      ofType(authActions.signIn),
      switchMap(mapSignInAction$)
    )

export default signInEpic

apiRequest:

import { get } from 'lodash'
import { throwError } from 'rxjs'
import { ajax } from 'rxjs/ajax'
import { map, catchError } from 'rxjs/operators'

import { API } from '../../../../config'

const apiRequest = ({ token, path, method, body }) => {
  const settings = {
    url: `${API}${path}`,
    headers: { 'Content-Type': 'application/json' },
    responseType: 'json',
    crossDomain: true,
    method,
    body
  }

  if (token) {
    settings.headers['Authorization'] = `Bearer: ${token}`
  }

  return ajax(settings)
    .pipe(
      catchError((request) => {
        const error = get(request, 'response.error')

        return throwError({ error, request })
      }),
      map(({ response }) => response)
    )
}

export default apiRequest

测试:     诺克(API)         .post('/ auth / signin / manager')         .reply(200,响应)

  scheduler.run(({ hot, expectObservable }) => {
    const source = hot('-a|', { a: authActions.signIn({ email: 'manager', password: '123123' }) })
    const output$ = epic(source)

    expectObservable(output$).toBe('-(bcde)', {
      b: asyncAction.setLoading({ type: 'signIn', status: true }),
      c: authActions.signInPending(),
      d: asyncAction.setLoading({ type: 'signIn', status: false }),
      e: authActions.signInSuccess(response)
    })
  })

结果:

Expected:

    [{"frame": 1, "notification": {"error": undefined, "hasValue": true, "kind": "N", "value": {"error": false, "payload": {"status": true, "type": "signIn"}, "type": "[8] async/setLoading"}}}, {"frame": 1, "notification": {"error": undefined, "hasValue": true, "kind": "N", "value": {"error": false, "payload": undefined, "type": "[3] [2] auth/signIn/pending"}}}, {"frame": 1, "notification": {"error": undefined, "hasValue": true, "kind": "N", "value": {"error": false, "payload": {"status": false, "type": "signIn"}, "type": "[8] async/setLoading"}}}, {"frame": 1, "notification": {"error": undefined, "hasValue": true, "kind": "N", "value": {"error": false, "payload": {"data": {"token": "skldjf", "user": {"email": "manager", "id": 2, "passwordHash": "asdf", "passwordSalt": "6819c23dc7", "role": {"name": "user"}, "roleId": 1}}}, "type": "[4] [2] auth/signIn/success"}}}]

Received:

    [{"frame": 1, "notification": {"error": undefined, "hasValue": true, "kind": "N", "value": {"error": false, "payload": {"status": true, "type": "signIn"}, "type": "[8] async/setLoading"}}}, {"frame": 1, "notification": {"error": undefined, "hasValue": true, "kind": "N", "value": {"error": false, "payload": undefined, "type": "[3] [2] auth/signIn/pending"}}}]

1 个答案:

答案 0 :(得分:1)

Ajax解析为微任务,因此史诗级程序不会发出同步,因此大理石图无法处理它,我无法找到如何使用大理石图进行处理。如此简单的解决方案是:

it('return token and user 2', async (done) => {
  const response = {...}

  nock(API)
    .post('/auth/signin/manager')
    .reply(200, response)

  const source = authActions.signIn({ email: 'manager', password: '123123' })
  const action$ = ActionsObservable.of(source)

  epic(action$).pipe(toArray()).subscribe((actions) => {
    expect(actions).toEqual([
      asyncAction.setLoading({ type: 'signIn', status: true }),
      authActions.signInPending(),
      asyncAction.setLoading({ type: 'signIn', status: false }),
      authActions.signInSuccess(response)
    ])

    done()
  })

})

如果发现大理石图,请写信。