Eyes-Storybook
用于 Storybook 的 Applitools Eyes SDK。
目录
- Eyes-Storybook
安装
安装 npm 包
在您的测试项目中将 Eyes-Storybook 安装为本地开发依赖项
npm install --save-dev @applitools/eyes-storybook
Applitools API 密钥
为了通过 Applitools 服务器进行身份验证,您需要向 Eyes-Storybook SDK 提供从 Applitools 获取的 API 密钥。阅读更多关于如何获取 API 密钥的信息,请点击这里。
为此,在运行测试之前,将环境变量 APPLITOOLS_API_KEY
设置为 API 密钥。例如,在 Linux/Mac 上
export APPLITOOLS_API_KEY=<your_key>
在 Windows 上
set APPLITOOLS_API_KEY=<your_key>
用法
完成安装并定义 API 密钥后,您将能够从命令行运行 Eyes-Storybook,并让它截取所有 story 的屏幕截图。
如果您的项目使用默认的 storybook 配置文件夹(即 <project_folder>/.storybook
),则运行以下命令
npx eyes-storybook
配置本地 storybook 服务器
通常,Eyes-Storybook 在 9000-9010 之间的可用端口中启动 storybook 开发服务器,用于测试期间。可以向 Eyes-Storybook 传递参数来配置本地 storybook 服务器
--storybook-port OR -p
:运行 storybook 的端口(作为-p
传递给start-storybook
)。--storybook-host OR -h
:运行 storybook 的主机(作为-h
传递给start-storybook
)。--storybook-config-dir OR -c
:从中加载 Storybook 配置的目录(作为-c
传递给start-storybook
)--storybook-static-dir OR -s
:从中加载静态文件的目录,逗号分隔列表(作为-s
传递给start-storybook
)
独立服务器
如上一节所述,Eyes-Storybook 启动了一个 storybook 开发服务器。如果您希望在 Eyes-Storybook 之外启动服务器,或者测试在特定 URL 上可用的生产构建,则只需在命令行(或配置文件中,请参阅下面的高级配置)中指定 storybook 的 URL。
例如
npx eyes-storybook -u https://127.0.0.1:6006
或者对于生产 storybook
npx eyes-storybook -u http://react.carbondesignsystem.com/
命令行参数
可以通过运行 npx eyes-storybook --help
查看完整的命令行参数列表
Usage: eyes-storybook.js [options]
Options:
--help Show help [boolean]
--version, -v Show the version number [boolean]
--conf, -f Path to applitools.config.js config file [string]
--storybook-url, -u URL to storybook [string]
--storybookPort, -p, --storybook-port Port to run Storybook [number]
--storybookHost, -h, --storybook-host Host to run Storybook [string]
--storybookConfigDir, -c, --storybook-config-dir Path to Storybook's config folder (defaults to .storybook) [string]
--storybookStaticDir, --storybook-static-dir Path to Storybook's static files folder [string]
--showStorybookOutput, --show-storybook-output Whether or not you want to see Storybook output [boolean]
--readStoriesTimeout, --read-stories-timeout The time to wait until all stories are read, before starting the visual tests [number]
--exitcode, -e If tests failed close with non-zero exit code [boolean]
并发
免费帐户的默认并发级别为 5
。这意味着最多只能并行运行 5 个视觉测试,因此执行速度可能会很慢。如果您的帐户支持更高的并发级别,则可以通过在 applitools.config.js 文件中的属性 testConcurrency
中指定不同的值来传递不同的值(请参阅下面的高级配置部分)。
如果您有兴趣加快视觉测试速度,请联系 sdr@applitools.com 以获得试用帐户和更快、更高并发的测试。
高级配置
除了命令行参数外,还可以使用环境变量或 applitools.config.js 文件为测试定义以下配置参数
属性名称 | 默认值 | 描述 |
---|---|---|
storybookUrl |
未定义 | Storybook 的 URL(也可用作命令行参数)。 |
storybookPort |
9000 | 运行 Storybook 的端口(也可用作命令行参数)。 |
storybookHost |
localhost | 运行 Storybook 的主机(也可用作命令行参数)。 |
storybookConfigDir |
.storybook | Storybook 配置文件夹的路径(也可用作命令行参数)。 |
storybookStaticDir |
未定义 | Storybook 静态文件文件夹的路径(也可用作命令行参数)。 |
showStorybookOutput |
未定义 | 是否要查看 Storybook 输出(也可用作命令行参数)。 |
viewportSize |
{ width: 1024, height: 600} | puppeteer 浏览器窗口的大小。这是最初渲染 story 的浏览器窗口(并以 viewportSize 参数中提供的大小打开),然后将 DOM 快照上传到服务器,服务器在 browser 参数中提供的所有浏览器和大小上渲染此快照。 |
exitcode |
true | 如果测试失败或存在视觉差异,则以非零退出代码关闭(也可用作命令行参数)。 |
browser |
{ width: 1024, height: 768, name: 'chrome' } | 生成的屏幕截图的大小和浏览器。有关更多信息和可能的值,请参阅下面的浏览器部分。 |
showLogs |
false | 是否要查看 Eyes-Storybook 插件的日志。 |
batch |
未定义 | 一个描述 batch 不同方面的对象。此表中的以下行描述了配置 batch 的各种方法。 |
batch.id |
随机 | 提供将测试分组到 batch 中的能力。阅读更多关于 batch 的信息,请点击这里。 |
batch.name |
batch 中第一个测试的名称 | 为 batch 提供名称(仅用于显示目的)。 |
batch.sequenceName |
未定义 | 用于管理 batch 统计信息的名称。 |
batch.notifyOnCompletion |
false | 如果为 true ,则发送 batch 完成通知。 |
batch.properties |
未定义 | 整个 batch 的自定义属性。格式是具有 name/value 属性的对象数组。例如:[{name: 'My prop', value:'My value'}] 。 |
baselineEnvName |
未定义 | 基线环境的名称。 |
envName |
未定义 | 被测应用程序正在运行的环境的名称。 |
ignoreCaret |
false | 比较图像时是否忽略闪烁的光标。 |
matchLevel |
未定义 | 在检查应用程序屏幕截图与预期输出时使用的测试范围匹配级别。可能的值为 Strict 、Exact 、Layout 和 Content 。阅读更多关于匹配级别的信息,请点击这里。 |
branchName |
未定义 | 分支的名称。 |
baselineBranchName |
未定义 | 基线分支的名称。 |
parentBranchName |
未定义 | 设置在哪个分支下创建新分支。 |
proxy |
未定义 | 设置用于向 Eyes 服务器发出网络请求的代理设置。可以是代理 URI 的字符串,也可以是包含 URI、用户名和密码的对象。例如:{url: 'https://myproxy.com:443', username: 'my_user', password: 'my_password', isHttpOnly: false} 或 "https://username:password@myproxy.com:443" |
saveFailedTests |
false | 设置是否默认保存失败的测试(保存为基线)。 |
saveNewTests |
true | 设置是否默认保存新测试(保存为基线)。 |
serverUrl |
默认 Eyes 服务器 URL | Eyes 服务器的 URL |
compareWithParentBranch |
false | |
ignoreBaseline |
false | |
runInDocker |
false | 如果您在 Docker 中运行 SDK 时遇到问题,请将此标志设置为 true 。请参阅下面的更多信息 |
puppeteerOptions |
未定义 | 发送到 puppeteer.launch 的选项。这是一个低级配置,应谨慎使用。示例用法 { args: ['--no-sandbox'], headless: false, devtools: true} |
jsonFilePath |
未定义 | 结果文件的目录路径。如果设置,则在此目录中创建一个 JSON 文件,该文件以 eyes.json 命名,并包含 Eyes 测试结果。 |
tapFilePath |
未定义 | 结果文件的目录路径。如果设置,则在此目录中创建一个 TAP 文件,该文件以 eyes.tap 命名,并包含 Eyes 测试结果。 |
xmlFilePath |
未定义 | 结果文件的目录路径。如果设置,则在此目录中创建一个 XUnit XML 文件,该文件以 eyes.xml 命名,并包含 Eyes 测试结果。 |
waitBeforeCapture |
未定义 | 选择器、函数或超时。如果 number ,则该参数被视为等待所有屏幕截图之前的时间(以毫秒为单位)。如果 string ,则该参数被视为在所有屏幕截图之前要等待的元素的 CSS 选择器。如果 function ,则该参数被视为在所有屏幕截图之前要等待的谓词。有关每个组件的配置,请参阅 waitBeforeCapture。请注意,我们使用 Puppeteer 的 page.waitForTimeout()、page.waitForSelector()、page.waitForXPath() 和 page.waitForFunction(),请查看其 API 以获取更多详细信息。 |
include |
true | 一个谓词函数、字符串或正则表达式,用于指定应进行视觉测试的 story。视觉基线将仅为指定的组件创建。该函数接收一个具有 name 、kind 、storyTitle 和 parameters 属性的对象。例如(排除所有名称以 [SKIP] 开头的 story):({name, kind, storyTitle, parameters}) => !/^\[SKIP\]/.test(name) 。有关更多信息,请参阅 每个组件的配置 - include。 |
variations |
未定义 | 为所有或部分 story 指定额外的变体。例如,RTL。有关更多信息,请参阅 每个组件的配置 - variations。 |
dontCloseBatches |
false | 如果为 true,则不会为 notifyOnCompletion 关闭 batch。 |
testConcurrency |
5 | 可以并发运行的最大测试数。默认值是免费帐户允许的数量。对于付费帐户,请将此数字设置为为您的帐户设置的配额。 |
readStoriesTimeout |
60000 | Eyes-Storybook 等待 storybook 加载的时间量(以毫秒为单位)。对于旧版本的 storybook 2 和 3,这也是 Eyes-Storybook 确认它正在处理这些版本的时间。因此,建议在使用 Storybook 版本 2 或 3 时将此值设置较小(例如 3000)。 |
ignoreDisplacements |
false | 设置 Test Manager 是否应最初显示仅已位移的图像特征的不匹配项,而不是真正的失配项。这也可以为每个 story 指定,请参阅 每个组件的配置 - ignoreDisplacements |
properties |
未定义 | 为每个测试添加自定义属性。这些属性会显示在 Test Manager 中,并且可以按自定义属性对测试进行分组。默认情况下,Eyes-Storybook 为每个测试添加 2 个自定义属性:每个组件的组件名称和状态。通过此配置参数添加更多属性将不会覆盖这两个属性。 |
ignoreRegions |
未定义 | 在将检查点屏幕截图与基线屏幕截图进行比较时要忽略的区域数组。有关更多信息,请参阅 每个组件的配置 - ignoreRegions |
floatingRegions |
未定义 | 在将检查点屏幕截图与基线屏幕截图进行比较时要视为浮动区域的区域数组。有关更多信息,请参阅 每个组件的配置 - floatingRegions |
layoutRegions |
未定义 | 在将检查点屏幕截图与基线屏幕截图进行比较时要视为匹配级别为 Layout 的区域数组。有关更多信息,请参阅 每个组件的配置 - layoutRegions |
strictRegions |
未定义 | 在将检查点屏幕截图与基线屏幕截图进行比较时要视为匹配级别为 Strict 的区域数组。有关更多信息,请参阅 每个组件的配置 - strictRegions |
contentRegions |
未定义 | 在将检查点屏幕截图与基线屏幕截图进行比较时要视为匹配级别为 Content 的区域数组。有关更多信息,请参阅 每个组件的配置 - contentRegions |
accessibilityRegions |
未定义 | 在将检查点屏幕截图与基线屏幕截图进行比较时要验证可访问性的区域数组。验证根据配置的 accessibilityValidation 进行。有关更多信息,请参阅 每个组件的配置 - contentRegions |
accessibilityValidation |
未定义 | 一个对象,用于指定屏幕截图要使用的可访问性级别和指南版本。level 的可能值为 None 、AA 和 AAA ,guidelinesVersion 的可能值为 WCAG_2_0 和 WCAG_2_1 。例如:{level: 'AA', guidelinesVersion: 'WCAG_2_0'} 。有关更多信息,请参阅 每个组件的配置 - accessibilityValidation |
layoutBreakpoints |
未定义 | 当设置为 true 时,将为 browser 配置中的每个浏览器/设备大小拍摄一次 DOM 快照。出于优化目的,可以传递数字数组。DOM 快照将为数组中的每个 width 拍摄一次。有关更多信息,请参阅 每个组件的配置 - layoutBreakpoints |
sendDom |
true | 一个标志,用于指定在渲染屏幕截图时是否应捕获 DOM 和 CSS。默认值为 true。仅应在排查意外行为时修改此值,不应用于正常的生产用途。有关更多信息,请参阅 组件配置 - sendDom |
visualGridOptions |
未定义 | 一个对象,用于指定在 Ultrafast 网格上配置渲染的选项。请参阅更多信息 组件配置 - visualGridOptions |
指定测试配置有两种方法
- 环境变量
applitools.config.js
文件
上面的列表也是优先级顺序,这意味着如果您将属性指定为环境变量,它将覆盖在 applitools.config.js
文件中为同一属性定义的值。
方法 1:环境变量
相应的环境变量名称为大写,带有 APPLITOOLS_
前缀,并用下划线分隔而不是驼峰式命名
APPLITOOLS_APP_NAME
APPLITOOLS_SHOW_LOGS
APPLITOOLS_BATCH_ID
APPLITOOLS_BATCH_NAME
APPLITOOLS_BATCH_SEQUENCE_NAME
APPLITOOLS_PROXY
APPLITOOLS_NOTIFY_ON_COMPLETION
...
// all other configuration variables apply as well..
方法 2:applitools.config.js
文件
可以在当前工作目录(运行 eyes-storybook
脚本时所在的目录)中创建一个名为 applitools.config.js
的文件。在此文件中指定所需的配置,作为导出的 CommonJS 模块。例如
module.exports = {
appName: 'My app',
showLogs: true,
batchName: 'My batch'
...
// all other configuration variables apply
}
配置浏览器
Eyes-Storybook 将按照 browser
配置参数中的指定,拍摄页面的屏幕截图。
可能的值包括
chrome
firefox
edgechromium
edgelegacy
ie10
ie11
safari
chrome-one-version-back
chrome-two-versions-back
firefox-one-version-back
firefox-two-versions-back
safari-one-version-back
safari-two-versions-back
edgechromium-one-version-back
edgechromium-two-versions-back
之前的浏览器版本
*-one-version-back
和 *-two-versions-back
相对于同一浏览器的版本。例如,如果 chrome
指的是 79 版本,那么 chrome-one-version-back
将是 Chrome 78,而 chrome-two-versions-back
将是 Chrome 77。
并行获取多个浏览器的屏幕截图
也可以发送浏览器数组,例如在 applitools.config.js
文件中
module.exports = {
browser: [
{width: 800, height: 600, name: 'firefox'},
{width: 1024, height: 768, name: 'chrome'},
{width: 1024, height: 768, name: 'ie11'}
]
}
设备模拟
要启用 Chrome 的设备模拟,可以发送设备名称和屏幕方向,例如
module.exports = {
browser: {
deviceName: 'iPhone X',
screenOrientation: 'landscape',
name: 'chrome' // optional, just to make it explicit this is browser emulation and not a real device. Only chrome is supported for device emulation.
}
}
屏幕方向的可能值为 landscape
和 portrait
,如果未指定值,则默认为 portrait
。
设备名称列表可在 https://github.com/applitools/eyes.sdk.javascript1/blob/master/packages/eyes-api/src/enums/DeviceName.ts 中找到
此外,除了 width
和 height
之外,还可以通过传递 deviceScaleFactor
和 mobile
来使用 Chrome 的设备模拟以及自定义视口大小、像素密度和移动模式。例如
module.exports = {
browser: {
width: 800,
height: 600,
deviceScaleFactor: 3,
mobile: true,
name: 'chrome' // optional, just to make it explicit this is browser emulation and not a real device. Only chrome is supported for device emulation.
}
}
iOS 设备
module.exports = {
browser: {
iosDeviceInfo: {
deviceName: 'iPhone XR',
screenOrientation: 'landscape', // optional, default: 'portrait'
iosVersion: 'latest' // optional, default: undefined (i.e. the default is determined by the Ultrafast grid)
},
}
}
iosVersion
的可能值包括
'latest'
- UFG 支持的最新 iOS 版本'latest-1'
- 最新版本的前一个版本undefined
- UFG 的默认值
伪造 IE 浏览器
某些页面在 Internet Explorer 上的渲染方式不同,因此,在使用 ultrafast 网格在伪造的 IE 浏览器上运行时,获取 dom 快照可能很重要。
使用 fakeIE
标志 - 您可以在伪装成 IE 的 Chrome 上渲染故事。
我们通过模拟页面的 userAgent
和 documentMode
来实现这一点 - 使页面认为它正在 IE 上渲染。
使用伪造的 IE 测试时,性能会略有下降 - 因为浏览器需要为它渲染的每个故事伪造 IE。
每个组件的配置
仅在 Storybook 版本 >= 4 中支持
有两种方法可以为特定故事或一组故事提供配置。
-
作为故事的参数 - 可以将第三个参数传递给 Storybook 的
.add
函数,以自定义每个故事。可以在参数对象的eyes
属性中指定配置属性。 -
在全局配置文件
applitools.config.js
中 - 如果为以下属性之一指定了函数,则将为每个故事调用该函数,并将传递故事的元数据,结构为{name, kind, parameters}
,其中name
是组件的名称,kind
是 Storybook 为类别构建的字符串,例如Forms|Input/Text
,parameters
是 Storybook 的.add
函数的第三个参数。该函数应返回特定属性+故事的配置值。
在故事中本地指定的值优先于全局配置值。
支持以下属性
include
global
当全局提供时,include
是一个函数,它接收故事的 kind
和 name
、storyTitle
和 parameters
。除了 storyTitle
之外,所有这些属性都来自 storybook
,它们代表故事的层次结构
kind
- 故事目录和部分(如果适用)。storybook
中允许嵌套目录结构。这些结构将以/
为后缀,而可以容纳许多目录的部分将以|
为后缀。例如- 名为
Button
的故事在Components
目录中 - 其kind
将为Components
。 - 名为
Button
的故事在App
部分下的Components
目录中 - 其kind
将为App|Components
。 - 名为
RadioButton
的故事在App
部分下的Components
目录的Radio
子目录中 - 其kind
将为App|Components/Radio
。
- 名为
name
- 故事名称。例如- 名为
Button
的故事在Components
目录中 - 其name
将为Button
。
- 名为
parameters
- 可以在故事中指定的自定义参数。
storyTitle
由 SDK 生成,并用作测试名称。因此,可以轻松查找和按其过滤。
更多信息可以在 Storybook 文档 - 命名组件和层次结构 中找到。
您可以按 kind
、name
、storyTitle
、parameters
、它们的组合或任何将产生 boolean
值的逻辑进行过滤。例如
// applitools.config.js
module.exports = {
...
// given the example above
// visually test only the stories in the 'Radio' subdirectory
include: ({kind}) => {
return kind === 'App|Components/Radio'
}
...
}
当将 storyTitle
作为 string
传递时,将仅测试此故事。例如
module.exports = {
...
include: "Button: with text",
...
}
当将 storyTitle
作为 Regex
传递时,将仅测试匹配的故事。例如
module.exports = {
...
include: /Button: */,
...
}
注意:您可以使用正则表达式或您喜欢的任何其他方法,只要您从此函数返回
boolean
值
component
当为 false
时,组件将不会进行视觉测试。例如
// This story will not be tested visually
storiesOf('Some kind', module)
.add(
'Some story',
() => <div>I am visually perfect!</div>,
{eyes: {include: false}}
)
variations
对象值数组,用于指定要为此故事添加哪些变体。对于每个值,将为组件执行额外的视觉测试。每个变体可以包含 queryParams
和 properties
字段,以分别指定自定义查询参数和 eyes 属性。变体测试将具有相同的名称。
这可以适应许多用例,例如 @storybook/addon-contexts
。使用这样的插件,可以根据 URL 中的查询参数以不同的方式渲染组件。例如,这是一个处理 RTL 变体的 Storybook
const isRTL = new URL(window.location).searchParams.get('eyes-variation') === 'RTL';
if (isRTL) {
document.documentElement.setAttribute('dir', 'rtl')
}
// 2 visual tests will be created - one for LTR and one for RTL
storiesOf('Components that support RTL', module)
.add(
'Some story',
() => <div>
<span>I am visually perfect!</span>
<span>{isRTL ? ' and rendered right to left as well :)' : ''}</span>
</div>,
{eyes: {variations: [{queryParams: {'eyes-variation': 'RTL'}, properties: {name: 'isRTL', value: 'true'}, {properties: {name: 'isRTL', value: 'false'}}]}}
)
waitBeforeCapture
选择器或超时,请参阅 高级配置 了解更多详细信息。
storiesOf('Components with a waitBeforeCapture', module)
.add(
'Some story',
() => <span id="container" class="loading"></span>,
{eyes: { waitBeforeCapture: '#container.ready' }}
);
请注意,waitBeforeCapture
的谓词选项当前在组件配置中不可用。
properties
为每个测试添加自定义属性。这些属性会显示在 Test Manager 中,并且可以按自定义属性对测试进行分组。默认情况下,Eyes-Storybook 为每个测试添加 2 个自定义属性:每个组件的组件名称和状态。通过此配置参数添加更多属性将不会覆盖这两个属性。
例如
storiesOf('Components with custom properties', module)
.add(
'Some story',
() => <span id="container" class="loading"></span>,
{eyes: { properties: [
{name: 'some prop #1', value: 'some value #1'},
{name: 'some prop #2', value: 'some value #2'},
] }}
);
ignoreRegions
在检查视觉差异时要忽略的单个或区域数组。例如
storiesOf('Components with ignored region', module)
.add(
'Some story',
() =>
<div>
<span>I am visually perfect!</span>
<span className="ignore-this">this should be ignored</span>
</div>,
{eyes: {
ignoreRegions: [
{selector: '.ignore-this'}, // by css selector
{left: 10, top: 20, width: 200, height: 80} // by absolute coordinates
]}
}
)
floatingRegions
在将检查点屏幕截图与基线屏幕截图进行比较时,要视为浮动的区域数组。例如
storiesOf('Components with floating region', module)
.add(
'Some story',
() =>
<div>
<span>I am visually perfect!</span>
<span className="floating-region">this should be floating</span>
</div>,
{eyes: {
floatingRegions: [
{ // by selector
selector: '.floating-region',
maxUpOffset: 10,
maxDownOffset: 20,
maxLeftOffset: 30,
maxRightOffset: 40,
},
{ // by absolute coordinates
left: 10,
top: 20,
width: 200,
height: 80,
maxUpOffset: 10,
maxDownOffset: 20,
maxLeftOffset: 30,
maxRightOffset: 40,
}
]}
}
)
layoutRegions
在将检查点屏幕截图与基线屏幕截图进行比较时,要视为匹配级别为 Layout 的区域数组。例如
storiesOf('Components with layout region', module)
.add(
'Some story',
() =>
<div>
<span>I am visually perfect!</span>
<span className="layout-region">this should be compared with layout match level</span>
</div>,
{eyes: {
layoutRegions: [
{selector: '.layout-region'}, // by css selector
{left: 10, top: 20, width: 200, height: 80} // by absolute coordinates
]}
}
)
contentRegions
在将检查点屏幕截图与基线屏幕截图进行比较时,要视为匹配级别为 Content 的区域数组。例如
storiesOf('Components with content region', module)
.add(
'Some story',
() =>
<div>
<span>I am visually perfect!</span>
<span className="content-region">this should be compared with content match level</span>
</div>,
{eyes: {
contentRegions: [
{selector: '.content-region'}, // by css selector
{left: 10, top: 20, width: 200, height: 80} // by absolute coordinates
]}
}
)
strictRegions
在将检查点屏幕截图与基线屏幕截图进行比较时,要视为匹配级别为 Strict 的区域数组。例如
storiesOf('Components with strict region', module)
.add(
'Some story',
() =>
<div>
<span>I am visually perfect!</span>
<span className="strict-region">this should be compared with strict match level</span>
</div>,
{eyes: {
strictRegions: [
{selector: '.strict-region'}, // by css selector
{left: 10, top: 20, width: 200, height: 80} // by absolute coordinates
]}
}
)
accessibilityRegions
用于可访问性检查的单个或区域数组。例如
storiesOf('Components with accessibility regions', module)
.add(
'Some story',
() =>
<div>
<span>I am visually perfect!</span>
<span className="check-me">this should be tested for accessibility</span>
</div>,
{eyes: {
accessibilityRegions: [
{accessibilityType: 'RegularText', selector: '.check-me'}, // by css selector
{accessibilityType: 'RegularText', left: 10, top: 20, width: 200, height: 80} // by absolute coordinates
]
}}
)
});
可能的 accessibilityType 值包括:IgnoreContrast
、RegularText
、LargeText
、BoldText
和 GraphicalObject
。
accessibilityValidation
在验证可访问性区域时应使用的级别和指南版本。例如
storiesOf('Components with accessibility regions', module)
.add(
'Some story',
() => <div>
<span>I am visually perfect!</span>
<span className="check-me">this should be tested for accessibility</span>
</div>,
{eyes: {
accessibilityValidation: {
level: 'AA',
guidelinesVersion: 'WCAG_2_0'
}
}}
)
});
level
的可能值为:AA
和 AAA
。guidelinesVersion
的可能值为:WCAG_2_0
和 WCAG_2_1
。
ignoreDisplacements
设置 Test Manager 是否应最初显示仅位移而非真正不匹配的图像特征的不匹配项。例如
storiesOf('Components with ignoreDisplacements', module)
.add(
'Some story',
() => <div>
<span>I am visually perfect!</span>
</div>,
{eyes: {
ignoreDisplacements: true
}}
)
});
sendDom
storiesOf('Components', module)
.add(
'Some story ',
() =>
<div>Some Story</div>, {
eyes: {
sendDom: false
}
})
visualGridOptions
一个对象,用于指定在 Ultrafast 网格上配置渲染的选项。可用选项
polyfillAdoptedStyleSheets
:当 DOM 包含adoptedStyleSheets
(参考) 时,为不支持它的浏览器创建 polyfill(目前仅在 Chrome 中支持)。当为true
时,这些浏览器将成功地将 CSS 作为内联样式标签包含在内。当为false
时,CSS 将不会被包含在内。当为undefined
时,将抛出错误,并显示消息说明所需浏览器不支持此功能。ieV2
:在 UFG 中使用 IE 环境 v2。
storiesOf('Components', module)
.add(
'Some story ',
() =>
<div>Some Story</div>, {
eyes: {
visualGridOptions: {
polyfillAdoptedStyleSheets: true,
ieV2: true
}
}
})
scriptHooks
一组脚本,在渲染期间由浏览器运行。它旨在用作在渲染时更改页面状态和结构的手段。具有以下属性的对象
beforeCaptureScreenshot
一个在页面加载后但在拍摄屏幕截图之前运行的脚本。例如
storiesOf('Components', module)
.add(
'Some story',
() =>
<div>Some Story</div>, {
eyes: {
scriptHooks: {
beforeCaptureScreenshot: "document.body.style.backgroundColor = 'gold'"
}
}
})
不能设置为 高级配置 的参数
runBefore
和 runAfter
函数
runBefore
函数可用于在拍摄故事快照之前执行任何操作。runAfter
方法应用于清理 runBefore
创建的任何副作用(如果有)。
例如,如果 runBefore
向 body
元素添加了一个类,则应在 runAfter
中删除此类。这是因为浏览器选项卡的窗口在故事之间不会重新加载。
注意:rootEl
也需要清理,因此在 runBefore
中对此元素所做的任何修改都应在 runAfter
中恢复。
runBefore
一个异步函数,将在拍摄故事的屏幕截图之前进行评估。这是使用 DOM API 与故事进行任何交互的地方。
为了执行各种 DOM 交互,我们建议查看 dom-testing-library。它提供了用于交互、查询和等待 DOM 上条件的实用程序。
例如,渲染弹出窗口的组件可以触发弹出窗口的打开并等待内容出现
// these are utilities from dom-testing-library
import {wait, within, fireEvent} from '@testing-library/dom';
// <Popover /> is a component in your UI library.
// The assumption in this example is that it is opened by an element with the text 'Open',
// and then that element's text changes to 'Close':
storiesOf('UI components', module)
.add('Popover', () => <Popover />, {
eyes: {
runBefore({rootEl, story}) {
fireEvent.click(within(rootEl).getByText('Open'))
return wait(() => within(rootEl).getByText('Close'))
}
},
})
runAfter
一个异步函数,在拍摄故事的屏幕截图后进行评估。这是执行任何可能改变下一个故事渲染方式的清理工作的地方。
例如,恢复为先前组件更改的原始背景颜色
.add('background color', () => (
<div style={{fontSize: '30px'}}>Component with runBefore hook that modifies the background color</div>
), {
eyes: {
runBefore({rootEl, story}) {
window.originalBackgoundColor = document.querySelector("html").style.backgroundColor;
document.querySelector("html").style.backgroundColor = 'fuchsia';
},
runAfter({rootEl, story}){
document.querySelector("html").style.backgroundColor = window.originalBackgoundColor;
delete window.originalBackgoundColor;
}
}
})
layoutBreakpoints
storiesOf('Components', module)
.add(
'Some story with breakpoints for all browser and device sizes',
() =>
<div>Some Story</div>, {
eyes: {
layoutBreakpoints: true
}
})
.add(
'Some story with breakpoints for desktop and mobile',
() =>
<div>Some Story</div>, {
eyes: {
layoutBreakpoints: [500, 1200]
}
})
在 Docker 中运行 Eyes-Storybook
在 Docker 中运行 SDK 时,可能会出现与通过 Puppeteer 正确启动内部 Chrome 浏览器相关的问题。如果您似乎遇到此类问题,请在配置文件中设置 runInDocker: true
。这将向内部 Chrome 浏览器传递特殊的参数,如 此处 所述。
如果您仍然遇到问题,您可能需要按照说明在 Docker 容器中使用您自己的 Chromium 浏览器,并将 SDK 的 Puppeteer 指向该浏览器。按照 此处 的说明进行操作,并通过 puppeteerOptions
设置 executablePath
。例如,applitools.config.js
module.exports = {
puppeteerOptions: {
executablePath: '/usr/bin/chromium-browser'
}
}
处理动态数据
有时组件会渲染动态数据,例如日期或随机数据。这在测试这些组件时会带来挑战。我们建议解决此问题的方法是在您的 Storybook 中插入代码,以在自动化环境中运行时标准化数据(使用固定日期或特定种子)。
Eyes Storybook 使组件可以意识到它们正在被测试。故事的 iframe 的 URL 上将有一个特定的查询参数:?eyes-storybook=true
。
这样就可以编写像这样的故事
const isBeingTested =
new URL(window.location).searchParams.get('eyes-storybook')
const SOME_FIXED_DATE = 354060000000
const date = new Date(isBeingTested ? SOME_FIXED_DATE : undefined)
storiesOf('Some kind', module).add('Date', () => <div>{date}</div>)
Storybook 交互 Play 功能
自 3.28.0 版本以来,支持 Storybook 的 Interactions Play 功能:使用“Play”的故事,屏幕截图将在“Play”流程完成后自动拍摄。这将取代现有的屏幕截图拍摄点,它不应影响任何不使用“Play”功能的新故事或现有故事。对于使用 waitBeforeCapture
属性的测试,等待时间段将在“Play”流程完成后开始。您可以在 Storybook 交互文档中阅读更多内容:https://storybook.org.cn/docs/react/essentials/interactions