Jest – 初探 JavaScript 測試框架

Share This Post

前言

Jest 是我第一個接觸的測試框架。在接觸 Jest 之前,測試程式其實都是手動去測試的,沒有想過這個過程可以自動化,節省了不少測試的時間。


什麼是 Jest

Jest 是個 JavaScript 的測試框架,目前由 Meta 維護,目地就是自動化測試程式結果是不是符合預期。提供大部分常用框架的支援,並且預設設定就可以完成大部分測試,非常好上手。

Jest


基礎使用

Jest 需求

  • Node.js
  • 一個 Node.js 專案

<aside> 💡 以下套件管理部分皆以 yarn 為例,如果沒有 yarn,請透過以下其中一個指令安裝

  • node.js ≥ 16.10 (包含在內建的 corepack 內,需自行啟用): corepack enable Corepack 是 Node.js 內建的實驗性功能,直接透過 Node.js 管理套件管理工具,而不用自行管理,目前支援 yarnpnpm ,啟用後即可直接使用,不需另外安裝 Corepack 內鑑於 Node.js 16.10 以上的版本如果您想要在 16.10 以下也使用 corepack,則需另外安裝: npm i -g corepack 相關資訊: Corepack | Node.js v18.9.1 Documentation
  • node.js < 16.10: npm i -g yarn@latest

</aside>

從 0 開始撰寫第一個測試

  1. 以預設值建立 Node.js 專案(以下皆以 yarn 為例) yarn init -y
  2. 撰寫 Javascript 程式 index.js const plus = (a, b) => { return a + b; } module.exports = plus; <aside> ⚠️ 檔案需要被 export 才能被測試框架接收並測試 本範例將要被測試的程式寫成一個含式,並透過下面那行程式匯出來給 Jest 使用 module.exports = plus; </aside>
  3. 可以先手動測試一下他的效果
    1. 在終端機中,輸入 node 進入 Node.js 的即時運算模式,此時畫面應該長這樣 Untitled
    2. 將剛剛寫的含式引進來 const plus = require("./index");
    3. 此時可以透過以下指令測試 plus 含式 plus(1, 1); <aside> 💡 如果輸出和以下截圖一樣,就可以繼續下一步 Untitled </aside>
    4. 按下 Ctrl + D 離開 Node.js 即時運算模式

<aside> 👉 此時您已經完成了主程式撰寫以及手動測試,不過現在強調的是自動化測試,接下來開始介紹如何寫測試檔

</aside>

  1. 安裝 Jest yarn add jest --dev
  2. 建立測試檔 index.test.js <aside> 💡 Jest 預設執行測試時會尋找檔名包含 .test. 的檔案然後執行 </aside> const plus = require("./index"); test("plus(1, 1) 應該要等於 2", () => { expect(plus(1, 1)).toBe(2); }) <aside> 💡 程式碼說明:
    1. 寫上測試描述 test(<測試描述>, <測試程式>) test("plus(1, 1) 應該要等於 2", () => { })
    2. 在測試程式區塊寫上程式預期結果 expect(<要測試的含式>).toBe(<預期的輸出值>) expect(plus(1, 1)).toBe(2); 這段代表「我預期 plus(1, 1) 的回傳值是 2」,如果這段程式成立代表測試成功
    </aside>
  3. 執行測試 yarn jest <aside> 💡 如果輸出長得跟下面截圖一樣,恭喜你完成第一個測試 Untitled </aside>
  4. 製造一個不通過的測試
    1. 修改 index.js,把剛剛的 + 改成 * Untitled
    2. 此時再執行一次測試,你就會發現他出錯了 Untitled <aside> 💡 解讀錯誤訊息:
      1. 他會說哪個測試出錯,此時剛才寫的描述會寫在這裡 Untitled
      2. 然後會說哪一行測試失敗,例如這個例子: Untitled 因為先前在測試中寫了「預期 plus(1, 1) 的回傳值為 2expect(plus(1, 1)).toBe(2); 但是他的實際結果卻收到了 1 Untitled 這個預期條件不成立了,因此他判定這個測試是失敗的。
      </aside>

相關說明:

Getting Started · Jest


VSCode 插件 – Jest

在講其他功能之前,先來介紹一個 VsCode 的插件。

Jest – Visual Studio Marketplace

這個插件將 Jest 整合到 VSCode 內,重點功能如下:

  1. **自動執行測試:**預設設定下存檔時就會直接執行測試
  2. **直接查看測試結果:**程式碼左邊會提示目前這個測試試否成功 Untitled Untitled
  3. **測試概觀檢視:**在左側邊欄查看所有測試狀態 Untitled

其他測試語法

  1. 值相等 剛剛使用過的 expect(<要測試的含式>).toBe(<預期的輸出值>),也是最簡單的,就是檢查兩邊是否相等 test("except-tobe", () => { const value = 1 + 1; expect(value).toBe(2); expect(value).not.toBe(3); }) <aside> 💡 任何測試語法都可以加上 .not 代表否定判斷,例如以下測試語法會通過測試: expect(1 + 1).not.toBe(3); </aside>
  2. 物件值相等 .toBe 使用的是 Object.is,也就是說只要兩邊都是 Object 測試就會通過,不會管內容是否相等,因此 Jest 會檔下來不給執行 test("except-tobe", () => { const value = { a:1, b:2 }; expect(value).toBe({ a:1, b:2 }); }) Untitled 因此要判斷物件內容是否相等時,需使用 toEqual test("except-toEqual", () => { const value = { a:1, b:2 }; expect(value).toEqual({ a:1, b:2 }); })
  3. 真假空測試 有時候,您想明確分辨 undefinednullfalse,但有時候你又不想這麼明確的分辨他。此時 Jest 提供了一系列語法供使用
    • toBeNull :只有 null 會通過
    • toBeUndefined :只有 undefined 會通過
    • toBeDefined : toBeUndefined 的相反
    • toBeTruthy : 只要在 if 內覺得是 true 的就會通過
    • toBeFalsy : 只要在 if 內覺得是 false 的就會通過
    範例:以下測試皆會通過 test("null", () => { const n = null; expect(n).toBeNull(); // n 為 null,因此 toBeNull 通過 expect(n).toBeDefined(); // n 不是 undefined,因此 toBeDefined 通過 expect(n).not.toBeUndefined(); // n 不是 undefined,因此 not toBeUndefined 通過 expect(n).not.toBeTruthy(); // if (n) 視為 false,因此 not toBeTruthy 通過 expect(n).toBeFalsy(); // if (n) 視為 false,因此 toBeFalsy 通過 }); test("zero", () => { const z = 0; expect(z).not.toBeNull(); // z 不是 null,因此 not toBeNull 通過 expect(z).toBeDefined(); // z 不是 undefined,因此 toBeDefined 通過 expect(z).not.toBeUndefined(); // z 不是 undefined,因此 not toBeUndefined 通過 expect(z).not.toBeTruthy(); // if (z) 視為 false,因此 not toBeTruthy 通過 expect(z).toBeFalsy(); // if (z) 視為 false,因此 toBeFalsy 通過 });
  4. 數字測試
    1. 數字測試比較 test('two plus two', () => { const value = 2 + 2; expect(value).toBeGreaterThan(3); // 2 + 2 > 3 --> 通過 expect(value).toBeGreaterThanOrEqual(3.5); // 2 + 2 >= 3.5 --> 通過 expect(value).toBeLessThan(5); // 2 + 2 < 5 --> 通過 expect(value).toBeLessThanOrEqual(4.5); // 2 + 2 <= 4.5 --> 通過 // toBe 和 toEqual 在數字比較上是相同的 expect(value).toBe(4); expect(value).toEqual(4); });
    2. 為了避免踩到 JavaScript 在浮點數上的雷,例如: Untitled 會導致以下的測試無法通過 test("adding floating point numbers", () => { const value = 0.1 + 0.2; expect(value).toBe(0.3); // 0.1 + 0.2 不會等於 0.3,因此不會通過 }); Untitled 因此 Jest 提供了 toBeCloseTo ,只要相似就會通過 test("adding floating point numbers", () => { const value = 0.1 + 0.2; expect(value).toBeCloseTo(0.3); // 0.1 + 0.2 近似於 0.3,因此會通過 });
  5. 字串比對 可以透過 toMatch 使用正規表達式(Regex)比對字串 test('there is no I in team', () => { expect('team').not.toMatch(/I/); }); test('but there is a "stop" in Christoph', () => { expect('Christoph').toMatch(/stop/); });
  6. 陣列比對 可以使用 .toContain 檢查項目是否在 list 內 const list = ["a", "b", "c", "f"]; test("the shopping list has milk on it", () => { expect(list).toContain("f"); expect(list).not.toContain("d"); });

相關說明:

Using Matchers · Jest


ES6 測試(Babel)

<aside> 💡 Babel 官網

Babel · The compiler for next generation JavaScript

</aside>

假設現在有一個簡單的 babel 專案:

jest-es6.zip

下載解壓縮後記得先執行一次 yarn 安裝相依,資料夾結構應該長這樣:

Untitled
  1. 安裝測試用套件 yarn add jest babel-jest --dev
  2. 設定 babel之前,需要先把設定檔格式換成 .js
    1. babel.config.json 重新命名成 babel.config.js Untitled
    2. 在第一個大刮號前面加上 module.exports = 完整檔案如下: module.exports = { "presets": ["@babel/preset-env"] }
  3. 在設定中,將 "@babel/preset-env" 取代成 ['@babel/preset-env', {targets: {node: 'current'}}] module.exports = { presets: [["@babel/preset-env", { targets: { node: "current" } }]], };
  4. 建立測試專用資料夾(推薦) Untitled
  5. 建立 index.test.js 開始寫測試,直接使用 ES6 語法即可 import { plus, minus } from '../src/index'; test("plus(1, 1) 應該要等於 2", () => { expect(plus(1, 1)).toBe(2); }); test("minus(1, 1) 應該要等於 0", () => { expect(minus(1, 1)).toBe(0); });

相關說明:

Getting Started · Jest


TypeScript 測試

<aside> 💡 TypeScript 官網

JavaScript With Syntax For Types.

</aside>

假設現在有一個簡單的 TypeScript 專案:

jest-ts.zip

下載解壓縮後記得先執行一次 yarn 安裝相依,資料夾結構應該長這樣:

Untitled
  1. 安裝測試用套件 yarn add jest ts-jest --dev
  2. tsconfig.json 加上這一段來忽略測試檔~~(讓 VsCode 閉嘴一下)~~,因為他不需要被編譯: "exclude": ["**/*.test.ts"] Untitled Is there such an tsconfig option such as exclude from compiling but not from linting ?
  3. 生成 jest 設定檔以讓 jest 自動使用 ts-jest 引擎 yarn ts-jest config:init
  4. 建立測試專用資料夾(推薦) Untitled
  5. 建立 index.test.ts 開始寫測試,直接使用 TypeScript 語法即可 <aside> ⚠️ 注意第一行是必須被引入的,因為 TypeScript 需要型態定義 </aside> import { expect, test } from '@jest/globals'; import { plus, minus } from '../src/index'; test("plus(1, 1) 應該要等於 2", () => { expect(plus(1, 1)).toBe(2); }); test("minus(1, 1) 應該要等於 0", () => { expect(minus(1, 1)).toBe(0); });

相關說明:

Getting Started · Jest

Installation | ts-jest


常用框架測試

<aside> 💡 以下教學皆以使用工具建立的空白專案為例

</aside>

Express.js

<aside> 💡 建立 Express.js 空白專案

Express application generator

</aside>

<aside> 💡 如果您的 express 專案是單頁式的,例如:app.js 的 listen 跟其他程式在同一頁

const express = require('express')
const app = express()
const port = 3000

app.get('/', (req, res) => {
  res.send('Hello World!')
})

app.listen(port, () => {
  console.log(`Example app listening on port ${port}`)
})

您需要先把 listen 分離,才能進行測試,例如上面的檔案改寫成兩個程式(檔名自取):

  • app.js – 主程式 const express = require('express') const app = express() app.get('/', (req, res) => { res.send('Hello World!') }) module.exports = app;
  • server.js – 啟動器 const app = require("./app"); const port = 3000 app.listen(port , () => { console.log(`Example app listening on port ${port}`) });

正式執行時改執行 server.js 即可

</aside>

  1. 安裝測試用套件 yarn add jest supertest --dev
  2. 建立測試專用資料夾(推薦) Untitled
  3. 以內建的範例檔快速寫一個測試 const request = require("supertest"); // Express.js 測試程式 const app = require("../app"); // Express 主程式 describe("Test /uesrs", () => { test("It should response the GET method", () => { return request(app) .get("/users") // 呼叫 GET /users .expect(200) // 預期回傳碼為 200 .then((response) => { expect(response.text).toMatch(/resource/); // 預期回傳文字包含 resource }); }); }); <aside> 💡 因為範例檔案回傳的是存文字 res.send('respond with a resource'); 因此判斷內容使用 response.text 但常見的 API 回應是使用 json 格式,例如: res.status(200).json({ message: 'respond with a resource' }); 那回應的內容會放在 response.body 內,因此測試會寫成 return request(app) .get("/users") .expect(200) .then((response) => { // 預期回傳的物件路徑包含 resource expect(response.body.message).toMatch(/resource/); }); </aside>

其他說明可參考:

How to test Express.js with Jest and Supertest


React.js

<aside> 💡 建立空白的 React.js 專案

Create a New React App – React

</aside>

React.js 在建立之後就已經內建一個測試檔案了,在 src/App.test.js

Untitled

內容如下:

import { render, screen } from '@testing-library/react';
import App from './App';

test('renders learn react link', () => {
  render(<App />);                                       // 渲染 App 頁面
  const linkElement = screen.getByText(/learn react/i);  // 透過文字尋找元件
  expect(linkElement).toBeInTheDocument();               // 預期元件有在網頁內
});

其他說明可參考:

Example | Testing Library


Vue.js

<aside> 💡 建立空白 Vue.js 專案

Vue CLI

</aside>

Vue 也有內建單元測試,可以在建立專案的時候選擇安裝,如果是現有 Vue 專案,在建立時沒有選擇測試元件,也可以手動安裝

新增 Vue 測試元件,有以下兩種方式:

  1. 建立專案時選擇安裝,在第一個選項需選擇 Manually select features Untitled
  2. 在現有專案手動安裝 vue add unit-jest

新增完之後會出現一些檔案,包括設定和一個範例測試檔

Untitled

example.spec.js 內容如下:

import { shallowMount } from '@vue/test-utils'
import HelloWorld from '@/components/HelloWorld.vue'

describe('HelloWorld.vue', () => {
  it('renders props.msg when passed', () => {
    const msg = 'new message'
    const wrapper = shallowMount(HelloWorld, {
      props: { msg }
    })
    expect(wrapper.text()).toMatch(msg)    // 預期元件內的文字包含傳進去的 msg
  })
})

本區塊來源:

[Day16] Vue 3 單元測試 (Unit Testing) – Vue Test Utils + Jest 基本介紹 & 安裝 – iT 邦幫忙::一起幫忙解決難題,拯救 IT 人的一天

其他測試可參考:

Testing | Vue.js


當然還有其他框架的測試方法,可以參考這頁:

https://jestjs.io/docs/testing-frameworks

其他 Jest 功能

Jest 雖然標榜免設定,但他還是可以視需要做調整,以符合 Node.js 專案的需求。

在設定之前,Jest 其實有提供初始化設定檔的指令,指令如下:

yarn jest --init

執行後他會問你一些問題

  1. 是否在 package.json 引入測試指令(例如: yarn testUntitled
  2. 是否在設定檔使用 TypeScript Untitled
  3. 您的測試環境為何?(Node/Browser) Untitled
  4. 是否產生覆蓋率報告 Untitled <aside> 👉 如果選 Y 會問你要用哪個引擎 Untitled </aside>
  5. 測試前是否清除 mock calls、instances、contexts 和 results <aside> 👉 我不太清楚這是清除啥,所以我選 N </aside> Untitled

問完之後會產生一個檔案叫 jest.config.js

Untitled

而如果您第一個問題回答 Y 則會在 package.json 新增這段

Untitled

<aside> 👉 Config 建立完了,開始介紹一些功能

</aside>

Coverage 程式碼覆蓋報表

Jest 在測試時可以選擇產生覆蓋率報表,可幫助檢查程式碼的所有部分是否都有被測試到

開啟報表的方式有兩種:

  1. 執行時加上 --coverage yarn jest --coverage
  2. 在設定檔中啟用,建立設定檔時可以選擇啟用或是透過以下選項手動啟用
    • jest.config.js 相關設定 // 執行測試時產生報表 collectCoverage: true, // 包含在覆蓋率報表內的程式碼路徑,以字串陣列表示 collectCoverageFrom: [], // 產生的報表輸出檔路徑 coverageDirectory: "coverage", // 跳過覆蓋率偵測的路徑列表,以 regexp 陣列表示 coveragePathIgnorePatterns: [ "/node_modules/" ], // 指定覆蓋率提供程式 coverageProvider: "babel", // 覆蓋率報告的輸出格式 coverageReporters: [ "json", "text", "lcov", "clover" ], // 指定最小允許的覆蓋值,若低於這個值會導致程式回傳非 0 值(執行失敗) coverageThreshold: { global: { branches: 80, functions: 80, lines: 80, statements: -10, }, },

開啟之後執行測試會多出一個表格:

Untitled

會列出所有檔案以及覆蓋率報告:

  • Stmts – (Statements): 在測試中至少執行一次的指令
  • Branch: if 的每個條件至少要執行一次
  • Funcs: 每個含式至少要執行一次
  • Lines: 測試中至少執行一次的行

另外也會列出沒有被涵蓋到的部分,以另一個專案為例,如下圖:

Untitled

先前的 VSCode 插件 – Jest 也有提供覆蓋率報告

打開命令列( Ctrl + Shift + PF1 ),輸入 toggle coverage

Untitled

即可切換覆蓋率報告,沒有被覆蓋到的程式碼會以紅底顯示,有時候需要用插件重新跑一次測試才會出現

Untitled

Setup / Teardown

此功能可以指定開始測試前跟測試後需要執行的程式碼,主要分成幾個範圍:

  1. 寫在測試檔內
    1. beforeEach / afterEach beforeEach(() => { // 放上你在每個測試開始前要執行的程式 }); afterEach(() => { // 放上你在每個測試結束後要執行的程式 }); 指定在每個測試開始前 / 結束後要執行的程式碼,執行單位是一個測試
    2. beforeAll / afterAll beforeAll(() => { // 放上範圍內所有測試開始前要執行的程式 }); afterAll(() => { // 放上範圍內所有測試結束後要執行的程式 }); 指定在所在範圍內的所有測試開始前 / 結束後要執行的程式碼
    在不同範圍下所有 before / after 的執行順序可以參考以下範例:
    • test/scope.test.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 - test1")); 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 - test1")); test("", () => console.log("2 - test2")); }); test("", () => console.log("1 - test2"));
    • 輸出: PASS test/scope.test.js ● Console console.log 1 - beforeAll at Object.log (test/scope.test.js:1:25) console.log 1 - beforeEach at Object.log (test/scope.test.js:3:26) console.log 1 - test at Object.log (test/scope.test.js:6:24) console.log 1 - afterEach at Object.log (test/scope.test.js:4:25) console.log 2 - beforeAll at Object.log (test/scope.test.js:9:27) console.log 1 - beforeEach at Object.log (test/scope.test.js:3:26) console.log 2 - beforeEach at Object.log (test/scope.test.js:11:28) console.log 2 - test at Object.log (test/scope.test.js:14:26) console.log 2 - afterEach at Object.log (test/scope.test.js:12:27) console.log 1 - afterEach at Object.log (test/scope.test.js:4:25) console.log 2 - afterAll at Object.log (test/scope.test.js:10:26) console.log 1 - afterAll at Object.log (test/scope.test.js:2:24)
    相關說明: Setup and Teardown · Jest
  2. 寫在 setup file 此方法為將測試開始前 / 結束後執行的程式碼獨立寫成檔案,需要在 jest.config.js 中指定
    1. setupFiles // 每個測試環境建立前執行的程式,以路徑陣列指定 setupFiles: [], <aside> 💡 因為此時測試環境還沒建立,因此包括 beforeAll 等所有測試語法尚未被定義,所以沒辦法指定是什麼時候執行,只能放在測試的最前面執行 </aside>
    2. setupFilesAfterEnv // 每個測試環境建立後測試執行前執行的程式,以路徑陣列指定 setupFilesAfterEnv: [], <aside> 💡 此時測試環境已經建立完成,因此可以用上述方法在每個測試檔案使用 beforeAll / afterAll / beforeEach / afterEach ,而且執行優先度最高 </aside>
    整合上述所有程式,各個程式碼的執行順序如以下範例:
    • test/scope.test.js
    • test/scope2.test.js beforeAll(() => console.log("1.2 - beforeAll")); afterAll(() => console.log("1.2 - afterAll")); beforeEach(() => console.log("1.2 - beforeEach")); afterEach(() => console.log("1.2 - afterEach")); test("", () => console.log("1.2 - test1")); describe("Scoped / Nested block", () => { beforeAll(() => console.log("2.2 - beforeAll")); afterAll(() => console.log("2.2 - afterAll")); beforeEach(() => console.log("2.2 - beforeEach")); afterEach(() => console.log("2.2 - afterEach")); test("", () => console.log("2.2 - test1")); test("", () => console.log("2.2 - test2")); }); test("", () => console.log("1.2 - test2"));
    • test/setup.js // 因為測試環境還沒建立 // 如果使用 beforeAll / afterAll / beforeEach / afterEach 會出現 undefined 錯誤 console.log("3 - setup");
    • test/setupAfterEnv.js beforeAll(() => console.log("4 - beforeAll - setupAfterEnv")); afterAll(() => console.log("4 - afterAll - setupAfterEnv")); beforeEach(() => console.log("4 - beforeEach - setupAfterEnv")); afterEach(() => console.log("4 - afterEach - setupAfterEnv"));
    • jest.config.json Untitled // The paths to modules that run some code to configure or set up the testing environment before each test setupFiles: ["./test/setup.js"], // A list of paths to modules that run some code to configure or set up the testing framework before each test setupFilesAfterEnv: ["./test/setupAfterEnv.js"],
    • 輸出 PASS test/scope2.test.js ● Console console.log 3 - setup at Object.<anonymous> (test/setup.js:3:9) console.log 4 - beforeAll - setupAfterEnv at Object.log (test/setupAfterEnv.js:1:25) console.log 1.2 - beforeAll at Object.log (test/scope2.test.js:1:25) console.log 4 - beforeEach - setupAfterEnv at Object.log (test/setupAfterEnv.js:3:26) console.log 1.2 - beforeEach at Object.log (test/scope2.test.js:3:26) console.log 1.2 - test1 at Object.log (test/scope2.test.js:6:24) console.log 4 - afterEach - setupAfterEnv at Object.log (test/setupAfterEnv.js:4:25) console.log 1.2 - afterEach at Object.log (test/scope2.test.js:4:25) console.log 2.2 - beforeAll at Object.log (test/scope2.test.js:9:27) console.log 4 - beforeEach - setupAfterEnv at Object.log (test/setupAfterEnv.js:3:26) console.log 1.2 - beforeEach at Object.log (test/scope2.test.js:3:26) console.log 2.2 - beforeEach at Object.log (test/scope2.test.js:11:28) console.log 2.2 - test1 at Object.log (test/scope2.test.js:14:26) console.log 2.2 - afterEach at Object.log (test/scope2.test.js:12:27) console.log 4 - afterEach - setupAfterEnv at Object.log (test/setupAfterEnv.js:4:25) console.log 1.2 - afterEach at Object.log (test/scope2.test.js:4:25) console.log 4 - beforeEach - setupAfterEnv at Object.log (test/setupAfterEnv.js:3:26) console.log 1.2 - beforeEach at Object.log (test/scope2.test.js:3:26) console.log 2.2 - beforeEach at Object.log (test/scope2.test.js:11:28) console.log 2.2 - test2 at Object.log (test/scope2.test.js:15:26) console.log 2.2 - afterEach at Object.log (test/scope2.test.js:12:27) console.log 4 - afterEach - setupAfterEnv at Object.log (test/setupAfterEnv.js:4:25) console.log 1.2 - afterEach at Object.log (test/scope2.test.js:4:25) console.log 2.2 - afterAll at Object.log (test/scope2.test.js:10:26) console.log 4 - beforeEach - setupAfterEnv at Object.log (test/setupAfterEnv.js:3:26) console.log 1.2 - beforeEach at Object.log (test/scope2.test.js:3:26) console.log 1.2 - test2 at Object.log (test/scope2.test.js:18:24) console.log 4 - afterEach - setupAfterEnv at Object.log (test/setupAfterEnv.js:4:25) console.log 1.2 - afterEach at Object.log (test/scope2.test.js:4:25) console.log 4 - afterAll - setupAfterEnv at Object.log (test/setupAfterEnv.js:2:24) console.log 1.2 - afterAll at Object.log (test/scope2.test.js:2:24) PASS test/scope.test.js ● Console console.log 3 - setup at Object.<anonymous> (test/setup.js:3:9) console.log 4 - beforeAll - setupAfterEnv at Object.log (test/setupAfterEnv.js:1:25) console.log 1 - beforeAll at Object.log (test/scope.test.js:1:25) console.log 4 - beforeEach - setupAfterEnv at Object.log (test/setupAfterEnv.js:3:26) console.log 1 - beforeEach at Object.log (test/scope.test.js:3:26) console.log 1 - test1 at Object.log (test/scope.test.js:6:24) console.log 4 - afterEach - setupAfterEnv at Object.log (test/setupAfterEnv.js:4:25) console.log 1 - afterEach at Object.log (test/scope.test.js:4:25) console.log 2 - beforeAll at Object.log (test/scope.test.js:9:27) console.log 4 - beforeEach - setupAfterEnv at Object.log (test/setupAfterEnv.js:3:26) console.log 1 - beforeEach at Object.log (test/scope.test.js:3:26) console.log 2 - beforeEach at Object.log (test/scope.test.js:11:28) console.log 2 - test1 at Object.log (test/scope.test.js:14:26) console.log 2 - afterEach at Object.log (test/scope.test.js:12:27) console.log 4 - afterEach - setupAfterEnv at Object.log (test/setupAfterEnv.js:4:25) console.log 1 - afterEach at Object.log (test/scope.test.js:4:25) console.log 4 - beforeEach - setupAfterEnv at Object.log (test/setupAfterEnv.js:3:26) console.log 1 - beforeEach at Object.log (test/scope.test.js:3:26) console.log 2 - beforeEach at Object.log (test/scope.test.js:11:28) console.log 2 - test2 at Object.log (test/scope.test.js:15:26) console.log 2 - afterEach at Object.log (test/scope.test.js:12:27) console.log 4 - afterEach - setupAfterEnv at Object.log (test/setupAfterEnv.js:4:25) console.log 1 - afterEach at Object.log (test/scope.test.js:4:25) console.log 2 - afterAll at Object.log (test/scope.test.js:10:26) console.log 4 - beforeEach - setupAfterEnv at Object.log (test/setupAfterEnv.js:3:26) console.log 1 - beforeEach at Object.log (test/scope.test.js:3:26) console.log 1 - test2 at Object.log (test/scope.test.js:18:24) console.log 4 - afterEach - setupAfterEnv at Object.log (test/setupAfterEnv.js:4:25) console.log 1 - afterEach at Object.log (test/scope.test.js:4:25) console.log 4 - afterAll - setupAfterEnv at Object.log (test/setupAfterEnv.js:2:24) console.log 1 - afterAll at Object.log (test/scope.test.js:2:24)
  3. global setup / teardown 而這個方法又是更外層的,是整個測試工作開始前和整個測試工作結束後才會執行一次測試的程式碼片段,需要在 jest.config.js 中指定,且程式碼需透過 module 的方式 export 出來
    • jest.config.js // 在所有測試單元開始前執行的程式模組 globalSetup: '', // 在所有測試單元結束後執行的程式模組 globalTeardown: '',
    • 被引用的檔案(以 ES6 語法為例) export default () => { // 放上要執行的程式片段 }

最後,整合上述範例,完整的測試執行順序,如以下範例:

  • test/scope.test.js
  • test/scope2.test.js
  • test/setup.js
  • test/setupAfterEnv.js
  • test/bootstrap.js export default () => { console.log("5 - bootstrap"); }
  • test/teardown.js export default () => { console.log("5 - teardown"); }
  • jest.config.js
    • 上個變更
    • 新增變更 Untitled // A path to a module which exports an async function that is triggered once before all test suites globalSetup: "./test/bootstrap.js", // A path to a module which exports an async function that is triggered once after all test suites globalTeardown: "./test/teardown.js",
  • 輸出 yarn run v1.22.19 $ jest Determining test suites to run...5 - bootstrap <---- Here
    • 中間部分和前一個一樣
    Test Suites: 3 passed, 3 total Tests: 10 passed, 10 total Snapshots: 0 total Time: 2.045 s Ran all test suites. 5 - teardown <---------------------------------------- Here Done in 4.11s.

設定檔

https://jestjs.io/docs/configuration

訂閱研究文章

Get updates and learn from the best

More To Explore

Commitizen

前言: 現今軟體功能複雜與龐大,在開發過程中,不管單人開發還是多人協作,對所編寫的代碼與代碼版本管控都是必須的

NFC x Mifare

實作紀錄 readMifare readNdef 知識補充 手機NFC隱含攻擊弱點 掌握原理避免無線盜刷 MI

Scroll to Top