我有以下Epic在应用程序中运行良好,但我不能让我的大理石测试工作。我在map
中调用动作创建者,它确实将正确的对象返回到流中,但在测试中我得到了空流回来。
export const updateRemoteFieldEpic = action$ =>
action$.pipe(
ofType(UPDATE_REMOTE_FIELD),
filter(({ payload: { update = true } }) => update),
mergeMap(({ payload }) => {
const { orderId, fields } = payload;
const requiredFieldIds = [4, 12]; // 4 = Name, 12 = Client-lookup
const requestData = {
id: orderId,
customFields: fields
.map(field => {
return (!field.value && !requiredFieldIds.includes(field.id)) ||
field.value
? field
: null;
})
.filter(Boolean)
};
if (requestData.customFields.length > 0) {
return from(axios.post(`/customfields/${orderId}`, requestData)).pipe(
map(() => queueAlert("Draft Saved")),
catchError(err => {
const errorMessage =
err.response &&
err.response.data &&
err.response.data.validationResult
? err.response.data.validationResult[0]
: undefined;
return of(queueAlert(errorMessage));
})
);
}
return of();
})
);
在服务器的成功响应中,我正在调用qazxsw poi动作创建者。
queueAlert
这是我的测试用例
export const queueAlert = (
message,
position = {
vertical: "bottom",
horizontal: "center"
}
) => ({
type: QUEUE_ALERT,
payload: {
key: uniqueId(),
open: true,
message,
position
}
});
describe("updateRemoteFieldEpic", () => {
const sandbox = sinon.createSandbox();
let scheduler;
beforeEach(() => {
scheduler = new TestScheduler((actual, expected) => {
expect(actual).toEqual(expected);
});
});
afterEach(() => {
sandbox.restore();
});
it("should return success message", () => {
scheduler.run(ts => {
const inputM = "--a--";
const outputM = "--b--";
const values = {
a: updateRemoteField({
orderId: 1,
fields: [{ value: "test string", id: 20 }],
update: true
}),
b: queueAlert("Draft Saved")
};
const source = ActionsObservable.from(ts.cold(inputM, values));
const actual = updateRemoteFieldEpic(source);
const axiosStub = sandbox
.stub(axios, "post")
.returns([]);
ts.expectObservable(actual).toBe(outputM, values);
ts.flush();
expect(axiosStub.called).toBe(true);
});
});
});
中的输出流返回空数组我试图从动作创建者的map observable返回,因为动作预期对象崩溃了应用程序。
通过将actual
作为axios.post(...)
存根,你可以在史诗中得到[]
--一个不会发出任何值的空观察者。这就是为什么你的from([])
永远不会被召唤的原因。您可以通过将单元素数组用作存根值来解决此问题,例如: mergeMap
或[null]
。
以下是该问题的先前版本的答案。我保留它作为参考,因为我认为这些内容对那些试图在史诗测试中模拟承诺返回函数的人有用。
我认为你的问题是史诗中的[{}]
。 Axios返回一个承诺,并且RxJS from(axios.post(...))
无法使其同步,因此TestScheduler
无法按预期工作。
我通常解决这个问题的方法是创建一个简单的包装器模块,它执行Promise-to-Observable转换。在您的情况下,它可能看起来像这样:
expectObservable
一旦你有了这个包装器,你就可以模拟该函数来返回一个常量的// api.js
import axios from 'axios';
import { map } from 'rxjs/operators';
export function post(path, data) {
return from(axios.post(path, options));
}
,将promises完全取出图片。如果您使用Jest执行此操作,则可以直接模拟模块:
Observable
否则,您还可以使用redux-observable的import * as api from '../api.js';
jest.mock('../api.js');
// In the test:
api.post.mockReturnValue(of(/* the response */));
来注入API模块。然后你的史诗将作为第三个参数接收它:
dependency injection mechanism
在你的测试中,你只需要传递一个模拟的export const updateRemoteFieldEpic = (action$, state, { api }) =>
action$.pipe(
ofType(UPDATE_REMOTE_FIELD),
filter(({ payload: { update = true } }) => update),
mergeMap(({ payload }) => {
// ...
return api.post(...).pipe(...);
})
);
对象。