用Jest測試JavaScript中的拒絕承諾

語言: CN / TW / HK

代碼

讓我們考慮一個簡單的函數,它返回一個Promise ,根據第一個參數
的值,可以解決或拒絕:

javascript export default function promiseMe(result, timeout = 1000) { return new Promise((resolve, reject) => { setTimeout(() => { if (result instanceof Error || result.startsWith("Error")) { reject(result) } else { resolve(result) } }, timeout) }) }

當用Jest測試異步代碼時,唯一要記住的是要從測試中返回Promise ,以便Jest可以
,等待它的解析或拒絕。最乾淨的方法是用.resolves 匹配器來做:

```javascript const successMessage = "Done.";

// with async/await it("resolves (1)", async () => { await expect(promiseMe(successMessage)).resolves.toEqual(successMessage); });

// without async/await it("resolves (2)", () => { return expect(promiseMe(successMessage)).resolves.toEqual(successMessage); }); ```

如果Promise 拒絕,而測試又沒有預料到,Jest會報告一個錯誤:

``` Error: expect(received).resolves.toEqual()

Received promise rejected instead of resolved Rejected to value: [...] ```

但是,如果想測試Promise 拒絕,並驗證拒絕的原因呢?

Try-catch與async/await(壞)

看起來使用try-catchasync/await 是實現這一目標的最簡單方法,因為拒絕值被拋出了:

javascript it("rejects (bad)", async () => { try { await promiseMe("Error"); } catch (e) { expect(e).toEqual("Error"); } });

但是,等等。當promiseMe 函數返回的Promise 不會被拒絕,而是解決了,會發生什麼?好吧,測試仍然通過,因為從來沒有到達過catch塊:

參見https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/await#promise_rejection

Try-catch與async/await(更好)

為了克服這個問題,我們可以預期實際的斷言將被執行,如果它沒有發生,則測試失敗。
這可以用expect.assertions 很容易做到,它驗證了在測試期間有一定數量的斷言被調用

javascript it("rejects (better)", async () => { expect.assertions(1); try { await promiseMe("Error"); } catch (e) { expect(e).toEqual("Error"); } });

現在,當沒有拒絕時,測試失敗:

``` Error: expect.assertions(1)

Expected one assertion to be called but received zero assertion calls. ```

.rejects (最佳)

為了使代碼更有表現力,可以使用.rejects 匹配器:

javascript it("rejects (best)", async () => { await expect(promiseMe("Error")).rejects.toEqual("Error"); });

當沒有拒絕時,Jest報告一個錯誤:

``` Error: expect(received).rejects.toEqual()

Received promise resolved instead of rejected
Resolved to value: [...]
```

如果拒絕的值是一個Error 對象,可以使用toThrow 匹配器:

javascript it("rejects (best)", async () => { await expect(promiseMe(new Error(errorMessage))).rejects.toThrow(errorMessage); await expect(promiseMe(new Error(errorMessage))).rejects.toThrow(Error); // type check await expect(promiseMe(new Error(errorMessage))).rejects.toThrow(new Error(errorMessage)); });

另請參見