跳至主要内容

图像比较(视觉回归测试)服务

@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 无头模式作为默认浏览器。

[!注意]

  • 大多数视觉测试选项也适用于 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 提供。

它将使用提供的浏览器来拍摄组件屏幕截图。

[!注意] 确保您在本地机器上安装了要运行的浏览器。

--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匹配的提供的设备来拍摄组件屏幕截图。

[!注意]

  • 如果您缺少设备配置,请随时提交功能请求
  • 这仅适用于 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
  • SRC:在桌面设备上使用移动仿真测试移动网站可能很有用,但测试人员应注意存在许多细微差异,例如
    • 完全不同的 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的限制。

[!重要] 在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。例如,此 URLhttps://127.0.0.1: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 实例,然后将您的测试添加到需要比较的故事中。如果您不希望将用于交互测试的组件进行两次比较,则可以通过提供 --skipStories 过滤器来添加过滤器,以从扫描中删除“默认”故事。这将如下所示

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' })

使用故事的 id,该 id 可以在故事的 URL 中找到。例如,此 URL https://127.0.0.1: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 频道中找到我们的贡献者。

问题

如果您有任何问题、错误或功能请求,请提交问题。在提交问题之前,请搜索问题存档以帮助减少重复,并阅读 常见问题解答

如果您在那里找不到,您可以提交一个问题,您可以在其中提交

  • 🐛错误报告:创建报告以帮助我们改进
  • 📖文档:建议改进或报告缺失/不清楚的文档。
  • 💡功能请求:为此模块提出一个想法。
  • 💬问题:提问。

开发工作流程

要为此项目创建 PR 并开始贡献,请按照此分步指南操作

  • 派生项目。

  • 将项目克隆到您计算机上的某个位置

    $ git clone https://github.com/webdriverio/visual-testing.git
  • 转到目录并设置项目

    $ cd visual-testing
    $ corepack enable
    $ corepack use [email protected]
    $ 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 运行器测试(测试版)

首先,需要创建本地基线。这可以通过以下方式完成

npm run test.local.desktop.storybook

这将在无头模式下使用 Chrome 对位于 https://govuk-react.github.io/govuk-react/ 的演示 Storybook 存储库运行 Storybook 测试。

要使用更多浏览器运行测试,您可以运行

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

[!注意] 确保您在本地机器上安装了要运行的浏览器。

使用 Sauce Labs 进行 CI 测试(PR 不需要)

以下命令用于在 GitHub Actions 上测试构建,它只能在那里使用,不能用于本地开发。

$ npm run test.saucelabs

它将针对许多配置进行测试,这些配置可以在 此处 找到。所有 PR 都会在 Sauce Labs 上自动检查。

发布

要发布上面列出的任何软件包的版本,请执行以下操作

  • 触发 发布管道
  • 生成发布 PR,让另一位 WebdriverIO 成员审查并批准。
  • 合并 PR。
  • 再次触发 发布管道
  • 应该发布新版本🎉

鸣谢

@wdio/visual-testing 使用来自 Sauce Labs 的开源许可证。

欢迎!我如何提供帮助?

WebdriverIO AI Copilot