測試插件
(⚠️ 實驗性功能)
⚠️ **實驗性功能** 🧪
雖然此插件為實驗性功能,但已作為 @storybook/experimental-addon-test
套件發布,且 API 可能在未來版本中變更。我們歡迎您提供回饋與貢獻,以協助改進此功能。
Storybook 的 Test 插件讓您直接在 Storybook 內部測試元件。它本身會將您的 stories 轉換為 元件測試,以在真實瀏覽器環境中測試元件的渲染和行為。它還可以計算由您的 stories 提供的專案 覆蓋率。
如果您的專案正在使用其他測試插件,例如 視覺測試插件 或 可訪問性插件,您可以將這些測試與元件測試一起執行。
當 story 執行測試時,狀態會顯示在側邊欄中。側邊欄可以篩選為僅顯示失敗的 stories,您可以按下失敗 story 上的選單按鈕以查看偵錯選項。
您也可以在觀察模式下執行測試,當您變更元件或 stories 時,這會自動重新執行測試。若要啟用,請按下測試模組中的觀察模式切換按鈕(眼睛圖示)。
安裝與設定
在安裝之前,請確保您的專案符合以下需求
- Storybook ≥ 8.5
- 使用 Vite 的 Storybook 框架(例如
vue3-vite
、react-vite
、'sveltekit` 等),或 搭配 Vite 的 Storybook Next.js 框架 - Vitest ≥ 2.1
- 如果您尚未使用 Vitest,則在您安裝插件時,將會為您安裝和設定 Vitest
- (選用)MSW ≥ 2.0
- 如果已安裝 MSW,則必須為 v2.0.0 或更高版本,以免與 Vitest 的依賴項衝突
搭配 Next.js 使用 — Test 插件在 Next.js ≥ 14.1 專案中受到支援,但您必須使用 @storybook/experimental-nextjs-vite
框架。當您執行以下設定命令時,如果您尚未安裝和使用該框架,系統將提示您安裝和使用。
如果您尚未使用 Storybook 8.5,您可以升級您的 Storybook 到預發布版本
npx storybook@next upgrade
自動設定
執行以下命令以安裝和設定插件,其中包含使用 Vitest 將您的 stories 作為測試執行的插件
npx storybook add @storybook/experimental-addon-test
該 add
命令 將安裝並註冊測試插件。它還將檢查您專案的 Vite 和 Vitest 設定,並在必要時使用合理的預設值安裝和設定它們。您可能需要調整設定以符合您專案的需求。完整的設定選項可以在下方的 API 區段 中找到。
手動設定
對於某些專案設定,add
命令可能無法自動化插件和插件設定,並要求您完成其他設定步驟。以下是應採取的步驟
- 確保在您的專案中設定了 Vite 和 Vitest。
- 設定 Vitest 以使用 瀏覽器模式。
- 在您的專案中安裝插件
@storybook/experimental-addon-test
,並在您的 Storybook 設定中註冊它。 - 建立測試設定檔
.storybook/vitest.setup.ts
。您可以使用範例設定檔作為指南。 - 調整您的 Vitest 設定以包含插件並參考設定檔。您可以使用範例設定檔作為指南。
設定檔範例
當插件自動設定時,它將為您建立或調整您的 Vitest 設定檔。如果您正在手動設定,您可以將以下範例作為參考來設定您的專案。
Vitest 設定檔範例
Storybook stories 包含在 .storybook/preview.js|ts
中定義的設定。為了確保該設定可用於您的測試,您可以在 Vitest 設定檔中套用它。以下是如何執行此操作的範例
import { beforeAll } from 'vitest';
// 👇 If you're using Next.js, import from @storybook/nextjs
// If you're using Next.js with Vite, import from @storybook/experimental-nextjs-vite
import { setProjectAnnotations } from '@storybook/react';
import * as previewAnnotations from './preview';
const annotations = setProjectAnnotations([previewAnnotations]);
// Run Storybook's beforeAll hook
beforeAll(annotations.beforeAll);
setProjectAnnotations
函式是 可攜式 stories API 的一部分,Vitest 插件在內部使用它將您的 stories 轉換為測試。
Vitest 設定檔範例
插件最簡單的應用是將其包含在您的 Vitest 設定檔中
import { defineConfig, mergeConfig } from 'vitest/config';
import { storybookTest } from '@storybook/experimental-addon-test/vitest-plugin';
import path from 'node:path';
import { fileURLToPath } from 'node:url';
const dirname =
typeof __dirname !== 'undefined' ? __dirname : path.dirname(fileURLToPath(import.meta.url));
import viteConfig from './vite.config';
export default mergeConfig(
viteConfig,
defineConfig({
plugins: [
storybookTest({
// The location of your Storybook config, main.js|ts
configDir: path.join(dirname, '.storybook'),
// This should match your package.json script to run Storybook
// The --ci flag will skip prompts and not open a browser
storybookScript: 'yarn storybook --ci',
}),
],
test: {
// Enable browser mode
browser: {
enabled: true,
name: 'chromium',
// Make sure to install Playwright
provider: 'playwright',
headless: true,
},
setupFiles: ['./.storybook/vitest.setup.ts'],
},
})
);
Vitest 工作區檔案範例
如果您正在使用 Vitest 工作區,您可以定義新的工作區專案
import { defineWorkspace } from 'vitest/config';
import { storybookTest } from '@storybook/experimental-addon-test/vitest-plugin';
import path from 'node:path';
import { fileURLToPath } from 'node:url';
const dirname =
typeof __dirname !== 'undefined' ? __dirname : path.dirname(fileURLToPath(import.meta.url));
export default defineWorkspace([
// This is the path to your existing Vitest config file
'./vitest.config.ts',
{
// This is the path to your existing Vite config file
extends: './vite.config.ts',
plugins: [
storybookTest({
// The location of your Storybook config, main.js|ts
configDir: path.join(dirname, '.storybook'),
// This should match your package.json script to run Storybook
// The --ci flag will skip prompts and not open a browser
storybookScript: 'yarn storybook --ci',
}),
],
test: {
name: 'storybook',
// Enable browser mode
browser: {
enabled: true,
name: 'chromium',
// Make sure to install Playwright
provider: 'playwright',
headless: true,
},
setupFiles: ['./.storybook/vitest.setup.ts'],
},
},
]);
用法
有多種方法可以使用插件執行測試。
我們建議(並預設設定)在 瀏覽器模式下執行 Vitest,使用 Playwright 的 Chromium 瀏覽器。瀏覽器模式確保您的元件在真實瀏覽器環境中進行測試,這比 JSDom 或 HappyDom 等模擬更準確。對於測試依賴瀏覽器 API 或功能的元件而言,這尤其重要。
Storybook UI
執行測試最簡單的方法是透過 Storybook UI。只需按一下,您就可以為專案中的所有 stories、stories 群組或單個 story 執行多種類型的測試。
若要為整個專案執行所有測試,請按下側邊欄底部測試模組中的「執行測試」按鈕。
或者,您可以展開測試模組以個別執行特定類型的測試。對於那些具有觀察模式的測試類型(這將在程式碼變更時自動重新執行相關測試),您可以開啟或關閉該模式。
若要為特定的 story 或 stories 群組執行測試,請按下側邊欄項目懸停時出現的選單按鈕(三個點)。然後,您可以選擇要執行的測試類型。
執行測試後,您現在將在 stories 和元件上看到狀態指示器,以指示它們的通過、失敗或錯誤狀態。當您懸停在 story 上時,可以按下選單按鈕以查看該 story 的測試結果。在選單中選擇結果將會導航您到該 story 並開啟適當的偵錯面板。例如,如果元件測試失敗,您可以直接跳到元件測試插件面板中的失敗處。該面板為您的元件測試提供了一個互動式偵錯工具,讓您可以逐步執行每個模擬行為或斷言。
當安裝 Test 插件時,元件測試插件面板會取代 Interactions 插件面板。雖然測試機制不同,但插件面板本身的功能保持不變。
測試模組還將顯示您執行的測試總數、通過的測試數量以及失敗或錯誤的測試數量。您可以按下失敗數字來篩選側邊欄,使其僅顯示那些失敗的 stories。
CLI
您也可以使用 Vitest CLI 執行測試。我們建議在您的 package.json
中新增腳本,以簡化執行測試的步驟。以下是如何執行此操作的範例
{
"scripts": {
"test": "vitest",
"test-storybook": "vitest --project=storybook"
}
}
在此範例中,我們新增了兩個腳本:test
用於執行專案中的所有測試(您可能已經有此腳本),以及 test-storybook
用於僅執行您的 Storybook 測試。--project=storybook
標記告訴 Vitest 執行 Storybook 專案的測試。
然後,執行此命令以使用 Vitest CLI 執行您的測試(在 觀察模式下,預設情況下)
npm run test-storybook
偵錯
雖然插件在測試時不需要 Storybook 執行,但您可能仍然希望執行 Storybook 以偵錯您的測試。若要啟用此功能,請在插件設定中提供 storybookScript
選項。當您在觀察模式下執行 Vitest 時,插件將使用此腳本啟動 Storybook,並在測試失敗時在輸出中提供 stories 的連結。這可讓您快速跳到 Storybook 中的 story 以偵錯問題。
您也可以在插件設定中提供 storybookUrl
選項。當您未使用觀察模式且測試失敗時,插件將在輸出中使用此 URL 提供 story 的連結。當 在 CI 中執行測試 或 Storybook 尚未執行的其他環境中時,這非常有用。
編輯器擴充功能
使用插件將您的 stories 轉換為 Vitest 測試,還可以讓您使用 Vitest IDE 整合來執行和偵錯測試。這可讓您直接從編輯器(例如 VSCode 和 JetBrains IDE)執行測試。
此螢幕截圖顯示如何在 VSCode 中使用 Vitest 擴充功能執行 Vitest 測試。Stories 會使用測試狀態進行註釋,並且當測試失敗時,會提供 story 的連結以進行偵錯。
在 CI 中
在大多數情況下,在 CI 中執行 Storybook 測試是透過 CLI 完成的。但是,為了讓測試輸出連結到您發布的 Storybook 以處理測試失敗,您需要在插件設定中提供 storybookUrl
選項。
以下是使用 GitHub Actions 的範例。其他 CI 提供者的步驟類似,但語法或設定中的詳細資訊可能會有所不同。
當 Vercel、Netlify 等服務的動作執行部署工作時,它們會遵循發出 deployment_status
事件的模式,其中包含 deployment_status.target_url
下新產生的 URL。這是已發布 Storybook 實例的 URL。然後,我們使用環境變數 SB_URL
將該 URL 傳遞到插件設定。最後,我們更新插件設定以在 storybookUrl
選項中使用該環境變數。
name: Storybook Tests
on: deployment_status
jobs:
test:
timeout-minutes: 60
runs-on: ubuntu-latest
if: github.event.deployment_status.state == 'success'
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '18.x'
- name: Install dependencies
run: yarn
- name: Run Storybook tests
run: yarn test-storybook
env:
SB_URL: '${{ github.event.deployment_status.target_url }}'
export default defineWorkspace([
// ...
{
// ...
{
plugins: [
storybookTest({
// ...
storybookScript: 'yarn storybook --ci',
storybookUrl: process.env.SB_URL
}),
],
},
},
])
運作方式
Test 插件透過使用 Vitest 插件將您的 stories 轉換為使用 可攜式 stories 的 Vitest 測試來運作。它還設定 Vitest 以在 瀏覽器模式下執行這些測試,使用 Playwright 的 Chromium 瀏覽器。由於它建立在 Vitest 之上,因此插件需要基於 Vite 的 Storybook 框架。
Stories 以兩種方式進行測試:冒煙測試以確保其渲染,以及如果定義了 play 函式,則執行該函式並驗證其中進行的任何斷言。
當您在 Storybook UI 中執行測試時,插件會在背景中執行 Vitest,並在側邊欄中報告結果。
設定測試
可以透過兩種方式設定插件執行的測試。您可以切換要執行的測試類型,並包含、排除或略過要測試的 stories。
切換測試類型
除了元件測試外,Test 插件還支援多種類型的測試,具體取決於您在專案中使用的其他插件。某些測試類型(例如 視覺測試)是獨立執行的。其他測試類型(例如 可訪問性)必須與元件測試一起執行。對於這些依賴性測試類型,您可以透過按下編輯按鈕(鉛筆圖示)並勾選或取消勾選您想要執行的測試類型,在測試模組中開啟或關閉它們。
請注意,根據您已安裝的插件,您可能不會擁有圖片中顯示的所有測試類型。
您也可以在 story 或 stories 群組的側邊欄項目選單中存取編輯模式
請注意,在選單的編輯模式中切換測試類型會影響所有測試,而不僅僅是針對所選 story 或 stories 群組的測試。它的目的是為了方便快速開啟或關閉測試類型。
包含、排除或略過測試
您可以使用標籤來包含、排除或略過要測試的 stories。包含的 stories 會進行測試,排除的 stories 不會進行測試,而略過的 stories 則不會進行測試,但會計入測試結果中。
預設情況下,插件將執行所有帶有 test
標籤的 stories。您可以透過在插件設定中提供 tags
選項來調整此行為。這可讓您根據 stories 的標籤來包含、排除或略過 stories。
在此範例中,我們將 stable
標籤套用至 Button 元件的所有 stories,但 ExperimentalFeatureStory 除外,後者將具有 experimental
標籤
// Replace your-framework with the framework you are using (e.g., nextjs, vue3-vite)
import type { Meta, StoryObj } from '@storybook/your-framework';
import { Button } from './Button';
const meta: Meta<typeof Button> = {
component: Button,
// 👇 Applies to all stories in this file
tags: ['stable'],
};
export default meta;
type Story = StoryObj<typeof Button>;
export const ExperimentalFeatureStory: Story = {
//👇 For this particular story, remove the inherited `stable` tag and apply the `experimental` tag
tags: ['!stable', 'experimental'],
};
若要將這些標籤連接到我們的測試行為,我們可以調整插件設定以排除 experimental
標籤
export default defineWorkspace([
// ...
{
// ...
{
plugins: [
storybookTest({
// ...
tags: {
include: ['test'],
exclude: ['experimental'],
},
}),
],
},
},
])
如果相同的標籤同時位於 include
和 exclude
陣列中,則 exclude
行為優先。
與測試執行器的比較
測試執行器需要執行的 Storybook 實例來測試您的 stories,因為它會訪問每個 story、執行 play 函式並監聽結果。但是,Vitest 插件會使用 Vite 和可攜式 stories 將您的 stories 轉換為測試,因此它不需要執行 Storybook 即可測試您的 stories。由於對 Vite 的依賴,該插件只能與使用 Vite 的 Storybook 框架(和 Next.js)一起使用。另一方面,測試執行器可以與任何 Storybook 框架一起使用。
測試執行器僅是一個 CLI 工具。它沒有用於執行測試的 UI,也沒有編輯器擴充功能。但是,該插件在 Storybook 中提供了一個 UI 用於執行測試,並且它使您能夠使用 Vitest IDE 整合來執行和偵錯測試。
此外,測試執行器在 Jest 中將您的 stories 作為協調測試執行,並且該協調帶來了一些複雜性。相比之下,此插件將您的 stories 轉換為真實測試,然後使用 Vitest 執行它們,這更簡單且更可設定。
最後,由於更簡單的架構和 Vitest 的使用,對於大多數專案而言,此插件應該比測試執行器更快。我們將在未來進行更多基準測試以量化這一點。
常見問題
如果 Vitest 本身發生錯誤會怎麼樣?
有時測試可能會因為 Vitest 本身發生錯誤而失敗。當這種情況發生時,Storybook UI 中的測試模組會提醒您注意此錯誤,您可以點擊連結以檢視完整錯誤訊息。錯誤訊息也會記錄到主控台。
Vitest 針對常見錯誤提供疑難排解協助。
當多個環境中出現不同的測試結果時,會發生什麼情況?
當您使用此附加元件執行測試時,它們會以 Vitest 測試的方式執行,並採用您在專案中設定的任何配置。預設情況下,它們將在瀏覽器模式下執行,使用 Playwright 的 Chromium 瀏覽器。有時,在附加元件中(或透過 CLI)執行測試會失敗,但在元件測試附加元件面板中檢視時(或反之亦然)卻會通過。這可能是因為測試在不同的環境中執行,而這些環境可能具有不同的行為。
我如何在 Storybook 中偵錯我的 CLI 測試?
當 CLI 中的測試失敗時,此插件會嘗試提供 Storybook 中故事的連結,以用於偵錯目的。
如果網址在監看模式下執行測試時無法運作,您應該檢查兩個配置選項
storybookUrl
:確保此網址正確且可存取。例如,預設值為https://#:6006
,這可能未使用您正在使用的相同埠號。storybookScript
:確保此腳本正確啟動 Storybook。
如果網址在 CI 中執行測試時無法運作,您應該確保在執行測試之前已建置並發布 Storybook。然後,您可以使用 storybookUrl
選項提供已發布 Storybook 的網址。請參閱在 CI 中章節以取得範例。
我如何確保我的測試可以找到 public 目錄中的資源?
如果您的故事使用 public 目錄中的資源,且您未使用預設的 public 目錄位置(public
),則需要調整 Vitest 配置以包含 public 目錄。您可以透過在 Vitest 配置檔案中提供 publicDir
選項來執行此操作。
我如何將 Storybook 測試與其他測試隔離?
某些專案可能在其 Vite 配置中包含 test
屬性。由於此插件使用的 Vitest 配置擴展了該 Vite 配置,因此 test
屬性會合併。這種缺乏隔離可能會導致您的 Storybook 測試出現問題。
若要將您的 Storybook 測試與其他測試隔離,您需要將 test
屬性從您的 Vite 配置移至 Vitest 配置。然後,插件使用的 Vitest 配置可以安全地擴展您的 Vite 配置,而不會合併 test
屬性。
為什麼我們建議使用瀏覽器模式?
Vitest 的瀏覽器模式會在真實瀏覽器(預設配置中透過 Playwright 使用 Chromium)中執行您的測試。另一種替代方案是模擬的瀏覽器環境,例如 JSDom 或 HappyDom,與真實瀏覽器相比,它們的行為可能存在差異。對於 UI 組件,它們通常依賴瀏覽器 API 或功能,在真實瀏覽器中執行測試更準確。
如需更多資訊,請參閱 Vitest 關於有效使用瀏覽器模式的指南。
我如何使用 WebDriver 而不是 Playwright?
我們建議使用 Playwright 在瀏覽器中執行測試,但您也可以改用 WebDriverIO。若要執行此操作,您需要調整 Vitest 配置檔案中的瀏覽器供應商。
我如何使用 Chromium 以外的瀏覽器?
我們建議使用 Chromium,因為它最有可能最符合您大多數使用者的體驗。但是,您可以透過調整 Vitest 配置檔案中的瀏覽器名稱來使用其他瀏覽器。請注意,Playwright 和 WebDriverIO 支援不同的瀏覽器。
我如何自訂測試名稱?
預設情況下,故事的匯出名稱會對應到測試名稱。若要建立更具描述性的測試說明,您可以為故事提供 name
屬性。這可讓您包含空格、括號或其他特殊字元。
export const Story = {
name: 'custom, descriptive name'
};
我該如何修正 m.createRoot is not a function
錯誤?
當在使用 React 18 以外版本的專案上使用附加元件時,可能會發生此錯誤。若要解決此問題,您可以提供別名以確保使用正確的 React 版本。以下範例說明如何在 Vitest 配置檔案中執行此操作
import { defineConfig } from 'vitest/config';
export default defineConfig({
// ...
resolve: {
alias: {
"@storybook/react-dom-shim": "@storybook/react-dom-shim/dist/react-16",
},
},
});
API
匯出
此附加元件具有以下匯出
import { storybookTest } from '@storybook/experimental-addon-test/vitest-plugin'
storybookTest
類型:function
一個 Vitest 插件,可將您的故事轉換為測試。它接受用於配置的選項物件。
選項
插件是使用選項物件配置的。以下是可用的屬性
configDir
類型:string
預設值:.storybook
相對於目前工作目錄,Storybook 配置所在的目錄。
如果您的 Storybook 配置不在預設位置,您必須在此處指定位置,插件才能正常運作。
storybookScript
類型:string
用於執行 Storybook 的選用腳本。如果提供此腳本,Vitest 將在監看模式下執行時使用此腳本啟動 Storybook。僅當 storybookUrl
中的 Storybook 尚不可用時才會執行。
storybookUrl
類型:string
預設值:https://#:6006
Storybook 託管的網址。這用於內部檢查,並提供測試輸出失敗時故事的連結。
tags
類型
{
include: string[];
exclude: string[];
skip: string[];
}
預設值
{
include: ['test'],
exclude: [],
skip: [],
}
要包含、排除或略過的標籤。這些標籤定義為您的故事、meta 或預覽中的註釋。
include
:具有這些標籤的故事將會進行測試exclude
:具有這些標籤的故事將不會進行測試,也不會計入測試結果中skip
:具有這些標籤的故事將不會進行測試,但會計入測試結果中