我正在尝试遵循此tutorial,但我不完全了解如何创建它。我认为执行操作的方式与示例显示方式不同。从组件中,我使用this.props.actionName
调用动作,但示例中使用dispatch
。以下是我的一个动作文件的样子
app / actions / admin.js
import axios from 'axios';
export const FETCH_CONTENT_VIDEO_LIST = 'fetch_content_video_list';
export function fetchContentVideoList(page, size, where, sort) {
const request = axios.get(`/api/user/get/content/management/method/video/list/format/json?quiet=1&page=` + page + `&size=` + size + `&where=` + JSON.stringify(where) + `&sort=` + sort);
return {
type: FETCH_CONTENT_VIDEO_LIST,
payload: request
};
}
app / reducers / reducer_content.js
import _ from 'lodash';
import { FETCH_CONTENTS } from '../actions';
import {
FETCH_APPSERVICES,
FETCH_APPSERVICES_COUNT,
FETCH_OSTYPES,
FETCH_OSTYPES_COUNT,
FETCH_ENVTYPES,
FETCH_ENVTYPES_COUNT,
FETCH_LOCATIONZONES,
FETCH_LOCATIONZONES_COUNT,
UPLOAD_DOCUMENT_SUCCESS,
UPLOAD_DOCUMENT_FAIL,
} from '../actions/content';
import { FETCH_CONTENT_VIDEO_LIST, FETCH_CONTENT_VIDEO_LIST_COUNT, UPDATE_CONTENT_VIDEO_LIST } from '../actions/admin';
export default function(state = {}, action) {
switch (action.type) {
case FETCH_CONTENTS:
if ( typeof action.payload.data !== 'object'){
return Object.assign({}, state, {
error: {
code: "AUTHENTICATION",
message: 'Your session has expired',
action
}
});
}else if (action.payload.data.header.error) {
return Object.assign({}, state, {
error: {
code: "INVALID ACTION",
message: action.payload.data.header.message,
action
}
});
} else {
return _.mapKeys(action.payload.data.body.recordset.record, 'target');
}
case FETCH_APPSERVICES:
case FETCH_APPSERVICES_COUNT:
case FETCH_LOCATIONZONES:
case FETCH_LOCATIONZONES_COUNT:
case FETCH_OSTYPES:
case FETCH_OSTYPES_COUNT:
case FETCH_ENVTYPES:
case FETCH_ENVTYPES_COUNT:
case FETCH_CONTENT_VIDEO_LIST:
case FETCH_CONTENT_VIDEO_LIST_COUNT:
case UPDATE_CONTENT_VIDEO_LIST:
if ( typeof action.payload.data !== 'object'){
return Object.assign({}, state, {
error: {
code: "AUTHENTICATION",
message: 'Your session has expired',
action
}
});
}else if (action.payload.data.header.error) {
return Object.assign({}, state, {
error: {
code: "INVALID ACTION",
message: action.payload.data.header.message,
action
}
});
} else {
return action.payload.data.body.recordset.record;
}
case UPLOAD_DOCUMENT_SUCCESS:
case UPLOAD_DOCUMENT_FAIL:
return action;
default:
return state;
}
}
我的测试如下所示,但失败。我没有使用redux-thunk
。
test / jest / actions / admin.test.js
import configureMockStore from 'redux-mock-store'
import * as actions from '../../../app/actions/admin'
import * as types from '../../../app/reducers/reducer_content'
import fetchMock from 'fetch-mock'
import expect from 'expect' // You can use any testing library
//const middlewares = [thunk]
const mockStore = configureMockStore()
describe('async actions', () => {
afterEach(() => {
fetchMock.reset()
fetchMock.restore()
})
it('FETCH_CONTENT_VIDEO_LIST', () => {
fetchMock
.getOnce('/contentvideolist', { body: { todos: ['do something'] }, headers: { 'content-type': 'application/json' } })
console.log(types.FETCH_CONTENT_VIDEO_LIST);
const expectedActions = [
{ type: types.FETCH_CONTENT_VIDEO_LIST }
]
const store = mockStore({ todos: [] })
console.log(store);
console.log(actions);
return store.dispatch(actions.fetchContentVideoList()).then(() => {
// return of async actions
console.log(store.getActions());
expect(store.getActions()).toEqual(expectedActions)
})
})
})
在这里失败。
FAIL tests/jest/actions/admin.test.js
async actions
✕ FETCH_CONTENT_VIDEO_LIST (14ms)
● async actions › FETCH_CONTENT_VIDEO_LIST
TypeError: store.dispatch(...).then is not a function
25 | const store = mockStore({ todos: [] })
26 |
> 27 | return store.dispatch(actions.fetchContentVideoList()).then(() => {
28 | // return of async actions
29 | console.log(store.getActions());
30 | expect(store.getActions()).toEqual(expectedActions)
at Object.<anonymous> (tests/jest/actions/admin.test.js:27:60)
更新
这是新错误
FAIL ../actions/admin.test.js
async actions
✕ FETCH_CONTENT_VIDEO_LIST (33ms)
● async actions › FETCH_CONTENT_VIDEO_LIST
TypeError: store.dispatch(...).then is not a function
25 | const store = mockStore({ todos: [] })
26 | console.log(actions);
> 27 | return store.dispatch(actions.fetchContentVideoList()).then(() => {
28 | // return of async actions
29 | console.log(store.getActions());
30 | expect(store.getActions()).toEqual(expectedActions)
at Object.<anonymous> (tests/jest/actions/admin.test.js:27:60)
console.log ../actions/admin.test.js:26
{ FETCH_CONTENT_VIDEO_LIST: 'fetch_content_video_list',
FETCH_CONTENT_VIDEO_LIST_COUNT: 'fetch_content_video_list_count',
UPDATE_CONTENT_VIDEO_LIST: 'update_content_video_list',
fetchContentVideoList: [Function: fetchContentVideoList],
fetchContentVideoListCount: [Function: fetchContentVideoListCount],
updateContentVideoList: [Function: updateContentVideoList] }
更新2
import configureMockStore from 'redux-mock-store'
//import fetchMock from 'fetch-mock'
import expect from 'expect' // You can use any testing library
import axios from 'axios';
import MockAdapter from 'axios-mock-adapter';
import * as actions from '../../../app/actions/admin'
import * as types from '../../../app/reducers/reducer_content'
//const middlewares = [thunk]
const mockStore = configureMockStore()
describe('async actions', () => {
afterEach(() => {
fetchMock.reset()
fetchMock.restore()
});
it('FETCH_CONTENT_VIDEO_LIST', () => {
let mock = new MockAdapter(axios);
const data = { response: true };
mock.onGet('/contentvideolist').reply(200, data);
console.log(types);
const expectedActions = [
{ type: types.FETCH_CONTENT_VIDEO_LIST }
]
const store = mockStore({ todos: [] })
console.log(actions);
store.dispatch(actions.fetchContentVideoList());
expect(store.getActions()).toEqual(expectedActions);
});
});
types
仅显示为[function]
,所以我不能做types.FETCH_CONTENT_VIDEO_LIST
。它显示为undefined
结果
● async actions › FETCH_CONTENT_VIDEO_LIST
expect(received).toEqual(expected)
Expected value to equal:
[{"type": undefined}]
Received:
[{"payload": {}, "type": "fetch_content_video_list"}]
Difference:
- Expected
+ Received
Array [
Object {
- "type": undefined,
+ "payload": Promise {},
+ "type": "fetch_content_video_list",
},
]
26 | console.log(actions);
27 | store.dispatch(actions.fetchContentVideoList());
> 28 | expect(store.getActions()).toEqual(expectedActions);
29 | });
30 | });
31 |
at Object.<anonymous> (tests/jest/actions/admin.test.js:28:32)
console.log tests/jest/actions/admin.test.js:21
{ default: [Function] }
console.log tests/jest/actions/admin.test.js:26
{ FETCH_CONTENT_VIDEO_LIST: 'fetch_content_video_list',
FETCH_CONTENT_VIDEO_LIST_COUNT: 'fetch_content_video_list_count',
UPDATE_CONTENT_VIDEO_LIST: 'update_content_video_list',
fetchContentVideoList:
[Function: fetchContentVideoList],
fetchContentVideoListCount: [Function: fetchContentVideoListCount],
updateContentVideoList: [Function: updateContentVideoList] }
更新3
我试图复制此https://www.leighhalliday.com/mocking-axios-in-jest-testing-async-functions
但是它的类型失败了
import * as actions from '../../../app/actions/admin'
//import * as types from '../../../app/reducers/reducer_content'
const mockAxios = {
get: jest.fn(() => Promise.resolve({ data: {} }))
};
it("fetches data for FETCH_CONTENT_VIDEO_LIST", async () => {
// setup
mockAxios.get.mockImplementationOnce(() =>
Promise.resolve({
data: { results: {"payload": {}, "type": actions.FETCH_CONTENT_VIDEO_LIST} }
})
);
// work
const contentVideoList = await actions.fetchContentVideoList(1,1,{},'id');
// expect
const expectedActions = {"payload": {}, "type": actions.FETCH_CONTENT_VIDEO_LIST}
expect(contentVideoList).toEqual(expectedActions);
expect(mockAxios.get).toHaveBeenCalledTimes(1);
expect(mockAxios.get).toHaveBeenCalledWith(
"/api/user/get/content/management/method/video/list/format/json",
{
params: {
client_id: process.env.REACT_APP_UNSPLASH_TOKEN,
query: "cats"
}
}
);
});
结果
● fetches data for FETCH_CONTENT_VIDEO_LIST
expect(received).toEqual(expected)
Expected value to equal:
{"payload": {}, "type": "fetch_content_video_list"}
Received:
{"payload": {}, "type": "fetch_content_video_list"}
Difference:
- Expected
+ Received
Object {
- "payload": Object {},
+ "payload": Promise {},
"type": "fetch_content_video_list",
}
20 | const expectedActions = {"payload": {}, "type": actions.FETCH_CONTENT_VIDEO_LIST}
21 |
> 22 | expect(contentVideoList).toEqual(expectedActions);
23 | expect(mockAxios.get).toHaveBeenCalledTimes(1);
24 | expect(mockAxios.get).toHaveBeenCalledWith(
25 | "https:///api/user/get/content/management/method/video/list/format/json",
at _callee$ (tests/jest/actions/admin.test.js:22:28)
at tryCatch (node_modules/regenerator-runtime/runtime.js:62:40)
at Generator.invoke [as _invoke] (node_modules/regenerator-runtime/runtime.js:296:22)
at Generator.prototype.(anonymous function) [as next] (node_modules/regenerator-runtime/runtime.js:114:21)
at step (tests/jest/actions/admin.test.js:9:191)
at tests/jest/actions/admin.test.js:9:361
更新4
import configureMockStore from 'redux-mock-store'
//import fetchMock from 'fetch-mock'
import expect from 'expect' // You can use any testing library
import axios from 'axios';
import MockAdapter from 'axios-mock-adapter';
import * as actions from '../../../app/actions/admin'
import * as types from '../../../app/reducers/reducer_content'
//const middlewares = [thunk]
const mockStore = configureMockStore()
describe('async actions', () => {
it('FETCH_CONTENT_VIDEO_LIST', () => {
let mock = new MockAdapter(axios);
const data = { response: true };
mock.onGet('/contentvideolist').reply(200, data);
console.log(types);
const expectedActions = [{"payload": {}, "type": actions.FETCH_CONTENT_VIDEO_LIST}]
const store = mockStore({ fetch_content_video_list: [] })
console.log(actions);
store.dispatch(actions.fetchContentVideoList());
expect(store.getActions()).toEqual(expectedActions);
});
});
结果4
● async actions › FETCH_CONTENT_VIDEO_LIST
expect(received).toEqual(expected)
Expected value to equal:
[{"payload": {}, "type": "fetch_content_video_list"}]
Received:
[{"payload": {}, "type": "fetch_content_video_list"}]
Difference:
- Expected
+ Received
Array [
Object {
- "payload": Object {},
+ "payload": Promise {},
"type": "fetch_content_video_list",
},
]
24 | console.log(actions);
25 | store.dispatch(actions.fetchContentVideoList());
> 26 | expect(store.getActions()).toEqual(expectedActions);
27 | });
28 | });
29 |
at Object.<anonymous> (tests/jest/actions/admin.test.js:26:32)
console.log tests/jest/actions/admin.test.js:21
{ default: [Function] }
console.log tests/jest/actions/admin.test.js:24
{ FETCH_CONTENT_VIDEO_LIST: 'fetch_content_video_list',
FETCH_CONTENT_VIDEO_LIST_COUNT: 'fetch_content_video_list_count',
UPDATE_CONTENT_VIDEO_LIST: 'update_content_video_list',
fetchCo
ntentVideoList: [Function: fetchContentVideoList],
fetchContentVideoListCount: [Function: fetchContentVideoListCount],
updateContentVideoList: [Function: updateContentVideoList] }
答案 0 :(得分:2)
store.dispatch
不返回承诺,而是返回已调度的操作(请参阅dispatch docs),因此无法在结果上调用then
。
相反,执行以下操作,即分派该函数创建的操作,然后检查是否分派了正确的操作:
store.dispatch(actions.fetchContentVideoList());
expect(store.getActions()).toEqual(expectedActions);