跳至主要內容

圖片比較(視覺回歸測試)服務

@wdio/visual-service 是一個第三方套件,更多資訊請參閱 GitHub | npm

有關使用 WebdriverIO 進行視覺測試的文件,請參閱文件。這個專案包含使用 WebdriverIO 執行視覺測試的所有相關模組。在 ./packages 目錄中,您會找到

  • @wdio/visual-testing:用於整合視覺測試的 WebdriverIO 服務
  • webdriver-image-comparison:一個圖片比較模組,可用於支援 WebDriver 通訊協定的不同 NodeJS 測試自動化框架

Storybook 執行器 (BETA)

點擊以了解更多關於 Storybook 執行器 BETA 的文件

Storybook 執行器仍處於 BETA 階段,文件稍後將移至WebdriverIO 文件頁面。

此模組現在透過新的視覺執行器支援 Storybook。此執行器會自動掃描本地/遠端 Storybook 執行個體,並建立每個元件的元素螢幕截圖。這可以透過新增

export const config: WebdriverIO.Config = {
// ...
services: ["visual"],
// ....
};

至您的 services 並透過命令列執行 npx wdio tests/configs/wdio.local.desktop.storybook.conf.ts --storybook 來完成。它將使用 Chrome 無頭模式作為預設瀏覽器。

[!NOTE]

  • 大多數視覺測試選項也適用於 Storybook 執行器,請參閱WebdriverIO 文件。
  • Storybook 執行器將覆蓋您的所有功能,並且只能在它支援的瀏覽器上執行,請參閱 --browsers
  • Storybook 執行器不支援使用多重遠端功能的現有設定,並且會擲回錯誤。
  • Storybook 執行器僅支援桌面 Web,不支援行動 Web。

Storybook 執行器服務選項

服務選項可以這樣提供

export const config: WebdriverIO.Config  = {
// ...
services: [
[
'visual',
{
// Some default options
baselineFolder: join(process.cwd(), './__snapshots__/'),
debug: true,
// The storybook options, see cli options for the description
storybook: {
clip: false,
clipSelector: ''#some-id,
numShards: 4,
// `skipStories` can be a string ('example-button--secondary'),
// an array (['example-button--secondary', 'example-button--small'])
// or a regex which needs to be provided as as string ("/.*button.*/gm")
skipStories: ['example-button--secondary', 'example-button--small'],
url: 'https://www.bbc.co.uk/iplayer/storybook/',
version: 6,
},
},
],
],
// ....
}

Storybook 執行器 CLI 選項

--browsers

  • 類型: string
  • 強制:
  • 預設: chrome,您可以從 chrome|firefox|edge|safari 中選擇
  • 範例: npx wdio tests/configs/wdio.local.desktop.storybook.conf.ts --storybook --browsers=chrome,firefox,edge,safari
  • 注意: 僅透過 CLI 提供

它將使用提供的瀏覽器來擷取元件螢幕截圖

[!NOTE] 請確保您已在本機上安裝要執行的瀏覽器

--clip

  • 類型: boolean
  • 強制:
  • 預設: true
  • 範例: npx wdio tests/configs/wdio.local.desktop.storybook.conf.ts --storybook --clip=false

停用時,它將建立視窗螢幕截圖。啟用時,它將根據 --clipSelector 建立元素螢幕截圖,這將減少元件螢幕截圖周圍的空白區域並減少螢幕截圖大小。

--clipSelector

  • 類型: string
  • 強制:
  • 預設: Storybook V7 為 #storybook-root > :first-child,Storybook V6 為 #root > :first-child:not(script):not(style),另請參閱 --version
  • 範例: npx wdio tests/configs/wdio.local.desktop.storybook.conf.ts --storybook --clipSelector="#some-id"

這是將用來

  • 選取要擷取螢幕截圖的元素的選取器
  • 用於等待元素在擷取螢幕截圖之前可見

--devices

  • 類型: string
  • 強制:
  • 預設: 您可以從 deviceDescriptors.ts 中選擇
  • 範例: npx wdio tests/configs/wdio.local.desktop.storybook.conf.ts --storybook --devices="iPhone 14 Pro Max","Pixel 3 XL"
  • 注意: 僅透過 CLI 提供

它將使用符合 deviceDescriptors.ts 的所提供裝置來擷取元件螢幕截圖

[!NOTE]

  • 如果您遺失裝置設定,請隨時提交功能要求
  • 這僅適用於 Chrome
    • 如果您提供 --devices,則所有 Chrome 執行個體都將在行動裝置模擬模式下執行
    • 如果您還提供其他瀏覽器,例如 --devices --browsers=firefox,safari,edge,它將自動在行動裝置模擬模式下新增 Chrome
  • Storybook 執行器預設會建立元素快照,如果您想查看完整的行動裝置模擬螢幕截圖,請透過命令列提供 --clip=false
  • 例如,檔案名稱看起來會像 __snapshots__/example/button/desktop_chrome/example-button--large-local-chrome-iPhone-14-Pro-Max-430x932-dpr-3.png
  • 來源: 使用行動裝置模擬在桌面上測試行動網站可能很有用,但測試人員應該注意許多細微的差異,例如
    • 完全不同的 GPU,這可能會導致效能產生重大變化;
    • 不會模擬行動裝置 UI(尤其是隱藏的 URL 列會影響頁面高度);
    • 不支援消除歧義快顯視窗(您可以在其中選取幾個觸控目標之一);
    • 許多硬體 API(例如,orientationchange 事件)都不可用。

--headless

  • 類型: boolean
  • 強制:
  • 預設: true
  • 範例: npx wdio tests/configs/wdio.local.desktop.storybook.conf.ts --storybook --headless=false
  • 注意: 僅透過 CLI 提供

這將預設在無頭模式下執行測試(當瀏覽器支援時)或可以停用

--numShards

  • 類型: number
  • 強制:
  • 預設: true
  • 範例: npx wdio tests/configs/wdio.local.desktop.storybook.conf.ts --storybook --numShards=10

這將是將用於執行故事的平行執行個體數量。這將受限於您的 wdio.conf 檔案中的 maxInstances

[!IMPORTANT] 在 headless 模式下執行時,請勿將數字增加到 20 以上,以防止因資源限制而導致不穩定

--skipStories

  • 類型: string|regex
  • 強制:
  • 預設: null
  • 範例: npx wdio tests/configs/wdio.local.desktop.storybook.conf.ts --storybook --skipStories="/.*button.*/gm"

這可以是

  • 字串 (example-button--secondary,example-button--small)
  • 或正規表示式 ("/.*button.*/gm")

以跳過某些故事。使用故事 URL 中可以找到的故事的 id。例如,此 URL https://#:6006/?path=/story/example-page--logged-out 中的 idexample-page--logged-out

--url

  • 類型: string
  • 強制:
  • 預設: http://127.0.0.1:6006
  • 範例: npx wdio tests/configs/wdio.local.desktop.storybook.conf.ts --storybook --url="https://example.com"

您的 Storybook 執行個體所在的 URL。

--version

  • 類型: number
  • 強制:
  • 預設值 7
  • 範例: npx wdio tests/configs/wdio.local.desktop.storybook.conf.ts --storybook --version=6

這是 Storybook 的版本,預設為 7。這用於判斷是否需要使用 V6 的 clipSelector

Storybook 互動測試

Storybook 互動測試允許您使用 WDIO 命令創建自訂腳本,與您的組件互動,使其進入特定狀態。例如,請參考以下程式碼片段

import { browser, expect } from "@wdio/globals";

describe("Storybook Interaction", () => {
it("should create screenshots for the logged in state when it logs out", async () => {
const componentId = "example-page--logged-in";
await browser.waitForStorybookComponentToBeLoaded({ id: componentId });

await expect($("header")).toMatchElementSnapshot(
`${componentId}-logged-in-state`
);
await $("button=Log out").click();
await expect($("header")).toMatchElementSnapshot(
`${componentId}-logged-out-state`
);
});

it("should create screenshots for the logged out state when it logs in", async () => {
const componentId = "example-page--logged-out";
await browser.waitForStorybookComponentToBeLoaded({ id: componentId });

await expect($("header")).toMatchElementSnapshot(
`${componentId}-logged-out-state`
);
await $("button=Log in").click();
await expect($("header")).toMatchElementSnapshot(
`${componentId}-logged-in-state`
);
});
});

在兩個不同的組件上執行兩個測試。每個測試首先設定一個狀態,然後截取螢幕快照。您也會注意到引入了一個新的自訂命令,可以在這裡找到。

上面的規格檔案可以儲存在一個資料夾中,並使用以下命令加入命令行

npm run test.local.desktop.storybook.localhost -- --spec='tests/specs/storybook-interaction/*.ts'

Storybook 執行器會先自動掃描您的 Storybook 實例,然後將您的測試加入需要比較的 stories。如果您不希望用於互動測試的組件被比較兩次,您可以添加一個篩選器,透過提供 --skipStories 篩選器,從掃描中移除「預設」的 stories。看起來會像這樣

npm run test.local.desktop.storybook.localhost -- --skipStories="/example-page.*/gm" --spec='tests/specs/storybook-interaction/*.ts'

新的自訂命令

一個名為 browser.waitForStorybookComponentToBeLoaded({ id: 'componentId' }) 的新自訂命令將被添加到 browser/driver 物件中,它將自動載入組件並等待其完成,因此您不需要使用 browser.url('url.com') 方法。它可以使用如下

import { browser, expect } from "@wdio/globals";

describe("Storybook Interaction", () => {
it("should create screenshots for the logged in state when it logs out", async () => {
const componentId = "example-page--logged-in";
await browser.waitForStorybookComponentToBeLoaded({ id: componentId });

await expect($("header")).toMatchElementSnapshot(
`${componentId}-logged-in-state`
);
await $("button=Log out").click();
await expect($("header")).toMatchElementSnapshot(
`${componentId}-logged-out-state`
);
});

it("should create screenshots for the logged out state when it logs in", async () => {
const componentId = "example-page--logged-out";
await browser.waitForStorybookComponentToBeLoaded({ id: componentId });

await expect($("header")).toMatchElementSnapshot(
`${componentId}-logged-out-state`
);
await $("button=Log in").click();
await expect($("header")).toMatchElementSnapshot(
`${componentId}-logged-in-state`
);
});
});

選項如下

clipSelector

  • 類型: string
  • 強制:
  • 預設值: Storybook V7 為 #storybook-root > :first-child,Storybook V6 為 #root > :first-child:not(script):not(style)
  • 範例
await browser.waitForStorybookComponentToBeLoaded({
clipSelector: "#your-selector",
id: "componentId",
});

這是將用來

  • 選取要擷取螢幕截圖的元素的選取器
  • 用於等待元素在擷取螢幕截圖之前可見

id

  • 類型: string
  • 必要:
  • 範例
await browser.waitForStorybookComponentToBeLoaded({ '#your-selector', id: 'componentId' })

使用 story 的 id,可以在 story 的 URL 中找到。例如,在此 URL https://#:6006/?path=/story/example-page--logged-out 中的 idexample-page--logged-out

timeout

  • 類型: number
  • 強制:
  • 預設值: 1100 毫秒
  • 範例
await browser.waitForStorybookComponentToBeLoaded({
id: "componentId",
timeout: 20000,
});

我們希望在頁面載入後等待組件可見的最長逾時時間

url

  • 類型: string
  • 強制:
  • 預設: http://127.0.0.1:6006
  • 範例
await browser.waitForStorybookComponentToBeLoaded({
id: "componentId",
url: "https://your.url",
});

您的 Storybook 執行個體所在的 URL。

貢獻

更新套件

您可以使用簡單的 CLI 工具來更新套件。請確保您已安裝所有依賴項,然後您可以執行

pnpm update.packages

這將觸發一個 CLI,它會問您以下問題

==========================
🤖 Package update Wizard 🧙
==========================

? Which version target would you like to update to? (Minor|Latest)
? Do you want to update the package.json files? (Y/n)
? Do you want to remove all "node_modules" and reinstall dependencies? (Y/n)
? Would you like reinstall the dependencies? (Y/n)

這將產生以下日誌

開啟以查看日誌範例
==========================
🤖 Package update Wizard 🧙
==========================

? Which version target would you like to update to? Minor
? Do you want to update the package.json files? yes
Updating root 'package.json' for minor updates...
Updating packages for minor updates in /Users/wswebcreation/Git/wdio/visual-testing...
Using pnpm
Upgrading /Users/wswebcreation/Git/wdio/visual-testing/package.json
[====================] 38/38 100%

@typescript-eslint/eslint-plugin ^8.7.0 → ^8.8.0
@typescript-eslint/parser ^8.7.0 → ^8.8.0
@typescript-eslint/utils ^8.7.0 → ^8.8.0
@vitest/coverage-v8 ^2.1.1 → ^2.1.2
vitest ^2.1.1 → ^2.1.2

Run pnpm install to install new versions.
Updating packages for minor updates in /Users/wswebcreation/Git/wdio/visual-testing/packages/ocr-service...
Using pnpm
Upgrading /Users/wswebcreation/Git/wdio/visual-testing/packages/ocr-service/package.json
[====================] 11/11 100%

All dependencies match the minor package versions :)
Updating packages for minor updates in /Users/wswebcreation/Git/wdio/visual-testing/packages/visual-reporter...
Using pnpm
Upgrading /Users/wswebcreation/Git/wdio/visual-testing/packages/visual-reporter/package.json
[====================] 11/11 100%

eslint-config-next 14.2.13 → 14.2.14
next 14.2.13 → 14.2.14

Run pnpm install to install new versions.
Updating packages for minor updates in /Users/wswebcreation/Git/wdio/visual-testing/packages/visual-service...
Using pnpm
Upgrading /Users/wswebcreation/Git/wdio/visual-testing/packages/visual-service/package.json
[====================] 5/5 100%

All dependencies match the minor package versions :)
Updating packages for minor updates in /Users/wswebcreation/Git/wdio/visual-testing/packages/webdriver-image-comparison...
Using pnpm
Upgrading /Users/wswebcreation/Git/wdio/visual-testing/packages/webdriver-image-comparison/package.json
[====================] 8/8 100%

All dependencies match the minor package versions :)
? Do you want to remove all "node_modules" and reinstall dependencies? yes
Removing root dependencies in /Users/wswebcreation/Git/wdio/visual-testing...
Removing dependencies in ocr-service...
Removing dependencies in visual-reporter...
Removing dependencies in visual-service...
Removing dependencies in webdriver-image-comparison...
? Would you like reinstall the dependencies? yes
Installing dependencies in /Users/wswebcreation/Git/wdio/visual-testing...

> @wdio/visual-testing-monorepo@ pnpm.install.workaround /Users/wswebcreation/Git/wdio/visual-testing
> pnpm install --shamefully-hoist

Scope: all 5 workspace projects
Lockfile is up to date, resolution step is skipped
Packages: +1274
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Progress: resolved 1274, reused 1265, downloaded 0, added 1274, done

dependencies:

- @wdio/ocr-service 2.0.0 <- packages/ocr-service
- @wdio/visual-service 6.0.0 <- packages/visual-service

devDependencies:

- @changesets/cli 2.27.8
- @inquirer/prompts 5.5.0
- @tsconfig/node20 20.1.4
- @types/eslint 9.6.1
- @types/jsdom 21.1.7
- @types/node 20.16.4
- @types/react 18.3.5
- @types/react-dom 18.3.0
- @types/xml2js 0.4.14
- @typescript-eslint/eslint-plugin 8.8.0
- @typescript-eslint/parser 8.8.0
- @typescript-eslint/utils 8.8.0
- @vitest/coverage-v8 2.1.2
- @wdio/appium-service 9.1.2
- @wdio/cli 9.1.2
- @wdio/globals 9.1.2
- @wdio/local-runner 9.1.2
- @wdio/mocha-framework 9.1.2
- @wdio/sauce-service 9.1.2
- @wdio/shared-store-service 9.1.2
- @wdio/spec-reporter 9.1.2
- @wdio/types 9.1.2
- eslint 9.11.1
- eslint-plugin-import 2.30.0
- eslint-plugin-unicorn 55.0.0
- eslint-plugin-wdio 9.0.8
- husky 9.1.6
- jsdom 25.0.1
- npm-run-all2 6.2.3
- release-it 17.6.0
- rimraf 6.0.1
- saucelabs 8.0.0
- ts-node 10.9.2
- typescript 5.6.2
- vitest 2.1.2
- webdriverio 9.1.2

. prepare$ husky
└─ Done in 204ms
Done in 9.5s
All packages updated!

問題

如果您對貢獻此專案有任何疑問或問題,請加入我們的 Discord 伺服器。在 🙏-contributing 頻道中找到我們的貢獻者。

問題回報

如果您有問題、錯誤或功能請求,請提出問題回報。在提交問題回報之前,請先搜尋問題存檔以減少重複,並閱讀 FAQ

如果您在那裡找不到答案,您可以提交一個問題回報,您可以在其中提交

  • 🐛錯誤回報:建立報告以幫助我們改進
  • 📖文件:建議改進或報告遺失/不明確的文件。
  • 💡功能請求:為此模組提出一個想法。
  • 💬問題:提出問題。

開發工作流程

要為此專案建立 PR 並開始貢獻,請按照此逐步指南

  • Fork 專案。

  • 將專案複製到您電腦上的某個位置

    $ git clone https://github.com/webdriverio/visual-testing.git
  • 前往目錄並設定專案

    $ cd visual-testing
    $ corepack enable
    $ corepack use pnpm@8.x
    $ pnpm pnpm.install.workaround
  • 執行將自動轉換程式碼的監看模式

    $ pnpm watch

    要建置專案,請執行

    $ pnpm build
  • 請確保您的變更不會破壞任何測試,執行

    $ pnpm test

此專案使用 changesets 自動建立變更日誌和發布。

測試

需要執行多個測試才能測試模組。新增 PR 時,所有測試至少必須通過本機測試。每個 PR 都會自動針對 Sauce Labs 進行測試,請參閱我們的 GitHub Actions 管道。在核准 PR 之前,核心貢獻者將針對模擬器/模擬器/真實裝置測試 PR。

本機測試

首先,需要建立本機基準。這可以使用以下命令完成

// With the webdriver protocol
$ npm run test.local.init

此命令將建立一個名為 localBaseline 的資料夾,其中將包含所有基準圖片。

然後執行

// With the webdriver protocol
npm run test.local.desktop

這將在 Chrome 上的本機執行所有測試。

本機 Storybook 執行器測試 (Beta)

首先,需要建立本機基準。這可以使用以下命令完成

npm run test.local.desktop.storybook

這將在無頭模式下使用 Chrome 針對位於 https://govuk-react.github.io/govuk-react/ 的 Demo Storybook 儲存庫執行 Storybook 測試。

要使用更多瀏覽器執行測試,您可以執行

npm run test.local.desktop.storybook -- --browsers=chrome,firefox,edge,safari

[!NOTE] 請確保您已在本機上安裝要執行的瀏覽器

使用 Sauce Labs 進行 CI 測試(PR 不需要)

以下命令用於在 GitHub Actions 上測試建置,它只能在那裡使用,而不能用於本機開發。

$ npm run test.saucelabs

它將針對許多配置進行測試,這些配置可以在這裡找到。所有 PR 都會自動針對 Sauce Labs 進行檢查。

發佈

要發佈上面列出的任何套件的版本,請執行以下操作

  • 觸發 發佈管道
  • 會產生一個發佈 PR,請讓另一個 WebdriverIO 成員審閱和核准
  • 合併 PR
  • 再次觸發 發佈管道
  • 應該會發布一個新版本 🎉

鳴謝

@wdio/visual-testing 使用 Sauce Labs 的開放原始碼授權。

歡迎!我可以幫您什麼忙?

WebdriverIO AI Copilot