Cypress使用教程

前置要求

安装Node.js

对应系统版本,下载并安装  Node.js (nodejs.org) 

更换Node.js源为国内镜像

查看当前源



npm config get registry



若源url为境外地址,更新为国内镜像



npm config set registry https://registry.npm.taobao.org/










安装Cypress

通过npm安装(Node.js的包管理工具)

1. 切换到项目根目录



cd /[项目根目录]



2. npm初始化

如果项目根目录下缺少 node_modules  文件夹或者  package.json  文件,需先执行npm初始化



npm init



3. 为该项目安装Cypress

 --save-dev 命令使Cypress作为dev dependency被安装,也可简写为 -D 



npm install cypress --save-dev



成功安装后项目根目录下会生成 node_modules 文件夹,并包含可执行文件 ./node_modules/.bin 

若遇到报错

The Cypress App could not be downloaded.

URL: https://download.cypress.io/desktop/10.1.0?platform=win32&arch=x64

Error: connect ETIMEDOUT 172.67.69.12:443

这个主要因为内网dhwifi网络做了屏蔽,则把网络切换为自己的移动wifi即可。

4. 权限设置

此步骤适用于VS Code,Powershell;若使用Git Bash终端或命令行(CommandLine),可跳过该步骤

查看当前命令终端权限



get-executionpolicy



如果显示为【限制】 Restricted ,则需要设置授权,执行



set-ExecutionPolicy RemoteSigned



之后再次查看权限,若显示为【远程签署】 RemoteSigned ,则表示授权成功








运行Cypress

启动命令

注意:若是对本地项目进行测试时,启动Cypress前需确保所在项目的网页APP已启动

方法1:完整命令



./node_modules/.bin/cypress open



方法2:快捷命令



$(npm bin)/cypress open



方法3:npx命令

注意:npx需要安装的npm版本 > 5.2



npx cypress open



安装Cypress执行文件

若启动命令时,遇到错误

 No version of Cypress is installed in: C:\..\Cypress\Cache\x.x.x\Cypress 

则需要手动安装Cypress执行文件



npx cypress install



而后,再使用启动命令



选择浏览器

成功启动Cypress后,会弹出Cypress的测试器窗口,如下。该测试器会自动识别该机器上与Cypress兼容的浏览器,并可通过右上角下拉式菜单选择。

测试器正下方【INTEGRATION TESTS】为测试示例,可以依次点击运行。



Cypress使用教程_第1张图片










编写测试

添加测试文件

1. 位置

测试文件需要添加在项目文件夹下的 /cypress/integration/ 文件夹中,可以通过新建文件夹归档。

2. 类型

测试文件为JavaScript类型,例 samepleTest.js 。添加文件后,可以注意到在Cypress测试器中对应测试 samepleTest.js 的增加。



Cypress使用教程_第2张图片



点击该测试查看细节(因为暂无测试用例,当前会显示找不到测试 No tests found. )。



Cypress使用教程_第3张图片



3. 简单的测试

在 samepleTest.js 中添加如下内容并保存,以查看Cypress如何展示测试是否成功



describe('成功的测试', () => {
    it('TRUE==TRUE', () => {
        expect(true).to.equal(true)
    })
})
describe('失败的测试', () => {
    it('TRUE!=FALSE', () => {
        expect(true).to.equal(false)
    })
})



4. 实时反馈

在打开Cypress的测试器时,可以更改测试文件,保存后的更改内容会实时反馈在测试器中,以便调试。



Cypress使用教程_第4张图片







测试构成

一般而言,测试由3个部分构成

1. Given

设定当前状态

2. When

执行某个操作

3. Then

断言状态变更



测试实例



describe('My First Test', () => {
    it('Gets, types and asserts', () => {
      // Given: 访问页面
      cy.visit('https://example.cypress.io')
      // When: 点击内容包含‘type’的元素
      cy.contains('type').click()
      // Then:获取URL,其中应包含‘/commands/actions’
      cy.url().should('include', '/commands/actions')
 
  
      // Given:找到class为‘action-email’的元素
      // When:输入‘[email protected]
      // Then:该元素的value应是‘[email protected]
      cy.get('.action-email')
        .type('[email protected]')
        .should('have.value', '[email protected]')
    })
})



注意:

(1)Cypress使用链式语法

(2)单个测试 describe('测试',()=>{}) 中可以包含多个测试用例 it('测试用例',()=>{}) ;单个测试用例中可以包含多个平行的或顺序的断言 xxx.should() 

(3)可以通过链式语句增加状态、动作和断言

(4)当步骤涉及到页面加载时,Cypress会等待加载完毕才会继续执行后续步骤








调试代码

Cypress提供了一系列的debugging工具,以帮助理解测试。

1. 时间旅行

在Cypress测试器中,将鼠标移动到测试用例中任意行命令并悬停,Cypress会回溯到该命令执行时的状态,在右侧界面显示当时的页面(注意截图中的URL为页面跳转前的地址),高亮并置顶相关DOM组件。



Cypress使用教程_第5张图片





2. 截图功能

在Cypress测试器中,单击任意行命令可以将其固定(以紫色高亮),这么做可以:



Cypress使用教程_第6张图片



2.1 固定截图

当命令被固定后,鼠标移动到其他命令上时,右侧界面不会再变化。这样可以手动查看截图时页面的DOM元素。

2.2 事件触发

因为 .click() 是一个动作命令,该命令被固定时,可以观察到右侧界面的 type 处有红点显示(代表此处有事件触发)

2.3 截图菜单

当被锁定的命令是动作命令时(如截图中的 .type() ),右侧界面下方会出现额外的截图菜单,通过选择 before 或 after 来查看该动作命令执行前后的页面区别。

注意:如果动作命令涉及到页面加载(非瞬时操作),取决于该页面的加载速度,会导致选择 after 后可能看不到变化,或者只显示页面加载时的空白。



Cypress使用教程_第7张图片





3. 报错信息

在测试中,当错误发生时,Cypress会提供以下信息:



Cypress使用教程_第8张图片



3.1 错误名称

显示错误的类型,如 CypressError , AssertionError 

3.2 错误信息

显示错误的具体信息。有时还会提供修复办法。

3.3 了解更多 Learn more 

如果有此选项,点击此项可以打开相关的Cypress文档页面

3.4 代码文件

显示报错代码所在文件名、行数、字数。点击此项可以使用默认编辑器打开该文件,并高亮报错行(高亮需要编辑器支持)。

3.5 代码框

显示报错代码及上下文,并高亮报错代码行。

3.6 查看堆栈轨迹 View stack trace 

打开或关闭改错误堆栈轨迹的开关。

3.7 打印到控制台 Print to console 

点击此项可以把完整错误信息打印到DevTools的控制台中。



4. 页面事件

在Cypress测试器的左侧界面中,注意到有以下这样的日志——它们并不属于代码中的任何命令。这是因为CYpress会自动记录下测试中的重要页面事件。





Cypress会记录的页面事件有:

  • 网络XHR的请求

  • URL hash的变更

  • 页面的加载

  • 表单的提交



5. 控制台输出

Cypress可以在控制台中提供额外的调试信息。

打开浏览器的Dev Tools F12 ,并点击左侧界面中的 GET class选择器命令行。



Cypress使用教程_第9张图片



可以看到Cypress提供的额外信息包括:

  •  Command :所触发的命令

  •  Yielded :命令返回的内容

  •  Elements :找到的元素数量

  •  Selector :所使用的参数

注意:若返回多个元素,可以在Dev Tools中展开以查看每个元素的信息。



6. 特殊命令

Cypess也提供了调试用的特殊命令,如 cy.pause() , cy.debug() 。

尝试在代码中加入 cy.pause() ,如下:



describe('My First Test', () => {
    it('Gets, types and asserts', () => {
      // Given: 访问页面
      cy.visit('https://example.cypress.io')
 
  
      // 调试:特殊命令
      cy.pause()
 
  
      // When: 点击内容包含‘type’的元素
      cy.contains('type').click()
      // Then:获取URL,其中应包含‘/commands/actions’
      cy.url().should('include', '/commands/actions')
 
  
      // Given:找到class为‘action-email’的元素
      // When:输入‘[email protected]
      // Then:该元素的value应是‘[email protected]
      cy.get('.action-email')
        .type('[email protected]')
        .should('have.value', '[email protected]')
    })
})



如此,在Cypress测试器中,我们可以仿照debugger,在暂停处使用下一步 step forward 的调试功能



Cypress使用教程_第10张图片










测试你的项目

第一步:启动你的服务器

注意:不要从Cypress脚本启动服务器。详情参考Cypress的最佳实践。



第二步:访问你的服务器

在测试文件夹 cypress/integration 下,新建你的测试脚本 xxx.js 



describe('应用首页', () => {
  it('加载成功', () => {
    cy.visit('http://localhost:8080') // URL替换为你的开发环境URL
  })
})



保存后在Cypress测试器中打开该测试 xxx.js 。若一切顺利,测试器中可以看到已访问对应URL的页面。



第三步:配置Cypress

考虑到每个测试都需要访问页面,Cypress提供了配置基础URL的方式:在配置文件中 cypress.json ,加上 baseUrl 的配置。



{
  "baseUrl": "http://localhost:8080"
}



如此,在测试中调用 cy.visit() 和 cy.request() 命令时,会自动使用配置URL作为前缀。

配置完成后,先前的 xxx.js 可以写成这样:



describe('应用首页', () => {
  it('加载成功', () => {
    cy.visit('/')
  })
})





测试策略

测试哪些方面,如何定义测试用例的边界值,如何做回归测试,等等,完全取决于你自己、你的应用和你的团队,请自由发挥。



种子数据

最常用的3个准备命令:

  •  cy.exec() :用以执行系统指令

  •  cy.task() :在Node中通过 pluginsFile 来执行命令

  •  cy.request() :发出HTTP请求

例如,如果机器上装有 node.js ,那么可以在 before 或者 beforeEach 钩子代码中执行 npm 任务。



describe('应用首页', () => {
  beforeEach(() => {
    // 重置数据库并使用种子数据
    cy.exec('npm run db:reset && npm run db:seed')
  })
  it('加载成功', () => {
    cy.visit('/')
  })
})





绕过服务器(Mock)

除了使用种子数据,Cypress也支持仿造返回的JSON,这与Mock相似。这么一来,不仅避免了数据从服务器到浏览器的同步等待时间,也避免了测试时的状态转变。这也意味着一个测试不会生成影响其他测试的状态。

此外,通过这种方法,可以完全无需后台服务器就建立一套完整的测试,并赋予想要准备的数据。

尽管如此,以上两种策略之间应该有个平衡点,需要自己去探索。

另一方面,使用Mock的话没办法保证仿造的数据与服务器的真实返回一致。幸运的是,Cypress提供了一些方法可以解决这个问题。

1. 基境数据

可以预先通过服务器生成的真实数据,并存为基境数据,用以Mock

2. E2E测试+Mock测试

这是一种更平衡的策略。可以先完成一个无Mock的端到端测试,再通过Mock去完成所有的边界测试和特殊情景测试。这样既保证了测试的真实性,同时也兼顾了测试用例的便捷性和完成速度。



登录测试

登录测试往往是你的应用里第一个(甚至是最难的之一)需要征服的测试。基于上一部分的两种策略,可以在Cypress中这样实现:

1. 完整的登录流程只测试一次

因为登录是最重要的功能之一,并且涉及到与服务器的交互,所以这里推荐使用UI交互的方式去测试。

以下是一段代码示例,包含了种子数据策略:



describe('登录页面', () => {
  beforeEach(() => {
    // 重置数据库并使用种子数据
    cy.exec('npm run db:reset && npm run db:seed')
    // 为接下来的测试创建一个种子账号
    // 假设它同时会生产一个随机密码
    cy.request('POST', '/test/seed/user', { username: 'jane.lane' })
      .its('body')
      .as('currentUser')
  })
  it('通过登录页面登录并设置权限cookie', function () {
    // 从this.currentUser中解构出username和password
    const { username, password } = this.currentUser
    cy.visit('/login')
    // 从name=username的输入框输入刚刚获得的username
    cy.get('input[name=username]').type(username)
    // 从name=password的输入框输入刚刚获得的password
    // {enter}模拟回车触发登录请求
    cy.get('input[name=password]').type(`${password}{enter}`)
    // 成功登录后,URL应当包含dashboard()
    cy.url().should('include', '/dashboard')
    // 权限cookie应当存在
    cy.getCookie('your-session-cookie').should('exist')
    // UI界面应当反映登录的用户名
    cy.get('h1').should('contain', 'jane.lane')
  })
})



类似的,完整的UI测试还可以覆盖如下:

  • 用户名/密码为空

  • 用户名/密码不正确

  • 注册时用户名已存在

  • 注册时密码强度不符合要求

  • 特殊情况如账号被锁/被删除



2. 其他相关的测试使用Mock

当需要继续进行其他依赖于登录状态的测试时,则推绕开UI登录的方法。Cypress提供了 cy.request() 指令,它可以自动获取和设置cookies。我们可以通过这个指令来构建和通过UI登录完全一致的登录状态,而不需要借助UI。

示例代码如下:



describe('Dashboard页面', () => {
  beforeEach(() => {
    // 重置数据库并使用种子数据
    cy.exec('npm run db:reset && npm run db:seed')
    // 创建一个种子账号
    // 假设它同时会生产一个随机密码
    cy.request('POST', '/test/seed/user', { username: 'jane.lane' })
      .its('body')
      .as('currentUser')
  })
  it('绕过UI,自动登录', function () {
    // 从this.currentUser中解构出username和password
    const { username, password } = this.currentUser
    // 通过POST请求自动登录,从而绕过UI
    cy.request('POST', '/login', {
      username,
      password,
    })
    // 现在已经是登录状态
    // 可以不受限制地访问任何页面了
    cy.visit('/dashboard')
    // 权限cookie应当存在
    cy.getCookie('your-session-cookie').should('exist')
    // UI界面应当反映登录的用户名
    cy.get('h1').should('contain', 'jane.lane')
  })
})



通过绕过UI的方法,对于后续的每个测试,我们都节约了大量的时间(加载登录页面,从UI输入用户名、密码再登录)。并且因为此前已经完整地测试过登录的流程,所以我们有十足的把握来用这一快捷方式。



一言以蔽之:

  • 当需要测试特定功能时,应当用完整的UI测试

  • 当需要准备某一状态(基境)且这个状态已经被完整测试过时,准备的过程可以通过绕过UI的方式来实现



开始你的测试

关于Cypress的介绍已经步入尾声。从现在起,开始为你的应用测试吧!








附录

Cypress官方文档

 Why Cypress? | Cypress Documentation 



ESLint插件

 GitHub - cypress-io/eslint-plugin-cypress: An ESLint plugin for projects that use Cypress

你可能感兴趣的:(功能测试)