之前我曾经在《Rize - 一个可以让你简单、优雅地使用 puppeteer 的 Node.js 库》一文简单介绍过 Rize 这个库。当时仅仅是介绍这个库本身,关于如何使用,我没有给太多的指导。

这篇文章讲的是如何使用 Rize 来做 UI 测试或 E2E 测试。

在正式开始之前,先给可能没了解过 Rize 的同学做个简单的介绍:Rize 是一个提供了相对顶层并且可链式调用的 API 的库,可与 puppeteer 一起使用。目前开源在 GitHub,地址是 https://github.com/g-plane/rize,欢迎大家前往 GitHub 给个 star。

安装

首先是安装 Rize 和 puppeteer。

如果您使用 Yarn:

  1. $ yarn add --dev rize puppeteer

如果您使用 npm:

  1. $ npm install --save-dev rize puppeteer

考虑到国内的网络原因,您可能需要使用国内的 Chromium 镜像:

对于 Linux 或 macOS 用户:

  1. PUPPETEER_DOWNLOAD_HOST=https://storage.googleapis.com.cnpmjs.org yarn add --dev puppeteer rize

Windows 用户:

  1. SET PUPPETEER_DOWNLOAD_HOST=https://storage.googleapis.com.cnpmjs.org yarn add --dev puppeteer rize

(npm 用户同理)

由于安装 puppeteer 的时候会下载 Chromium,所以整个过程可能比较费时,需要耐心等待。

约定

我们假定要被测试的页面是这样的:

  1. <html>
  2. <head>
  3. <title>标题</title>
  4. </head>
  5. <body>
  6. <div class="greeting">
  7. Hello World!
  8. </div>
  9. <a href="">Another Page</a>
  10. <button id="btn">Click Me</button>
  11. <input type="checkbox" name="cb1" checked />
  12. <input type="checkbox" name="cb2" />
  13. </body>
  14. </html>

开始编写测试

首先是导入。我们推荐使用 ES2015 的 import 语法:

  1. import Rize from 'rize'

当然您也可以用 CommonJS 方式:

  1. const Rize = require('rize')

第一件事是构造一个 Rize 实例:

  1. describe('UI test', () => {
  2. it('example test', async () => {
  3. const rize = new Rize()
  4. })
  5. })

然后要转到要被测试的页面。我们假定前面设定的页面运行在 http://localhost:8000/ 上,那么我们可以:

  1. describe('UI test', () => {
  2. it('example test', async () => {
  3. const rize = new Rize()
  4. rize
  5. .goto('http://localhost:8000/')
  6. })
  7. })

断言

断言页面标题

我们可以使用 assertTitle 方法来断言当前页面的标题:

  1. describe('UI test', () => {
  2. it('example test', async () => {
  3. const rize = new Rize()
  4. rize
  5. .goto('http://localhost:8000/')
  6. .assertTitle('标题')
  7. })
  8. })

断言文本内容

可以使用 assertTitle 方法来断言当前页面存在指定的文本:

  1. describe('UI test', () => {
  2. it('example test', async () => {
  3. const rize = new Rize()
  4. rize
  5. .goto('http://localhost:8000/')
  6. .assertTitle('标题')
  7. .assertSee('Hello World!')
  8. })
  9. })

我们还可以明确在某个元素中存在指定文本,只需给出该元素的 CSS 选择器即可:

  1. describe('UI test', () => {
  2. it('example test', async () => {
  3. const rize = new Rize()
  4. rize
  5. .goto('http://localhost:8000/')
  6. .assertTitle('标题')
  7. .assertSee('Hello World!')
  8. .assertSeeIn('.greeting', 'Hello World!')
  9. })
  10. })

断言是否存在指定的类名

我们可以断言某个元素存在指定的类名:

  1. describe('UI test', () => {
  2. it('example test', async () => {
  3. const rize = new Rize()
  4. rize
  5. .goto('http://localhost:8000/')
  6. .assertTitle('标题')
  7. .assertSee('Hello World!')
  8. .assertSeeIn('.greeting', 'Hello World!')
  9. .assertClassHas('div', 'greeting')
  10. })
  11. })

还可以断言不存在指定的类名:

  1. describe('UI test', () => {
  2. it('example test', async () => {
  3. const rize = new Rize()
  4. rize
  5. .goto('http://localhost:8000/')
  6. .assertTitle('标题')
  7. .assertSee('Hello World!')
  8. .assertSeeIn('.greeting', 'Hello World!')
  9. .assertClassHas('div', 'greeting')
  10. .assertClassMissing('div', 'greet')
  11. })
  12. })

断言表单状态

我们可以断言一些表单控件的状态,例如复选框(checkbox)选中或未选中:

  1. describe('UI test', () => {
  2. it('example test', async () => {
  3. const rize = new Rize()
  4. rize
  5. .goto('http://localhost:8000/')
  6. .assertTitle('标题')
  7. .assertSee('Hello World!')
  8. .assertSeeIn('.greeting', 'Hello World!')
  9. .assertClassHas('div', 'greeting')
  10. .assertClassMissing('div', 'greet')
  11. .assertChecked('[name="cb1"]') // 断言已选中
  12. .assertNotChecked('[name="cb2"]') // 断言未选中
  13. })
  14. })

与页面交互

在实际测试的过程中,我们不仅仅需要进行一些断言,还需要与页面进行交互。

例如,我们以上面的页面为例,我们可以单击那个按钮:

  1. describe('UI test', () => {
  2. it('example test', async () => {
  3. const rize = new Rize()
  4. rize
  5. .goto('http://localhost:8000/')
  6. .assertTitle('标题')
  7. .assertSee('Hello World!')
  8. .assertSeeIn('.greeting', 'Hello World!')
  9. .assertClassHas('div', 'greeting')
  10. .assertClassMissing('div', 'greet')
  11. .assertChecked('[name="cb1"]') // 断言已选中
  12. .assertNotChecked('[name="cb2"]') // 断言未选中
  13. .click('#btn')
  14. })
  15. })

也可以单击某个链接,我们只需要给出该链接上的文本:

  1. describe('UI test', () => {
  2. it('example test', async () => {
  3. const rize = new Rize()
  4. rize
  5. .goto('http://localhost:8000/')
  6. .assertTitle('标题')
  7. .assertSee('Hello World!')
  8. .assertSeeIn('.greeting', 'Hello World!')
  9. .assertClassHas('div', 'greeting')
  10. .assertClassMissing('div', 'greet')
  11. .assertChecked('[name="cb1"]') // 断言已选中
  12. .assertNotChecked('[name="cb2"]') // 断言未选中
  13. .click('#btn')
  14. .clickLink('Another Page')
  15. })
  16. })

当然,我们还能与表单进行交互。例如,勾选某个复选框:

  1. describe('UI test', () => {
  2. it('example test', async () => {
  3. const rize = new Rize()
  4. rize
  5. .goto('http://localhost:8000/')
  6. .assertTitle('标题')
  7. .assertSee('Hello World!')
  8. .assertSeeIn('.greeting', 'Hello World!')
  9. .assertClassHas('div', 'greeting')
  10. .assertClassMissing('div', 'greet')
  11. .assertChecked('[name="cb1"]') // 断言已选中
  12. .assertNotChecked('[name="cb2"]') // 断言未选中
  13. .click('#btn')
  14. .clickLink('Another Page')
  15. .check('[name="cb2"]')
  16. })
  17. })

或者取消勾选某个复选框:

  1. describe('UI test', () => {
  2. it('example test', async () => {
  3. const rize = new Rize()
  4. rize
  5. .goto('http://localhost:8000/')
  6. .assertTitle('标题')
  7. .assertSee('Hello World!')
  8. .assertSeeIn('.greeting', 'Hello World!')
  9. .assertClassHas('div', 'greeting')
  10. .assertClassMissing('div', 'greet')
  11. .assertChecked('[name="cb1"]') // 断言已选中
  12. .assertNotChecked('[name="cb2"]') // 断言未选中
  13. .click('#btn')
  14. .clickLink('Another Page')
  15. .check('[name="cb2"]')
  16. .uncheck('[name="cb1"]')
  17. })
  18. })

关闭浏览器

在完成所有工作之后,需要退出浏览器:

  1. describe('UI test', () => {
  2. it('example test', async () => {
  3. const rize = new Rize()
  4. rize
  5. .goto('http://localhost:8000/')
  6. .assertTitle('标题')
  7. .assertSee('Hello World!')
  8. .assertSeeIn('.greeting', 'Hello World!')
  9. .assertClassHas('div', 'greeting')
  10. .assertClassMissing('div', 'greet')
  11. .assertChecked('[name="cb1"]') // 断言已选中
  12. .assertNotChecked('[name="cb2"]') // 断言未选中
  13. .click('#btn')
  14. .clickLink('Another Page')
  15. .check('[name="cb2"]')
  16. .uncheck('[name="cb1"]')
  17. await rize.end()
  18. })
  19. })

更多

实际上 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

利用 Rize 来进行 UI 测试或 E2E 测试的更多相关文章

  1. e2e测试框架之Cypress

    谈起web自动化测试,大家首先想到的是Selenium!随着近几年前端技术的发展,出现了不少前端测试框架,这些测试框架大多并不依赖于Selenium,这一点跟后端测试框架有很大不同,如Robot Fr ...

  2. UT, FT ,E2E 测试的意思

    前端实现自动化就要借助到unit和e2e端到端测试了 一.unit测试(FT 就是Fucntion Test 功能测试,  注意不是: funciton函数 ...fucntion功能   不一样哦  ...

  3. e2e 测试(1)

    距离上一随笔,已经有一个月没有没写.到今天,刚刚好好,是学习e2e测试的一个月.今天有点时间可以总结一下这个月来的收获. 1.搭建e2e的测试环境 我是使用 Vue 构建项目,所以我也是通过Vue-c ...

  4. angularjs e2e测试初步学习(一)

    e2e测试是从用户角度出发,认为整个系统都是一个黑盒,只有UI暴露出来. angularjs的测试框架是采用protractor. 1.创建文件 首先创建一个项目文件夹test,然后再创建两个文件,一 ...

  5. Webpack单元测试,e2e测试

    此篇文章是续 webpack多入口文件.热更新等体验,主要说明单元测试与e2e测试的基本配置以及相关应用. 一.单元测试 实现单元测试框架的搭建.es6语法的应用.以及测试覆盖率的引入. 1. 需要安 ...

  6. 使用Angular CLI进行单元测试和E2E测试

    第一篇文章是: "使用angular cli生成angular5项目" : http://www.cnblogs.com/cgzl/p/8594571.html 第二篇文章是: & ...

  7. UI测试和GUI测试的区别

    UI 测试 包含GUI测试和command line 测试 分享连接 https://www.ranorex.com/resources/testing-wiki/gui-testing/

  8. E2E测试框架

    1. 目前E2E测试工具有哪些? 项目 Web Star puppeteer Chromium (~170Mb Mac, ~282Mb Linux, ~280Mb Win) 41427 nightma ...

  9. e2e 测试 出现的错误

    每次开始学习vue的新知识时,总在环境这一块出现很多坑.这次我来记录一下,我在搭建vue e2e测试框架是踏过的坑吧. 我们都只知道,使用vue init webpack 项目名字<项目名字不能 ...

随机推荐

  1. Linux基础篇八:VIM

    新知识: 普通模式光标跳转: G     ##光标跳转到末端  (shift +g) gg   ##光标跳转到开端 Ngg 15gg  ##光标跳转到当前文本中的15行 $     ##光标移动到当前 ...

  2. Super Mario HDU - 4417 (主席树询问区间比k小的个数)

    Mario is world-famous plumber. His “burly” figure and amazing jumping ability reminded in our memory ...

  3. An internal error occurred during: "Redeploy".

    原因:项目中JDK使用的版本与现在使用的JDK版本不同所致. 解决方法:右键选择项目>properties>java Build Path>Libraries 查看下面的JRE Sy ...

  4. DAG Optimal Coin Change

    题目描述 In a 10-dollar shop, everything is worthy 10 dollars or less. In order to serve customers more ...

  5. Ubuntu navicat 连接mysql:access denied for user 'root'@'localhost'

    真是醉了,Ubuntu装了navicat后,准备在桌面建立图标不成,结果直接打开后连接mysql都不行,真坑,奈何远程连接就成,这就尬了,今天终于解决了 问题 我也百度了好几个方案,奈何解决不了,最后 ...

  6. ISIS

    R1到R6配置ip和环回口 交换机不用配置 R6多加10.0.1.1 10.0.2.1 10.0.3.1 三个环回口 需求: 1.假如你是公司A网络管理员,公司A网络如图所示,现公司A要求如下:() ...

  7. iOS炫酷动画图案、多种选择器、网络测速、滑动卡片效果等源码

    iOS精选源码 对网络进行测速 自实现大标题,配合原生骨架屏demo 简单方便的pickerVIew记录数据 LZPickerView 科技风绘制组件,简单快速"画"出炫酷图案 R ...

  8. Leetcode1_两数之和

    题目 给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那 两个 整数,并返回他们的数组下标. 你可以假设每种输入只会对应一个答案.但是,你不能重复利用这个数组中同 ...

  9. 吴裕雄 python 神经网络——TensorFlow 卷积神经网络水果图片识别

    #-*- coding:utf- -*- import time import keras import skimage import numpy as np import tensorflow as ...

  10. Python opencv PIL numpy base64互相转化

    PIL2numpy and numpy2PIL from PIL import Image import numpy image = Image.open('timg.jpeg')# image is ...