参考文件

官方文档:https://playwright.dev/docs/intro GitHub链接:https://github.com/microsoft/playwright-python

Playwright简介

Playwright Test是专门为满足端到端测试的需求而创建的。Playwright支持所有现代搜索引擎,包括Chrome、WebKit和Firefox。在Windows、Linux和macOS上测试,使用Android和mobile Safari的Google Chrome原生移动模拟进行测试。

环境安装

安装python环境 Playwright安装 使用pip install playwright命令进行安装 使用playwright install命令进行各种工具包和依赖,有报错,我们先不管,继续往下走 安装pytest插件:pip install pytest-playwright

简单跑一个demo,发现报错了,我们换一种执行方式

我们使用pytest命令执行发现没有报错

Playwright的自带工具

Playwright codegen 我们在pycharm中使用终端,输入该命令,之后,就会启用被测浏览器,并且启用inspector记录操作的脚本

Playwright inspector 之后我们可以将inspector里面的代码复制到pycharm里面自己编辑了

当然,我们也可以针对某个浏览器的网址,比如说https://www.baidu.com/

回车之后,浏览器自动启动一个标签,以及一个inspector来记录操作代码

也可以固定浏览器某个窗口的大小进行操作

Playwright codegen --viewport-size=800,600 www.baidu.com

访问移动端手机浏览器,比如说苹果13

Playwright codegen --device=“iPhone 13” www.baidu.com

帮助我们自动记录和管理cookie信息

首先我们使用如下命令Playwright codegen --save-storage=auth.json work-be.test.mi.com/main-buildstore/home/address:8000 然后浏览器启动一个窗口

接下来我们自动输入密码,如下: 之后,我们把启动的浏览器关掉 接下来,我们再次使用如下命令再次回车 Playwright codegen --load-storage=auth.json work-be.test.mi.com/main-buildstore/home/address:8000

浏览器会再次启动一个新窗口,但是此窗口浏览器的地址我们可以看到是登录状态的 Trace Viewer是Playwright的另一个神器,顾名思义就是痕迹查看,也就是我们后期可以查看我们之前都操作了哪些地方

Playwright架构技术介绍

Playwright是由Puppeteer-https://puppeteer.bootcss.com/改造过来的,Puppeteer 是一个 Node 库,它提供了一个高级 API 来通过 DevTools 协议控制 Chromium 或 Chrome。Puppeteer 默认以 headless 模式运行,但是可以通过修改配置文件运行“有头”模式。再加上,Playwright官方没有给出架构图,所以我们可以参考Puppeteer的架构图来学习Playwright 首先我们可以通过Puppeteer来控制浏览器的,他是通过谷歌开发者协议,简称CDP,该协议是建立在WebSocket协议之上 这里的Brower其实是一个浏览器实例,一个浏览器可以包含很多个上下文,也就是包含很多Context,通俗来讲,就跟我们打开了一个谷歌浏览器,又开启了一个无痕模式浏览器一样,Brower的Context具有独立的Session,cookie&cache 一个Context可以包含很多个Page页面,一个Page是一个独立页面 一个Page可以包含很多个Frame,一个Frame可以理解为是一个框架,可以包含多个子框架 再往下就是ExecutionContext,它是javascript的执行环境,每一个Frame都有一个默认的javascript的执行环境 在Playwright中,这些概念也是一样的

第一个Playwright脚本

from playwright.sync_api import sync_playwright

def test_pla():

with sync_playwright() as p:

#实例化一个浏览器,使用谷歌为例

#代码运行默认是无头模式运行,如果要看运行效果,可以加入参数headless

browser = p.chromium.launch(headless=False)

#实例化一个页面

page = browser.new_page()

#打开一个网站

page.goto("https://www.bilibili.com")

#打印网页标题

print(page.title())

#关闭浏览器

browser.close()

运行之后:

Playwright浏览器控制

谷歌官方相关命令地址:https://peter.sh/experiments/chromium-command-line-switches/

from playwright.sync_api import sync_playwright

def test_pla():

with sync_playwright() as p:

#实例化一个浏览器,使用谷歌为例

#代码运行默认是无头模式运行,如果要看运行效果,可以加入参数headless

#--start-maximized表示窗口最大化,no_viewport表示的是默认窗口大小失效

#slow_mo表示的是每一步操作,默认等待3s

browser = p.chromium.launch(headless=False,args=["--start-maximized"],slow_mo=3000)

#实例化一个页面

page = browser.new_page(no_viewport=True)

#打开一个网站

page.goto("https://www.zhihu.com")

#打印网页标题

print(page.title())

#点击开通机构号

page.get_by_text("开通机构号").click()

#后退

page.go_back()

#前进

page.go_forward()

#刷新

page.reload()

#关闭浏览器

browser.close()

Playwright浏览器启动参数详解

executable_path——数据路径 channel——指定使用哪种浏览器 args——参数数组 ignore_default_args——忽略默认参数,慎用,使用不当,脚本无法执行 timeout——等待浏览器实例启动的最长时间,单位毫秒,一般是30s,设置为0,功能失效 headless——有头和无头模式运行的设置 traces_dir——数据报错路径 chromium_sandbox——是否启动谷歌沙盒浏览器 等等,基本所有参数都是launch()函数里面的,可以自行查看

Playwright xpath元素定位

XML Path Language

from playwright.sync_api import sync_playwright

def test_pla():

with sync_playwright() as p:

#实例化一个浏览器,使用谷歌为例

#代码运行默认是无头模式运行,如果要看运行效果,可以加入参数headless

#--start-maximized表示窗口最大化,no_viewport表示的是默认窗口大小失效

#slow_mo表示的是每一步操作,默认等待3s

browser = p.chromium.launch(headless=False,args=["--start-maximized"],slow_mo=3000)

#实例化一个页面

page = browser.new_page(no_viewport=True)

#打开一个网站

page.goto("https://www.baidu.com")

"""

/:从根节点选取

//:从非根节点选取

*:任意节点选取

@:根据属性筛选

text():根据文本筛选

and:关联属性或者链接文本

[]:可以防止下标/属性/链接文本

.:选取当前节点

..:选取当前节点的父节点

contains:包含

"""

#使用单一属性定位, 点击百度首页设置按钮,使用text_content获取内容

t_1 = page.locator("//span[@name='tj_settingicon']").text_content()

print(t_1)

#多属性定位

t_2 = page.locator("//span[@id='s-usersetting-top' and @name='tj_settingicon']").text_content()

print(t_2)

#父节点定位

t_3 = page.locator('//div[@id="u1"]/span').text_content()

print(t_3)

#通过下标进行定位,新闻这个按钮

t_4 = page.locator('//div[@id="s-top-left"]/a[1]').text_content()

print(t_4)

#通过.和..来定位

t_5= page.locator('//a[@name="tj_fanyi"]/div/../../../../../a[1]').text_content()

print(t_5)

#通过文本定位

t_6 = page.locator('//a[text()="新闻"]').text_content()

print(t_6)

#通过模糊匹配定位

t_7 = page.locator('//a[contains(text(),"hao")]').text_content()

print(t_7)

#关闭浏览器

browser.close()

运行之后:

Playwright css定位

css定位方式有五种,分别是: id选择器 class选择器 元素选择器 属性选择器 层级选择器

from playwright.sync_api import Playwright, sync_playwright, expect

playwright = sync_playwright().start()

browser = playwright.chromium.launch(headless=False,slow_mo=2000)

page = browser.new_page()

page.goto("https://www.baidu.com/")

#id属性定位

page.locator("#kw").fill("playwright")

page.locator("#su").click()

page.go_back()

page.locator(".s_ipt").fill("playwright")

page.locator("#su").click()

page.go_back()

page.locator("input#kw").fill("playwright")

page.locator("#su").click()

page.go_back()

page.locator("div>form>span>input.s_ipt").fill("playwright") #层级关系

page.locator("#su").click()

browser.close()

Playwright特有定位方式

"""

特有元素定位方法

locator.get_by_alt_text(text,**kwargs), alt属性

locator.get_by_label(text,**kwargs),label属性

locator.get_by_placeholder(text,**kwargs),placeholder属性

locator.get_by_role(role,**kwargs),role属性

locator.get_by_text(text,**kwargs)

locator.get_by_title(text,**kwargs)

"""

Playwright元素常用操作

我们以该网页为例子进行测试 登陆页面,我们输入用户名、密码、验证码,点击登录

同时,我们介绍怎么处理iframe进行上传文件以及自动化,在上传文件中,我们要注意,每一个图片都有一个随机的字符串

所以我们可以使用父节点定位方式进行定位处理 “//*[@id=‘filePicker’]/div[2]/input” 接下来是图片的上传,图片我们先使用set_input_files函数,绝对路径处理,前面添加r r"C:\Users\jinlai\111.jpg" 具体代码如下:

from playwright.sync_api import Playwright, sync_playwright, expect

playwright = sync_playwright().start()

browser = playwright.chromium.launch(headless=False,slow_mo=2000)

context = browser.new_context()

page = browser.new_page()

page.goto("http://testingedu.com.cn:8000/Home/user/login.html")

#输入用户名

page.fill('//*[@id="username"]','13800138006')

#输入密码

page.fill('//*[@id="password"]','123456')

#输入验证码,这里做了处理

page.fill('//*[@id="verify_code"]','1111')

#点击登录

page.click('//*[@id="loginform"]/div/div[6]/a')

#进入个人信息页面

page.goto("http://testingedu.com.cn:8000/Home/User/info.html")

#点击图片

page.click('//*[@id="preview"]')

#点击点击选择图片按钮

page.frame_locator('//*[@id="layui-layer-iframe1"]').locator("//*[@id='filePicker']/div[2]/input").set_input_files(r"C:\Users\jinlai\111.jpg")

#点击确认使用

page.frame_locator('//*[@id="layui-layer-iframe1"]').locator("//div[@class='saveBtn']").click()

#点击页面的确认保存

page.click("//input[@class='save']")

#关闭浏览器

browser.close()

接下来我们看下拉框怎么处理

#下拉框收货地址处理,我们需要定位到要操作的输入框,然后根据内容属性处理即可

page.select_option('//*[@id="province"]',value='19280')

page.select_option('//*[@id="city"]',value='19281')

page.select_option('//*[@id="district"]',value='19283')

page.select_option('//*[@id="twon"]',value='19285')

from playwright.sync_api import Playwright, sync_playwright, expect

playwright = sync_playwright().start()

browser = playwright.chromium.launch(headless=False,slow_mo=2000)

context = browser.new_context()

page = browser.new_page()

page.goto("http://testingedu.com.cn:8000/Home/user/login.html")

#输入用户名

page.fill('//*[@id="username"]','13800138006')

#输入密码

page.fill('//*[@id="password"]','123456')

#输入验证码,这里做了处理

page.fill('//*[@id="verify_code"]','1111')

#点击登录

page.click('//*[@id="loginform"]/div/div[6]/a')

#打开地址管理页面

page.goto("http://testingedu.com.cn:8000/Home/User/address_list.html")

#点击增加新地址

page.click("//*[@class='co_blue']")

#点击并输入收货人

page.fill("//*[@name='consignee']","ceshi")

#点击并输入手机或者电话

page.fill("//*[@name='mobile']","13176358824")

#下拉框收货地址处理

page.select_option('//*[@id="province"]',value='19280')

page.select_option('//*[@id="city"]',value='19281')

page.select_option('//*[@id="district"]',value='19283')

page.select_option('//*[@id="twon"]',value='19285')

#点击并输入详细地址

page.fill("//*[@name='address']","凯胜家园小区2号楼2单元802")

#点击报错按钮

page.click("//*[@id='address_submit']")

#刷新页面

page.reload()

#删除新增的地址

page.click('//span[text()="ceshi"]/../..//a[text()="删除"]')

#关闭浏览器

browser.close()

如何获取多个元素

比如说获取所有搜索商品的名字 我们可以使用query_selector_all方法

goods = page.query_selector_all('//div[@class="shop-list-splb p"]//div[@class="shop_name2"]')

for good in goods:

print(good.text_content().strip()) #strip去除空格

具体代码如下:

from playwright.sync_api import Playwright, sync_playwright, expect

playwright = sync_playwright().start()

browser = playwright.chromium.launch(headless=False,slow_mo=2000)

context = browser.new_context()

page = browser.new_page()

page.goto("http://testingedu.com.cn:8000/Home/user/login.html")

#输入用户名

page.fill('//*[@id="username"]','13800138006')

#输入密码

page.fill('//*[@id="password"]','123456')

#输入验证码,这里做了处理

page.fill('//*[@id="verify_code"]','1111')

#点击登录

page.click('//*[@id="loginform"]/div/div[6]/a')

#进入地址管理页面

page.goto("http://testingedu.com.cn:8000/Home/User/address_list.html")

#点击搜索框输入内容

page.fill('//input[@class="search_usercenter_text"]','手机')

#点击搜索

page.click('//a[text()="搜索"]')

#query_selector_all方法获取所有元素

goods = page.query_selector_all('//div[@class="shop-list-splb p"]//div[@class="shop_name2"]')

for good in goods:

print(good.text_content().strip()) #strip去除空格

#关闭浏览器

browser.close()

运行结果之后: 页面上显示: 两者相对应。

Playwright元素常用操作

import re

from playwright.sync_api import Playwright, sync_playwright, expect

playwright = sync_playwright().start()

browser = playwright.chromium.launch(headless=False,slow_mo=5000)

context = browser.new_context()

page = browser.new_page()

page.goto("http://testingedu.com.cn:8000/Home/user/login.html")

#输入用户名

page.fill('//*[@id="username"]','13800138006')

#输入密码

page.fill('//*[@id="password"]','123456')

#输入验证码,这里做了处理

page.fill('//*[@id="verify_code"]','1111')

#点击登录

page.click('//*[@id="loginform"]/div/div[6]/a')

#进入产品站

page.goto("http://testingedu.com.cn:8000/Home/Goods/goodsInfo/id/55.html")

#点击加入购物车

page.click('//*[@id="join_cart"]')

#点击弹层叉号

page.click('//*[@class="layui-layer-ico layui-layer-close layui-layer-close1"]')

#鼠标悬停,我的购物车按钮,以及点击去购物车结算

page.hover('//span[text()="我的购物车"]')

page.click('//a[@class="c-btn"]')

#点击去结算

page.click('//a[text()="去结算"]')

#点击提交订单

page.click('//button[@class="checkout-submit"]')

#获取订单号,我们可以使用正则表达式获取

t = page.locator('//p[@class="succ-p"]').text_content()

print(t)

text = re.findall(r'\d{18}',t)[0]

print(text)

"""

接下来,我们进入到我的订单页面,点击我的订单的时候,我们发现打开了一个新的网页,在selenium中,是通过切换句柄实现的,而在playwright中,我们可以使用新的写法

"""

print("444")

with context.expect_page() as new_page_info:

page.click('a[target="_blank"]') #点击我的订单

new_page = new_page_info.value

new_page.wait_for_load_state()

print(new_page.title())

#点击取消订单,并格式化

new_page.click('//em[text()="{}"]/../..//a[text()="取消订单"]'.format(text))

#点击弹层里面的确定按钮

new_page.click('//*[@class="layui-layer-btn layui-layer-btn-"]/a[text()="确定"]')

#刷新页面

new_page.reload()

#关闭浏览器

browser.close()

Playwright自动化框架设计

Playwright作为一个新进的自动化特殊工具,在易用性方面做了很多工作。针对Playwright我们甚至可以不用做任何处理,把它当成一个封装好的第三方库去使用即可。 那么整体的框架又该怎么去设计呢?又该考虑哪些问题呢? 如果我们站在公司的角度上来说,公司层面需要打造一个通用性很强的自动化框架。也就是说a项目能用,b项目也能用。另外还需要将测试结果、测试过程等都完整的输出出来,这是基本条件。不然我们花了很多时间写代码,换一个项目就不能用了,几乎需要从头到尾的再写写一遍,那就没有任何意义。而测试人员都是拿结果的,画的结果越详细越好。除此之外,我们也应该考虑到,在一个公司写一个完整的框架和使用框架,不太可能是一个人去完成。我们需要考虑代码托管和持续集成等等问题。所以大体的思路呢便有了。我们也可以根据刚刚的这个思路细化出一个架构图来 我们可以将整体的架构,从上到下可以分成五个层次。一是数据层、服务层、对象层,用例层和输出层。 数据方面,为了拥有一定的适应性,我们可以设计框架,让它支持多种外部数据格式。如说新老版本的excel、yaml等等。 而服务层方面,因为需要针对excel文件的操作,所以需要自己去封装excel读写库等等。 对象层面,我们实际上是借助于PO思想进行设计就可以了。 用例方面主要是考虑用例该如何去组织,该如何去执行。 当然我们选择pytest,在用例执行的过程中,我们是需要进行日志和报告的输出的。所以我们需要封装日志,并且加入allure测试报告。最后我们需要考虑的是,在整个框架的实现过程中,可能某些第三方库有些人没有安装。为了让框架的执行更加简单一点,我们可以直接将整个框架打包到docker里面,这样去执行。就不用担心环境的问题了。框架设计好之后,我们可以打开pycharm,把目录结构呢大体的来设计一下。 我们新建一个工程。新建好之后呢,按照我们刚刚的设计思路,将整体的目录结构呢可以设置成下面这种样子。 首先我们新建一个python package,比如叫做common,在common中,我们要做的事情呢,一般就是把一些公共用的库在这儿。比如excel的读写啊、日志啊等等, 再新建一个package,比如叫做ddt。我们在利用外部文件来执行测试用例的时候呢,实际上就是一个数据驱动。那我们可以把数据驱动的一些执行的逻辑代码放到此处。 再接着我们需要存放文件。比如说我们的测试用例、日志结果等等,我们可以新建一个文件夹,叫做lib。在lib文件下我们可以再新建一个cases,用来存放用例,再新建一个日志的文件夹,log用于存放日志。 最后我们还可以将结果和报告单独的进行设计。result和report。为了运行方便,我们也可以在根目录下创建一个runner。运行入口,我们可以新建一个runner的文件。那么整体的结构呢我们就可以按照这种格式设计完成了

Playwright自动化框架之excel文件读取

直接上代码吧

import os

import openpyxl

class Reader:

"""

pip install openpyxl

读取excel数据文件

"""

def __init__(self):

"""

全局变量

"""

self.workbook = None

self.sheet = None

self.rows = 0

self.r = 0 #表示当前读取到的行数

def open_excel(self, srcfile):

"""

打开文件

:param srcfile:

:return:

"""

if not os.path.isfile(srcfile):

print("%s not exist" % (srcfile))

return

#设置读取文件使用编码

openpyxl.Workbook.encoding = 'utf-8'

self.workbook = openpyxl.load_workbook(filename=srcfile)

#默认从第一个sheet文件读取

self.sheet = self.workbook[self.workbook.sheetnames[0]]

self.rows = self.sheet.max_row

self.r = 0

return

def get_sheet(self):

"""

获取sheet名称

:return:

"""

sheets = self.workbook.sheetnames

return sheets

def set_sheet(self,name):

"""

切换sheet

:param name:

:return:

"""

self.sheet = self.workbook[name]

self.rows = self.sheet.max_row

self.r = 0

return

def readline(self):

"""

逐行读取文件数据

:return:

"""

lines = []

for row in self.sheet.rows:

line = []

for cell in row:

#如果是空行,添加一个空字符串

if cell.value is None:

line.append('')

else:

line.append(cell.value)

lines.append(line)

return lines

import os

from common.Excel import NewExcel

def get_reader(srcfile='') -> NewExcel.Reader:

reader = None

if not os.path.isfile(srcfile):

print("%s not exist" % (srcfile))

return reader

if srcfile.endswith('.xlsx'):

reader = NewExcel.Reader()

reader.open_excel(srcfile)

return reader

好了,先介绍这里吧~后面再更新哈哈

精彩链接

评论可见,请评论后查看内容,谢谢!!!
 您阅读本篇文章共花了: