图像比较(视觉回归测试)服务
有关使用 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
中的id
是example-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
中的 id
为 example-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 上自动检查。
发布
要发布上面列出的任何软件包的版本,请执行以下操作
鸣谢
@wdio/visual-testing
使用来自 Sauce Labs 的开源许可证。