前端自动化测试入门教程

news2024/11/22 6:02:57

🪴 背景

前端的自动化测试主要可以分为以下四种:

  • 单元测试(Unit Test):对一个函数/组件进行测试,一般用于公共函数/公共组件的测试维护。常用框架有 Jest、Jasmine、Mocha等;

  • 集成测试(Integration Test):对多个模块作为一个整体进行测试,一般用于耦合度较高的函数/组件、经过二次封装的函数/组件、多个函数/组件组合而成的函数/组件等。常用的框架有ReactTestUtils、Enzyme、Vue-Test-Utils 、React-Testing-Library等;

  • UI测试:是对界面样式和交互的测试。

  • 端到端测试(end to end,简称e2e):模拟用户操作的黑盒测试。设定一系列操作,测试系统是否能够按照我们设置的步骤正确执行,可以完整测试整个功能的运行。常用的框架有 Puppeteer、Cypress、Playwright(微软出品,配合vscode插件使用)、Selenium 、cucumber、TestCafe等。

前端开发一般也就单元测试用到比较多,像e2e这种测试几乎不会用到。

确实,因为e2e测试也有一定的开发成本,再好的东西也得适用不是。

那么什么情况下适合引入自动化测试呢?例如以下三个场景:

  • 公共类库、公共组件的开发维护;
  • 中长期项目的迭代/重构;
  • 引用了不可控的第三方依赖;

举个例子,项目中有一个非常重要的下单页面,经过长期的功能迭代重构,核心逻辑可能没变,但是新增了很多新功能,也修改了部分旧功能,已经是一个非常重要的屎山页面。

这时候要你接手这个页面做一些调整,你能保证捋清并且不破坏掉以前的代码逻辑逻辑吗?我敢说你不敢保证,修改点代码生怕造成“事故”,全公司通报。

这时候自动化测试的重要性就体现了,如果在开始就设计好一套核心逻辑的自动化测试脚本,那么在之后迭代的过程中不仅可以通过跑测试脚本缕清逻辑,并且还能在修改代码后用脚本验证自己是否破坏了核心的逻辑。

本文和大家讲解一下e2e自动化测试框架 – puppeteer的基础使用教程。

🌻 教程

1. Puppeteer是什么?

Puppeteer 是一个 Node.js 库,使用它可以运行一个无头的谷歌浏览器(即不显示图形用户界面的浏览器)。然后我们就可以在运行的浏览器中启动我们的页面,并且通过 Puppeteer 提供的 API 操作页面了。

Puppeteer默认是以 headless 无头模式运行,在写测试脚本的时候,为了方便看到效果,可以配置关闭无头模式,即可正常打开浏览器看到页面自动操作的效果。

2. Puppeteer能做什么?

基本上我们平常在浏览器中进行的操作都可以用 Puppeteer 模拟操作,例如:

  • 操作dom,执行dom的各种点击,移动等事件;
  • 模拟键盘输入,鼠标操作。触摸移动等一系列操作;
  • 捕获网站的timeline trace,分析网站性能;
  • 网页截图,生成 PDF;
  • 抓取 SPA(单页应用)并生成预渲染内容(即“SSR”(服务器端渲染))
    等…

3. Puppeteer怎么上手?

(1) 首先安装 Puppeteer

安装 Puppeteer 时会安装一个内置的 Chromium 浏览器,国内用 npm 安装会报错失败,装不上 Chromium,可以改用 yarn 或者 cnpm 安装。

puppeteer还提供了一个轻量级的包—puppeteer-core,这个包不需要下载 Chromium,而是直接启动现有浏览器或连接到远程安装。

yarn add puppeteer
//或者
cnpm i puppeteer

(2) 上手

先 require 引入 puppeteer

const puppeteer = require('puppeteer');

然后开始使用 puppeteer 启动一个浏览器并操作页面。首先需要创建一个 Browser 实例,打开页面,然后使用就可以使用 Puppeteer 的 API 进行你想要的操作了。

const puppeteer = require('puppeteer');

(async () => {  
    //首先创建一个 Browser 实例
    const browser = await puppeteer.launch();  
    //然后创建一个 tab页的 Page 实例
    const page = await browser.newPage();  
    //然后可以打开我们的网页了
    await page.goto('https://example.com');  
})();

可以看到我们用了 async / await 语法,是的,在 puppeteer 中,几乎所有操作都是异步的,所以一般使用时需要频繁的用到 async / await ,所以使用前要检查 Node 版本大于 v7.6.0。

如果你需要手动下载 Chromium,还可以配置 Chromium 或 Chrome 可执行文件的位置。

const browser = await puppeteer.launch({executablePath: '/path/to/Chrome'});

正如我们上面所说,怎么关闭 puppeteer 的无头模式呢?只需要在实例化时配置即可。

  //关闭无头模式
  const browser = await puppeteer.launch({headless: false}); 

配置无头模式之后,我们就可以看到puppeteer会调起一个可视的 Chromium 或 Chrome 浏览器了,这样方便我们直观的看到效果。但是由于puppeteer的操作一步接一步,速度非常快,可能看不清,所以可以使用slowMo参数配置延迟每步操作的时间,如下:

  //关闭无头模式
  const browser = await puppeteer.launch({
    headless: false,
    slowMo: 1000
  }); 

4. Puppeteer的 API

puppeteer 常用的实例有以下几种:

  • Brower(浏览器实例):Puppeteer通过 launch
    connect 方法连接到 Chromium 时创建一个浏览器实例;可以执行浏览器断开连接、重连、关闭浏览器、打开tab页、获取useragent代理信息等操作;
  • Page(tab页实例):Brower实例通过newPage方法打开一个tab页。关于页面内容的操作一般都会用到这个实例,例如截图、操作dom、跳转tab页、关闭tab页、延迟操作。凡是和页面元素相关的基本都是用它。
  • Keyboard(键盘实例):模拟键盘操作
  • Mouse(鼠标实例):模拟鼠标操作
  • Touchscreen(触屏操作):模拟触屏操作
  • Frame窗口实例

我这里就简单说明几个常用操作,详细的 API 使用可以查看官网文档

(1)获取元素 page.$()、page.$$()

page.$()相当于 document.querySelector,返回匹配的元素节点的第一个。比如获取按钮,然后执行点击事件:

let submitBtn = await page.$("#submit");
submitBtn.click()

page.$$(selector) 相当于 document.querySelectorAll,返回所有匹配的元素节点。

let inputArr = await page.$$('input')

(2)获取元素属性 page.$eval()、page.$$eval()
获取元素属性不能像平常写js那样,获取到元素之后,用dom.value获取它的值或者获取其他属性。可以使用 page. e v a l ( ) 或 p a g e . eval() 或 page. eval()page.$eval() 获取元素属性,区别和上面获取元素雷同。

$eval()是对单个元素进行操作。

$$eval()是对匹配到的所有元素进行操作。

//获取输入框的值
const value = await page.$eval('input[name=search]', input => input.value)
//获取输入框的个数
const num = await page.$$eval('input', input => input.length)

(3)脚本注入 page.evaluate()

如果要执行某段自定义的js代码,可以用page.evaluate()方法。
例如按钮点击你也可以这么写:

await page.evaluate(() => document.querySelector("#submit").click() )

(4) 执行等待
有时候可能需要延迟代码执行,例如修改了元素的可见性,需要等元素显示出来再执行操作,就可以用page.waitForSelector延迟代码执行。常用的延迟执行的api有:

  • page.waitForSelector():等待选择器解析的页面元素出现在页面中;
  • page.waitForNavigation():等待页面跳转后;
  • page.waitForXPath():等待 xpath 解析的页面元素出现在页面中;
  • page.waitForFunction():等待放到页面上下文执行的方法返回真值;
  • page.waitForRequest():等待页面上发起的请求满足判断条件并返回真值;
  • page.waitForResponse():等待页面上接收的请求响应满足判断条件并返回真值;
  • page.waitFor():可充当 page.waitForXPath、page.waitForSelector 、page.waitForFunction 和延时效果用。

(5)page实例分为三个管理模块

  • _frameManager : 管理页面相关行为,例如页面跳转(goto),等待加载(waitFor), 元素选择与处理(evaluate)等
  • _networkManager : 管理网络相关行为,例如请求拦截(setRequestInterception):离线模式(setOfflineMode)等
  • _emulationManager - 管理模拟行为,例如修改浏览器的UserAgent代理信息,修改视窗大小等

👣 实操

我这里写一个简单的小案例,方便大家理解。

打开掘金搜索到我的主页,进入个人主页并截图

创建 check.js,具体的操作步骤看下面代码里的注释:

const puppeteer = require('puppeteer');

(async () => {

  //创建 brower 实例,关闭无头模式,方便查看效果,同时可以设置 slowMo ,放慢自动化操作。
  const browser = await puppeteer.launch({
    headless: false,
    slowMo: 0
  });
  
  //创建 page 实例
  const page = await browser.newPage();
  
  //设置视口宽高
  const viewWidth = 1000
  const viewHeight = 800
  await page.setViewport({
    width: viewWidth,
    height: viewHeight,
  });
  
  //跳转掘金首页
  await page.goto('https://juejin.cn/');
  
  //使用 type 方法向掘金搜索框输入 “前端阿彬”
  await page.type('.search-input','前端阿彬',{
    delay: 300
  })

  //使用 keyboard 类的 press 方法模拟键盘按下 "Enter" 键
  await page.keyboard.press('Enter');

  //这里一定要用 waitForSelector 方法等搜索结果显示出来再继续操作
  await page.waitForSelector('.nav-item.route-active')

  //点击搜索结果的 “用户” tab
  await page.evaluate(() => document.querySelectorAll(".nav-item.route-active>a")[4].click() )

  //等用户列表显示出来再继续操作
  await page.waitForSelector('.main-list .item')

  //获取第一个item,也就是我的个人主页的a链接地址
  const href = await page.$$eval('.main-list .item a',link => link[0].href)

  //获取到个人主页的href,然后用goto跳转
  await page.goto(href);

  //等待页面跳转完成再继续操作
  page.waitForNavigation()
   
  //调用 screenshot 方法进行截图,并裁减可视区域内的部分
  await page.screenshot({
    path: '个人主页.png',
    clip: {
      x: 0,
      y: 0,
      width: viewWidth,
      height: viewHeight,
    }
  });
 
  //关闭浏览器
  await browser.close();
})();

命令行执行 node check.js 执行我们的测试脚本,效果如下:

tutieshi_640x668_9s.gif

截图如下:

个人主页.png

最后

puppeteer的功能非常强大,基本上平常在浏览器里能手动完成的操作都可以用它模拟。而测试脚本逻辑无非就是调用它的 API,实际逻辑其实还是靠js,所以上手并不难。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1069680.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

VR全景拍摄酒店,为用户消除“不透明度”

近日在各大社交平台上,出现了不少吐槽国庆期间酒店价格太贵的帖子,而一些热门旅游地的度假酒店、网红民宿的热门房型已经“一房难求”,这就出现酒店房型与预定房型不同的现象出现,VR全景拍摄技术同酒店行业的结合,就可…

韩语学习|韩语零基础|柯桥韩语学校,每日一词

今日一词:개방도 평지 韩语每日一词打卡:개방도[개방도]【名词】开放度,开放程度 原文:한 지역의 개방도는 경제 발전 수준에 달려 있습니다. 意思:一个地区的开放程度取决于经济发展水平。 【原文分解】 1、경제[경제]经济 2、지역[지역]地域 3、발전[발…

代码随想录算法训练营第23期day12| 239. 滑动窗口最大值 、347. 前K个高频元素

目录 一、(leetcode 239)滑动窗口最大值​​​jiao 二、(leetcode 347)前 K 个高频元素 优先级队列与大小顶堆 一、(leetcode 239)滑动窗口最大值​​​jiao 力扣题目链接 状态:待回顾&…

kafka、rabbitmq 、rocketmq的区别

一、语言不同 RabbitMQ是由内在高并发的erlanng语言开发,用在实时的对可靠性要求比较高的消息传递上。 kafka是采用Scala语言开发,它主要用于处理活跃的流式数据,大数据量的数据处理上 二、结构不同 RabbitMQ采用AMQP(Advanced Message Q…

Excel·VBA使用ADO读取工作簿工作表数据

目录 查询遍历写入数组查询整体写入数组查询工作簿所有工作表名称查询工作簿所有工作表数据 不打开工作簿读取数据,以下举例都为《ExcelVBA合并工作簿》中 7,合并子文件夹同名工作簿中同名工作表,纵向汇总数据所举例的工作簿,使用…

国庆作业day10.4

QT实现TCP服务器客户端搭建的代码,现象 服务器 #include "widget.h" #include "ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget) {ui->setupUi(this);//实例化一个服务器servernew QTcpServer(this);c…

探秘小米增程汽车与仿生机器人的未来:AI大模型的潜在影响及苹果iPhone15Pro发热问题解决之道

🌷🍁 博主猫头虎 带您 Go to New World.✨🍁 🦄 博客首页——猫头虎的博客🎐 🐳《面试题大全专栏》 文章图文并茂🦕生动形象🦖简单易学!欢迎大家来踩踩~🌺 &a…

智能井盖传感器:城市安全卫士

随着城市人口的不断增加和城市基础设施的不断发展,井盖作为城市道路和排水系统的重要组成部分,承担着确保城市安全和便利性的关键角色。然而,井盖在日常使用中常常面临倾斜、水浸和翻转等问题,这些问题可能导致交通阻塞、行人坠井…

漏洞挖掘--edusrc两连杀

免责声明:文章中涉及的漏洞均已修复,敏感信息均已做打码处理,文章仅做经验分享用途,切勿当真,未授权的攻击属于非法行为! 最近闲来无事,研究了下通达的day,由于本人太菜了&#xff…

软考网络工程师考前如何复习?

先看一下这知识点总结图,在备考复习前大致简单了解一遍! 第一步: 通读教程(《网络工程师》),首先对教程中的各章节及知识点有一个基本的认识,第一阶段基本以泛读为主,不求立刻记得所…

Maven 配置阿里云镜像

1. 查找maven setting.xml配置文件 find / -name "setting.xml" 2. 添加阿里云镜像 修改maven根目录下的conf文件夹中的setting.xml文件中的mirrors下添加mirror标签 <settings> <localRepository>E:\Maven\repository</localRepository> <…

LLMs Python解释器程序辅助语言模型(PAL)Program-aided language models (PAL)

正如您在本课程早期看到的&#xff0c;LLM执行算术和其他数学运算的能力是有限的。虽然您可以尝试使用链式思维提示来克服这一问题&#xff0c;但它只能帮助您走得更远。即使模型正确地通过了问题的推理&#xff0c;对于较大的数字或复杂的运算&#xff0c;它仍可能在个别数学操…

【Kotlin精简】第2章 集合

1 简介 在 Kotlin 中集合主要分为可变集合与只读集合&#xff0c;其中可变集合使用 “Mutable” 前缀 集合类名表示&#xff0c;比如 MutableList、MutableSet、MutableMap 等。而对于只读集合就是和 Java 中集合类名是一致。 Java 中的 List 非 Kotlin 中的 List , 因为 Kot…

深度学习——权重衰减(weight_decay)

深度学习——权重衰减&#xff08;weight_decay) 文章目录 前言一、权重衰减1.1. 范数与权重衰减1.2. 高维线性回归1.3. 从零开始实现1.3.1.初始化模型参数1.3.2. 定义L₂范数惩罚1.3.3. 定义训练代码实现1.3.4. 不管正则化直接训练1.3.5. 使用权重衰减 1.4. 简洁实现 总结 前言…

寒露到了,冬天还会远吗?

寒露惊秋晚&#xff0c;朝看菊渐黄。 日复一日间&#xff0c;光影如梭&#xff0c;我们便很快将告别了秋高气爽&#xff0c;白日将变得幽晦&#xff0c; 天寒夜长&#xff0c;风气萧索&#xff0c;雾结烟愁。 还没好好体会秋高气爽,寒露就到了。 今天晚上9点多&#xff0c;我们…

成都直播产业未来发展新方向一览,又一大型直播基地入驻成都!

成都直播产业正迎来一股蓬勃发展的新浪潮&#xff0c;展现出无限的潜力和前景。最新消息显示&#xff0c;又一座大型直播基地——成都天府蜂巢直播产业基地即将入驻成都&#xff0c;为这座城市的直播产业注入了新的动力和活力。 天府蜂巢 行业模范 成都天府蜂巢直播产业基地采…

LLMs 入门实战系列

link 【LLMs 入门实战系列】 【LLMs 入门实战系列】交流群 (注&#xff1a;人满 可 添加 小编wx&#xff1a;yzyykm666 加群&#xff01;) 【LLMs 入门实战系列】 第一层 LLMs to Natural Language Processing (NLP) 第一重 ChatGLM-6B 系列 ChatGLM-6BChatGLM2-6B 第十一重 L…

WebSocket ----苍穹外卖day8

介绍 实现步骤 各个模块详解 OnOpen OnOpen:标记一个方法作为处理WebSocket连接打开的方法 当一个客户端与服务器建立 WebSocket 连接时&#xff0c;服务器会接收到一个连接请求。一旦服务器接受了这个连接请求&#xff0c;一个 WebSocket 连接就会被建立。这时&#xff0c;被…

Eclipse iceoryx™ - 真正的零拷贝进程间通信

1 序言 通过一个快速的背景教程&#xff0c;介绍项目范围和安装所需的所有内容以及第一个运行示例。 首先&#xff1a;什么是冰羚&#xff1f; iceoryx是一个用于各种操作系统的进程间通信&#xff08;IPC&#xff09;中间件&#xff08;目前我们支持Linux、macOS、QNX、FreeBS…

一文搞懂频率响应中的相位响应与信号在时域变化的关系

我们知道一个信号通过一个系统后&#xff0c;输出信号的频谱输入信号的频谱*传递函数的频谱 那么衡量输出信号与输入信号的关系通常是考虑他们的幅度和相位。即&#xff1a;传递函数的相位相应和幅度响应。幅度响应好理解&#xff0c;即输出信号相比于输入信号幅值放大多少倍。…