cypress测试本地web应用


Posted in Javascript onJune 01, 2022

cypress测试本地web应用

在之前的cypress介绍里曾提到过,cypress虽然也可以测试部署好的应用,但是它最大的能力还是发挥在测试本地应用上。
本章主要内容就是关于如何测试本地web应用的概述:

  • cypress与后台应用之间的关系。
  • 如何配置cypress使其适合我们的应用
  • 更好的绕过应用的身份验证机制

一、启动本地应用

在前面几章内容中,代码示例都是用的官方文档的网页进行测试的。那个环境相当于一个线上的生产环境,而且是cypress官方的,咱们除了正常访问
啥也做不了。启动本地应用就是启动你自己开发的web应用,比如我本地的测试平台的前端应用。

不过应该还会有小伙伴好奇,为什么就不能直接用线上已经部署好的,而非要用本地的?
这里,我概述一下官方的回答,以供参考:

  • 在日常的本地开发中,cypress是围绕着构建、优化的工具。
  • 数据存根。
  • 最重要的还是你要有控制这个应用的能力,比如,根据需要随时更改调整应用的一些配置之类。

不过,也不是说线上环境和本地环境,你必须二选一才行,也可以都写测试,这也是一个实用场景。比如,大多数的测试可以在本地环境跑,然后留一些
测试可以作为冒烟测试用,可以用到部署好的环境上去。

二、访问本地应用

之前演示用的代码用不上了,现在可以新建一个测试文件home_page_spec.js

describe('The Home Page', () => {
  it('successfully loads', () => {
    cy.visit('http://localhost:8010') // 这里换成你自己本地的url
  })
})

访问成功。

cypress测试本地web应用

三、配置Cypress

在Cypress项目中,其实有个配置文件cypress.json,就在项目根目录下,内容默认为空{}
在这里可以根据需要来添加cypress的各种配置,比如说 测试文件的位置、默认超时时间、环境变量、用哪个报告等等,这里暂时不展开了。

不过现在,可以在这里加一个baseUrl的配置,因为后续访问的路径都是以这个url为基础的。这样就可以给cys.visit()cys .request()这种命令
自动添加baseUrl前缀了。

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

现在访问一个相对路径试下:

describe('The Home Page', () => {
  it('successfully loads', () => {
    cy.visit('/')
  })
})

访问成功。

cypress测试本地web应用

到这里,就可以开始写你本地应用的测试了,至于怎么写,就还是取决不同的项目需求了。

四、Seeding data

这里我理解为初始化数据,比如要测试一个页面的登录,可能就得向数据库里插入一个用户数据,方便使用。在之前用selenium的时候,
通常就在setup 和 teardown里来安排初始化测试数据的准备和清理。

在cypress中,也会有一些支持做这些额外拓展的事情的方法,通常是这3种:

cy.exec(),可以执行系统命令。

cy.task(),可以通过pluginsFile来在node中运行代码。

cy.request(),可以发送http请求。

比如下面这段代码,演示的就是在测试执行之前,要做一系列事情来完成数据的初始化:

describe('The Home Page', () => {
  beforeEach(() => {
    // reset and seed the database prior to every test
    cy.exec('npm run db:reset && npm run db:seed')
    // seed a post in the DB that we control from our tests
    cy.request('POST', '/test/seed/post', {
      title: 'First Post',
      authorId: 1,
      body: '...',
    })
    // seed a user in the DB that we can control from our tests
    cy.request('POST', '/test/seed/user', { name: 'Jane' })
      .its('body')
      .as('currentUser')
  })
  it('successfully loads', () => {
    // this.currentUser will now point to the response
    // body of the cy.request() that we could use
    // to log in or work with in some way
    cy.visit('/')
  })
})

这种用法其实本质上来说没什么错的,但实际上每个测试都要与服务器或者浏览器交互的,这难免会拖慢测试的效率。对于这个问题,cypress
提供了些更快更好的解决方案。

1. Stubbing the server

这里就是我理解的mock了,断开与后端服务的依赖。既然我需要跟服务器交互才可以拿到需要的返回数据,如果能绕开交互,直接需要用啥数据就有啥数据,连后端应用都
不需要启了,岂不美哉?关于stub内容很多,后续使用到再继续分解。

2. 解决登录问题

在以往编写测试的过程中,登录一直是一个比较大的问题。你只有登录了,才可以进行后续的测试活动。那么如果我们把登录抽离出去,然后每个测试执行之前都进行一次登录操作,
理论上来讲,也是可行的。

describe('The Login Page', () => {
  beforeEach(() => {
    // reset and seed the database prior to every test
    cy.exec('npm run db:reset && npm run db:seed')
    // seed a user in the DB that we can control from our tests
    // assuming it generates a random password for us
    cy.request('POST', '/test/seed/user', { username: 'jane.lane' })
      .its('body')
      .as('currentUser')
  })
  it('sets auth cookie when logging in via form submission', function () {
    // destructuring assignment of the this.currentUser object
    const { username, password } = this.currentUser
    cy.visit('/login')
    cy.get('input[name=username]').type(username)
    // {enter} causes the form to submit
    cy.get('input[name=password]').type(`${password}{enter}`)
    // we should be redirected to /dashboard
    cy.url().should('include', '/dashboard')
    // our auth cookie should be present
    cy.getCookie('your-session-cookie').should('exist')
    // UI should reflect this user being logged in
    cy.get('h1').should('contain', 'jane.lane')
  })
})

只不过这样整个测试下来就变得非常的慢。所以,cypress呼吁不要在每次测试前使用UI登录。

当然了,你正儿八经写的测试代码里肯定是测试UI的,但是如果这个测试涉及到其他前置的一些数据状态的依赖,那么要避免通过UI去设置。
这里官方还举了个购物车的例子加以说明。

假设要测试购物车的功能。要进行测试的话,得把产品添加到购物车中。那么产品从哪里来? 我是否要使用UI登录到管理后台,然后创建所有的产品,包括它们的描述、类别和图片?
如果这样做了,那是不是所有的产品我都要访问一遍并且加到购物车里呢?

答案显然是否定的,至于怎样做最合适,还得到后续的学习中再分享。

继续回到上面UI登录的问题,因为cypress与selenium不同,在cypress中,可以通过使用cy.request()来跳过使用UI的需要,cy.request()可以自动获取和设置cookie,完成登录态的设置。那么上述的用UI执行登录的代码就可以优化成:

describe('The Dashboard Page', () => {
  beforeEach(() => {
    // reset and seed the database prior to every test
    cy.exec('npm run db:reset && npm run db:seed')
    // seed a user in the DB that we can control from our tests
    // assuming it generates a random password for us
    cy.request('POST', '/test/seed/user', { username: 'jane.lane' })
      .its('body')
      .as('currentUser')
  })
  it('logs in programmatically without using the UI', function () {
    // destructuring assignment of the this.currentUser object
    const { username, password } = this.currentUser
    // programmatically log us in without needing the UI
    cy.request('POST', '/login', {
      username,
      password,
    })
    // now that we're logged in, we can visit
    // any kind of restricted route!
    cy.visit('/dashboard')
    // our auth cookie should be present
    cy.getCookie('your-session-cookie').should('exist')
    // UI should reflect this user being logged in
    cy.get('h1').should('contain', 'jane.lane')
  })
})

在官方看来,这个相比于selenium是一个大优点,其实我觉得也不尽然。这个优化思想是对的,不过在之前使用selenium的时候,虽然它内置的方法不支持这么做,但是可以借助
requests库来迂回解决直接像后端发送请求的问题。

以上就是cypress测试本地web应用的详细内容,更多关于cypress测试web的资料请关注三水点靠木其它相关文章!


Tags in this post...

Javascript 相关文章推荐
Js获取数组最大和最小值示例代码
Oct 29 Javascript
含有CKEditor的表单如何提交
Jan 09 Javascript
jquery form 加载数据示例
Apr 21 Javascript
js实现获取div坐标的方法
Nov 16 Javascript
jQuery基于cookie实现的购物车实例分析
Dec 24 Javascript
vue.js中引入vuex储存接口数据及调用的详细流程
Dec 14 Javascript
vue v-model动态生成详解
Jun 30 Javascript
js运算符的一些特殊用法
Jul 29 Javascript
Vue在页面数据渲染完成之后的调用方法
Sep 11 Javascript
JavaScript数据结构与算法之二叉树插入节点、生成二叉树示例
Feb 21 Javascript
JS开发自己的类库实例分析
Aug 28 Javascript
JavaScript控制台的更多功能
Apr 28 Javascript
vue实现登陆页面开发实践
May 30 #Vue.js
Echarts如何重新渲染实例详解
May 30 #Javascript
vue router 动态路由清除方式
May 25 #Vue.js
vue如何清除浏览器历史栈
May 25 #Vue.js
ant design charts 获取后端接口数据展示
May 25 #Javascript
vue3不同环境下实现配置代理
May 25 #Vue.js
Typescript类型系统FLOW静态检查基本规范
You might like
简单PHP上传图片、删除图片实现代码
2010/05/12 PHP
PHP设计模式 注册表模式
2012/02/05 PHP
PHP5权威编程阅读学习笔记 附电子书下载
2012/07/05 PHP
PHP环形链表实现方法示例
2017/09/15 PHP
extJs 常用到的增,删,改,查操作代码
2009/12/28 Javascript
jQuery动画效果animate和scrollTop结合使用实例
2014/04/02 Javascript
jquery获取选中的文本和值的方法
2014/07/08 Javascript
JavaScript中双叹号!!作用示例介绍
2014/09/21 Javascript
ECMAScript6新增值比较函数Object.is
2015/06/12 Javascript
用Move.js配合创建CSS3动画的入门指引
2015/07/22 Javascript
jQuery实现左侧导航模块的显示与隐藏效果
2016/07/04 Javascript
JQuery异步提交表单与文件上传功能示例
2017/01/12 Javascript
详解基于angular路由的requireJs按需加载js
2017/01/20 Javascript
AngularJS+bootstrap实现动态选择商品功能示例
2017/05/17 Javascript
详解JavaScript数组过滤相同元素的5种方法
2017/05/23 Javascript
vue中用H5实现文件上传的方法实例代码
2017/05/27 Javascript
微信小程序 转发功能的实现
2017/08/04 Javascript
Node层模拟实现multipart表单的文件上传示例
2018/01/02 Javascript
详解vantUI框架在vue项目中的应用踩坑
2018/12/06 Javascript
JavaScript常见鼠标事件与用法分析
2019/01/03 Javascript
javascript刷新父页面方法汇总详解
2019/10/10 Javascript
如何使用gpu.js改善JavaScript的性能
2020/12/01 Javascript
[48:26]VGJ.S vs infamous Supermajor 败者组 BO3 第二场 6.4
2018/06/05 DOTA
python代码制作configure文件示例
2014/07/28 Python
Python中死锁的形成示例及死锁情况的防止
2016/06/14 Python
Python3实现发送QQ邮件功能(html)
2017/12/15 Python
Python+OpenCV人脸检测原理及示例详解
2020/10/19 Python
python中实现数组和列表读取一列的方法
2018/04/03 Python
修复 Django migration 时遇到的问题解决
2018/06/14 Python
Python 必须了解的5种高级特征
2020/09/10 Python
难忘的一天教学反思
2014/04/30 职场文书
说明书范文
2014/05/07 职场文书
民族团结好少年事迹材料
2014/08/19 职场文书
营销总经理岗位职责范本
2014/09/02 职场文书
党员三严三实对照检查材料
2014/10/13 职场文书
小学语文教学反思范文
2016/03/03 职场文书