一个使用 `@storybook/test-runner` 提供稳定屏幕截图捕获功能的实用程序。

在 Github 上查看

storycap-testrun 为 Story 提供类似于 storycap 内部稳定性检查的功能,从而可以准确地捕获 Story 的屏幕截图 :camera

为什么选择 storycap-testrun?

在使用 @storybook/test-runner 进行视觉回归测试时,会使用 waitForPageReady 函数在拍摄屏幕截图之前等待。这仅支持最基本的稳定性检查。因此,在实际用例中,需要设计方法来进行更准确的稳定性检查。

storycap 通过使用 CDP 监控 Story 在浏览器中渲染时的各种指标来实现稳定的拍摄。storycap-testrun 遵循 storycap 的策略,执行准确检查渲染内容稳定性的屏幕截图捕获。此外,它还提供了一种通过验证多个捕获的屏幕截图图像的哈希值是否相同来检查渲染内容稳定性的机制。

此外,它还提供了用于避免不稳定测试的启发式实用程序,例如蒙版和移除,这些实用程序可以在每个 Story 的参数中指定。

特性

  • 对渲染内容进行高稳定性检查
  • 准确等待 Play 函数
  • 使用 Hook 自定义屏幕截图捕获前后的操作
  • 屏蔽不稳定的元素
  • 移除不稳定的元素
  • 跳过不稳定的元素

限制

  • 无法捕获多个视口
  • 不支持 :hover:focus、点击等变体。
    • 虽然这是 storycap 支持的一个方便的功能,但为了避免影响在 postVisit 中执行的其他进程,它不被支持。

需求

安装

通过 npm 安装

$ npm install --save-dev storycap-testrun

入门

请事先设置 @storybook/test-runner

您可以通过在 postVisit 中调用 screenshot 函数立即开始使用它。

// .storybook/tesr-runner.ts
import type { TestRunnerConfig } from '@storybook/test-runner';
import { screenshot } from 'storycap-testrun';

const config: TestRunnerConfig = {
  async postVisit(page, context) {
    await screenshot(page, context, {
      /* options */
    });
  },
};

export default config;

[!重要] 由于 screenshot 函数会在内部自动执行稳定性检查,因此无需使用 waitForPageReady 等等待函数。

$ test-storybook

然后,只需适当地运行 @storybook/test-runner

默认情况下,屏幕截图图像保存在 __screenshots__ 目录中。

TypeScript 设置

通过导入 ScreenshotParameters 并合并您使用的框架的类型,您可以为每个 Story 中指定的参数启用类型检查。

import type { ScreenshotParameters } from 'storycap-testrun';

// Replace it with the framework you are using.
declare module '@storybook/react' {
  interface Parameters {
    screenshot?: ScreenshotParameters;
  }
}

API

screenshot(page, context, options)

  • page: Page
    • postVisit 中传递的 Playwright 页面实例。
  • context: TestContext
  • options: ScreenshotOptions
  • 返回:Promise<Buffer | null>
    • 捕获的屏幕截图图像的缓冲区。如果指定了 skip: true,则返回 null

选项

可以在 screenshot 函数的第三个参数中指定的选项。

output.dry

类型: boolean
默认值: false

如果指定了 true,则 screenshot 函数在执行时不会保存图像。这在处理返回的 Buffer 时很有用。

output.dir

类型: string
默认值: path.join(process.cwd(), '__screenshots__')

指定保存屏幕截图图像的根目录。

output.file

类型: string | ((context: TestContext) => string)
默认值: path.join('[title]', '[name].png')

指定每个 Story 的屏幕截图图像的文件名。

在指定 string 时,可以使用以下模板

  • [id]:Story ID
  • [title]:Story 的标题
  • [name]:Story 的名称

flakiness.metrics.enabled

类型: boolean
默认值: true

当指定为 true 时,它会监控与 Story 渲染相关的多个指标并执行稳定性检查。

[!警告]
由于此过程依赖于 CDP,因此它仅在 Chromium 浏览器中有效。如果在 Chromium 以外的浏览器中启用,则会显示警告。

flakiness.metrics.retries

类型: number
默认值: 1000

指标监控期间的重试次数。它会持续监控指定数量的帧(1 帧 = 16 毫秒),并确保指标稳定。

flakiness.retake.enabled

类型: boolean
默认值: true

它计算屏幕截图图像的哈希值,并通过确保图像没有变化来检查渲染内容的稳定性。

[!提示]
在 Chromium 的情况下,仅使用 flakiness.metrics.enabled 通常就足够了。启用此选项意味着至少捕获两次屏幕截图,因此如果它导致性能下降,建议将其禁用。

flakiness.retake.interval

类型: number
默认值: 100

再次尝试捕获屏幕截图之前的毫秒间隔。第二次捕获立即执行以进行哈希检查。

flakiness.retake.retries

类型: number
默认值: 10

重复捕获屏幕截图直到图像的哈希值相同为止的次数。建议使用 3 或更大的值来达到重试的效果。

hooks

类型: ScreenshotHook[]
默认值: []

用于中断屏幕截图捕获前后的进程的 Hook。请指定一个实现以下接口的对象。

export type ScreenshotHook = {
  setup?: TestHook;
  preCapture?: TestHook;
  postCapture?: (
    page: Page,
    context: TestContext,
    image: ScreenshotImage,
  ) => Promise<void>;
};

每个 Hook 都在以下生命周期中执行

方法 描述
setup 在执行 screenshot 函数后立即执行
preCapture 在执行 waitForPageReady 后执行
postCapture 在捕获屏幕截图后,保存图像之前执行

蒙版和移除等内置函数是使用 Hook 实现的。

fullPage

类型: boolean
默认值: true

参见 Page | Playwright

omitBackground

类型: boolean
默认值: false

参见 Page | Playwright

scale

类型: 'css' | 'device'
默认值: 'device'

参见 Page | Playwright

参数

这些是可以在每个 Story 中指定的参数。

// Button.stories.tsx
const meta: Meta<typeof Button> = {
  component: Button,
  parameters: {
    screenshot: {
      /* parameters... */
    },
  },
};

export default meta;

skip

类型: boolean
默认值: false

跳过屏幕截图捕获。在您想使用 @storybook/test-runner 但禁用屏幕截图捕获的情况下很有用。

delay

类型: number
默认值:

捕获屏幕截图之前的毫秒延迟。在完成基本稳定性检查后等待。

mask

类型: string | { selector: string; color: string }
默认值:

使用矩形遮盖与 CSS 选择器对应的元素。用于隐藏在每次渲染时内容不可避免地不同的元素。

remove

类型: string
默认值:

移除与 CSS 选择器对应的元素。

更新日志

参见 CHANGELOG.md

许可证

MIT © reg-viz

reg-viz