一、概要

前面介绍了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

  1. 看api的介绍,expect-puppeteer封装了一些可供我们使用的方法,断言比如toMatch(验证页面是否能匹配到值),toMathcElement((验证页面是否能匹配到元素),这两个还是比较好用的,尤其toMathcElement,具体实战再说
  2. 其他api,看跟puppeteer api有点不一样,puppeteer一样有click方法那么expect-puppeteer好处是什么呢?这个时候我们就要看源码了这里建议即使有现成的库,我们也要多看看源码
  3. 查看expect-puppeteer - index.d.ts 发现写了一个ExpectPuppeteer接口,这里里面就有我们所有的api,我们顺便点看任意一个js文件看看,目录(expect-puppeteer - lib - options.js),我们就看看这个文件,看不懂没关系,但是大概我们能猜出,就是控制运行时间的嘛,实际工作中一个case可能会写大量的waitfor()是不是很麻烦,所以,我建议,吧options.js的timeout设置长一点,这样方便更准确的寻找页面元素
  4. api不多做介绍,照着api文档就会了,比较简单
  1. options.js -> 修改timeout2s
  2. let defaultOptionsValue = {
  3. timeout: 2000
  4. };

三、PO 模式

问:什么是PO模式?

答:概念自行百度,我就不粘贴了,我想稍微写过一点UI自动化的,应该都会多多少少了解一点,通俗的说,我们把元素,方法,测试case 分开写,这样方便我们去管理,逻辑也不叫清晰,具体下面拿实例来说明

四、实例 (以同程网站为实例)

今天我们来写,从首页进入ly.com,点击机票 - 国内机票 - 验证机票默认弹框

(一)我的脚本目录

  1. -----__tests__
  2. -------ui
  3. --------DomesticTictet
  4. -------- cases
  5. -------- basic.test.ts
  6. -------- element
  7. --------Index
  8. -------- action
  9. -------- Navi.action.help.ts
  10. -------- element
  11. -------- Navigation.help.ts
  12. -----env
  13. ------ ly.yaml
  14. -----utils
  15. ------ config.js
  • 测试用例都在__tests__文件夹中,DomesticTictet,Index 不同模块的文件夹,分别有cases(测试用例存放的文件夹)element(管理页面元素)action(方法)
  • env,管理yaml文件的文件夹,所有的yaml文件放在这里
  • utils 自己写的工具类,config.js读取yaml文件

(二)element类管理

  1. Navigation.help.ts
  2. import { Page } from 'puppeteer';
  3. import expectPuppeteer = require('expect-puppeteer');
  4. export const Nav_Ticket = '#menuNav li:nth-child(3) b';
  5. export const DomesticTicket = '.submenu-nav .flight-submenu1';
  1. home.help.ts
  2. // 标题名
  3. export const titleContent = '.s-title.dflex span';
  4. // 出发城市
  5. export const start_city_input = '.s-box:nth-child(1) input[value]';
  6. // 到达城市
  7. export const arrive_city_input = '.s-box:nth-child(3) input[value]';
  8. // 出发时间
  9. export const start_data_input = 'input[placeholder="出发日期"]';
  10. // 到达时间
  11. export const return_data_input = 'input[placeholder="返回日期"]';
  12. // 搜索按钮
  13. export const domestic_tictet_search = '.s-button';
  14. // 搜索不到航班信息提示
  15. export const flight_no_data_tip = '.flight-no-data span'
  16. // 存在航班的元素
  17. export const flight_get_data = '.top-flight-info span b'

(三)action方法编写

  1. Navi.action.help.ts
  2. import { Page } from 'puppeteer';
  3. import expectPuppeteer = require('expect-puppeteer');
  4. const navi_element = require('../element/Navigation.help');
  5. export class Navi_Action {
  6. /**
  7. * 点击国内机票
  8. */
  9. public async hover_home_ticket(page:Page) {
  10. await page.waitForSelector(navi_element.Nav_Ticket);
  11. await page.hover(navi_element.Nav_Ticket);
  12. await page.waitFor(3000);
  13. await expectPuppeteer(page).toClick(navi_element.DomesticTicket);
  14. await page.waitFor(3000);
  15. }
  16. }

(四)yaml配置文件编写

  1. ly.yaml
  2. url:
  3. web: https://www.ly.com/
  4. flighthome: https://www.ly.com/flights/home
  5. # puppeteer lanuch配置
  6. puppeteer:
  7. proxy:
  8. viewport:
  9. width: 1920
  10. height: 1080

(五)测试用例编写

  1. basic.test.ts
  2. import { Page } from 'puppeteer';
  3. import { Navi_Action } from '../../Index/action/Navi.action.help';
  4. const config = require('../../../../utils/config');
  5. const Home_Element = require('../element/home.help');
  6. const time = require('silly-datetime');
  7. const ly = config.readConfig('ly');
  8. describe('domestic ticket page content verification', () => {
  9. let page : Page;
  10. beforeEach( async () => {
  11. page = await browser.newPage();
  12. await page.setViewport(ly.puppeteer.viewport);
  13. await page.goto(ly.url.web,{waitUntil:'networkidle2'});
  14. let navi_action = new Navi_Action();
  15. await navi_action.hover_home_ticket(page);
  16. },30000)
  17. afterEach ( async () => {
  18. await page.close();
  19. })
  20. test('TEST_001:验证跳转链接' , async() => {
  21. const url = await page.url();
  22. await expect(url).toBe(ly.url.flighthome);
  23. },30000);
  24. test('TEST_002:验证标题名' , async() => {
  25. const titleElement = Home_Element.titleContent;
  26. const content = await page.evaluate( (titleElement) => {
  27. return document.querySelector(titleElement).innerHTML;
  28. },titleElement);
  29. await expect(content).toEqual('国内机票');
  30. },30000);
  31. test('TEST_003:验证出发默认城市' , async() => {
  32. const content = await page.$eval(Home_Element.start_city_input,el => el.getAttribute('value'));
  33. await expect(content).toEqual('上海');
  34. },30000);
  35. test('TEST_004:验证到达默认城市' , async() => {
  36. const content = await page.$eval(Home_Element.arrive_city_input,el => el.getAttribute('value'));
  37. await expect(content).toEqual('北京');
  38. },30000);
  39. test('TEST_004:验证时间为当天时间' , async() => {
  40. const current_time = time.format(new Date(),'YYYY-MM-DD');
  41. const start_time_element = Home_Element.start_data_input;
  42. const start_time_content = await page.evaluate( (start_time_element) => {
  43. return document.querySelector(start_time_element).value;
  44. },start_time_element);
  45. await expect(start_time_content).toEqual(current_time);
  46. },30000);
  47. test('TEST_005:验证到达默认值' , async() => {
  48. const return_input = await page.$eval(Home_Element.return_data_input,el => el.getAttribute('placeholder'));
  49. await expect(return_input).toEqual('返回日期');
  50. },30000);
  51. })

结果

【基于Puppeteer前端自动化框架】【二】PO模式,断言(如何更简便逻辑的写测试代码)的更多相关文章

  1. 【基于PUPPETEER前端自动化框架】【一】TypeScript+Puppeteer+Jest 整合

    前提:掌握Jest + Puppeteer 1.Jest环境配置 2.Jest-MATCHERS匹配器 3.Jest-全局变量设置 4.Puppeteer安装 5.Puppeteer元素获取 6.Pu ...

  2. UI自动化测试框架:PO模式+数据驱动

    1. PO 设计模式简介 2. 工程结构说明 3. 工程代码实现 page 包 action 包 business_process 包 util 包 conf 包 test_data 目录 log 目 ...

  3. 说说UI自动化中的PO模式

    PO模式,全称PageObject模式,即页面对象模式.将页面定位与业务操作分离. po模式有以下几个优点: 1.易读性好 2.扩展性高 3.复用性强 4.维护性好 5.代码冗余率低 了解了po模式及 ...

  4. 3分钟手把手带你搭建基于selenium的自动化框架

    1 .什么是seleniumSelenium 是一个基于浏览器的自动化工具,它提供了一种跨平台.跨浏览器的端到端的web自动化解决方案.Selenium主要包括三部分:Selenium IDE.Sel ...

  5. Selenium基于Python web自动化基础二 -- 免登录、等待及unittest单元测试框架

    一.免登录在进行测试的过程中难免会遇到登录的情况,给测试工作添加了工作量,本文仅提供一些思路供参考解决方式:手动请求中添加cookies.火狐的profile文件记录信息实现.人工介入.万能验证码.去 ...

  6. 自动化框架的两种断言设计(pytest 版)

    自动化测试断言失败时,根据不同业务场景,可能需要立即终止或继续执行.这里以 Appium + pytest 为例. 一. 断言失败立即终止 用途一:用例的预期结果是其他用例的前提条件时,assert ...

  7. net.sz.framework 框架 轻松搭建服务---让你更专注逻辑功能---初探

    前言 在之前的文章中,讲解过 threadmodel,socket tcp ,socket http,log,astart ,scripts: 都是分片讲解,从今天开始,将带大家,一窥 net.sz. ...

  8. ShutIt:一个基于 Python 的 shell 自动化框架

    ShutIt是一个易于使用的基于shell的自动化框架.它对基于python的expect库(pexpect)进行了包装.你可以把它看作是“没有痛点的expect”.它可以通过pip进行安装. Hel ...

  9. 前端Js框架 UI框架汇总 特性 适用范围 选择

    身为一个资深后端工程师,面对层出不穷的前端框架,总让人眼花缭乱,做一个综合解析贴,从全局着眼,让我们明白各种前端框架的应用范围,为如何选择前端框架,从不同的维度提供一些线索,做为一个长期优化贴,欢迎指 ...

随机推荐

  1. 【bug录】安装项目编译环境bug录

    安装mySQL是遇到一些问题: 刚开始按照教程配置int文件,看着图标没有显示正确,把隐藏文件夹后缀名去掉, mysql由两种版本,zip和msi格式,我用的是zip格式,mysql后进行解压,记住解 ...

  2. build设计模式

    又叫生成器模式 public class MainActivity extends AppCompatActivity { TextView textView; Button button; prot ...

  3. 解决Linux-Centos7启动Mysql服务失败丢失mysql.sock问题

    在新安装mysql后进行启动发现报错 mysql启动服务命令 systemctl start mysqld@3306 Starting mysqld (via systemctl):  Job for ...

  4. 20202405李昕亮《BASE64编码》

    BASE64编码 20202405李昕亮 参考网址: 1.https://baike.baidu.com/item/base64/8545775?fr=aladdin 2.https://blog.c ...

  5. 【Java GC系列】垃圾收集简介(1)

    说明: 在本文中, Garbage Collection 翻译为 "垃圾收集", garbage collector 翻译为 "垃圾收集器"; 一般认为, 垃圾 ...

  6. Python爬虫实战详解:爬取图片之家

    前言 本文的文字及图片来源于网络,仅供学习.交流使用,不具有任何商业用途,版权归原作者所有,如有问题请及时联系我们以作处理 如何使用python去实现一个爬虫? 模拟浏览器请求并获取网站数据在原始数据 ...

  7. 浅谈 Tarjan 算法

    目录 简述 作用 Tarjan 算法 原理 出场人物 图示 代码实现 例题 例题一 例题二 例题三 例题四 例题五 总结 简述 对于初学 Tarjan 的你来说,肯定和我一开始学 Tarjan 一样无 ...

  8. Raft算法原理剖析

    一.复制状态机(replicated state machine) Raft协议可以使得一个集群的服务器组成复制状态机,在详细了解Raft算法之前,我们先来了解一下什么是复制状态机.一个分布式的复制状 ...

  9. Liquibase+SpringBoot的简单使用笔记!update+rollback

    该笔记记录了springboot整合liquibase之后,如何根据liquibase ChangeLogFile对数据库进行修改以及回滚操作 参考: baeldung.com JHipster 1. ...

  10. idea 远程debug springboot

    idea 远程debug springboot 1.新建一个springboot工程. 新建一个controller接口 @RestController @RequestMapping public ...