一:实施的背景
相信使用过Selenium WebDriver的小伙伴对其最大的诟病有3点,一是浏览器的driver和版本对应问题,第二是Selenium的执行速度,最后一个槽点是对页面元素文本值的断言非常不便。在我们长期维护大量UI自动化测试用例的过程中这两个痛点会让我们耗费不少精力和时间。
二:PlayWright最佳实践
2.1为何要选择PlayWright?
对Selenium的痛点,PlayWright给出了完美的解决方案!
PlayWright的架构:
Playwright使用 Chrome DevTools 协议与 Chromium 通信。一旦触发测试,client端代码将被转换为JSON格式,然后使用websocket协议发送到服务器。
Playwright通过单个 websocket 协议连接传达所有请求,该连接将保持不变,直到所有测试执行完成。由于命令是在单个连接上发送的,因此测试失败或不稳定的可能性较小,并且命令可以快速执行。
Playwright启动速度比较快,拥有更多的定位方式,不需要安装驱动,能够在多个平台上运行,提供录制功能实现录制用例视屏,使用上来说Playwright也比较容易,无需过多封装即可直接使用.
2.2 环境部署
安装playwright前先配置好node和python环境,之后通过pip来安装playwright和其他库。
以Mac OS为例,执行如下命令:
安装playwright库
pip install playwright
然后安装browsers(会安装chromium,firefox,webkit浏览器)
playwright install
如果只想安装指定的browser,则执行如下命令
playwright install chromium
2.3 重要的名词
在开始尝试使用playwright之前,需要先了解它的几个重要概念。
Browser:是一个浏览器实例,代表一个浏览器会话。它是一个全局的上下文,可以包含多个 BrowserContext。
使用:创建浏览器实例管理浏览器生命周期:可以启动浏览器、关闭浏览器等。
from playwright.sync_api import Playwright
def test_api_show(playwright: Playwright):
browser = playwright.chromium.launch()
BrowserContext:是浏览器中的一个隔离环境,可以包含多个 Page。每个 BrowserContext有自己的浏览器存储,例如 cookies 和本地存储。
使用:创建新的上下文,管理上下文。可以添加页面、关闭页面等。
from playwright.sync_api import Playwright
def test_api_show(playwright: Playwright):
browser = playwright.chromium.launch()
context = browser.new_context()
Page:是浏览器中的一个标签页,可以进行页面导航、操作 DOM 元素、捕获页面截图等。
使用:导航页面,操作 DOM 元素,捕获页面截图,处理页面事件。
from playwright.sync_api import Playwright
def test_api_show(playwright: Playwright):
browser = playwright.chromium.launch()
context = browser.new_context()
page = context.new_page()
page.goto("")
2.4 元素定位
元素定位是PlayWright的核心部分,我们会详细演示常用方法的使用。
get_by_placeholder:根据页面元素的placeholder属性值定位。
以上图为例,我们想定位<销售机会名称>输入框可以使用get_by_placeholder方法。
page.get_by_placeholder("销售机会名称").fill("商机名称")
get_by_role:允许通过元素的ARIA角色、ARIA属性和可访问名称来定位它们。
初次使用get_by_role方法可能会有点懵,因为不知道元素的role该写为什么!
PlayWright官网上给出了role的类型:
role "alert" | "alertdialog" | "application" | "article" | "banner" | "blockquote" | "button" | "caption" | "cell" | "checkbox" | "code" | "columnheader" | "combobox" | "complementary" | "contentinfo" | "definition" | "deletion" | "dialog" | "directory" | "document" | "emphasis" | "feed" | "figure" | "form" | "generic" | "grid" | "gridcell" | "group" | "heading" | "img" | "insertion" | "link" | "list" | "listbox" | "listitem" | "log" | "main" | "marquee" | "math" | "meter" | "menu" | "menubar" | "menuitem" | "menuitemcheckbox" | "menuitemradio" | "navigation" | "none" | "note" | "option" | "paragraph" | "presentation" | "progressbar" | "radio" | "radiogroup" | "region" | "row" | "rowgroup" | "rowheader" | "scrollbar" | "search" | "searchbox" | "separator" | "slider" | "spinbutton" | "status" | "strong" | "subscript" | "superscript" | "switch" | "tab" | "table" | "tablist" | "tabpanel" | "term" | "textbox" | "time" | "timer" | "toolbar" | "tooltip" | "tree" | "treegrid" | "treeitem"
在上图销售机会新建页右上角,有<取消>和<保存>两个button组件。定位它们,可以用get_by_role。
page.get_by_role("button", name="保存").click()
上图中,销售阶段的下拉框选项值是一个div元素,除了xpath或者css-selector方式外很难想到其他发方式来定位到它。但是在PlayWright中,我们可以使用get_by_role来处理它,具体的代码如下:
//点击下拉框选项值的父级元素,即:div。
page.locator(parent_locator_path).locator("visible=true").click()
// 直接处理选项值,根据has_text=””来选中下拉选项值
page.get_by_role("listitem").filter(has_text=item_name).click()
get_by_text:根据包含的文本值定位元素。
page.locator('//div[@x-placement="bottom-start"]').get_by_text(model_name, exact=True).locator("visible=true").click()
locator:可以在定位器的子树中找到一个与指定选择器匹配的元素。它还可以过滤选项值。
locator可以接受任何形式定位方式,也就是说locator_path可以是id,xpath,css,role等。
locator(locator_path).locator("visible=true").click()
page.locator("locator_path", has_text="")
page.locator("locator_path", has_not_text="")
索引nth
大多数时候,我们会遇到在一个页面上存在多个类似元素的情况。如下图,页面中存在多个类似的元素,这种业务场景下,我们可以考虑先定位一组元素然后根据返回的元素列表的索引来定位到具体的组件。
relation_list =page.locator('//div[@class="field-input-block__suffix"]').locator("visible=true")
relation_list.nth(element_index).click()
filter: 这个方法根据选项缩小现有定位器的范围,例如按文本过滤。它可以被链接起来进行多次过滤。
page.get_by_role("listitem").filter(has_text=item_name).click()
本文节选自第七十九期《51测试天地》
《PlayWright实战》一文
想继续阅读全文或查看更多精彩内容,请点击下载:
版权声明:本文出自《51测试天地》第七十九期。51Testing软件测试网及相关内容提供者拥有51testing.com内容的全部版权,未经明确的书面许可,任何人或单位不得对本网站内容复制、转载或进行镜像,否则将追究法律责任。