在if语句中测试redux-saga并使用实值
testing redux-saga inside if statement and using real values
如何在if语句或try/catch中测试函数?例如,
export function* onFetchMessages(channel) {
yield put(requestMessages())
const channel_name = channel.payload
try {
const response = yield call(fetch,'/api/messages/'+channel_name)
if(response.ok){
const res = yield response.json();
const date = moment().format('lll');
yield put(receiveMessages(res,channel.payload,date))
}
} catch (error){
yield put(rejectMessages(error))
}
}
我需要输入数据库中实际存在的真实通道名称,以便它为随后要执行的yield返回有效响应,否则它将抛出错误。此外,我会得到一个错误消息,无法读取未定义的属性json,因此由于此错误消息,无法达到yield。所以我的第一个问题是'if(response.ok)',但即使我删除它,yield response.json()会返回一个错误,此外yield之后不会被执行。如果有人能告诉我如何测试这些,我将不胜感激。
将响应对象传递给先前的执行和测试条件,我会这样做,希望这有助于:
export function* onFetchMessages(channel) {
try {
yield put(requestMessages())
const channel_name = channel.payload
const response = yield call(fetch,'/api/messages/'+channel_name)
if(response.ok){
const res = yield response.json();
const date = moment().format('lll');
yield put(receiveMessages(res,channel.payload,date))
}
} catch (error){
yield put(rejectMessages(error))
}
}
describe('onFetchMessages Saga', () => {
let output = null;
const saga = onFetchMessages(channel); //mock channel somewhere...
it('should put request messages', () => {
output = saga.next().value;
let expected = put(requestMessages()); //make sure you import this dependency
expect(output).toEqual(expected);
});
it('should call fetch...blabla', ()=> {
output = saga.next(channel_name).value; //include channel_name so it is avaiable on the next iteration
let expected = call(fetch,'/api/messages/'+channel_name); //do all the mock you ned for this
expect(output).toEqual(expected);
});
/*here comes you answer*/
it('should take response.ok into the if statemenet', ()=> {
//your json yield is out the redux-saga context so I dont assert it
saga.next(response).value; //same as before, mock it with a ok property, so it is available
output = saga.next(res).value; //assert the put effect
let expected = put(receiveMessages(res,channel.payload,date)); //channel should be mock from previous test
expect(output).toEqual(expected);
});
});
注意到你的代码可能做了更多我没有意识到的事情,但这至少应该把u放在一些行来解决你的问题。
您可能需要使用辅助库,例如redux-saga-testing。
免责声明:我编写这个库是为了解决完全相同的问题
对于您的特定示例,使用Jest(但对Mocha也一样),我将做两件事:
- 首先,我会将API调用分离到不同的函数 然后我会使用redux-saga-testing以同步的方式测试你的逻辑:
代码如下:
import sagaHelper from 'redux-saga-testing';
import { call, put } from 'redux-saga/effects';
import { requestMessages, receiveMessages, rejectMessages } from './my-actions';
const api = url => fetch(url).then(response => {
if (response.ok) {
return response.json();
} else {
throw new Error(response.status); // for example
}
});
function* onFetchMessages(channel) {
try {
yield put(requestMessages())
const channel_name = channel.payload
const res = yield call(api, '/api/messages/'+channel_name)
const date = moment().format('lll');
yield put(receiveMessages(res,channel.payload,date))
} catch (error){
yield put(rejectMessages(error))
}
}
describe('When testing a Saga that throws an error', () => {
const it = sagaHelper(onFetchMessages({ type: 'foo', payload: 'chan1'}));
it('should have called the API first, which will throw an exception', result => {
expect(result).toEqual(call(api, '/api/messages/chan1'));
return new Error('Something went wrong');
});
it('and then trigger an error action with the error message', result => {
expect(result).toEqual(put(rejectMessages('Something went wrong')));
});
});
describe('When testing a Saga and it works fine', () => {
const it = sagaHelper(onFetchMessages({ type: 'foo', payload: 'chan2'}));
it('should have called the API first, which will return some data', result => {
expect(result).toEqual(call(api, '/api/messages/chan2'));
return 'some data';
});
it('and then call the success action with the data returned by the API', result => {
expect(result).toEqual(put(receiveMessages('some data', 'chan2', 'some date')));
// you'll have to find a way to mock the date here'
});
});
你会在项目的GitHub上找到很多其他的例子(更复杂的)
这里有一个相关的问题:在redux-saga
文档中,他们有take
侦听多个操作的示例。基于此,我写了一个授权传奇,看起来或多或少像这样(你可能会意识到这是redux-saga
文档中一个例子的修改版本:
function* mySaga() {
while (true) {
const initialAction = yield take (['AUTH__LOGIN','AUTH__LOGOUT']);
if (initialAction.type === 'AUTH__LOGIN') {
const authTask = yield fork(doLogin);
const action = yield take(['AUTH__LOGOUT', 'AUTH__LOGIN_FAIL']);
if (action.type === 'AUTH__LOGOUT') {
yield cancel(authTask);
yield call (unauthorizeWithRemoteServer)
}
} else {
yield call (unauthorizeWithRemoteServer)
}
}
}
我不认为在处理saga时这是一个反模式,并且代码当然在测试环境之外按照预期运行(开玩笑)。但是,我认为没有办法在这种上下文中处理if语句。这是怎么回事?
相关文章:
- 可以't让我的if语句处理js中的html表单输入
- 如果 a 为 false,则 if(a) === if(false)
- 如何在ReactJS JSX中执行嵌套的if-else语句
- 我已经创建了一个jquery转盘,并使用if条件来运行和停止转盘
- 正在尝试使用if和else添加类,但无法正常工作
- 在PHP中使用javascript更改页面标题'if'
- Redux Saga连接多个发电机进行存储
- 将 redux-saga 与 ES6 生成器与 ES2017 async/await 一起使用 redux-thunk
- Redux-saga实际消耗数据
- 如何处理Redux-Saga的fetch()响应中的错误
- Redux-saga不等待API的响应
- 《Redux-saga》一开始并不能奏效
- 《Redux-Saga》会因为一个动作而运行两次
- redux-saga生成器在回调中产生失败
- 在if语句中测试redux-saga并使用实值
- 用磁带测试Redux-saga
- 我的redux-saga出了什么问题?
- 在回调中调用yield, redux saga给出了一个异常原因
- React Redux Saga效果无法执行
- getState in redux-saga?