Dan*_*anV 10 fetch reactjs jestjs redux redux-thunk
我对Jest很陌生,不可否认我是测试异步代码的专家......
我有一个简单的Fetch
帮手:
export function fetchHelper(url, opts) {
return fetch(url, options)
.then((response) => {
if (response.ok) {
return Promise.resolve(response);
}
const error = new Error(response.statusText || response.status);
error.response = response;
return Promise.reject(error);
});
}
Run Code Online (Sandbox Code Playgroud)
并像这样实现它:
export function getSomeData() {
return (dispatch) => {
return fetchHelper('http://datasource.com/').then((res) => {
dispatch(setLoading(true));
return res.json();
}).then((data) => {
dispatch(setData(data));
dispatch(setLoading(false));
}).catch(() => {
dispatch(setFail());
dispatch(setLoading(false));
});
};
}
Run Code Online (Sandbox Code Playgroud)
但是,我想测试在正确的情况下以正确的顺序触发正确的调度.
这曾经很容易用a sinon.spy()
,但我无法弄清楚如何在Jest中复制它.理想情况下,我希望我的测试看起来像这样:
expect(spy.args[0][0]).toBe({
type: SET_LOADING_STATE,
value: true,
});
expect(spy.args[1][0]).toBe({
type: SET_DATA,
value: {...},
});
Run Code Online (Sandbox Code Playgroud)
在此先感谢您的任何帮助或建议!
redux文档有关于测试异步动作创建者的精彩文章:
对于使用Redux Thunk或其他中间件的异步操作创建者,最好完全模拟Redux存储以进行测试.您可以使用redux-mock-store将中间件应用于模拟存储.您还可以使用fetch-mock来模拟HTTP请求.
import configureMockStore from 'redux-mock-store'
import thunk from 'redux-thunk'
import * as actions from '../../actions/TodoActions'
import * as types from '../../constants/ActionTypes'
import fetchMock from 'fetch-mock'
import expect from 'expect' // You can use any testing library
const middlewares = [thunk]
const mockStore = configureMockStore(middlewares)
describe('async actions', () => {
afterEach(() => {
fetchMock.reset()
fetchMock.restore()
})
it('creates FETCH_TODOS_SUCCESS when fetching todos has been done', () => {
fetchMock
.getOnce('/todos', { body: { todos: ['do something'] }, headers: { 'content-type': 'application/json' } })
const expectedActions = [
{ type: types.FETCH_TODOS_REQUEST },
{ type: types.FETCH_TODOS_SUCCESS, body: { todos: ['do something'] } }
]
const store = mockStore({ todos: [] })
return store.dispatch(actions.fetchTodos()).then(() => {
// return of async actions
expect(store.getActions()).toEqual(expectedActions)
})
})
})
Run Code Online (Sandbox Code Playgroud)
他们的方法不是使用jest(或sinon)进行间谍,而是使用模拟存储并断言调度的操作.这具有能够处理thunks调度thunk的优点,这对于间谍来说是非常困难的.
这一切都直接来自文档,但是如果你想让我为你的thunk创建一个例子,请告诉我.
2018 年的许多有用答案现在已经过时,截至 2023 年的答案是避免嘲笑商店,而是使用真正的商店,更喜欢集成测试(仍然使用笑话)而不是单元测试。
更新后的官方 Redux 测试文档中的一些亮点:
更喜欢编写所有东西一起工作的集成测试。对于使用 Redux 的 React 应用程序,渲染一个包含正在测试的组件的真实存储实例。与正在测试的页面的交互应该使用真正的 Redux 逻辑,并模拟 API 调用,这样应用程序代码就不必更改,并断言 UI 已适当更新。
不要尝试模拟选择器函数或 React-Redux 钩子!从库中模拟导入很脆弱,并且无法让您确信实际的应用程序代码正在运行。
接下来说明了如何实现这一点,其renderWithProvider
功能详细信息请参见此处。
为了对此进行推理,它链接到的文章包含以下引用,解释了 redux 测试最佳实践思想的演变:
我们的文档一直教导“隔离”方法,这对于减速器和选择器尤其有意义。“整合”方法只占少数。
但是,RTL 和 Kent C Dodds 极大地改变了 React 生态系统中测试的思维方式和方法。我现在看到的模式是关于“集成”式测试 - 大量代码,一起工作,就像它们在真实应用程序中使用一样。
对于使用Redux Thunk或其他中间件的异步操作创建者,最好完全模拟Redux存储以进行测试.您可以使用中间件应用于模拟商店redux-mock-store
.为了模拟HTTP请求,您可以使用nock
.
根据redux-mock-store
文档,您需要store.getActions()
在请求结束时调用异步操作,您可以配置您的测试
mockStore(getState?: Object,Function) => store: Function
返回已配置的模拟存储的实例.如果要在每次测试后重置商店,则应调用此功能.
store.dispatch(action) => action
通过模拟商店调度操作.该操作将存储在实例内的数组中并执行.
store.getState() => state: Object
返回模拟商店的状态
store.getActions() => actions: Array
返回模拟商店的操作
store.clearActions()
清除存储的操作
你可以写测试动作
import nock from 'nock';
import configureMockStore from 'redux-mock-store';
import thunk from 'redux-thunk';
//Configuring a mockStore
const middlewares = [thunk];
const mockStore = configureMockStore(middlewares);
//Import your actions here
import {setLoading, setData, setFail} from '/path/to/actions';
test('test getSomeData', () => {
const store = mockStore({});
nock('http://datasource.com/', {
reqheaders // you can optionally pass the headers here
}).reply(200, yourMockResponseHere);
const expectedActions = [
setLoading(true),
setData(yourMockResponseHere),
setLoading(false)
];
const dispatchedStore = store.dispatch(
getSomeData()
);
return dispatchedStore.then(() => {
expect(store.getActions()).toEqual(expectedActions);
});
});
Run Code Online (Sandbox Code Playgroud)
PS保持模拟存储在模拟操作被触发时不会自动更新,并且如果您在上一个操作之后依赖于更新的数据,则需要编写自己的实例喜欢
const getMockStore = (actions) => {
//action returns the sequence of actions fired and
// hence you can return the store values based the action
if(typeof action[0] === 'undefined') {
return {
reducer: {isLoading: true}
}
} else {
// loop over the actions here and implement what you need just like reducer
}
}
Run Code Online (Sandbox Code Playgroud)
然后配置mockStore
类似
const store = mockStore(getMockStore);
Run Code Online (Sandbox Code Playgroud)
希望能帮助到你.还要检查该对测试异步操作的创造者终极版文档中
如果您使用 模拟调度函数jest.fn()
,您只需访问即可dispatch.mock.calls
获取对存根进行的所有调用。
const dispatch = jest.fn();
actions.yourAction()(dispatch);
expect(dispatch.mock.calls.length).toBe(1);
expect(dispatch.mock.calls[0]).toBe({
type: SET_DATA,
value: {...},
});
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
18221 次 |
最近记录: |