2017-08-08 26 views
2

私は、APIコールを行うためにgetItemInfo.jsと、それぞれのJestテストファイルであるgetItemInfo.test.jsの2つのファイルを持っています。なぜ私のjest.mockのpromise reject()がcatch()ではなくthen()に行くのですか?

テストファイルで、ノードモジュールrequest-promiseによってトリガーされたhttp呼び出しを嘲笑しています。

質問は、*********で囲まれた2番目のコードブロックにあります。 基本的に、reject()エラーは、まだ2番目のユニットテストでthen()ブロックに移動していますか?

// getItemInfo.js 

const rp = require('request-promise'); 

const getItemInfo = (id) => { 
    const root = 'https://jsonplaceholder.typicode.com/posts/'; 
    const requestOptions = { 
     uri: `${root}/${id}`, 
     method: 'GET', 
     json: true 
    } 

    return rp(requestOptions) 
    .then((result) => { 
     return result; 
    }) 
    .catch((err) => { 
     return err; 
    }); 
}; 

module.exports = { 
    getItemInfo: getItemInfo 
}; 

ここに私のJestユニットテストファイルがあります。

// getItemInfo.test.js 
const ItemService = require('./getItemInfo'); 

jest.mock('request-promise',() => (options) => { 
    const id = Number.parseInt(options.uri.substring(options.uri.lastIndexOf('/') + 1)); 

    return new Promise((resolve, reject) => { 
     if (id === 12) { 
      return resolve({ 
       id: id, 
       userId: 1, 
       title: '', 
       body: '' 
      }); 
     } else { 
      return reject('something went wrong'); // <-- HERE IS THE REJECT 
     } 
    }) 
}); 

describe('getItemInfo',() => { 
    it('can pass', done => { 
     const TEST_ID = 12 
     ItemService.getItemInfo(TEST_ID).then((result) => { 
      console.log('result:',result); 
      expect(result.id).toBe(TEST_ID); 
      expect(result.userId).toBeDefined(); 
      expect(result.title).toBeDefined(); 
      expect(result.body).toBeDefined(); 
      done(); 
     }); 
    }); 

    it('can fail', (done) => { 
     const TEST_ID = 13; 
     ItemService.getItemInfo(TEST_ID) 
     .catch((err) => { 
      // ************* 
      // This "catch" block never runs 
      // even if the jest.mock above Promise.rejects 
      // Why is that??? 
      // ************* 
      console.log('catch():', err); 
      done(); 
     }) 
     .then((result) => { 
      // this block runs instead. 
      // and it returns "then: something went wrong" 
      console.log('then():', result); 
      done(); 
     }); 
    }); 
}); 

これは単体テストの出力です。コマンドは単にjestです。最後の行はcatch()声明、ないthen()から実行する必要があります。

PASS ./getItemInfo.test.js 
getItemInfo 
    ✓ can pass (9ms) 
    ✓ can fail (1ms) 

Test Suites: 1 passed, 1 total 
Tests:  2 passed, 2 total 
Snapshots: 0 total 
Time:  0.703s, estimated 1s 
Ran all test suites. 
----------------|----------|----------|----------|----------|----------------| 
File   | % Stmts | % Branch | % Funcs | % Lines |Uncovered Lines | 
----------------|----------|----------|----------|----------|----------------| 
All files  |  100 |  100 |  100 |  100 |    | 
getItemInfo.js |  100 |  100 |  100 |  100 |    | 
----------------|----------|----------|----------|----------|----------------| 
console.log getItemInfo.test.js:25 
    result: { id: 12, userId: 1, title: '', body: '' } 

console.log getItemInfo.test.js:48 
    then(): something went wrong 

私が間違って何をしているのですか?

+1

'.catch((ERR)=> {; 戻りERR});ため'エラーを処理!あなたはおそらくそれをしたくありません。 – Bergi

答えて

3

なぜ私のjest.mockのpromise reject()がcatch()ではなくthen()に行くのですか?

あなた.catch()ハンドラは解決約束に拒否された約束を変換しているので、唯一の外.then()ハンドラが呼び出されます。

あなたはこのよう.catch()を使用します。

.catch((err) => { 
    return err; 
}); 

とエラーを再スローまたは拒否約束、そして拒絶は「扱い」とみなされ、返された約束が拒否されていない、解決してしまうを返しません。これはtry/catchを使うのと同じです。 catchハンドラでは、例外を再度スローしない限り例外が処理されます。

あなたはそれがこの単純なスニペットで見ることができます

new Promise((resolve, reject) => { 
 
    reject(new Error("reject 1")); 
 
}).catch(err => { 
 
    // returning a normal value here (anything other than a rejected promise) 
 
    // causes the promise chain to flip to resolved 
 
    return err; 
 
}).then(val => { 
 
    console.log("Promise is now resolved, not rejected"); 
 
}).catch(err => { 
 
    console.log("Don't get here"); 
 
});


これらのいずれかには理由が本当にありません:

.then((result) => { 
    return result; 
}) 
.catch((err) => { 
    return err; 
}); 

あなただけの両方を削除することができますそのうちの。 .then()ハンドラは余分なコードに過ぎず、.catch()ハンドラが拒否を食い止め、それを解決済みの約束に変えます。

.catch()ハンドラを保持し、拒否が上方に伝播するようにしたい場合は、再スローする必要があります。

.catch((err) => { 
    console.log(err); 
    throw err;  // keep promise rejected so reject will propagate upwards 
}); 
2

あなたは解像度に拒絶反応を変換してきたので:あなたは拒絶がgetItemInfoの外に伝播したい場合は、getItemInfoからcatchハンドラを削除

.catch((err) => { 
    return err; 
}); 

catchthenの両方を作成することを忘れないでくださいと約束を返し、そのハンドラが同じに扱われます:

  1. あなたは彼らから値を返す場合、作成された約束then/catchはそれと解決されます値。

  2. あなたは彼らから thenableを返す場合、作成された約束then/catchがそのthenable(つまりthenableが何に基づいて解決または拒否)に従属されます。

  3. あなたがスローその中、作成した約束then/catchは、そのエラーで拒否された場合。

    場合にのみcatchハンドラを必要とする

  • あなたはあなたがする必要がある(あなたがgetItemInfoである)何か他のものに沿ってチェーンを渡し、または

  • していませんエラーを変換(復旧)するか、別のエラーに変換するなど、何らかの方法でエラーを変換します。後者をするには、throwを返すか、または拒否される約束を返す。

関連する問題