cypress测试示例-首屏加载时间测试

本文介绍了如何使用Cypress框架精确测量页面首屏加载时间,通过hooks实现测试逻辑,保存数据并生成详细的报告,以评估和优化网页性能。
摘要由CSDN通过智能技术生成

Cypress是常见的UI测试框架之一,UI测试的场景不做赘述,本文旨在探索Cypress检测页面首屏加载时间的最佳实践,目的是为了检测页面首屏加载的性能。文章主要包含实现逻辑、数据保存和报告生成三部分。

API介绍

本文主要使用到了Cypress提供的hooks,包含before、after、beforeEach和afterEach,可理解为测试用例不同的生命周期,具体说明如下:

describe('Hooks', () => {
  before(() => {
    // runs once before all tests in the block
    // 在所有用例之前触发一次
  })

  after(() => {
    // runs once after all tests in the block
    // 在所有用例之后触发一次
  })

  beforeEach(() => {
    // runs before each test in the block
    // 在每个用例之前触发一次
  })

  afterEach(() => {
    // runs after each test in the block
    // 在每个用例之后触发一次
  })
})

实现逻辑

说到页面首屏加载时间,我们不难想到可以通过获取页面加载前后时间戳之差来计算,根据刚刚介绍的hooks函数,我们可利用before和after钩子实现简单逻辑,代码如下

let startTime;
const url = '';
describe('test fp', () => {
  before(() => {
    startTime = +new Date();
  })

  after(() => {
    const fp = +new Date() - startTime;
  })
  
  it(() => {
  	cy.visit(`${url}`);
  })
})

这段代码存在两个比较明显的问题

  1. 没有描述页面完成加载的标志,代码层面表现为cy.visit()没有给出断言,这样会导致计算出的首屏加载时间不准确。
  2. 只对页面的首屏加载时间进行一次计算,结果可能存在误差,需要完善为多次测试取均值。

针对以上两个问题,我们把用例进行调整,利用dom结构进行断言确认页面已完成加载;并增加一个for循环测试该用例,利用beforeEach和afterEach钩子完成首屏加载时间计算。代码如下,最终5次测试结果保存在fpArr数组中

const TEST_TIMES = 5;
let startTime;
let fpArr = [];
const url = '';
describe('test fp', () => {
  beforeEach(() => {
    startTime = +new Date();
  })

  afterEach(() => {
    fpArr.push(+new Date() - startTime);
  })
 
  for (let i = 0; i < TEST_TIMES; i++) {
    it((`加载页面`) => {
  	  cy.visit(`${url}`)
        .get('.app-container', { timeout: 10000 })
        .should('have.length', 1);
    });
  }
})

数据保存

为了完善用例,可将历史数据进行保存记录,便于后续数据提取对比。实现思路如下

定义cy.collectData命令,将数据序列化后以参数的形式传入,执行node collectData.js,完成数据写入,如下

Cypress.Commands.add('collectData', data => {
  // 将参数序列化
  const argv = ...
  cy.exec(`node collectData.js ${argv}`);
});

collectData.js主要是利用fs提供的文件读写能力完成数据写入,如下 。

// 将参数反序列化
const argv = ...
// 读取已有数据并合并数据
const filePath = path.join(process.cwd(), path.join('cypress/data', argv.dir));
const fileJSON = JSON.parse(fs.readFileSync(filePath).toString() || '[]');
fileJSON.push(argv);
// 写入
fs.writeFileSync(filePath, JSON.stringify(fileJSON, null, '  '));

接着便可通过cy.collectData收集首屏加载时间,具体用法如下。

cy.collectData({
  dir: 'fp.json',
  startTime,
  fp,
});

报告生成

对于测试用例而言,报告的可读性和可用性及其重要,好的测试报告可以帮开发者快速获取结果、定位问题。

在本文的场景中,首屏性能不能仅以是或否通过这种简单标准来衡量,还需要在报告中提供一份首屏加载时间数据便于查看分析,因此需要将测试数据层现在报告中。

使用mochawesome模块可以生成漂亮的HTML、JSON等格式的报告,mochawesome提供的addContext API可以将附加信息记录在mochawesome的报告中,使用方法如下

const addContext = require('mochawesome/addContext');
cy.once('test:after:run', test => {
  addContext({ test }, {
    title: '首屏时长',
    value: 234,
  });
});

可以将该方法封装为一个Cypress Command(如下),通过cy.addContext使用。

const addContext = require('mochawesome/addContext');

Cypress.Commands.add('addContext', (context) => {
  cy.once('test:after:run', test => {
    addContext({ test }, context);
  });
});

使用addContext记录的数据,最终会层现在生成的报告(以JSON报告为例)中。 如下,context字段记录着我们通过addContext增加的信息。

[mochawesome_0001.json] 

image.png

然而addContext有一个局限性,即mochawesome没有将该字段数据层现在可视化报告中,因此可读性较差。笔者摸索了一种方式在可视化报告中打印这部分信息。

基于mochawesome模块的源码,在mochawesome/src/mochawesome.js中,增加consoleContext逻辑。以4.1.0版本为例,在runner的end事件回调中增加consoleContext(suites),如下

function Mochawesome(runner, options) {
  ...
  runner.on('end', () => {
    try {
      const suites = this.runner.suite.suites;
      consoleContext(suites);
      ...
    } catch (e) {
      // required because thrown errors are not handled directly in the
      // event emitter pattern and mocha does not have an "on error"
      /* istanbul ignore next */
      log(`Problem with mochawesome: ${e.stack}`, 'error');
    }
  });
}

consoleContext的思路是提取每个用例结果中的context,并将其组合在一个对象中,利用console.table打印出来。代码如下,

function consoleContext(suites) {
  var family = {};
  for (let i = 0; i < suites.length; i++) {
    const tests = suites[i].tests;
    for (let j = 0; j < tests.length; j++) {
      const t = tests[j];
      if (!t.context) {
        continue;
      }
      Object.keys(t.context.fields).forEach(key => {
        const value = t.context.fields[key];
        !family[t.title] && (family[t.title] = {});
        family[t.title][key] = value;
      });
    }
  }
  console.table(family);
}

最终使用方法为

cy.addContext({
  title: '首屏时长',
  value: '首屏时长',
  fields: {
    '页面url': 'http://baidu.com',
    '版本': '0.0.1',
    '第一次加载/ms': 2000,
  }
});

如下图的表格,成功将context数据可视化。 

image.png

 当然,你也可以参考mochawesome自定义一个reporter来完成报告输出。

小结

回到一开始的首屏时间测试用例,结合以上介绍的逻辑实现、数据保存和报告生成,最终我们可以写出一个完整的用例

const TEST_TIMES = 5;
let startTime;
let fpArr = [];
const url = '';
describe('test fp', () => {
  beforeEach(() => {
    startTime = +new Date();
  })

  afterEach(() => {
    const fp = +new Date() - startTime;
    fpArr.push(fp);
    // 记录数据写入本地文件
    cy.collectData({
      dir: 'fp.json',
      pageUrl: url,
      fp,
      version: '0.0.1',
    });
    
    // 打印context信息
    let fields = {};
    fpArr.forEach((item, index) => {
      fields[`第${index+1}次/ms`] = item;
    });
    cy.addContext({
      fields,
      title: '首屏时长',
      value: '首屏时长'
    });
  })
 
  for (let i = 0; i < TEST_TIMES; i++) {
    it((`加载页面`) => {
  	  cy.visit(`${url}`)
        .get('.app-container', { timeout: 10000 })
        .should('have.length', 1);
    });
  }
})
  • 4
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值