PlayWright 工具(一)
🍰 2020年微软开源的UI自动化测试工具, 支持Node.js、Python、Java等,满足端到端测试创建,支持现代渲染引擎。
1 浏览器操作
1 | |
1-1 API
- API
- Playwright支持两种运行方式:同步和异步。
- 同步运行指的是程序按照顺序执行,每个任务必须等待上一个任务完成后,才能进行下一个任务。
- 异步运行指的是程序可以同时执行多个任务,不需要等待上一个任务完成,就能进行下一个任务。
- 官网地址:https://playwright.dev/python/。
- Playwright支持两种运行方式:同步和异步。
(1) 同步运行
1 | |
(2) 异步运行
1 | |
1-2 上下文
- 上下文
- Playwright的测试层级关系:
Broswer > Context > Page。 browser = playwright.chromium.launch():启动浏览器。context = browser.new_context():创建context对象,即启动上下文。- context之间相互隔离,即为轻量级的浏览器实例,不与其他浏览器上下文共享cookie或缓存。
- 如果需要不同用户登录同一个网页,不用创建多个浏览器实例,只需要创建多个context即可。
context.add_cookies([cookie_object1, cookie_object2]):添加cookie。- 配置选项:无痕模式启动浏览器适合自动化测试、非无痕模式启动适合爬数据。
- launch_persistent_context参数
- user_data_dir:用户数据目录,此参数必须,可自定义目录,不推荐写Chrome安装目录。
- 网站是否可以保持登录,主要看cookies有效期,有些网站关闭浏览器登录状态就失效。
- 例如银行网站,有些博客站,登录后cookies一直生效,即利用缓存的cookies保持登录。
- channel:指定浏览器的类型,默认chromium,支持chromium、chrome、msedge。
- 若同时打开多个浏览器,每个浏览器登录不同的账号进行操作,则要用到多线程。
- user_data_dir:用户数据目录,此参数必须,可自定义目录,不推荐写Chrome安装目录。
- 测试在浏览器上下文的隔离全新环境中执行,隔离模型提高了可重复性,并防止级联测试失败。
- Playwright使用BrowserContext实现测试隔离,相当于隐身式配置文件。
- 测试隔离有两种不同的策略,从头开始清理,以及在两者之间进行清理。
- Playwright的测试层级关系:
1 | |
(1) 添加权限
1 | |
(2) 无痕模式
1 | |
(3) 非无痕模式
1 | |
(4) 同浏不同标签
1 | |
(5) 不同浏同标签
1 | |
1-3 无头模式
- 无头模式
- 默认情况下,Playwright是以headless无头模式运行浏览器的。
headless=False在启动浏览器时传递标志,可查看浏览器UI。
1 | |
1-4 截图使用
- 截图使用
- 除截取当前屏幕外,还支持截取长图,也可对某个元素截图。
- 快速截图方法:
page.screenshot(path="screenshot.png")。 - 截取单元素方法:
page.locator().screenshot(path="screenshot.png")。 - 捕获图片数据流:
print(base64.b64encode(page.screenshot()).decode())。 - 截取长图方法:
page.screenshot(path="screenshot.png", full_page=True)。
1 | |
1-5 视频录制
1 | |
1-6 弹出窗口
- 弹出窗口
- 页面中,通过链接打开一个弹出窗口,可以通过监听页面上的事件
target="_blank"来获取引用。 - 处理弹出窗口时,可以选择监听此特定事件,以便更精确地捕获与当前页面关联的弹出窗口信息。
- 页面中,通过链接打开一个弹出窗口,可以通过监听页面上的事件
1 | |
1-7 切换标签页
1 | |
(1) 遍历page对象
1 | |
(2) title和url判断
1 | |
1-8 浏览器窗口
1 | |
- 窗口最大化
- 启动浏览器时,通过参数
args=['--start-maximized']开启最大化。 - 并设置
no_viewport参数为True,否则默认按800*600像素创建窗口。 - 若不是通过context上下文创建的page对象,可以直接将viewport参数写到
new_page()里。
- 启动浏览器时,通过参数
1 | |
1-9 特定设备打开
1 | |
2 页面元素定位
- 页面元素定位
- 选择器(Selector):用于创建定位器的字符串。
- CSS和XPath
- 通过CSS选择器、XPath选择器,依据元素属性、标签名、文本内容等特征来定位元素。
- 操作元素可使用定位器(Locator)先定位再操作,也可直接定位方法后再传选择器(推荐)。
- 文本内容:指定元素所包含的文本内容,可以找到对应的元素。
- 属性:指定元素的某个属性及其对应的值,可以唯一地定位到元素。
- 坐标:通过指定元素在页面中的x和y坐标,可以精确地定位到元素。
- 元素层级关系:通过元素的父元素、子元素、相邻元素等关系来确定元素的位置。
- CSS和XPath
- 定位器(Locator):Playwright自动等待和重试能力的核心部分。
- 输入文字:fill()是填写表单字段的最简方法、type()键入字符。
- 鼠标点击click()、拖放drag_to()、下拉框选择select_option()。
- iframe定位、单选与复选set_checked()、聚焦给定元素focus()。
- 选择器(Selector):用于创建定位器的字符串。
2-1 选择器
- 选择器
- CSS和XPath
- 浏览器F12开发者工具,Elements中鼠标选中元素右键可以Copy选择器或XPath内容。
page.fill('css=#kw', 'Playwright')、page.click('xpath=//*[@id="su"]')。page.fill('#kw', 'Playwright')、page.click('//*[@id="su"]')(前缀可不写)。- 长CSS或XPath链容易不稳定,选择器绑定到DOM,结构发生变化时选择器可能会中断。
- 文本内容
- Playwright封装了两种text文本定位的方式。
page.click("text=xxx"):无引号,模糊匹配,对大小写不敏感。page.click("text='xxx'"):有引号,精确匹配,对大小写敏感。
- 除了支持定位a标签,还可以定位button按钮、input标签的button按钮。
- Playwright封装了两种text文本定位的方式。
- CSS和XPath
(1) CSS和XPath
1 | |
(2) 文本定位a标签
1 | |
(3) 文本定位button
1 | |
(4) 获取内容与文本
1 | |
(5) 获取输入框的值
1 | |
(6) 选择器组合定位
1 | |
2-2 定位器
- 定位器
- 过滤定位器:
locator.filter()可以对locator定位到的元素进行筛选过滤。count():统计元素的个数。first:定位多个时,匹配第一个。last:定位多个时,匹配最后一个。nth():定位多个时,根据索引定位元素。
- Locator定位机制与元素句柄ElementHandle
locator()是定位当前页面元素,不会自动等待,若结合click等方法,会自动等待处于可操作状态。- JavaScript中ElementHandle即页内DOM元素,ElementHandles使用page.query_selector()方法创建。
- Locator和ElementHandle之间的区别在于后者指向特定元素,而Locator捕获元素,检索元素的逻辑。
- 不鼓励使用ElementHandle,而是使用Locator对象和网络优先断言。
- Selenium采用的是HTTP协议,获取的元素句柄是固定的,不能实时去获取页面上的元素。
- Playwright采用Websocket协议,可实时获取页面元素,DOM结构变化时也能重新获取到。
page.get_by_role()- 优先考虑通过显式和隐式可访问性属性进行定位具有可访问性特征的元素。
- 显式可访问性属性,指开发人员明确地为元素设置的属性,具有描述元素及其功能的可访问性信息。
- 隐式可访问性属性,根据元素的其他属性和内容推断可访问性信息,而非特定设置为可访问性属性。
- 可以考虑将鼠标悬停在定位器指向的元素上,再点击定位器所指向的元素,底层DOM元素将被定位两次。
- 创建定位器的方法也可用于Locator类和FrameLocator类,支持将其链接起来并迭代地缩小定位器的范围。
- Locator类定位页面上的元素,
page.locator()、ElementHandle.locator()、locator.nth()。 - FrameLocator类定位页面上的框架(iframe),方法有
page.frame_locator()、locator.frame()。
- Locator类定位页面上的元素,
- 考虑DOM结构,也可以通过隐含角色定位元素。
- 角色定位器包括按钮、复选框、标题、链接、列表、表格等。
- 且定位遵循ARIA角色、ARIA属性和可访问名称的W3C规范。
- 优先考虑通过显式和隐式可访问性属性进行定位具有可访问性特征的元素。
page.get_by_text():文本内容定位,非交互式元素如div、span、p等。page.get_by_title():通过标题title的属性定位元素。page.get_by_label():通过关联标签的文本定位元素。page.get_by_test_id():依据data-testid属性定位元素。page.get_by_alt_text():依据替代文本来进行图像定位,例如img、area元素。page.get_by_placeholder():定位无标签但具有占位符文本的表单元素时使用。
- 过滤定位器:
1 | |
(1) 过滤链式定位
1 | |
(2) get_by_role()
1 | |
(3) get_by_text()
1 | |
(4) get_by_title()
1 | |
(5) get_by_label()
1 | |
(6) get_by_test_id()
1 | |
(7) get_by_alt_text()
1 | |
(8) get_by_placeholder()
1 | |
2-3 输入文字
- 输入文字
locator.fill()是填写表单字段的最简单方法,适用于<input>、<textarea>、[contenteditable]。- 大多时候,
locator.fill()会正常工作,如果页面上有特殊的键盘处理,只需要使用locator.type()。
1 | |
(1) 同步输入
1 | |
(2) 异步输入
1 | |
2-4 鼠标点击*
- 鼠标点击
locator.click()(单击)、locator.dbclick()(双击)、locator.click(button="right")(右击)。locator.click(modifiers=["Shift"])(Shift+鼠标左键单击操作)、locator.hover()(鼠标悬停)。locator.click(position={ "x": 0, "y": 0})(模拟在指定坐标位置处,进行鼠标左键点击的操作)。- 相比Selenium,不用自定义轮询等待,不用判断元素是否隐藏,元素在视图中也不需要手动设置滚动。
1 | |
2-5 拖放操作*
- 拖放操作
- 使用
locator.drag_to()执行拖放操作,需要进行如下步骤。- 将鼠标悬停在要拖动的元素上,按住鼠标左键不放。
- 将鼠标移动到将接收放置的元素上,松开鼠标左键。
- 如果想要精确地控制拖放操作,需使用如下较低级别的方法。
page.locator(selector).hover():悬停在页面元素上。page.mouse.down()按下鼠标,button="middle"按住鼠标的中间位置,page.mouse.up()释放鼠标。page.mouse.move()把鼠标放到指定的x和y坐标位置(即绝对坐标位置,selenium使用相对偏移位置)。
- 使用
1 | |
2-6 iframe定位
- iframe定位
- iframe即一个html嵌套了另一个html,最简单的识别方法就是看定位元素外层有没iframe标签名。
- frame与iframe都用于表示页面框架,iframe特指嵌入式框架,而frame可以表示主框架或子框架。
page.main_frame:获取page对象本身的frame对象。frame.child_frames:获取frame下的子frame对象。page.frames:获取page对象全部iframes,包含page本身的frame对象。
page.frame_locator(selector):仅查找页面中,第一个匹配的frame对象。frame_locator().first:定位多个时,匹配第一个。frame_locator().last:定位多个时,返回最后一个。frame_locator().nth(index):定位多个时进行索引。
page.locator(selector).frame_locator(selector):允许在指定frame内查找元素,可操作多个frame。page.frame(name, url):通过page对象直接定位iframe对象,传入name参数或传入url参数,说明如下。- name属性不能模糊匹配,只能精确匹配字符串。
- iframe没有name属性时,可以使用id属性来定位。
- url属性值,即页面上看到的src属性,支持模糊匹配。
- iframe上的动态id非固定,可使用css的正则匹配元素属性,也可使用xpath的contains包含元素属性。
$('[name^="value"]'):匹配name以value开头的元素。$('[name$="value"]'):匹配name以value结尾的元素。$('[class*="value"]'):匹配class属性包含value的元素。
page.frame():返回的对象能直接使用fill()和click方法。page.frame_locator(selector):返回的对象只能用locator()方法定位元素,然后click()等操作。
page.query_selector(selector).content_frame():通过query_selector定位元素,再切换到iframe对象上。- 多层iframe需要一层一层定位,若需要在iframe上执行js代码,必须使用
page.frame()方法定位到iframe对象。 - 才有
iframe.evaluate(js)方法执行js,而page.frame_locator()方法只能定位操作元素,没有执行js的方法。
1 | |
2-7 下拉框选择
- 下拉框选择
- 使用
locator.select_option()选择元素中的一个选项或者多个选项,可以指定value或label来选择。 - 先定位select元素再定位选项(根据选项名称、index索引、label标签定位)、通过page对象直接调用。
- 使用
(1) select_option.py
1 | |
(2) select_option.html
1 | |
2-8 单选与复选
- 单选与复选
locator.set_checked()选中和取消选中单复选框的最简单方法。locator.check()选中,locator.uncheck()不选。locator.click()点击,locator.is_checked()断言是否被选中。- 上述方法都适用于
input[type=checkbox]和input[type=radio]。
(1) set_checked.py
1 | |
(2) set_checked.html
1 | |
2-9 聚焦给定元素
- 聚焦给定元素
- focus()主要用于模拟用户与网页元素的交互。
- 确保正确的元素处于活动状态,以便执行相应操作。
- 通常用于交互性测试、表单输入,或者键盘事件上。
1 | |
3 等待和定时器
- 等待和定时器
- 等待
locator.wait_for():在延迟加载的页面中等待元素可见,可等待页面加载完成后再执行操作。chromium.launch(headless=False, slow_mo=50):可能会增加执行时间。- 将减慢浏览器的执行速度,slow_mo的单位为毫秒,作用范围是全局的。
- 从启动浏览器到操作元素每个动作都会有等待间隔,方便查看操作情况。
locator.click()和locator.fill():自动等待元素可见,可简化代码,但可能导致超时异常。page.wait_for_timeout(5000):等待一定时间后再执行操作,设置时间过长可能影响执行效率。
- 定时器:使用Python的asyncio库来创建异步定时任务。
- timeout等待超时,默认30秒,传递0将超时时间设为无限大,指不会主动超时,会一直等待直到条件满足。
page.set_fault_navigation_timeout、browser_context.set_fault_timeout()。page.set_fault_timeout()、browser_context.set_fault_navigation_timeout()。
- 等待
3-1 等待元素
1 | |
3-2 自定义等待
1 | |
3-3 定时器操作
1 | |
3-4 timeout等待超时
1 | |
4 弹窗或对话框
- 弹窗或对话框
- Playwright支持监听dialog事件,JavaScript对话框包括alert、beforeunload、confirm、prompt。
- 侦听器必须使用
dialog.accept()或dialog.dismiss()操作对话框。 - 否则页面将冻结等待对话框,并且无法进行单击、搜索等下一步操作。
- 侦听器必须使用
- 部分场景应用时,可能弹出一些麦克风或摄像头的权限框,通过监听alert没法捕获到。
- 可以给浏览器配置默认允许麦克风和摄像头等权限,不让弹窗出来。
- 使用context的
grant_permissions()方法添加麦克风或摄像头权限。
- Playwright支持监听dialog事件,JavaScript对话框包括alert、beforeunload、confirm、prompt。
4-1 alert_box.py
1 | |
4-2 alert_box.html
1 | |
5 模拟键盘操作
- 模拟键盘操作
locator.press()方法:可以聚焦所选元素,并产生单个击键。- 接受在键盘事件的keyboardEvent.key属性中发出的逻辑键名称。
- Backquote、Minus、Equal、Backslash、Backspace、Tab、Delete、Escape、ArrowDown、End、Enter。
- Home、Insert、PageDown、PageUp、ArrowRight、ArrowUp、F1-F12、Digit 0-9、Key A-Z、Key a-z。
1 | |
6 文件上传和下载
- 文件上传和下载
- 文件上传
- 文件上传是input输入框,并且类型是
type="file"情况时,使用locator.set_input_files()。 - 如果不是input输入框且必须点开文件框的情况下,使用
page.expect_file_chooser()进行监听。 - 点击选择文件按钮时,自动触发操作,则使用
page.on("filechooser", )监听filechooser事件。
- 文件上传是input输入框,并且类型是
- 文件下载:当浏览器上下文关闭时,所有属于浏览器上下文的下载文件都会被删除。
- 文件上传
6-1 文件上传
- 文件上传
locator.set_input_files():用于设置文件输入框的文件路径。- 模拟向文件输入框中填充文件路径,以实现文件上传的自动化操作。
- 该方法接受一个文件路径参数,指定一个或多个文件路径进行上传。
- 操作方法
file_chooser.page:返回此文件选择器所属的页面。file_chooser.element:返回与此文件选择器关联的输入元素。file_chooser.is_multiple():判断此文件选择器是否接受多个文件。
(1) upload_file.py
1 | |
(2) upload_file.html
1 | |
6-2 文件下载
- 文件下载
download.cancel():取消下载。download.delete():删除下载文件,如有必要,将等待下载完成。download.failure():返回下载错误,如有必要,将等待下载完成。download.path():下载成功将返回文件的路径,如有必要,将等待下载完成。download.suggested_filename:获取建议文件名,下载的文件名是随机GUID。
(1) download_file.py
1 | |
(2) download_file.html
1 | |
7 错误处理和调试
- 错误处理和调试
- 异常处理:一种常见的错误处理机制,使用try-except代码块捕获和处理可能出现的异常。
- 控制台调试定位
- 使用
page.pause()进入断点状态,浏览器F12开发者工具打开Console页面调试定位。 - 还可以使用Playwright Inspector工具,来开启录制,页面操作生成对应的元素和步骤。
- Playwright Inspector可使用命令行启动,如:
playwright codegen http://xxx.com/。 - Playwright Inspector的Pick locator可在浏览器上选需定位的元素,生成对应的locator。
- 录制相关命令
playwright codegen --viewport-size=800,600 http://xxx.com/。playwright codegen --lang="it-IT" http://xxx.com/:模拟语言。playwright codegen --color-scheme=dark http://xxx.com/:模拟配色。playwright codegen --timezone="Europe/Rome" http://xxx.com/:模拟时区。playwright codegen --geolocation="41.890221,12.492348" http://xxx.com/:模拟地理位置。playwright codegen --device="iPhone 11":模拟移动设备iPhone11,device值必须双引号且区分大小写。playwright open --load-storage=auth.json:打开Playwright上下文并加载存储数据文件以保留会话状态。playwright codegen --load-storage=auth.json:在生成代码时加载存储数据,以保持与之前会话的连续性。playwright codegen --save-storage=auth.json http://xxx.com/:用于生成代码时将存储数据保存到文件中。
- console页面语法
playwright.selector(element):为给定元素生成选择器。playwright.$$(selector):类似于playwright.$,但是会返回全部的匹配元素。playwright.$(selector):使用实际的Playwright查询引擎查询Playwright选择器。playwright.locator(selector):使用实际的Playwright查询引擎查询Playwright元素。playwright.inspect(selector):元素面板中显示元素(需相应浏览器的DevTools支持)。
- 使用
- 高亮定位与调试:为清楚当前定位方式在页面上找到哪些元素,可以使用highlight()高亮定位元素。
7-1 异常处理
1 | |
7-2 控制台调试定位
1 | |
7-3 高亮定位与调试
1 | |
8 console事件监听
- console事件监听
page.on("console", handler):监听特定页面的Console事件,传入处理函数handler。cdpSession.on("Console.messageAdded", handler):监听CDP会话上的Console事件。- 后者可在不同页面间共享同一个Chrome DevTools Protocol(CDP)会话,并监听该会话下的Console事件。
- 监听Console事件后,可执行以下操作。
page.on("console", handler)或cdpSession.on("Console.messageAdded", handler)添加相应事件监听器。page.remove_listener("event", print_request_finished)可用来删除已添加的特定页Console事件监听器。- 目前没有删除CDP会话的特定事件监听器方法,使用创建新的CDP会话事件监听器来替代旧的,以达删除目的。
- 如果某个事件需要处理一次,可使用
page.once("console", handler)添加一次性事件,该方法针对page页面对象。
1 | |
PlayWright 工具(一)
https://stitch-top.github.io/2023/09/09/zi-dong-hua/at05-playwright/at01-playwright-gong-ju-yi/