【基于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

  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);
})

结果

原文地址:https://www.cnblogs.com/totoro-cat/p/11401482.html

时间: 2024-11-05 13:44:03

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

Android TV磁贴类app自动化框架二次改造(基于UiAutomator)

简介 项目一直是手工测试为主,加上一直是TV类应用,很多自动化工具都没有针对TV类项目做很好的适配,所以只有自己动手了.主要针对项目的特殊性进行了部分改造,不一定适用于其他项目.(涉及隐私,就不提供json文件和软件名字啦) 痛点 1.非标准控件的难处 通过uiautomatorviewer获取到的不一样的磁贴,属性全部相同(除了坐标点),意味着没法通过id和class+index方式获取,text属性为空,也就没有办法通过byText的方式获取uiobject,高度定制的磁贴,让自动化很为难,

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

1 .什么是seleniumSelenium 是一个基于浏览器的自动化工具,它提供了一种跨平台.跨浏览器的端到端的web自动化解决方案.Selenium主要包括三部分:Selenium IDE.Selenium WebDriver 和Selenium Grid: Selenium IDE:Firefox的一个扩展,它可以进行录制回放,并可以把录制的操作以多种语言(例如java,python等)的形式导出成测试用例. Selenium WebDriver:提供Web自动化所需的API,主要用作浏览

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

一.免登录在进行测试的过程中难免会遇到登录的情况,给测试工作添加了工作量,本文仅提供一些思路供参考解决方式:手动请求中添加cookies.火狐的profile文件记录信息实现.人工介入.万能验证码.去掉验证码 1.手动在请求中添加cookies信息 1 url = "http://www.baidu.com" 2 driver = webdriver.Firefox() 3 driver.get(url) 4 time.sleep(3) 5 #添加cookies的方式 6 7 c1 =

【前端自动化框架】TypeScript+Puppeteer+Jest 整合 (一)

前提:掌握Jest + Puppeteer 1.Jest环境配置 2.Jest-MATCHERS匹配器 3.Jest-全局变量设置 4.Puppeteer安装 5.Puppeteer元素获取 6.Puppeteer文本值获取 7.Puppeteer iframe切换 8.Puppeteer 拖拽 9.Puppeteer Js脚本执行 一 需要安装的插件 安装包 命令 TypeScript npm install typescript --save-dev Jest npm install jes

20170901 基于wsgi的web框架二

.wiz-code-container { position: relative; padding: 8px 0; margin: 5px 25px 5px 5px; text-indent: 0 } .CodeMirror { font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace; color: black; font-size: 0.83rem } .CodeMirror-lines { paddin

基于excel的自动化框架

设定项目文件大致结构 atp/: 项目名 conf/:存放配置文件 data/:存放sql文件 lib/: 存放项目的所有源代码. logs/:存放日志文件 uploads/:存放下载的文件 start.py: 程序启动脚本 readme.txt: 项目说明文件. case/:存放用例表 理清思路 基本思想与原则A: 数据很多,就放到一个列表或字典里: 用for语句,处理一条数据即可. 基本思想与原则B: 考虑是否传参,如何传参. 一般把要处理的对象作为参数传入. 1.有多个用例表,取所有的表到

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

前言 在之前的文章中,讲解过 threadmodel,socket tcp ,socket http,log,astart ,scripts: 都是分片讲解,从今天开始,将带大家,一窥 net.sz.framework 框架: net.sz.framework 框架分为java版本和C#.net 版本,两种语言版本保持高一致性: net.sz.framework 能做什么呢? net.sz.framework 是经过多年实践和研究,包括在线项目验证的底层框架,致力于解决框架问题: 让你更轻松,愉

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

ShutIt是一个易于使用的基于shell的自动化框架.它对基于python的expect库(pexpect)进行了包装.你可以把它看作是"没有痛点的expect".它可以通过pip进行安装. Hello World 让我们从最简单的例子开始吧.创建一个名为example.py的文件: import shutit session = shutit.create_session('bash') session.send('echo Hello World', echo=True) 运行这

Web自动化框架搭建——前言

1.web测试功能特性 a.功能逻辑测试(功能测试),这一块所有系统都是一致的,比如数据的添加.删除.修改:功能测试案例设计感兴趣和有时间的话可以另外专题探讨: b.浏览器兼容性测试,更重要的是体验这块,想提供建设性建议,是建立在业务场景.用户使用的深刻理解基础上,然后对产品目规划理解是否合理,提出自己的看法与想法:体验这块,一定要有一个比较全局的概念,换个意思说,就是应该站在产品经理的角度去看系统,看系统的各个子功能.各个子功能协调是否合理.是否还有更优建议.而不仅仅只局限一个界面.一个菜单.