利用 Rize 来进行 UI 测试或 E2E 测试
之前我曾经在《Rize - 一个可以让你简单、优雅地使用 puppeteer 的 Node.js 库》一文简单介绍过 Rize 这个库。当时仅仅是介绍这个库本身,关于如何使用,我没有给太多的指导。
这篇文章讲的是如何使用 Rize 来做 UI 测试或 E2E 测试。
在正式开始之前,先给可能没了解过 Rize 的同学做个简单的介绍:Rize 是一个提供了相对顶层并且可链式调用的 API 的库,可与 puppeteer 一起使用。目前开源在 GitHub,地址是 https://github.com/g-plane/rize,欢迎大家前往 GitHub 给个 star。
安装
首先是安装 Rize 和 puppeteer。
如果您使用 Yarn:
$ yarn add --dev rize puppeteer
如果您使用 npm:
$ npm install --save-dev rize puppeteer
考虑到国内的网络原因,您可能需要使用国内的 Chromium 镜像:
对于 Linux 或 macOS 用户:
PUPPETEER_DOWNLOAD_HOST=https://storage.googleapis.com.cnpmjs.org yarn add --dev puppeteer rize
Windows 用户:
SET PUPPETEER_DOWNLOAD_HOST=https://storage.googleapis.com.cnpmjs.org yarn add --dev puppeteer rize
(npm 用户同理)
由于安装 puppeteer 的时候会下载 Chromium,所以整个过程可能比较费时,需要耐心等待。
约定
我们假定要被测试的页面是这样的:
<html> <head> <title>标题</title> </head> <body> <div class="greeting"> Hello World! </div> <a href="">Another Page</a> <button id="btn">Click Me</button> <input type="checkbox" name="cb1" checked /> <input type="checkbox" name="cb2" /> </body> </html>
开始编写测试
首先是导入。我们推荐使用 ES2015 的 import 语法:
import Rize from 'rize'
当然您也可以用 CommonJS 方式:
const Rize = require('rize')
第一件事是构造一个 Rize 实例:
describe('UI test', () => { it('example test', async () => { const rize = new Rize() }) })
然后要转到要被测试的页面。我们假定前面设定的页面运行在 http://localhost:8000/ 上,那么我们可以:
describe('UI test', () => { it('example test', async () => { const rize = new Rize() rize .goto('http://localhost:8000/') }) })
断言
断言页面标题
我们可以使用 assertTitle
方法来断言当前页面的标题:
describe('UI test', () => { it('example test', async () => { const rize = new Rize() rize .goto('http://localhost:8000/') .assertTitle('标题') }) })
断言文本内容
可以使用 assertTitle
方法来断言当前页面存在指定的文本:
describe('UI test', () => { it('example test', async () => { const rize = new Rize() rize .goto('http://localhost:8000/') .assertTitle('标题') .assertSee('Hello World!') }) })
我们还可以明确在某个元素中存在指定文本,只需给出该元素的 CSS 选择器即可:
describe('UI test', () => { it('example test', async () => { const rize = new Rize() rize .goto('http://localhost:8000/') .assertTitle('标题') .assertSee('Hello World!') .assertSeeIn('.greeting', 'Hello World!') }) })
断言是否存在指定的类名
我们可以断言某个元素存在指定的类名:
describe('UI test', () => { it('example test', async () => { const rize = new Rize() rize .goto('http://localhost:8000/') .assertTitle('标题') .assertSee('Hello World!') .assertSeeIn('.greeting', 'Hello World!') .assertClassHas('div', 'greeting') }) })
还可以断言不存在指定的类名:
describe('UI test', () => { it('example test', async () => { const rize = new Rize() rize .goto('http://localhost:8000/') .assertTitle('标题') .assertSee('Hello World!') .assertSeeIn('.greeting', 'Hello World!') .assertClassHas('div', 'greeting') .assertClassMissing('div', 'greet') }) })
断言表单状态
我们可以断言一些表单控件的状态,例如复选框(checkbox)选中或未选中:
describe('UI test', () => { it('example test', async () => { const rize = new Rize() rize .goto('http://localhost:8000/') .assertTitle('标题') .assertSee('Hello World!') .assertSeeIn('.greeting', 'Hello World!') .assertClassHas('div', 'greeting') .assertClassMissing('div', 'greet') .assertChecked('[name="cb1"]') // 断言已选中 .assertNotChecked('[name="cb2"]') // 断言未选中 }) })
与页面交互
在实际测试的过程中,我们不仅仅需要进行一些断言,还需要与页面进行交互。
例如,我们以上面的页面为例,我们可以单击那个按钮:
describe('UI test', () => { it('example test', async () => { const rize = new Rize() rize .goto('http://localhost:8000/') .assertTitle('标题') .assertSee('Hello World!') .assertSeeIn('.greeting', 'Hello World!') .assertClassHas('div', 'greeting') .assertClassMissing('div', 'greet') .assertChecked('[name="cb1"]') // 断言已选中 .assertNotChecked('[name="cb2"]') // 断言未选中 .click('#btn') }) })
也可以单击某个链接,我们只需要给出该链接上的文本:
describe('UI test', () => { it('example test', async () => { const rize = new Rize() rize .goto('http://localhost:8000/') .assertTitle('标题') .assertSee('Hello World!') .assertSeeIn('.greeting', 'Hello World!') .assertClassHas('div', 'greeting') .assertClassMissing('div', 'greet') .assertChecked('[name="cb1"]') // 断言已选中 .assertNotChecked('[name="cb2"]') // 断言未选中 .click('#btn') .clickLink('Another Page') }) })
当然,我们还能与表单进行交互。例如,勾选某个复选框:
describe('UI test', () => { it('example test', async () => { const rize = new Rize() rize .goto('http://localhost:8000/') .assertTitle('标题') .assertSee('Hello World!') .assertSeeIn('.greeting', 'Hello World!') .assertClassHas('div', 'greeting') .assertClassMissing('div', 'greet') .assertChecked('[name="cb1"]') // 断言已选中 .assertNotChecked('[name="cb2"]') // 断言未选中 .click('#btn') .clickLink('Another Page') .check('[name="cb2"]') }) })
或者取消勾选某个复选框:
describe('UI test', () => { it('example test', async () => { const rize = new Rize() rize .goto('http://localhost:8000/') .assertTitle('标题') .assertSee('Hello World!') .assertSeeIn('.greeting', 'Hello World!') .assertClassHas('div', 'greeting') .assertClassMissing('div', 'greet') .assertChecked('[name="cb1"]') // 断言已选中 .assertNotChecked('[name="cb2"]') // 断言未选中 .click('#btn') .clickLink('Another Page') .check('[name="cb2"]') .uncheck('[name="cb1"]') }) })
关闭浏览器
在完成所有工作之后,需要退出浏览器:
describe('UI test', () => { it('example test', async () => { const rize = new Rize() rize .goto('http://localhost:8000/') .assertTitle('标题') .assertSee('Hello World!') .assertSeeIn('.greeting', 'Hello World!') .assertClassHas('div', 'greeting') .assertClassMissing('div', 'greet') .assertChecked('[name="cb1"]') // 断言已选中 .assertNotChecked('[name="cb2"]') // 断言未选中 .click('#btn') .clickLink('Another Page') .check('[name="cb2"]') .uncheck('[name="cb1"]') await rize.end() }) })
更多
实际上 Rize 的功能远不只上面那些。想要获取更多信息,可以前往以下页面:
Rize 的 GitHub 仓库:https://github.com/g-plane/rize (欢迎 star)
Rize 的文档教程:https://rize.js.org/
Rize 所有的 API 参考:https://rize.js.org/api/classes/_index_.rize.html