jest 的工程文件後綴都是xx.test.js,咱們在運行一個jest工程的時候,jest會自動查找運行的後綴爲*.test.js的腳本進行單元測試。前端
js 基於單線程異步的特性,在代碼中充斥的異步程序和各類回調,因此咱們在測試異步代碼的時候要格外注意。一下是各類異步的案例node
test('the data is peanut butter', () => {
function callback(data) {
expect(data).toBe('peanut butter');
}
fetchData(callback);
});
// 這種狀況有問題,你們都知道一個ajax請求是一個事件(由兩個事務發送和返回組成),當發送成功和返回成功這個事件就是完成的,就是成功的,這個時候jest就認爲ajax事件完成了,因此檢驗會在回調判斷執行前結束,沒有驗證data數據,因此這是有問題的。
複製代碼
Jest 提供了相應的方法來done來解決這樣的問題,確保回調執行的來完成整個test驗證。 使用單個參數調用 done,而不是將測試放在一個空參數的函數。Jest會等done回調函數執行結束後,結束測試。 let's show codeajax
test('the data is peanut butter', done => {
function callback(data) {
expect(data).toBe('peanut butter');
done();
}
fetchData(callback);
});
若是 done()永遠不會調用,這個測試將失敗,這也是你所但願發生的。
複製代碼
test('Promise test', ()=>{
// 斷言測試
expect.assertions(1);
// 必定記得return,不然測試拿不到promise的狀態,測試會在fetchData()完成前完成。
return fetchData().then(data=>{
expect(data).tobe('promise')
})
})
複製代碼
若是指望的promise是reject,咱們能夠經過catch來捕獲咱們的錯誤。 請確保添加 expect.assertions 來驗證必定數量的斷言被調用。 不然一個fulfilled態的 Promise 不會讓測試失敗。npm
test('the fetch fails with an error', () => {
expect.assertions(1);
return fetchData().catch(e => expect(e).toMatch('error'));
});
複製代碼
// let's show code~ // resolves test('the data is peanut butter', () => { expect.assertions(1); return expect(fetchData()).resolves.toBe('peanut butter'); }); // rejects test('the fetch fails with an error', () => { expect.assertions(1); return expect(fetchData()).rejects.toMatch('error'); }); 複製代碼
// 提早了解async和await的使用方法和場景
test('the data is peanut butter', async () => {
// 切記添加斷言測試
expect.assertions(1);
const data = await fetchData();
expect(data).toBe('peanut butter');
});
test('the fetch fails with an error', async () => {
expect.assertions(1);
// 切記添加斷言測試
try {
await fetchData();
} catch (e) {
expect(e).toMatch('error');
}
});
複製代碼
還能夠混合使用.resolves / .rejects和Async/Await編程
// 由於await自己返回的就是一個promise。因此咱們能夠在返回的promise的基礎之上繼續測試咱們的代碼。
test('the data is peanut butter', async () => {
expect.assertions(1);
await expect(fetchData()).resolves.toBe('peanut butter');
});
test('the fetch fails with an error', async () => {
expect.assertions(1);
await expect(fetchData()).rejects.toMatch('error');
});
複製代碼
#Jest的遍歷 和 Setup 和 Teardown 進行一些重複的test設置的時候,咱們可使用beforeEach和afterEach。假設咱們在一個交互數據上須要重複的作一些測試設置。假如測試前調用initializeCityDatabase()和測試後調用clearCityDatabase()。那咱們就可使用beforeEach和afterEach了。 let's show code~數組
beforeEach(() => {
initializeCityDatabase();
});
afterEach(() => {
clearCityDatabase();
});
test('city database has Vienna', () => {
expect(isCity('Vienna')).toBeTruthy();
});
test('city database has San Juan', () => {
expect(isCity('San Juan')).toBeTruthy();
});
複製代碼
beforeEach 和 afterEach處理異步的代碼,一樣能夠採用done和promise,若是initializeCityDatabase()返回的是一個promise咱們能夠這樣處理他。let's show codepromise
beforeEach(()=>{
return initializeCityDatabase(); // return一個promise
})
複製代碼
咱們能夠經過Jest的describe函數,經過js函數式編程的思想來建立一個做用域,來模塊化咱們的測試。具體場景就是的經過describe來模塊咱們的foreach的做用範圍。 let's show codebash
// 這裏的beforeEach適用於全部的test
beforeEach(() => {
return initializeCityDatabase();
});
test('city database has Vienna', () => {
expect(isCity('Vienna')).toBeTruthy();
});
test('city database has San Juan', () => {
expect(isCity('San Juan')).toBeTruthy();
});
describe('matching cities to foods', () => {
// 這裏beforeEach僅僅適用於describe中的測試
beforeEach(() => {
return initializeFoodDatabase();
});
test('Vienna <3 sausage', () => {
expect(isValidCityFoodPair('Vienna', 'Wiener Schnitzel')).toBe(true);
});
test('San Juan <3 plantains', () => {
expect(isValidCityFoodPair('San Juan', 'Mofongo')).toBe(true);
});
});
複製代碼
既然這麼多beforeEach/afterEach和beforeAll/afterAll,那結合descibe來看看咱們的執行順序。相信你們看完之後會想起js的(任務隊列和做用域)。異步
beforeAll(() => console.log('1 - beforeAll'));
afterAll(() => console.log('1 - afterAll'));
beforeEach(() => console.log('1 - beforeEach'));
afterEach(() => console.log('1 - afterEach'));
test('', () => console.log('1 - test'));
describe('Scoped / Nested block', () => {
beforeAll(() => console.log('2 - beforeAll'));
afterAll(() => console.log('2 - afterAll'));
beforeEach(() => console.log('2 - beforeEach'));
afterEach(() => console.log('2 - afterEach'));
test('', () => console.log('2 - test'));
});
// 1 - beforeAll
// 1 - beforeEach
// 1 - test
// 1 - afterEach
// 2 - beforeAll
// 1 - beforeEach
// 2 - beforeEach
// 2 - test
// 2 - afterEach
// 1 - afterEach
// 2 - afterAll
// 1 - afterAll
正如結果查看順序,全局的會做用到describe內部。 注意執行順序,beforeALL和afterAll只會執行一次, 全局的beforeEach做用到了describe中的test,還要注意的是after做用域中的after比全局的after先執行。
beforeAll 在beforeEach前先執行,而afterAll在afterEach後執行。
複製代碼
若是你想在衆多的test中,僅僅想進行其中的一個test,很簡單,你只要在他的test語句中添加.only標識就能夠了,其餘的測試則會跳過了.let's show codeasync
// 只有這個test會跑
test.only('this will be the only test that runs', () => {
expect(true).toBe(false);
});
// 這個test則會跳過
test('this test will not run', () => {
expect('A').toBe('A');
});
複製代碼