測試環境

什麼是測試?所述,JavaScript 中的測試只是確保可成功執行的程式碼,也就是不會擲回 Error 的程式碼。不過,這個定義有一個簡化的方式,就是不會考慮執行程式碼的「位置」,也就是「測試環境」

我們大致上可以將測試環境視為兩個元件:您用來執行測試的執行階段環境 (例如 Node 或瀏覽器),以及您可以使用的 API。

執行階段環境

Node 等執行階段或類似工具 (如 Deno 或 Bun) 旨在支援伺服器端或一般用途的 JS 程式碼。這些元素的環境不包含您可能會預期在瀏覽器中使用的 API,例如建立和使用 DOM 和 HTML 元素,也不包含視覺元件或轉譯目標的任何概念 (也就是說,除了「只是」元素,而是透過 CSS 將這些元素視覺化呈現至可視區域)。

因此,如果您嘗試轉譯 React 元素,這些一般用途的執行階段就會失敗,因為沒有可用的 documentwindow 物件而能夠測試這些元素。

另一方面,如果您在瀏覽器中執行測試,則需要進行折線處理或進行一些額外工作,才能取得這些執行階段中預期能使用的內建 API。常見的挑戰就像讀取和寫入檔案一樣:您無法在瀏覽器內以這種方式讀取檔案 (做為測試的一部分)。import { fs } from 'node:'fs';

這個「網頁」與「後端」API 問題比測試範圍還不夠,因為如果同時擁有伺服器和用戶端部分的程式碼集,可能會令人感到困惑,但涉及編寫可測試程式碼的概念,本課程將再來會說明。

測試演算法或商業邏輯

部分程式碼不必匯入節點或瀏覽器就能運作,因此無須匯入。本課程稍後會說明這點,但如果您藉由建構程式碼集,將單純的「商業邏輯」與轉譯或節點專屬程式碼分開,即可更輕鬆地進行測試。

舉例來說,您可能有 Node 函式,可從磁碟讀取及寫入檔案,並在過程中進行修改。透過重構函式來接受可執行磁碟讀取和寫入的函式,您即可在任何地方進行測試。

在這種情況下,您可以使用任何環境在伺服器端執行階段或瀏覽器中測試這段程式碼。在測試中,您可以提供輔助程式,將虛擬檔案儲存在記憶體中,或是傳回預留位置資料。這種輔助程式很適合加入測試中,因為「不」需要檢查此輔助程式,例如 fs.writeFileSync 是否有效。專注於程式碼,以及程式碼的獨特性或風險

模擬瀏覽器 API

Vitest 等許多測試架構都讓您選擇在不執行瀏覽器的情況下模擬瀏覽器的 API 環境。Vitest 內部使用名為 JSDOM 的程式庫。對於簡單的元件測試,由於使用瀏覽器的負擔很高,這很適合採用。

模擬程式庫的其中一項常見功能是,雖然可模擬瀏覽器,但其實沒有視覺元件,例如 DOM、元素和 Cookie。也就是說,系統會提供使用 HTML 元素和其他原始檔案的命令式方法,但無法將輸出內容算繪到圖片或畫面,也無法檢查元素在網頁上的位置 (以像素為單位)。

同樣,這個選項也適用於元件測試,因為當中的元件代表 React 元素,或是 Web 元件。這些類型的元件通常以相對較小的方式建立並與 DOM 互動,模擬瀏覽器則可提供足夠的功能,可確認元件的運作方式是否符合您的預期。以下章節提供使用 Vitest 和 JSDOM 的 React 元件測試範例。

模擬瀏覽器是一套公有的做法 (JSDOM 於 2014 年推出),但一定會和使用實際瀏覽器不同。這些差異顯而易見:舉例來說,JSDOM 不含版面配置引擎,因此無法檢查元素的大小,也無法測試複雜的手勢 (例如滑動)。差異也可能有「細微」且明顯的差異,因此最好保持 JSDOM 型測試精簡扼要,這樣才能在「即時箱」中發現任何行為偏離實際行為的風險。

實際操作瀏覽器

如要以使用者體驗測試程式碼,最好使用實際瀏覽器。實際上,即使在 Node.js 中執行「start」,測試支援瀏覽器的執行階段也會啟動並控制真實瀏覽器的執行個體。

在測試中控制瀏覽器後,系統會像在使用者測試時開啟瀏覽器一樣開啟瀏覽器,讓您能透過載入網址、自訂 HTML 和 JS 或任何執行測試所需的項目來控制瀏覽器。接著,您可以編寫程式碼來操作使用者,例如控制滑鼠,或在輸入方塊中輸入輸入內容。

WebdriverIOWeb TestRunner 等新式工具可控制所有主要瀏覽器,甚至可以同時執行多個執行個體。這些瀏覽器可以在測試執行器附近執行 (例如您自己的電腦,或做為持續整合動作的一部分),或交由外部商業服務代為執行。

許多已建立的測試程式庫 (包括 Vitest 和 Jest) 通常都有瀏覽器模式,但由於其來源來自 Node.js,因此他們的瀏覽器模式往往會「擴充」,並缺少實用功能。舉例來說,Vitest 無法模擬瀏覽器中的模組匯入作業,這是我們在下一頁的範例中使用的強大基本功能。

實務中

隨著測試變得越來越複雜,使用實際瀏覽器變得更加重要。

  • 如果測試使用 DOM 沒有任何或最少的功能,甚至是在 Node.js 和類似執行階段提供的功能 (例如 fetchEventTarget) 的情況下,則環境並不重要。
  • 如果是小型元件測試,就適合使用 JSDOM。
  • 大型測試 (例如端對端測試) 可以模擬使用者登入並執行核心動作,因此在實際瀏覽器中完整執行是合理的做法。

本節內容著重在理論上,其中包含測試執行位置的不同觀點。實際執行時,程式碼集通常會根據需求和測試工具提供的功能,使用多種不同方法執行不同類型的測試。

隨堂測驗

瀏覽器模擬層 jsdom「不支援」哪些瀏覽器功能?

版面配置引擎。
由於 JSDOM 並非視覺化工具,因此無法用來檢查元素在網頁上的位置、已解析的 CSS 屬性,或是網站版面配置的任何其他部分。
WebSocket
JSDOM 內含 WebSocket polyfill,因此使用這項工具的程式碼才能正常運作。
requestAnimationFrame
使用 `pretendToBeVisual` 旗標時,即使實際上沒有繪製任何內容,jsdom 也會以 60fps 叫用「animation」回呼。