跳至主要内容

3 篇文章 含有標籤「Jest」

檢視所有標籤

Jest 使用 ES Module 入門教學筆記 | 學習筆記

· 閱讀時間約 5 分鐘
kdchang

前言

在 JavaScript 開發中,ES Modules (ESM) 已成為標準。從 Node.js 12 開始,ESM 已獲得原生支援,而前端開發(如 React、Vue、Svelte 等框架)早已全面採用 ES Module。 然而,當我們使用 Jest 來撰寫與執行測試時,若要直接使用 ES Module,會遇到一些設定上的挑戰。本篇筆記將說明如何在專案中讓 Jest 正確執行 ES Module 程式碼,並透過實例展示操作流程。


1. Jest 是否支援 ES Module?

Jest 自 v27 版本開始實驗性支援 ES Module,到了 v28 以後更加穩定。但因為 Node.js 與 CommonJS、ESM 的處理邏輯不同,仍需要額外設定。

若你使用 ES Module(例如 .mjs 檔案、type: module),或是前端專案用 ES6 import / export,就必須進行相應的 Jest 設定。


2. 初始化專案與安裝 Jest

首先,我們建立一個 Node.js 專案:

mkdir jest-esm-demo
cd jest-esm-demo
npm init -y

接著安裝 Jest:

npm install --save-dev jest

重點!package.json 中加入 type: "module",讓整個專案採用 ES Module:

{
"name": "jest-esm-demo",
"version": "1.0.0",
"type": "module",
"scripts": {
"test": "jest"
},
"devDependencies": {
"jest": "^29.0.0"
}
}

3. 撰寫 ES Module 程式碼

假設我們有一個簡單的 加法模組 sum.mjs

// sum.mjs
export function sum(a, b) {
return a + b;
}

接著建立測試檔案 sum.test.mjs

// sum.test.mjs
import { sum } from './sum.mjs';

test('adds 1 + 2 to equal 3', () => {
expect(sum(1, 2)).toBe(3);
});

這時候直接執行 npm test 會報錯:

SyntaxError: Cannot use import statement outside a module

因為 Jest 預設使用 CommonJS,不認得 ES Module,需要額外設定。


4. 設定 Jest 支援 ES Module

方案一:使用 jest.config.js 並指定 transform

首先,安裝 Babeljest-esm-transformer 之類的工具。如果希望簡單一點,可以直接使用 Jest 的內建 ESM 模式(推薦)。

建立 jest.config.js

// jest.config.js
export default {
transform: {},
extensionsToTreatAsEsm: ['.mjs'],
testEnvironment: 'node',
};

重點設定解釋:

  • transform: {} 表示不使用 Babel 或其他轉譯器
  • extensionsToTreatAsEsm 告訴 Jest 哪些副檔名視為 ESM
  • testEnvironment: 'node' 使用 Node 環境(非 jsdom)

執行 npm test,這時候仍會報錯:

Jest encountered an unexpected token

因為 Jest 內建 transform 無法處理 ES Module 語法(即便 Node.js 支援,但 Jest 內部解析流程不同)。


5. 方案二:使用 babel-jest 轉譯 ESM

安裝 Babel 及相關套件:

npm install --save-dev @babel/preset-env babel-jest

建立 .babelrc

{
"presets": ["@babel/preset-env"]
}

更新 jest.config.js

export default {
transform: {
'^.+\\.m?js$': 'babel-jest',
},
extensionsToTreatAsEsm: ['.mjs'],
testEnvironment: 'node',
};

這樣 Jest 會用 babel-jest 處理 .js.mjs 檔案,並當作 ESM 解析。

此時執行 npm test,測試就會通過:

PASS  ./sum.test.mjs
✓ adds 1 + 2 to equal 3 (5 ms)

6. 測試更複雜情境

假設我們有一個 fetch 模組,使用 async function:

// fetchData.mjs
export async function fetchData() {
return 'peanut butter';
}

測試檔:

// fetchData.test.mjs
import { fetchData } from './fetchData.mjs';

test('returns peanut butter', async () => {
const data = await fetchData();
expect(data).toBe('peanut butter');
});

一樣執行 npm test,因為已經設定好 Babel 與 ESM,非同步測試也能正常運作。


7. 使用 import.meta.url 注意事項

如果你的程式中有用 import.meta.url(例如讀取檔案、動態載入),要注意 Jest 執行時 context 與 Node.js 直跑不同

例如:

// fileUtil.mjs
import { readFile } from 'node:fs/promises';
import { fileURLToPath } from 'node:url';
import { dirname, join } from 'node:path';

const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);

export async function readConfig() {
const filePath = join(__dirname, 'config.json');
const content = await readFile(filePath, 'utf-8');
return JSON.parse(content);
}

測試時要確保 import.meta.url 能被正確解析(可能需要 jest-environment-node,或 Mock 檔案路徑)。


8. 常見錯誤與解法

問題:SyntaxError: Cannot use import statement outside a module

  • 確認 jest.config.js 中有 extensionsToTreatAsEsm
  • 測試檔、副程式檔是否副檔名為 .mjs

問題:Unexpected token export

  • 確認有設定 transform 使用 babel-jest
  • 確認 .babelrc 正確啟用 @babel/preset-env

問題:ESM 測試檔找不到 module

  • 確認 package.jsontype: module
  • 相對路徑記得補 .mjs 副檔名

9. 實用 Jest CLI 指令

  • 執行單一測試檔:
npx jest sum.test.mjs
  • 只跑某個測試:
test.only('專跑這個測試', () => { ... });
  • 顯示覆蓋率:
npx jest --coverage

總結

Jest 預設是為 CommonJS 設計,但隨著 ES Module 在 Node.js 與前端日漸普及,支援 ESM 變得越來越重要。

透過本文介紹,我們可以知道:

  1. type: module 啟用 ESM
  2. Jest 需要設定 transformextensionsToTreatAsEsm
  3. 使用 babel-jest 來處理 ESM
  4. 注意 import.meta.url、路徑、非同步等 ESM 細節

雖然設定比 CJS 稍微複雜,但一旦設定好後,整個測試流程一樣流暢,也能為未來更符合現代標準的專案奠定基礎。

建議未來若有使用 TypeScript、React、Vue 等,也可以結合對應的 transformer 與設定,讓 Jest 完全支援你的開發。

Jest AAA 測試原則入門教學筆記 | 學習筆記

· 閱讀時間約 2 分鐘
kdchang

範例測試:saveMoney 方法

atm.js

class ATM {
constructor(balance) {
this.balance = balance;
}
saveMoney(amount) {
if (amount <= 0) {
throw new Error('Amount must be positive');
}
this.balance += amount;
return this.balance;
}
withdrawMoney(amount) {
if (amount <= 0) {
throw new Error('Amount must be positive');
}
if (amount > this.balance) {
throw new Error('Insufficient balance');
}
this.balance -= amount;
return this.balance;
}
getBalance() {
return this.balance;
}
reset() {
this.balance = 0;
}
setBalance(balance) {
if (balance < 0) {
throw new Error('Balance cannot be negative');
}
this.balance = balance;
}
}

export default ATM;

atm.test.js

import ATM from '../atm.js';

test('saveMoney adds money to balance', () => {
// Arrange: 建立一個 ATM 實例,初始餘額 0
const atm = new ATM(0);

// Act: 存入 1000
atm.saveMoney(1000);

// Assert: 餘額應該變成 1000
expect(atm.balance).toBe(1000);
});

逐步對應:

步驟內容
Arrange建立 ATM 物件並給初始值
Act呼叫 saveMoney(1000)
Assert驗證 atm.balance 是否等於 1000

另一個範例:檢查錯誤拋出

如果要測試當金額是負數時會丟錯誤:

test('saveMoney throws error when amount <= 0', () => {
// Arrange
const atm = new ATM(0);

// Act & Assert
expect(() => atm.saveMoney(0)).toThrow('Amount must be positive');
});

這裡因為 actassert 綁在一起,所以在 expect 裡包了一個 function,來驗證是否拋出錯誤。


完整測試檔(用 AAA 標註)

import ATM from '../atm.js';

test('saveMoney adds money to balance', () => {
// Arrange
const atm = new ATM(0);

// Act
atm.saveMoney(1000);

// Assert
expect(atm.balance).toBe(1000);
});

test('saveMoney throws error when amount <= 0', () => {
// Arrange
const atm = new ATM(0);

// Act & Assert
expect(() => atm.saveMoney(0)).toThrow('Amount must be positive');
});

Google Lighthouse 介紹與入門教學筆記 | 學習筆記

· 閱讀時間約 4 分鐘
kdchang

一、什麼是 Lighthouse?

Google Lighthouse 是 Google 開發的開源自動化工具,主要用來評估網頁的品質,包含 效能 (Performance)、無障礙 (Accessibility)、最佳化 (Best Practices)、SEO、漸進式網頁應用 (PWA) 等五大面向。透過 Lighthouse,開發者可以快速找到網站問題與優化建議,幫助網站在使用者體驗與搜尋引擎上表現更好。

Lighthouse 可以透過以下方式執行:

  • Chrome DevTools(瀏覽器內建)
  • Node.js CLI(命令列工具)
  • Lighthouse CI(持續整合工具)
  • Web 版https://pagespeed.web.dev/)

本教學以 Chrome DevTools 為主,搭配 命令列工具輔助說明。


二、如何在 Chrome 使用 Lighthouse

1. 開啟 Chrome DevTools

  • 使用 Chrome 瀏覽器打開我們想分析的網站
  • 按下 F12Ctrl+Shift+I (Mac: Cmd+Option+I) 開啟 DevTools
  • 點選 「Lighthouse」 分頁(如果沒有看到,點選 >> 更多選項即可)

2. 設定 Lighthouse 報告

在 Lighthouse 分頁中,可以看到幾個選項:

  • Categories:選擇要測試的項目(預設全選)
  • Device:選擇模擬裝置(Mobile 或 Desktop)

一般來說,建議從 Mobile 開始測試,因為 Google 搜尋主要使用行動端指標作為排名依據。

3. 開始產生報告

設定好後,點擊 「Analyze page load」(或「Generate report」),Lighthouse 會開始分析。分析過程會自動重新載入頁面並執行模擬測試,過程大約 30 秒至 1 分鐘。

完成後,會生成一份報告,包含分數、每個項目的問題說明與建議。


三、報告解讀與優化建議

以下為報告中幾個重要指標:

  1. Performance(效能)

    • First Contentful Paint (FCP):第一次內容繪製時間
    • Largest Contentful Paint (LCP):主要內容繪製完成時間
    • Time to Interactive (TTI):頁面可互動時間
    • Cumulative Layout Shift (CLS):累積版面位移

優化方向範例

  • 壓縮圖片(使用 WebP)
  • 延遲非必要 JavaScript 載入(lazy loading)
  • 使用 CSS/JS minify 工具
  • 啟用瀏覽器快取 (cache)
  1. Accessibility(無障礙)

    • 圖片是否有 alt 屬性
    • 表單元素是否有 label
    • 按鈕是否有可辨識的名稱

優化方向範例

  • 確保所有互動元件有適當的 ARIA 標籤
  • 保持足夠的色彩對比
  1. Best Practices(最佳化)

    • 是否使用 HTTPS
    • 是否避免過時的 API
    • 檢查瀏覽器安全設定
  2. SEO

    • 是否有 meta 描述
    • 是否設定 <title>
    • 是否有 robots.txt
    • 頁面是否可被索引

四、實際範例:分析一個網頁

前往 https://example.com 網站,操作步驟如下:

使用 Chrome DevTools:

  1. 用 Chrome 瀏覽 https://example.com
  2. 開啟 DevTools → Lighthouse 分頁
  3. 選擇 Mobile + 全部 Categories
  4. 點擊 Analyze page load

執行後,我們會看到一份報告,例如:

CategoryScore
Performance68
Accessibility92
Best Practices85
SEO90

針對效能分數 68,Lighthouse 會提出具體建議,例如:

  • "Serve images in next-gen formats" → 建議將 JPG/PNG 圖片轉換為 WebP
  • "Eliminate render-blocking resources" → 建議將 CSS/JS 非同步或延遲載入

此時,我們可以採取以下修正:

  • 使用 ImageMagickSquoosh 等工具壓縮並轉換圖片
  • 加上 <link rel="preload"> 標籤預先載入必要資源
  • script 標籤加上 defer 屬性

五、使用命令列執行 Lighthouse

如果需要自動化測試或整合到 CI/CD,可以用 Node.js 安裝 Lighthouse:

1. 安裝

npm install -g lighthouse

2. 執行

lighthouse https://example.com --view

執行後會產生一個 HTML 報告並自動打開。

可以用額外參數調整輸出:

lighthouse https://example.com --output json --output html --output-path ./report.html --preset desktop

六、實務應用與建議

  • 開發階段就導入:開發過程中就應該多次使用 Lighthouse,而不是到上線前才檢查。
  • 設定目標分數:通常建議 Mobile 效能達到 80 分以上。
  • 結合 CI/CD:用 Lighthouse CI 在部署時自動檢查網站品質,確保每次更新不會退步。

如果是大型專案,也可以與 WebPageTest、PageSpeed Insights 搭配,取得更廣泛的性能數據。


七、總結

Google Lighthouse 是一個功能強大的網站品質檢測工具,不僅能協助提升效能,還能兼顧 SEO、無障礙與最佳實務。無論是初學者或資深前端工程師,都建議將 Lighthouse 納入開發流程中,定期檢查與優化,為網站帶來更好的使用者體驗與搜尋排名。

透過本篇教學,相信我們已能夠:

  1. 知道如何使用 Chrome DevTools 產生報告
  2. 理解報告中指標與優化方式
  3. 用命令列執行 Lighthouse 以自動化分析

後續可以根據團隊需求,進一步探索 Lighthouse CI、API 或與其他性能工具整合的進階應用。