我使用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"}}}]
答案 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()
})
})
如果发现大理石图,请写信。