2016-10-27 86 views
0

我遇到了RxJs沒有捕獲可觀察流中的異常的問題。RxJs沒有捕獲拋出的錯誤

這是我的代碼的樣子。

const Rx = require('rx'); 
if (process.env.NODE_ENV === 'development') { 
    require('dotenv').load(); 
} 

const getTransactionsVerificationStatus = (params, models, retryLimit = process.env.CARD_VERIFICATION_ATTEMPTS_LIMIT) => { 
    const potCheckResult$ = models.pot().exists([params.userId, params.potId]); 

    const needsVerified$ = models.transaction() 
    .listUnverifiedCards([params.userId, params.potId]) 
    .map(card => { 
     return { 
     status: 'success', 
     data: { 
      card: { 
      id: card.id, 
      cardNumberMask: card.cardNumberMask, 
      attemptsRemaining: (retryLimit - card.attempts), 
      chargeDate: card.chargeDate, 
      expiry: card.expiry, 
      status: card.status 
      }, 
      requiresVerification: true 
     } 
     }; 
    }) 
    .take(1); 

    const verified$ = models.user() 
    .getDefaultCard([params.userId]) 
    .map(card => { 
     return { 
     status: 'success', 
     data: { 
      card: { 
      id: card.id, 
      cardNumberMask: card.cardNumberMask, 
      attemptsRemaining: (retryLimit - card.attempts), 
      chargeDate: card.chargeDate, 
      expiry: card.expiry, 
      status: card.status 
      }, 
      requiresVerification: false 
     } 
     }; 
    }) 
    .take(1); 

    const error$ = potCheckResult$ 
    .filter(x => x.len <= 0) 
    .map(() => { 
     return { 
     status: 'error', 
     message: ['Requested pot does not exist for current user'] 
     }; 
    }); 

    return Rx.Observable 
    .concat(error$, needsVerified$, verified$) 
    .take(1) 
    .catch(e => { 
     logger.warn(e); 

     return Rx.Observable.just(
     { 
      status: 'error', 
      type: 'array', 
      data: ['Something went wrong'] 
     } 
    ); 
    }); 
}; 

module.exports = getTransactionsVerificationStatus; 

從本質上講,這裏有三個觀察到的數據流,正在與concat法合併。

問題是,如果這些模型中的任何一個引發異常,則不會被catch方法捕獲。我如何捕獲這些例外情況?

任何幫助將不勝感激!

編輯:

爲了完整起見,這裏有我在上面的代碼運行測試。

const chai = require('chai'); 
chai.use(require('chai-json-schema')); 
const expect = chai.expect; 
const getTransactionsVerificationStatus = require('../get-transactions-verification-status'); 
const Rx = require('rx'); 

describe('Get Transactions Verification Logic', function() { 
    let models; 

    beforeEach(function() { 
    // Mock models 
    models = (params) => { 
     return { 
     pot:() => { 
      return { 
      exists:() => { 
       if(params.potExists) { 
       return Rx.Observable.just({ 
        len: params.potExists 
       }).toArray() 
       } else { 
       return Rx.Observable.just({ 
        len: 0 
       }); 
       } 
      } 
      } 
     }, 
     transaction:() => { 
      return { 
      listUnverifiedCards:() => { 
       if(params.error) { 
       throw new Error('This is an error!'); 
       } 
       if (params.unverifiedCards) { 
       return Rx.Observable.just({ 
        id: "unverified card", 
        cardNumberMask: 123456, 
        attempts: 0, 
        chargeDate: null, 
        expiry: 2016123, 
        status: 'UNVERIFIED' 
       }); 
       } else { 
       return Rx.Observable.empty() 
       } 
      } 
      }; 
     }, 
     user:() => { 
      return { 
      getDefaultCard:() => Rx.Observable.just(
       { 
       id: "verified card", 
       cardNumberMask: 123456, 
       attempts: 0, 
       chargeDate: null, 
       expiry: 2016123, 
       status: 'VERIFIED' 
       } 
      ) 
      }; 
     } 
     }; 
    }; 
    }); 

    it('should return a non-verified card if one has been used in a transaction', done => { 
    const params = { 
     userId: 123, 
     potId: 123 
    }; 

    const modelParams = { 
     potExists: 1, 
     unverifiedCards: true 
    }; 

    const response$ = getTransactionsVerificationStatus(
     params, 
     models(modelParams), 
     3 
    ); 

    response$.subscribe(json => { 
     expect(json).to.deep.equal({ 
     status: "success", 
     data: { 
      card: { 
      id: "unverified card", 
      cardNumberMask: 123456, 
      attemptsRemaining: 3, 
      chargeDate: null, 
      expiry: 2016123, 
      status: 'UNVERIFIED' 
      }, 
      "requiresVerification": true 
     } 
     }); 
     done(); 
    }); 
    }); 

    it('should return the active card if no transactions have used an unverified card', done => { 
    const params = { 
     userId: 123, 
     potId: 123 
    }; 

    const modelParams = { 
     potExists: 1, 
     unverifiedCards: false 
    }; 

    const response$ = getTransactionsVerificationStatus(
     params, 
     models(modelParams), 
     3 
    ); 

    response$.subscribe(json => { 
     expect(json).to.deep.equal({ 
     status: "success", 
     data: { 
      card: { 
      id: "verified card", 
      cardNumberMask: 123456, 
      attemptsRemaining: 3, 
      chargeDate: null, 
      expiry: 2016123, 
      status: 'VERIFIED' 
      }, 
      "requiresVerification": false 
     } 
     }); 
     done(); 
    }); 
    }); 

    it('should return an error message if the user does not have a pot with the id requested', done => { 
    const params = { 
     userId: 1, 
    }; 

    const modelParams = { 
     potExists: 0, 
     unverifiedCards: false, 
     verifiedCards: false 
    }; 

    const response$ = getTransactionsVerificationStatus(
     params, 
     models(modelParams), 
     3 
    ); 

    response$.subscribe(json => { 
     expect(json).to.deep.equal({ 
     status: 'error', 
     message: ['Requested pot does not exist for current user'] 
     }); 
     done(); 
    }); 
    }); 

    it('should handle all other errors', done => { 
    const params = { 
     userId: 1, 
    }; 

    const modelParams = { 
     potExists: 1, 
     unverifiedCards: true, 
     error: true 
    }; 

    const response$ = getTransactionsVerificationStatus(
     params, 
     models(modelParams), 
     3 
    ); 

    response$.subscribe(json => { 
     expect(json).to.deep.equal({ 
     status: 'error', 
     type: 'array', 
     data: ['Something went wrong'] 
     }); 
     done(); 
    }); 
    }); 
}); 

以上所有的斷言通過除了最後一個,它拋出一個錯誤的模型,這個錯誤是從來沒有拿起它使客戶端。

回答

0

我想通了。

問題出在測試上,而不是getTransactionsVerificationStatus函數。

問題是,我拋出的錯誤應該是從可觀察的拋出。這是我更新的代碼位。

if (params.error) { 
    return Rx.Observable.create(() => { 
     throw new Error('Data error'); 
    }); 
    } 

這是不是

if (params.error) { 
    throw new Error('Data error'); 
    } 

希望有人認爲這很有幫助。

0

在串聯的流上,在concat後面有take(1)運算符。這意味着你只會聽第一個值。然後,運營商將執行隱式退訂。這意味着,如果第一個值不是錯誤,那麼將不會有下一個事件發生,因此您的「catch」操作符不會出錯。

其次,您沒有在您的示例中訂閱此流。這只是在你的代碼上面或現實生活中。如果你沒有訂閱你的信息流,那麼這些信息流將不會被啓動(因爲你正在爲我所看到的而使用冷的觀察對象)。

+0

在這種情況下,我只想要一個值。我要麼需要一張有效的卡片列表,不要列出一個或者一個錯誤。錯誤是這個實例中最重要的項目,這就是爲什麼錯誤是'concat'方法中的第一項。 問題是,錯誤正在讓它瀏覽器。 該功能正在導出並訂閱到其他文件中。 我目前正在使用摩卡/柴測試人爲地拋出一個錯誤。如果我包含測試會有用嗎? –

+0

你在哪裏拋出一個錯誤。在錯誤$的映射函數中,你正在返回一個對象而不是拋出錯誤。這可能是問題嗎? – KwintenP

+0

聽起來可能是這個問題。我將如何捕捉它在地圖功能? 我認爲錯誤應該冒泡,直到它雖然抓住了。 –