一、概要

前面介绍了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文档就会了,比较简单
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模式,断言(如何更简便逻辑的写测试代码)的更多相关文章

  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. C# 编译器对局部变量的优化

    C# 编译器对局部变量的优化 C# 的编译器可以对代码进行优化,所以,我们在写代码的时候,可以更多地考虑一下代码的易读性问题. 不考虑基本的对齐和换行美化.看一下局部变量优化问题. C# 示例代码 例 ...

  2. 八皇后问题-recall算法

    #!/usr/bin/env python3# -*- coding: utf-8 -*-import numbersimport numpyimport math'''八皇后为题:在国际象棋棋盘上摆 ...

  3. Day12 HTML知识

    1.html初识 超文本标记语言(Hypertext Markup Language,HTML)通过标签语言来标记要显示的网页中的各个部分.一套规则,浏览器认识的规则 浏览器按顺序渲染网页文件,然后根 ...

  4. 通过Azure bot framework composer 设计一个AI对话机器人bot(查询天气)

    本文介绍通过机器人框架设计器 (Bot framework composer)接近拖拉拽的方式设计一个聊天机器人,该聊天机器人的主要功能是发起http请求查询天气.当然,稍微变通下,可以用来查询几乎任 ...

  5. 我用 Python 撸了一个 plist 图集拆图工具!附上github源码

    这些年,我一直在使用 JavaScript .CocosCreator 做开发,只要是他们不能解决的,我都不太愿意去弄,或者说是不太情愿去做.真的是手中有把锤子,看什么都是钉子,越是熟悉一样东西,越容 ...

  6. [Luogu P2831] 愤怒的小鸟 (状压DP)

    题面: 传送门:https://www.luogu.org/problemnew/show/P2831 Solution 首先,我们可以先康一康题目的数据范围:n<=18,应该是状压或者是搜索. ...

  7. Dapr实现分布式有状态服务的细节

    Dapr是为云上环境设计的跨语言, 事件驱动, 可以便捷的构建微服务的系统. balabala一堆, 有兴趣的小伙伴可以去了解一下. Dapr提供有状态和无状态的微服务. 大部分人都是做无状态服务(微 ...

  8. 力扣 - 768. 最多能完成排序的块II

    目录 题目 思路 代码实现 复杂度分析 题目 这个问题和"最多能完成排序的块"相似,但给定数组中的元素可以重复,输入数组最大长度为2000,其中的元素最大为10**8. arr是一 ...

  9. XDG0062 XAML 与XDG0008 XAML 错误的解决办法

    昨天在使用wpf开发系统的时候,突然出现了错误(其实也不能称为错误,就是打开XAML文件时,在解决方案管理器中出现错误提示,XAML编辑文档出现波浪线的提示 The XAML designer dis ...

  10. 生活tips_织毛衣

    生梨润肺化痰好,苹果止泻营养高. 黄瓜减肥有成效,抑制癌症猕猴桃. 番茄补血助容颜,莲藕除烦解酒妙. 橘子理气好化痰,韭菜补肾暖膝腰. 萝卜消食除胀气,芹菜能治血压高. 白菜利尿排毒素,菜花常吃癌症少 ...