Redux-observable 测试和丢失我的 Marbles
Posted
技术标签:
【中文标题】Redux-observable 测试和丢失我的 Marbles【英文标题】:Redux-observable Testing and losing my Marbles 【发布时间】:2021-12-06 20:25:39 【问题描述】:我想测试这个 observable 但我什么也没得到:
const fetchUsersApi = (action$: any) => action$.pipe(
ofType(FETCH_USERS),
mergeMap(() => from(
API.graphql(graphqlOperation(queries.LIST_ALL_USERS)),
).pipe(
map((res: any) => fetchUsersSuccess(
// TODO - standardise this to 'items' so fetchApi can be used
pathOr(null, ['data', 'listAllUsers', 'users'], res),
)),
catchError((error: Error) =>
const processedError = processAppSyncErrorMessage(error);
console.log('Error', processedError);
return of(addError(processedError), fetchUsersError(processedError));
),
)),
);
测试如下:
import TestScheduler from 'rxjs/testing';
import API from 'aws-amplify';
import ActionsObservable from 'redux-observable';
import fetchUsersSuccess, fetchUsers from '../actions';
import fetchUsersEpic from './fetchUsersApi';
jest.mock('aws-amplify');
const testScheduler = new TestScheduler(
(actual, expected) => expect(actual).toStrictEqual(expected),
);
describe('fetchUsersEpic', () =>
it('should fetch the users', () =>
const mockFetchedUsers = [
id: 'fakeUser1' ,
];
(API.graphql as jest.Mock).mockImplementation(() => Promise.resolve(
data: listAllUsers: users: mockFetchedUsers ,
));
testScheduler.run((helpers) =>
const
hot,
cold,
expectObservable,
flush,
= helpers;
const action$ = cold('-a',
a: fetchUsers(),
);
const reduxObservableaAction = ActionsObservable.from(action$);
const actual = fetchUsersEpic(reduxObservableaAction);
const expectedMarbles = '-b';
const expectedValues = b: fetchUsersSuccess(mockFetchedUsers) ;
expectObservable(actual).toBe(expectedMarbles, expectedValues);
flush();
);
);
);
我得到的结果是:
● fetchUsersEpic › 应该获取用户
expect(received).toStrictEqual(expected) // 深度相等
预计 - 18 收到+1显然我在这里遗漏了一些东西,我认为返回的值应该是带有一些数据的 fetchUsersSuccess() 回调,但我们得到的是一个空数组。能得到一些想法会很棒。
【问题讨论】:
尝试模拟API.graphql
以返回一个可观察的而不是一个承诺。 Promise 回调是异步执行的
我刚刚决定在商店级别使用黑盒并调度事件,并编写了一个中间件,其中传入了一个 jest.fn() 来接收商店上的任何操作。即使它几乎不是单元测试也能正常工作!
我很高兴你有一些工作。以后请记住,任何时候引入 Promises 都需要等待结果,而不仅仅是大理石测试!
【参考方案1】:
我决定忽略提供的测试解决方案,对整个商店进行测试。它工作得更好,如果我们决定 bin redux-observable,我们仍然可以保留测试。
import
applyMiddleware, createStore, Action,
from 'redux';
import composeWithDevTools from 'redux-devtools-extension';
import createEpicMiddleware, combineEpics, Epic from 'redux-observable';
import rootReducer from '../../store/reducers';
/**
* makeActionListMiddleware is a function to allow us to pass a jest mock
* function to the store to pick up on any actions that are called on it
*/
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const makeActionMiddleware = (jestMockFunction: jest.Mock) => (store: object) => (next: any) => (action: Action<any>) =>
jestMockFunction(action);
// continue to the next action
return next(action);
;
// creates a fake version of the store with selected epics combined and a jest
// function middleware that received all store events.
const createEpicTester = (
epics: Epic[],
reducers = rootReducer,
initialState = ,
) =>
const storeActionJestCallback = jest.fn();
const jestActionMiddleware = makeActionMiddleware(storeActionJestCallback);
const composeEnhancers = composeWithDevTools();
const epicMiddleware = createEpicMiddleware();
const store = createStore(reducers, initialState, composeEnhancers(
applyMiddleware(epicMiddleware, jestActionMiddleware),
));
epicMiddleware.run(combineEpics(...epics));
return store, dispatch: store.dispatch, storeActionJestCallback ;
;
export default createEpicTester;
用法
const dispatch, storeActionJestCallback = createEpicTester([epic]);
dispatch( type: "someEvent" );
expect(storeActionJestCallback).toHaveBeenCalledWith( type: "someEvent" );
您现在可以期待您的史诗应用到商店的更多事件。
【讨论】:
以上是关于Redux-observable 测试和丢失我的 Marbles的主要内容,如果未能解决你的问题,请参考以下文章
为啥我的 redux-observable 史诗没有被触发?
redux-observable Promise 在单元测试中没有得到解决
React + Redux-Observable + Typescript - 编译,参数不可分配错误
在 catchError 之后不会执行 redux-observable