視覺 UI 測試(也稱為回歸測試)是一種測試技術,用于驗證您的更改是否對 UI 產生了意外的影響。通常,這類測試會對整個應用程序或特定元素進行圖像快照,并將其與之前批準的基準圖像進行比較。如果圖像相同(在設定的像素容差范圍內),則可以確定 web 應用程序的外觀對用戶來說沒有變化。如果存在差異,則可能是 DOM 布局、字體、顏色或其他視覺屬性發生了變化,需要進一步調查。
這篇文章將探討如何使用 Playwright 和 GitHub Actions 自動化測試“現代”web 應用程序的視覺回歸測試。目標是構建一個測試設置,在每個 Pull Request 上檢查 UI 回歸,并在需要時選擇性地更新基準圖像。
建議具備基本的 JavaScript(或 TypeScript)和 GitHub Actions 知識。
我們假設您會將此設置集成到現有的 web 應用程序中。如果您想從頭開始嘗試,建議使用 Vite 搭建一個新的 web 應用程序。
您可以在這個 GitHub 倉庫 中找到完整的示例應用程序。
以下是我們正在測試的小型 web 應用程序的外觀:
Playwright 設置
對于我們的測試設置,將使用 Playwright,這是一個端到端(E2E)測試框架。我喜歡 Playwright,因為它提供了優秀的開發體驗和默認配置。不過,您也可以用類似工具(如 Cypress 或 Selenium)實現相同的結果。
安裝 Playwright
進入項目目錄并運行以下命令:
npm init playwright
運行后會提示您進行一些選擇(例如 JavaScript 或 TypeScript 等)。當被詢問是否添加 GitHub Actions 工作流時,選擇 true
以便于在 CI 上運行測試:
? Add a GitHub Actions workflow? (y/N) · true
安裝完成后,Playwright 會生成一個示例測試文件(./tests/example.spec.ts
)、一個演示文件(./tests-examples/demo-todo-app.spec.ts
,可以忽略),以及配置文件(./playwright.config.ts
)。
? Success! Created a Playwright Test project at ~/your-project-dir
在此目錄中,您可以運行以下命令:
-
npx playwright test
運行端到端測試。 -
npx playwright test --project=chromium
僅在桌面 Chrome 上運行測試。 -
npx playwright test example
運行特定文件中的測試。 -
npx playwright test --debug
在調試模式下運行測試。 -
npx playwright codegen
自動生成測試代碼。
建議從以下命令開始:
npx playwright test
并查看以下文件:
-
./tests/example.spec.ts
- 示例端到端測試文件 -
./tests-examples/demo-todo-app.spec.ts
- 示例 ToDo App 測試文件 -
./playwright.config.ts
- Playwright 配置文件
訪問 Playwright 文檔 獲取更多信息。?
修改 Playwright 配置文件
Playwright 在生成的配置文件(./playwright.config.ts
)中提供了一些不錯的默認設置,但可以做一些改進。
-
簡化測試瀏覽器配置
更新projects
列表,僅在 Chromium 上運行測試:projects: [ { name: "chromium", use: { ...devices["Desktop Chrome"], }, }, ]
需要時,可以稍后再添加更多瀏覽器或設備支持。
-
自動啟動本地服務器
配置webServer
部分,以便 Playwright 在運行測試時自動啟動應用程序:webServer: { command: 'npm run dev --port 8080', port: 8080, reuseExistingServer: true, },
生成初始快照
Playwright 生成的示例測試文件(./tests/example.spec.ts
)不是視覺回歸測試,因此需要替換為適合的測試代碼:
import { test, expect } from "@playwright/test";
test("example test", async ({ page }) => {
await page.goto("/"); // 此處的 baseURL 為 webServer 的 URL
await expect(page).toHaveScreenshot();
});
Playwright 支持通過 await expect(page).toHaveScreenshot()
生成并比較快照。首次運行時,會生成基準快照;后續運行將與基準進行比較。
運行測試命令:
npx playwright test
運行后,您可能會看到類似以下信息:
Error: example.spec.ts-snapshots/example-test-1-chromium-darwin.png is missing in snapshots, writing actual.
這是因為還沒有基準圖像,測試會不斷生成快照,直到兩次快照匹配,并將最后一次快照保存到文件系統中(例如:tests/example.spec.ts-snapshots/example-test-1-chromium-darwin.png
)。
再次運行測試:
npx playwright test
如果當前 UI 與之前生成的基準快照一致,測試將成功通過!
本地更新快照
讓我們進入有趣的部分。
如果對 UI 進行了任何視覺更改并重新運行測試,測試會失敗,Playwright 會顯示“實際”與“預期”快照之間的清晰差異:
在這種情況下,如果我們希望頁面的視覺變化是自愿的,就需要更新基準快照。可以使用 --update-snapshots
標志來完成:
npx playwright test --update-snapshots
示例輸出:
[chromium] ? example.spec.ts:3:1 ? example test
tests/example.spec.ts-snapshots/example-test-1-chromium-darwin.png is re-generated, writing actual.
現在,我們已經了解了如何運行視覺測試并在本地更新快照,接下來準備轉向 CI 流程。
在 CI 上運行測試(使用 GitHub Actions)
GitHub Actions 是一個持續集成和持續交付(CI/CD)平臺,可以自動化構建、測試和部署流水線。借助 GitHub Actions,可以為每次 Pull Request 創建和更新設置工作流,自動運行構建和測試。
一個良好的視覺回歸測試設置起點是,在每次創建或更新 Pull Request 時運行測試。幸運的是,Playwright 已經在 .github/workflows/playwright.yml
中生成了一個方便的 GitHub Actions 工作流,專門用于此用例。
這個工作流可以開箱即用,但建議稍作調整:
-
只安裝目標測試所需的瀏覽器(
--with-deps chromium
)。 -
僅在測試失敗時保存測試結果工件(
if: failure()
),以避免存儲不必要的文件。
以下是修改后的 playwright.yml
文件:
name: Playwright Tests
on:
push:
branches: [main, master]
pull_request:
branches: [main, master]
jobs:
test:
timeout-minutes: 60
runs-on: ubuntu-latest
steps:
# 檢出代碼并設置環境
- uses: actions/checkout@v2
- uses: actions/setup-node@v2
with:
node-version: "14.x"
- name: Install dependencies
run: npm install
- name: Install Playwright Browsers
run: npx playwright install --with-deps chromium
# 運行 Playwright 測試
- name: Run Playwright tests
run: npx playwright test
# 上傳測試結果工件
- uses: actions/upload-artifact@v2
if: failure()
with:
name: playwright-report
path: playwright-report/
retention-days: 30
將此工作流提交到 GitHub 倉庫后,每次提交新的 Pull Request 時,Playwright 測試將被觸發。
注意:參考快照與 CI 環境的兼容性
測試在 CI 環境中運行時可能會失敗,因為倉庫中的基準快照可能是在與 CI 環境不同的機器上捕獲的(除非這些快照是在運行 Ubuntu 的機器上生成的)。
要了解更多測試結果,可以檢查 GitHub Action 的輸出或查看測試工件。例如,如果在 macOS 上生成的基準快照會導致在 Linux 上的測試失敗,錯誤可能會類似于:
Error: tests/example.spec.ts-snapshots/example-test-1-chromium-linux.png is missing in snapshots
接下來,我們將學習如何為 CI 環境更新參考快照。
在 CI 中通過 Pull Request 評論更新快照
使用 --update-snapshots
本地生成基準快照相對簡單,而在 CI 中進行類似操作則更復雜,因為需要決定快照的存儲位置、方式和時間。
有多種方法可以實現這個流程,為了簡化,我們從簡單的方式開始。
一種行之有效的模式是:通過 GitHub Action,當在 Pull Request 中發布包含 /update-snapshots
的特定評論時,觸發工作流來更新基準快照。
基本思路如下:
當我們提交一個預計會影響 UI 的 Pull Request 時,可以添加一條 /update-snapshots
評論,這會觸發 CI 自動生成更新后的快照,并將它們提交到 Pull Request 的分支中。
工作流:.github/workflows/update-snapshots.yml
name: Update Snapshots
on:
issue_comment:
types: [created]
jobs:
updatesnapshots:
if: ${{ github.event.issue.pull_request && github.event.comment.body == '/update-snapshots'}}
timeout-minutes: 60
runs-on: ubuntu-latest
steps:
# 檢出代碼并加載所有提交 ID
- uses: actions/checkout@v2
with:
fetch-depth: 0
token: ${{ secrets.GITHUB_TOKEN }}
# 獲取 Pull Request 的分支名稱和最新提交的 SHA
- name: Get SHA and branch name
id: get-branch-and-sha
run: |
sha_and_branch=$(\
curl \
-H 'authorization: Bearer ${{ secrets.GITHUB_TOKEN }}' \
https://api.github.com/repos/${{ github.repository }}/pulls/${{ github.event.issue.number }} \
| jq -r '.head.sha," ",.head.ref');
echo "::set-output name=sha::$(echo $sha_and_branch | cut -d " " -f 1)";
echo "::set-output name=branch::$(echo $sha_and_branch | cut -d " " -f 2)";
# 檢出評論對應的分支
- name: Fetch Branch
run: git fetch
- name: Checkout Branch
run: git checkout ${{ steps.get-branch-and-sha.outputs.branch }}
# 設置測試環境
- uses: actions/setup-node@v2
with:
node-version: "14.x"
- name: Install dependencies
run: npm install
- name: Install Playwright browsers
run: npx playwright install --with-deps chromium
# 根據當前 UI 更新快照
- name: Update snapshots
run: npx playwright test --update-snapshots --reporter=list
# 提交更新的快照到 Pull Request 分支
- uses: stefanzweifel/git-auto-commit-action@v4
with:
commit_message: "[CI] Update Snapshots"
運行流程概覽
- 每當 Pull Request 中添加評論時,GitHub Actions 會觸發此工作流。
- 若評論嚴格匹配
/update-snapshots
,則獲取當前 Pull Request 的分支名和最新的提交 SHA。 - 檢出對應分支并設置環境。
- 使用 Playwright 根據分支當前 UI 更新基準快照。
- 將更新的快照提交到 Pull Request 分支中。
發布此工作流后,創建新的 Pull Request 并添加 /update-snapshots
評論時,CI 將生成更新的快照。
運行 Playwright 測試以驗證部署預覽(Netlify、Vercel 等)
如果你的 Web 應用托管在 Netlify 或 Vercel 等平臺上,你可能會使用它們的“部署預覽”功能。這項功能允許你在不影響生產環境的情況下預覽拉取請求的更改。部署預覽默認對 GitHub 的拉取請求啟用,它通過將更改部署到一個不同于生產站點的唯一 URL 來實現。
如果你的 Web 應用支持部署預覽,我們可以將其集成到視覺回歸測試工作流中,以對比快照,而不是依賴本地 Web 服務器。
這種方法有兩個好處:
- 避免為運行測試而啟動本地 Web 服務器。
- 使用預覽鏈接運行測試會生成更可靠的快照,因為這些鏈接與生產環境的展示內容一致。
從總體上看,要使 Playwright 測試支持部署預覽,我們需要對代碼庫進行以下三項主要更改:
- 允許通過參數傳遞測試 URL,使測試能夠識別部署預覽鏈接。
- 更新 GitHub Action 工作流,等待部署預覽完成。
- 將部署預覽的 URL(作為環境變量)傳遞給 Playwright。
以下是如何在 Netlify 中實現(如果你使用的是 Vercel 或其他支持部署預覽的平臺,所需更改幾乎相同)。
首先,在 playwright.config.ts
中更新 use.baseURL
的值,使其能夠通過環境變量(WEBSITE_URL
)接收部署 URL:
use: {
baseURL: process.env.WEBSITE_URL,
}
此外,如果提供了 WEBSITE_URL
環境變量,禁用 Playwright 的 Web 服務器:
webServer: process.env.WEBSITE_URL
? undefined
: {
command: "npm run dev --port 8080",
port: 8080,
reuseExistingServer: true,
},
接下來,更新 playwright.yaml
工作流,以便針對部署預覽運行測試。
要等待 Netlify 的部署預覽 URL,我們可以使用 mmazzarolo/wait-for-netlify-action
GitHub Action。
mmazzarolo/wait-for-netlify-action
是 probablyup/wait-for-netlify-action
的一個分支。默認情況下,probablyup/wait-for-netlify-action
假定在由拉取請求推送觸發的工作流中運行。而我們的 update-snapshots.yml
工作流是由評論觸發的,因此我分叉了這個 GitHub Action,以確保它可以在任何工作流中運行,無論觸發方式如何。
wait-for-netlify-action
GitHub Action 需要兩項配置:
- 設置一個
NETLIFY_TOKEN
GitHub Action 密鑰,使用 Netlify 個人訪問令牌。 - 將 Netlify 站點 ID(Netlify 中:設置 → 站點詳情 → 通用)傳遞給工作流中的
site_id
參數。
以下是 playwright.yaml
示例:
name: Playwright Tests
on:
push:
branches: [main, master]
pull_request:
branches: [main, master]
workflow_run:
workflows: ["Update Snapshots"]
types:
- completed
jobs:
test:
timeout-minutes: 60
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/setup-node@v2
with:
node-version: "14.x"
- name: Install dependencies
run: npm install
- name: Install Playwright Browsers
run: npx playwright install --with-deps chromium
- name: Wait for Netlify Deploy
uses: mmazzarolo/wait-for-netlify-action@8a7a8d8cf5b313c916d805b76cc498380062d268
id: get-netlify-preview-url
with:
site_id: "YOUR_SITE_ID"
env:
NETLIFY_TOKEN: ${{ secrets.NETLIFY_TOKEN }}
- name: Run Playwright tests
run: WEBSITE_URL=${{ steps.get-netlify-preview-url.outputs.url }} npx playwright test
- uses: actions/upload-artifact@v2
if: failure()
with:
name: playwright-report
path: playwright-report/
retention-days: 30
最后,像上面一樣更新 update-snapshots.yml
工作流,確保 Playwright 的視覺回歸測試可以針對部署預覽運行。
結論
希望這篇博客文章為你搭建視覺測試體系提供了一個堅實的基礎。以下是一些可以進一步改進的思路:
- 你可能希望通過使用
fullScreen
參數測試全屏快照,而不僅僅是可見視口。此外,還可以嘗試捕獲移動端的快照。 - 如果你的 Web 應用會異步加載部分 UI(例如圖片、視頻),可能需要在測試中等待它們加載完成,或者將它們從測試中排除。
- 可以限制
/update-snapshots
命令的權限,僅允許倉庫的所有者調用。 - 你可以通過其他方式(例如 Webhooks)觸發快照更新流程,而不是依賴 GitHub 評論。
- 將快照存儲在第三方存儲解決方案中可能是更靈活的選擇。
- 如果你在使用部署預覽,可以通過并行化等待預覽鏈接的步驟與其他工作流步驟來優化工作流效率。