2016-02-27 4 views
0

Я создал небольшой учебный проект в Redux и по существу скопировал промежуточное программное обеспечение для асинхронных действий с documentation. Теперь я хочу написать несколько тестов для этого, чтобы убедиться, что он будет работать нормально после того, как я изменю некоторые вещи.Тестирование не обещаний после обещания завершается с помощью Mocha, Chai и Sinon

Чтобы написать мои тесты, я использую Mocha, с chai, chai-as-обещанным и синоном.

У меня нет проблем с сокращением в любом случае, но я не уверен, как тестировать вещи.

Соответствующий код из промежуточного слоя:

export default function callApiMiddleware({ dispatch }) { 
    return next => action => { 
    // ... various checks 

    const [ requestType, successType, errorType ] = types; 
    dispatch({ ...payload, type: requestType }); 

    return callApi().then(
     response => dispatch({ ...payload, type: successType, response }), 
     error => dispatch({ ...payload, type: errorType, error }) 
    ); 
    } 
} 

Промежуточные отправляет соответствующее действие выполняется ли или отвергнуто обещание.

Чтобы проверить это, я завершаю функцию отправки вместе с другими, и я также передаю фиктивное обещание, которое я выполняю или отклоняю в зависимости от того, что я хочу проверить.

тест я написал выглядит следующим образом:

it('should trigger success action when successful',() => { 
    let promise = callApiMiddleware({ dispatch, getState })(next)({ 
    ...action, 
    callApi:() => new Promise((resolve, reject) => resolve('SUCCESS')) 
    }); 
    return expect(promise).to.eventually.be.fulfilled; 
}); 

Это прекрасно работает, но первая проблема, которую я столкнулся, когда я пытался имитировать отклоненный обещание, которое может возникнуть в результате подключения к интернету, так что я написал этот тест:

it('should trigger failure action when failure occurs',() => { 
    let promise = callApiMiddleware({ dispatch, getState })(next)({ 
    ...action, 
    callApi:() => new Promise((resolve, reject) => reject('ERROR')) 
    }); 
    return expect(promise).to.eventually.be.rejected; 
}); 

Но это терпит неудачу со следующим сообщением:

AssertionError: expected promise to be rejected but it was fulfilled with undefined

Expected :[undefined]

Actual :[undefined]

Это не имеет никакого смысла для меня, поскольку я четко передаю обещание, что только функция должна быть отвергнута.

Другая проблема заключается в том, что я также хочу делать другие утверждения, которые не обязательно имеют какое-либо отношение к самому обещанию, но их нужно оценивать, когда обещание заканчивается, например. Я хочу сказать, что метод dispatch вызывался дважды. Сам метод dispatch вычеркивается в тесте с использованием синона для выполнения требуемых утверждений. Потенциально, я хочу сделать несколько утверждений таким образом.

Я попытался следующие:

it('should trigger success action when successful',() => { 
    let promise = callApiMiddleware({ dispatch, getState })(next)({ 
    ...action, 
    callApi:() => new Promise((resolve, reject) => resolve('SUCCESS')) 
    }); 
    return Q.all([ 
    expect(promise).to.eventually.be.fulfilled, 
    expect(dispatch).to.eventually.be.calledTwice 
    ]); 
}); 

Но это возвращает некоторые очень большую ошибку, что просто говорит мне, что dispatch не thenable т.е. не обещание.

У меня нет идей о том, как это сделать, поэтому любой вход будет очень оценен.

+0

Хотя это не отвечает на ваш вопрос, вы можете найти генераторы Redux Saga (http://stackoverflow.com/questions/35654334/how-to-test-api-request-failures-with-redux-saga/35674990 # 35674990) намного легче проверить. –

+0

Спасибо! Я не слышал об этом, я обязательно это проверю, но проблема, которую я имею, вероятно, не относится к сокращению, но больше к инструментам тестирования, которые я пытаюсь понять. – Pavlin

ответ

2

Причиной вы получите обещание правдивого с undefined это потому, что это то, что промежуточный слой возвращается:

return callApi().then(
    response => dispatch({ ...payload, type: successType, response }), 
    error => dispatch({ ...payload, type: errorType, error }) 
); 

Поскольку он не повторно выдать ошибку в второй обратный вызов, полученное обещание выполняется. Так как он ничего не возвращает, он выполняется с undefined.

Вы можете изменить код, чтобы повторно выдать ошибку в этом случае:

return callApi().then(
    response => dispatch({ ...payload, type: successType, response }), 
    error => { 
    dispatch({ ...payload, type: errorType, error }) 
    throw error; 
    } 
); 

Это даст результат, который вы ожидаете, но сообщит необработанный отказ в Devtools каждый раз, ваш запрос не удается. Что может быть хорошо в вашем случае.

Что касается второго примера:

But this returns some very large error that simply tells me that dispatch is not thenable i.e. not a promise.

Похоже .to.eventually.*works on Promises. Действительно, dispatch не является обещанием, поэтому вы не можете использовать его так. Вы можете написать что-то вроде этого, вместо:

return expect(promise).to.eventually.be.fulfilled.then(() => { 
    expect(dispatch).to.be.calledTwice(); 
}); 

Наконец, я хотел бы призвать вас, чтобы проверить Redux Saga. Описание побочных эффектов с генераторами может быть проще, чем с помощью специального промежуточного программного обеспечения, а генераторы - way easier to test.

+1

Спасибо за очень полный ответ, я не очень хорошо знаком с инструментами тестирования, так что это очень помогает. Я определенно проведу редукс-сагу, это выглядит как более чистый способ сделать именно то, чего я хочу достичь. – Pavlin

3

Обещания не регрессируют ошибки, поэтому, если вы поймаете ошибку в первом обработчике захвата, обещание будет выполнено в следующем обработчике, если вы снова не сбросите зацепившую ошибку.

// this does not work 
promise.catch((e) => console.log(e)).catch((e) => console.log(e)); 

Если вы хотите, чтобы это сработало, вам необходимо повторно опробовать ошибку.

promise.catch((e) => { 
    console.log(e); 
    throw e; 
}).catch((e) => console.log(e)); 

Если вы хотите, чтобы тест проходил, вам нужно пересмотреть ошибку, уловленную в обработчике уловов обещания.Так что ваш код должен выглядеть следующим образом:

export default function callApiMiddleware({ dispatch }) { 
    return next => action => { 
    // ... various checks 

    const [ requestType, successType, errorType ] = types; 
    dispatch({ ...payload, type: requestType }); 

    return callApi().then(
     response => dispatch({ ...payload, type: successType, response }), 
     error => { 
      dispatch({ ...payload, type: errorType, error }); 
      throw error; 
     } 
    ); 
    } 
} 
+0

Спасибо, я не знал об этом поведении. Это действительно решает мою первую проблему. – Pavlin

Смежные вопросы