cypress(三) 具体应用案例

181 阅读4分钟

1 前言

image.png

在我们启动cypress运行后,会看到有E2E (End-to-End) 测试和组件测试的选择,八青妹会在本文介绍下两者之间的区别,然后介绍下八青妹在项目中是如何使用的。

2. E2E测试与组件测试区别

  1. E2E 测试:

    • E2E 测试是独立于单个项目的,通常放在一个专门的 E2E 测试目录中。
    • E2E 测试是针对整个应用程序的端到端流程进行测试,模拟用户的真实使用场景。
    • E2E 测试需要启动整个应用程序环境,包括前端和后端。
    • E2E 测试更关注于应用程序的集成和工作流,测试粒度较粗。
    • E2E 测试通常在持续集成和部署管道中使用。
  2. 组件测试:

    • 组件测试是写在项目代码中的,通常放在与组件代码相邻的目录中。
    • 组件测试关注于单个 UI 组件的隔离测试,验证组件的行为和功能。
    • 组件测试只需要前端组件本身,不需要整个应用程序环境。
    • 组件测试的粒度较细,更关注于组件的单元行为。
    • 组件测试更容易维护,可以快速运行在开发阶段。

总的来说,E2E测试是独立于单个项目的,而组件测试则是写在项目代码中的。所以如果是测试一套流程,且该流程跨用户端和管理端,那就可以选择E2E测试,但是如果是一套项目中,每次开发完想及时测试组件的完成情况,就可以用组件测试。例如之前谈到的OHIF/Viewers项目,使用的就是组件测试。确定好测试目标和策略,确定好使用两种测试方式的比例。最终的目标就是在保证程序质量的同时,要提高测试的效率和可维护性。

八青妹所在的项目目录如下所示(E2E测试)。

├─ cypress     
    ├─ download		下载文件处,例如一些截图或者录屏文件
    ├─ e2e		测试用例编写处
    ├─ fixtures		静态文件文件夹
    ├─ mockdata		mock数据文件夹
        ├─ data.json    可放置所有生成的mock数据
    ├─ support		共用文件处理文件夹	
        ├─ commands.js   共用command配置处
        ├─ e2e.js   应用配置的js
├─ cypress.config.js    配置文件
├─ cypress.dev.json     开发环境的参数配置
├─ cypress.test.json    测试环境的参数配置
├─ package.json

3. 实际应用

3.1 场景介绍

用户端使用的是h5,管理端使用的是web。有三个项目运行环境,分别为开发、测试和生产。 假设我们这是一个商城的项目,用户通过h5进行下单,下完单后,要在管理单指定的单据列表页面查看该单据状态是否存在且正常。

3.2 环境配置

由于存在三个不同的环境,希望能像前端那样,通过在终端运行不同的指令访问对应的环境。

npm run dev//运行开发环境
npm run test//运行测试环境

首先,在项目的根目录中,创建两个文件cypress.dev.jsoncypress.test.json文件的内容即为两个环境区别的地方.

{//cypress.dev.json
    "env": {
        "h5Host": "https://dev.h5.com",
        "webHost": "https://dev.web.com",
        "user": "18866660001",
        "manager": "admin",
    }
}
{//cypress.test.json
    "env": {
        "h5Host": "https://test.h5.com",
        "webHost": "https://test.web.com",
        "user": "18766660001",
        "manager": "administrator",
    }
}

在cypress.config.js中增加如下设置

const { defineConfig } = require('cypress')
const fs = require('fs-extra')
const path = require('path')
function getConfigurationByFile(file) {
  const pathToConfigFile = path.resolve('.', 'cypress.' + `${file}.json`)
  return fs.readJson(pathToConfigFile)
}
module.exports = defineConfig({
  e2e: {
    setupNodeEvents(on, config) {
      // implement node event listeners here
      on('before:browser:launch', (browser = {}, launchOptions) => {
        if (browser.family === 'chromium' && browser.name !== 'electron') {
          // auto open devtools
          //   launchOptions.args.push('-devtools')
        }
        // whatever you return here becomes the launchOptions
        return launchOptions
      })
      const file = config.env.configFile || 'dev'

      return getConfigurationByFile(file)
    },

    watchForFileChange: false,
    experimentalOriginDependencies: true,
  },
  sourceType: 'module',
})

package.json中添加如下命令

  "scripts": {
    "dev": "cypress open --env configFile=dev",
    "test": "npm run data && cypress open --env configFile=test",
  }

通过上述三个地方的设置,在终端运行npm run dev或者npm run test的时候,就是执行对应的环境命令了 当需要读取特定环境的内容的时候,可以如下:

 cy.visit(Cypress.env('h5Host'))
 //https://dev.h5.com(npm run dev) 或者是https://test.h5.com(npm run test)

即为读取运行环境下在cypress.xxx.json里面设置的值。

3.3 常用的自定义命令如何封装

3.31 接口请求如何封装成自定义命令

登录的自定义组件在上一篇文章的案例中介绍过。还有常用的为api接口的请求、上传图片的自动化 先看下post接口请求如何封装。

   cy.postApi(
        '/h5/security/login',
        { loginName: 'administrator', password: '123456' },
        '登录web后台管理系统'
      )

期望是按照如上操作,将接口路径、入参、描述作为这个postApi这个自定义指令的参数。

common.js中需要增加如下设置:

Cypress.Commands.add(
  'postApi',
  (url, param, remark = '接口请求结果') => {
    //根据url前缀判断是h5接口还是web接口
    let tempUrl = url
    if (tempUrl.indexOf('-') > -1) tempUrl = tempUrl.replace(/-/g, '/')
    let currentOrigin = tempUrl.substring(
      tempUrl.indexOf('/') + 1,
      tempUrl.indexOf('/', tempUrl.indexOf('/') + 1)
    )
    //拼凑出当前环境对应的url前缀,例如这里Cypress.env('h5Host'),找到的就是https://dev.h5.com
    let currentHost = Cypress.env(currentOrigin + 'Host')

    let config = {
      url: currentHost + url,
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
      },
      body: JSON.stringify(param),
    }
    //发起请求
    cy.request(config).then((result) => {
    //根据返回结果去判断结果是成功还是失败
        if (result.body.result) cy.log(result.body, remark + '成功!')
        else cy.log(result.body.message, remark + '失败!')
      }
    })
)

关于其他方式的接口请求的方法都可以按照上述的方式去封装。

3.32 上传图片的封装

图片上传的步骤可以分为以下几步:

  1. 选择本地文件,位于fixtures目录下,使用cy.fixture()命令拿到对应的图片文件
  2. 然后使用[Cypress.Blob.base64StringToBlob()](https://docs.cypress.io/api/utilities/blob)方法将图片转为blob格式
  3. 创建FormData对象用于上传入参
  4. 请求上传图片的接口

代码如下所示:

Cypress.Commands.add('uploadPicture', (url, params = {}) => {
  cy.fixture('picture.png').then((fileContent) => {
    // 转换为Blob对象
    const blob = Cypress.Blob.base64StringToBlob(fileContent, 'image/png')
    // 创建FormData对象
    const formData = new FormData()
    // 添加文件到FormData对象
    formData.append('file', blob, 'picture.png')
    //遍历params对象,将参数添加到formData中
    if (params) {
      for (let key in params) {
        formData.append(key, params[key])
      }
    }

    cy.postApi(url, formData, '上传图片')
  })
})

使用方法:

 cy.uploadPicture('/h5/saveFile')

该方式为接口的自动化调用,没有涉及到操作ui点击交互事件。

3.33 vant的confirm弹窗的封装

这里距离一个自定义的命令,封装内容为vant里面的picker选择器。如果在h5端使用了vant,那这个picker肯定大部分都用到了,是作为下拉选择的必不可少的组件。

vantpicker.png

期望的使用方法是,使用要定位的这个vantPicker的placeholder作为靶子进行点击。然后选择默认展示的值,点击确认按钮

 cy.vantPickerComfirm('请选择城市')

实现方式如下:

Cypress.Commands.add('vantPickerComfirm', (placeholder, value, eqIndex = 0) => {
  let isSkip = false // 当输入框内有值时是否跳过

  cy.get(`input[placeholder=${placeholder}]`)
    .eq(eqIndex)
    .then(($el) => {
      let val = $el.val()
      if (isSkip && (val || val === 0)) return // 已经有值的不再处理
      cy.wrap($el).click({ force: true })
      if (value) {
        // 选中对应的选项
        cy.get('.van-picker-column__wrapper')
          .children()
          .contains(value)
          .should('exist')
          .click()
      }

      cy.get('.van-popup')
        .find('.van-picker__confirm')
        .should('be.visible')
        .click({ multiple: true, force: true })
    })
})

4. 总结

关于cypress的文档八青妹就写到这里了。其他的运用就看自己所在的项目需要什么了,Cypress之前的一些特性(例如screenshot)playwright也支持。当你需要什么操作命令且不相信自己英文阅读能力的时候,可以翻阅上一篇文档cypress(二)命令与API速查文档