【基于Puppeteer前端自动化框架】【二】PO模式,断言(如何更简便逻辑的写测试代码)
一、概要
前面介绍了Puppeteer+jest+TypeScript做UI自动化,但是这知识基础的,我们实现自动化要考虑的很多,比如PO模式,比如配置文件,比如断言等等。下面就来一一实现我是怎么用puppeteer 做UI自动化的
二、断言
(一)需要依赖的安装包
依赖包 | 命令 |
---|---|
Jest | npm install jest --save-dev |
@types/jest | npm install @types/jest --save-dev |
expect-puppeteer | npm install expect-puppeteer --save-dev |
@types/expect-puppeteer | npm install @types/expect-puppeteer --save-dev |
我们写过Jest的知道Jest自己就带有断言,但是Jest的断言有时候可能不全满足我们,我们来看看expect-puppeteer的api
链接:expect-puppeteer(api)
(二) 简单介绍下api
- 看api的介绍,expect-puppeteer封装了一些可供我们使用的方法,断言比如toMatch(验证页面是否能匹配到值),toMathcElement((验证页面是否能匹配到元素),这两个还是比较好用的,尤其toMathcElement,具体实战再说
- 其他api,看跟puppeteer api有点不一样,puppeteer一样有click方法那么expect-puppeteer好处是什么呢?这个时候我们就要看源码了这里建议即使有现成的库,我们也要多看看源码
- 查看expect-puppeteer - index.d.ts 发现写了一个ExpectPuppeteer接口,这里里面就有我们所有的api,我们顺便点看任意一个js文件看看,目录(expect-puppeteer - lib - options.js),我们就看看这个文件,看不懂没关系,但是大概我们能猜出,就是控制运行时间的嘛,实际工作中一个case可能会写大量的waitfor()是不是很麻烦,所以,我建议,吧options.js的timeout设置长一点,这样方便更准确的寻找页面元素
- api不多做介绍,照着api文档就会了,比较简单
options.js -> 修改timeout为2s
let defaultOptionsValue = {
timeout: 2000
};
三、PO 模式
问:什么是PO模式?
答:概念自行百度,我就不粘贴了,我想稍微写过一点UI自动化的,应该都会多多少少了解一点,通俗的说,我们把元素,方法,测试case 分开写,这样方便我们去管理,逻辑也不叫清晰,具体下面拿实例来说明
四、实例 (以同程网站为实例)
今天我们来写,从首页进入ly.com,点击机票 - 国内机票 - 验证机票默认弹框
(一)我的脚本目录
-----__tests__
-------ui
--------DomesticTictet
-------- cases
-------- basic.test.ts
-------- element
--------Index
-------- action
-------- Navi.action.help.ts
-------- element
-------- Navigation.help.ts
-----env
------ ly.yaml
-----utils
------ config.js
- 测试用例都在__tests__文件夹中,DomesticTictet,Index 不同模块的文件夹,分别有cases(测试用例存放的文件夹)element(管理页面元素)action(方法)
- env,管理yaml文件的文件夹,所有的yaml文件放在这里
- utils 自己写的工具类,config.js读取yaml文件
(二)element类管理
Navigation.help.ts
import { Page } from 'puppeteer';
import expectPuppeteer = require('expect-puppeteer');
export const Nav_Ticket = '#menuNav li:nth-child(3) b';
export const DomesticTicket = '.submenu-nav .flight-submenu1';
home.help.ts
// 标题名
export const titleContent = '.s-title.dflex span';
// 出发城市
export const start_city_input = '.s-box:nth-child(1) input[value]';
// 到达城市
export const arrive_city_input = '.s-box:nth-child(3) input[value]';
// 出发时间
export const start_data_input = 'input[placeholder="出发日期"]';
// 到达时间
export const return_data_input = 'input[placeholder="返回日期"]';
// 搜索按钮
export const domestic_tictet_search = '.s-button';
// 搜索不到航班信息提示
export const flight_no_data_tip = '.flight-no-data span'
// 存在航班的元素
export const flight_get_data = '.top-flight-info span b'
(三)action方法编写
Navi.action.help.ts
import { Page } from 'puppeteer';
import expectPuppeteer = require('expect-puppeteer');
const navi_element = require('../element/Navigation.help');
export class Navi_Action {
/**
* 点击国内机票
*/
public async hover_home_ticket(page:Page) {
await page.waitForSelector(navi_element.Nav_Ticket);
await page.hover(navi_element.Nav_Ticket);
await page.waitFor(3000);
await expectPuppeteer(page).toClick(navi_element.DomesticTicket);
await page.waitFor(3000);
}
}
(四)yaml配置文件编写
ly.yaml
url:
web: https://www.ly.com/
flighthome: https://www.ly.com/flights/home
# puppeteer lanuch配置
puppeteer:
proxy:
viewport:
width: 1920
height: 1080
(五)测试用例编写
basic.test.ts
import { Page } from 'puppeteer';
import { Navi_Action } from '../../Index/action/Navi.action.help';
const config = require('../../../../utils/config');
const Home_Element = require('../element/home.help');
const time = require('silly-datetime');
const ly = config.readConfig('ly');
describe('domestic ticket page content verification', () => {
let page : Page;
beforeEach( async () => {
page = await browser.newPage();
await page.setViewport(ly.puppeteer.viewport);
await page.goto(ly.url.web,{waitUntil:'networkidle2'});
let navi_action = new Navi_Action();
await navi_action.hover_home_ticket(page);
},30000)
afterEach ( async () => {
await page.close();
})
test('TEST_001:验证跳转链接' , async() => {
const url = await page.url();
await expect(url).toBe(ly.url.flighthome);
},30000);
test('TEST_002:验证标题名' , async() => {
const titleElement = Home_Element.titleContent;
const content = await page.evaluate( (titleElement) => {
return document.querySelector(titleElement).innerHTML;
},titleElement);
await expect(content).toEqual('国内机票');
},30000);
test('TEST_003:验证出发默认城市' , async() => {
const content = await page.$eval(Home_Element.start_city_input,el => el.getAttribute('value'));
await expect(content).toEqual('上海');
},30000);
test('TEST_004:验证到达默认城市' , async() => {
const content = await page.$eval(Home_Element.arrive_city_input,el => el.getAttribute('value'));
await expect(content).toEqual('北京');
},30000);
test('TEST_004:验证时间为当天时间' , async() => {
const current_time = time.format(new Date(),'YYYY-MM-DD');
const start_time_element = Home_Element.start_data_input;
const start_time_content = await page.evaluate( (start_time_element) => {
return document.querySelector(start_time_element).value;
},start_time_element);
await expect(start_time_content).toEqual(current_time);
},30000);
test('TEST_005:验证到达默认值' , async() => {
const return_input = await page.$eval(Home_Element.return_data_input,el => el.getAttribute('placeholder'));
await expect(return_input).toEqual('返回日期');
},30000);
})
结果
【基于Puppeteer前端自动化框架】【二】PO模式,断言(如何更简便逻辑的写测试代码)的更多相关文章
- 【基于PUPPETEER前端自动化框架】【一】TypeScript+Puppeteer+Jest 整合
前提:掌握Jest + Puppeteer 1.Jest环境配置 2.Jest-MATCHERS匹配器 3.Jest-全局变量设置 4.Puppeteer安装 5.Puppeteer元素获取 6.Pu ...
- UI自动化测试框架:PO模式+数据驱动
1. PO 设计模式简介 2. 工程结构说明 3. 工程代码实现 page 包 action 包 business_process 包 util 包 conf 包 test_data 目录 log 目 ...
- 说说UI自动化中的PO模式
PO模式,全称PageObject模式,即页面对象模式.将页面定位与业务操作分离. po模式有以下几个优点: 1.易读性好 2.扩展性高 3.复用性强 4.维护性好 5.代码冗余率低 了解了po模式及 ...
- 3分钟手把手带你搭建基于selenium的自动化框架
1 .什么是seleniumSelenium 是一个基于浏览器的自动化工具,它提供了一种跨平台.跨浏览器的端到端的web自动化解决方案.Selenium主要包括三部分:Selenium IDE.Sel ...
- Selenium基于Python web自动化基础二 -- 免登录、等待及unittest单元测试框架
一.免登录在进行测试的过程中难免会遇到登录的情况,给测试工作添加了工作量,本文仅提供一些思路供参考解决方式:手动请求中添加cookies.火狐的profile文件记录信息实现.人工介入.万能验证码.去 ...
- 自动化框架的两种断言设计(pytest 版)
自动化测试断言失败时,根据不同业务场景,可能需要立即终止或继续执行.这里以 Appium + pytest 为例. 一. 断言失败立即终止 用途一:用例的预期结果是其他用例的前提条件时,assert ...
- net.sz.framework 框架 轻松搭建服务---让你更专注逻辑功能---初探
前言 在之前的文章中,讲解过 threadmodel,socket tcp ,socket http,log,astart ,scripts: 都是分片讲解,从今天开始,将带大家,一窥 net.sz. ...
- ShutIt:一个基于 Python 的 shell 自动化框架
ShutIt是一个易于使用的基于shell的自动化框架.它对基于python的expect库(pexpect)进行了包装.你可以把它看作是“没有痛点的expect”.它可以通过pip进行安装. Hel ...
- 前端Js框架 UI框架汇总 特性 适用范围 选择
身为一个资深后端工程师,面对层出不穷的前端框架,总让人眼花缭乱,做一个综合解析贴,从全局着眼,让我们明白各种前端框架的应用范围,为如何选择前端框架,从不同的维度提供一些线索,做为一个长期优化贴,欢迎指 ...
随机推荐
- 基于ssm的客户管理系统
查看更多系统:系统大全,课程设计.毕业设计,请点击这里查看 01 概述 一个简单的客户关系管理系统 管理用户的基本数据 客户的分配 客户的流失 已经客户的状态 02 技术 ssm + jdk1.8 + ...
- Centos 7 firewall 命令
Centos 7 firewall 命令: 查看已经开放的端口: firewall-cmd --list-ports 开启端口 firewall-cmd --zone=public --add-por ...
- Docker知识进阶与容器编排技术
目录 1 使用Dockerfile定制redis镜像 1.1 环境准备 1.2 编写Dockerfile文件 1.3 通过Dockerfile构建镜像 1.4 通过镜像运行容器 1.5 官方镜像替代我 ...
- Luogu P4271 [USACO18FEB]New Barns P
题意 给一个一开始没有点的图,有 \(q\) 次操作,每次为加点连边或者查询一个点到连通块内所有点的距离最大值. \(\texttt{Data Range}:1\leq q\leq 10^5\) 题解 ...
- printk 流程分析
1. 概述 printk 用于在终端上打印内核想要输出的信息,平常我们较多使用的打印函数是 printf,两者名字虽然只有最后一个字母不同,且都是为了在终端上显示信息,但是它们的应用场景并不相同.pr ...
- python框架Django中MTV框架之Template(模板/界面)
MTV框架之Template(模板/界面) 关注公众号"轻松学编程"了解更多. 1.模板目录位置 应用下 不需要注册 无法跨应用地进行复用 工程下 需要注册 settings.py ...
- Python3网络学习案例二:traceroute详解
1. 写在前面 本文是基于上一篇"ping详解"写的: 不同操作系统下的命令也不同,本文仅针对windows系统,命令为"tracert xxx",效果如下 2 ...
- Hash 算法与 Manacher 算法
目录 前言 简单介绍 简述 Hash 冲突 离散化 基本结构 普通 Hash 简述 例题 字符串 Hash 简单介绍 核心思想 基本运算 二维字符串 Hash 例题 兔子与兔子 回文子串的最大长度 后 ...
- 为什么要谨慎使用Arrays.asList、ArrayList的subList?
1. 使用Arrays.asList的注意事项 1.1 可能会踩的坑 先来看下Arrays.asList的使用: List<Integer> statusList = Arrays.asL ...
- 【SpringCloud】04.SpringCloud Eureka Server与Client的创建
Eureka是Netflix开发的服务发现框架,本身是一个基于REST的服务,主要用于定位运行在AWS域中的中间层服务,以达到负载均衡和中间层服务故障转移的目的.SpringCloud将它集成在其子项 ...