使用 TestScheduler 测试 Epic 时出现的问题
Issues when testing Epic with TestScheduler
我在 react-redux 应用程序中使用 rxjs 史诗作为异步操作的中间件。
我正在尝试模拟 ajax 请求(通过依赖项注入)并根据响应测试此史诗的行为。
这是我的史诗:
export const loginEpic = (action$, store$, { ajax }) => { // Ajax method is injected
return action$.ofType(LoginActions.LOGIN_PENDING).pipe(
mergeMap(action => {
if (action.mail.length === 0) {
return [ loginFailure(-1) ]; // This action is properly returned while testing
} else {
return ajax({ ... }).pipe(
mergeMap(response => {
if (response.code !== 0) {
console.log(response.code); // This is logged
return [ loginFailure(response.code) ]; // This action is expected
} else {
return [ loginSuccess() ];
}
}),
catchError(() => {
return [ loginFailure(-2) ];
})
);
}
})
);
};
这部分测试邮件地址是否为空并且工作正常(或者至少符合预期):
it("empty mail address", () => {
testScheduler.run(({ hot, expectObservable }) => {
let action$ = new ActionsObservable(
hot("a", {
a: {
type: LoginActions.LOGIN_PENDING,
mail: ""
}
})
);
let output$ = loginEpic(action$, undefined, { ajax: () => ({}) });
expectObservable(output$).toBe("a", {
a: {
type: LoginActions.LOGIN_FAILURE,
code: -1
}
});
});
});
但是,我的第二个测试失败了,因为实际值是一个空数组(没有返回登录失败):
it("wrong credentials", () => {
testScheduler.run(({ hot, cold, expectObservable }) => {
let action$ = new ActionsObservable(
hot("a", {
a: {
type: LoginActions.LOGIN_PENDING,
mail: "foo@bar.com"
}
})
);
let dependencies = {
ajax: () =>
from(
new Promise(resolve => {
let response = {
code: -3
};
resolve(response);
})
)
};
let output$ = loginEpic(action$, undefined, dependencies);
expectObservable(output$).toBe("a", {
a: {
type: LoginActions.LOGIN_FAILURE,
code: -3
}
});
});
});
知道我做错了什么/为什么这部分 returns 是一个空数组(console.log
确实记录了代码):
if (response.code !== 0) {
console.log(response.code);
return [ loginFailure(response.code) ];
}
虽然这部分 returns 是一个填充数组:
if (action.mail.length === 0) {
return [ loginFailure(-1) ];
}
我猜 Promise 的使用导致测试实际上是异步的。尝试将 ajax
的存根更改为使用 of(response)
而不是 from
我在 react-redux 应用程序中使用 rxjs 史诗作为异步操作的中间件。
我正在尝试模拟 ajax 请求(通过依赖项注入)并根据响应测试此史诗的行为。
这是我的史诗:
export const loginEpic = (action$, store$, { ajax }) => { // Ajax method is injected
return action$.ofType(LoginActions.LOGIN_PENDING).pipe(
mergeMap(action => {
if (action.mail.length === 0) {
return [ loginFailure(-1) ]; // This action is properly returned while testing
} else {
return ajax({ ... }).pipe(
mergeMap(response => {
if (response.code !== 0) {
console.log(response.code); // This is logged
return [ loginFailure(response.code) ]; // This action is expected
} else {
return [ loginSuccess() ];
}
}),
catchError(() => {
return [ loginFailure(-2) ];
})
);
}
})
);
};
这部分测试邮件地址是否为空并且工作正常(或者至少符合预期):
it("empty mail address", () => {
testScheduler.run(({ hot, expectObservable }) => {
let action$ = new ActionsObservable(
hot("a", {
a: {
type: LoginActions.LOGIN_PENDING,
mail: ""
}
})
);
let output$ = loginEpic(action$, undefined, { ajax: () => ({}) });
expectObservable(output$).toBe("a", {
a: {
type: LoginActions.LOGIN_FAILURE,
code: -1
}
});
});
});
但是,我的第二个测试失败了,因为实际值是一个空数组(没有返回登录失败):
it("wrong credentials", () => {
testScheduler.run(({ hot, cold, expectObservable }) => {
let action$ = new ActionsObservable(
hot("a", {
a: {
type: LoginActions.LOGIN_PENDING,
mail: "foo@bar.com"
}
})
);
let dependencies = {
ajax: () =>
from(
new Promise(resolve => {
let response = {
code: -3
};
resolve(response);
})
)
};
let output$ = loginEpic(action$, undefined, dependencies);
expectObservable(output$).toBe("a", {
a: {
type: LoginActions.LOGIN_FAILURE,
code: -3
}
});
});
});
知道我做错了什么/为什么这部分 returns 是一个空数组(console.log
确实记录了代码):
if (response.code !== 0) {
console.log(response.code);
return [ loginFailure(response.code) ];
}
虽然这部分 returns 是一个填充数组:
if (action.mail.length === 0) {
return [ loginFailure(-1) ];
}
我猜 Promise 的使用导致测试实际上是异步的。尝试将 ajax
的存根更改为使用 of(response)
而不是 from