翻译:使用 Cypress 测试 HTML canvas

2,604 阅读5分钟

原文:Testing an HTML canvas with Cypress

如何测试 HTML canvas? 让我们看看一个用 Cypress 做视觉回归测试的例子。

image.png

什么是 canvas?

HTML canvas 是一个能用 JavaScript 在页面画图的元素。考虑如下例子:

image.png

我们用 HTML <canvas> 画这个矩形。HTML canvas 用途广泛,从 HTML 游戏到图表。一个流行的 JavaScript 表格库,Chart.js 用 canvas 绘制精美的图表。

Canvas 的确很好,但是由于它们的特性、有些难以测试。在这个快速指南中让我看看如何测试 canvas。

设置项目

以创建一个新目录为开始并且进入该目录:

mkdir testing-canvas && cd $_

初始化新的 JavaScript 项目:

npm init -y

在项目目录里创建一个 index.html HTML 文档:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Testing a Canvas</title>
</head>
<body>
<div>
    <canvas width="400" height="400">
        Alternative text
    </canvas>
</div>
</body>
<script>
    const canvas = document.querySelector('canvas');
    const context = canvas.getContext('2d');
    context.fillStyle = 'yellow';
    context.fillRect(20, 20, 200, 200);
</script>
</html>

在项目目录里执行命令测试所有事都恰当:

npx serve

然后访问 http://localhost:5000, 你应该能看到:

image.png

现在让我讨论如何测试这样一个元素。

你是怎样测试 HTML canvas 的?

测试工具分为两大类:

  • 单元测试 框架。
  • 功能测试*(或端到端测试)框架。

单元测试框架的例子有 Mocha 或 Jest。功能测试的例子有 Cypress,或 Testcafe。

单元测试工具对测试 canvas 来说不是恰当的工具。我们需要真实的浏览器渲染 canvas,在单元测试中模拟 DOM 常常不切实际。

另一方面,功能测试工具不是严格意义上视觉测试。利用一个像 Cypress 的工具我们可以点击和选取页面上的元素,但是测试视觉呈现(样式、图表)不是这些工具所擅长的。

image.png 一个由 canvas 制作的 Chart.js 图表

有时功能测试工具也包含某种 视觉回归测试

视觉回归测试是一种发现一个测试和另一测试间差异的技术。

这个工具分类通常通过 拍摄基线用户界面 来工作,该基线被认为是正确实现的。然后用基线和每次后续的测试比较。

由于 canvas 是纯粹的视觉元素,并在用户访问页面的时候绘制,用支持视觉回归测试的测试工具渲染它们是有意义的

让我们付诸实践。

安装 Cypress 和安装 snapshot 插件

视觉回归测试的工具之一是 cypress-plugin-snapshots,它能容易的集成到 Cypress 里。

和 Cypress 一起安装该插件,执行:

npm i cypress cypress-plugin-snapshots js-base64@2.5.2 --save-dev

(为了使插件工作,这时写确切版本号 js-base64@2.5.2 是必要的)。

安装插件后配置 cypress.json 如下:

{
  "ignoreTestFiles": [
    "**/__snapshots__/*",
    "**/__image_snapshots__/*"
  ],
  "env": {
    "cypress-plugin-snapshots": {
      "imageConfig": {
        "threshold": 0.01
      }
    }
  }
}

这里我们告诉 Cypress 忽略快照文件,并以低阈值配置 ypress-plugin-snapshots

阈值是快照插件触发失败测试的视觉差异总量。配置失败将会导致即使错误的测试也能通过。

一旦完成了这部分,打开 cypress/plugins/index.js 并导入该插件:

const { initPlugin } = require("cypress-plugin-snapshots/plugin");

module.exports = (on, config) => {
  initPlugin(on, config);
  return config;
};

作为最后一步在 cypress/support/commands.js 里加载 cypress-plugin-snapshots 命令:

import "cypress-plugin-snapshots/commands";

方便起见,你可以在 package.json 配置运行 Cypress 的脚本:

  "scripts": {
    "e2e": "cypress open"
  },

如果一切就位以如下方式第一次运行 Cypress:

node_modules/.bin/cypress open

从现在器你将能执行测试如下:

npm run e2e

我们现在 准备好了测试 canvas 了

用 Cypress 测试 HTML canvas

第一个、朴素的测试

我们以创建一个新文件 cypress/integration/Canvas.spec.js 为开始:

describe("Some app", () => {
  it("should see a yellow canvas", () => {
    cy.visit("http://localhost:5000");
    cy.get("canvas");
  });
});

在这个测试中我们告诉 Cypress:访问 localhost 上的页面并查找 canvas。为了尝试这个测试在终端用如下命令启动页面:

npx serve

然后在另一个终端运行测试:

npm run e2e

你应该看到测试通过:

image.png

的确,它通过了。大部分 Cypress 命令,例如 .get() 也是 隐式断言。它意味着对 Cypress 来说所有事是好的,只要它在页面找到给定的元素。

但是,这里我们事实上没有测试任何事物。检查 canvas 存在不能告诉它的形状及颜色信息。

我们想要的是一个 视觉回归测试代替

一个视觉回归测试

为了一个用 cypress-plugin-snapshots 的适当的视觉测试我们可以生产页面快照:

describe("Some app", () => {
  it("should see a yellow canvas", () => {
    cy.visit("http://localhost:5000");
    cy.get("canvas");

    // 生成快照
    cy.get("body").toMatchImageSnapshot();
  });
});

这里我选择生成整个页面快照:

cy.get("body").toMatchImageSnapshot();

如果你对一个特定页面元素快照感兴趣你当然可以稍微调整选择。

再次提醒,为了保证视觉差异被正确发现务必在 cypress.json 中配置一个低阈值:

{
  "ignoreTestFiles": [
    "**/__snapshots__/*",
    "**/__image_snapshots__/*"
  ],
  "env": {
    "cypress-plugin-snapshots": {
      "imageConfig": {
        "threshold": 0.01
      }
    }
  }
}

为了尝试新测试在终端以如下方式启动页面:

npx serve

然后在另一个终端运行测试:

npm run e2e

你应该看到第一个测试通过:

image.png

这是怎么工作的?

当你第一次生产快照时,插件保存实际的图片到 cypress/integration/__image_snapshots__。在 后续运行中该快照将会和其他当前界面快照相比较,并且如果工具发现 任何不同则测试失败

实际上如果我们改变 canvas 颜色从黄色:

<!-- 省略 -->
<script>
    const canvas = document.querySelector('canvas');
    const context = canvas.getContext('2d');
    context.fillStyle = 'yellow';
    context.fillRect(20, 20, 200, 200);
</script>
</html>

红色

<!-- 省略 -->
<script>
    const canvas = document.querySelector('canvas');
    const context = canvas.getContext('2d');
    context.fillStyle = 'red';
    context.fillRect(20, 20, 200, 200);
</script>
</html>

快照不再匹配,则测试失败

image.png

注意 以图片快照的视觉回归测试与 Jest 快照测试 不同

视觉回归测试用真实的用户界面图片,而 Jest 快照测试用可序列化格式保存快照。

什么是你最喜欢的视觉回归测试工具?

感谢阅读!