《最新出炉》系列小成篇-Python+Playwright自动化测试-66 - 等待元素至指定状态(出现、移除、显示和隐藏)
1.简介
在我们日常工作中进行UI自动化测试时,保证测试的稳定性至关重要。其中一个关键方面是正确地定位和操作网页中的元素。在网页中,元素可能处于不同的状态,有些可能在页面加载完成之前不在DOM中,需要某些操作后才会出现,而其他元素可能一直存在于DOM中,但最初处于隐藏状态,需要通过操作才能使其出现进而处于可见状态。 因此如果在执行脚本时没有考虑到元素的状态,很可能导致脚本执行失败。为了保证自动化测试的稳定性,我们需要确保在执行操作之前,所需的元素已经达到了指定状态。
下面宏哥将介绍和分析讲解三种常用的元素等待方式:wait_for_timeout(),wait_for(),wait_for_selector() 和 wait_for_element_state()以及四者之间的优劣势。
2.强制等待
2.1wait_for_timeout()
wait_for_timeout()
方法会等待调用方法时指定的时间。
这个方法用于设置一个等待的超时时间,它允许程序在执行某些操作前等待指定的时间。如果在设定的时间内操作未完成,则可能会抛出超时错误。这种机制在编程中非常有用,尤其是在需要等待某个条件满足或资源可用时。例如,在使用playwright
进行网页自动化测试时,wait_for_timeout()
方法可以用来确保在继续执行操作之前,网页元素已经加载完成或处于可操作状态。如果元素未在给定的时间内加载完成,则可以通过捕获超时错误来处理这种情况,从而避免操作失败。官方定义的函数如下:
def wait_for_timeout(self, timeout: float) -> None:
"""Page.wait_for_timeout Waits for the given `timeout` in milliseconds. Note that `page.waitForTimeout()` should only be used for debugging. Tests using the timer in production are going
to be flaky. Use signals such as network events, selectors becoming visible and others instead. **Usage** ```py
# wait for 1 second
await page.wait_for_timeout(1000)
``` ```py
# wait for 1 second
page.wait_for_timeout(1000)
``` Parameters
----------
timeout : float
A timeout to wait for
""" return mapping.from_maybe_impl(
self._sync(self._impl_obj.wait_for_timeout(timeout=timeout))
)
3.自动等待
3.1.wait_for()
wait_for() 是先定位元素,再等待元素满足指定状态。先定位元素,再使用wait_for() 方法也可以等待元素到达指定的状态。
如果元素已满足条件,则立即返回。否则,它会等待直到超时时间到达为止。
该方法接受两个关键字参数:
timeout:指定最大等待时间(以毫秒为单位)。默认为 30000(30秒),但可以更改。
state:指定要等待的状态。默认为 ‘visible’。可以是 ‘attached’、‘detached’、‘hidden’ 或 ‘visible’ 中的一个。
官方定义的函数如下:
def wait_for(
self,
*,
timeout: typing.Optional[float] = None,
state: typing.Optional[
Literal["attached", "detached", "hidden", "visible"]
] = None
) -> None:
"""Locator.wait_for Returns when element specified by locator satisfies the `state` option. If target element already satisfies the condition, the method returns immediately. Otherwise, waits for up to
`timeout` milliseconds until the condition is met. **Usage** ```py
order_sent = page.locator(\"#order-sent\")
await order_sent.wait_for()
``` ```py
order_sent = page.locator(\"#order-sent\")
order_sent.wait_for()
``` Parameters
----------
timeout : Union[float, None]
Maximum time in milliseconds. Defaults to `30000` (30 seconds). Pass `0` to disable timeout. The default value can
be changed by using the `browser_context.set_default_timeout()` or `page.set_default_timeout()` methods.
state : Union["attached", "detached", "hidden", "visible", None]
Defaults to `'visible'`. Can be either:
- `'attached'` - wait for element to be present in DOM.
- `'detached'` - wait for element to not be present in DOM.
- `'visible'` - wait for element to have non-empty bounding box and no `visibility:hidden`. Note that element
without any content or with `display:none` has an empty bounding box and is not considered visible.
- `'hidden'` - wait for element to be either detached from DOM, or have an empty bounding box or
`visibility:hidden`. This is opposite to the `'visible'` option.
""" return mapping.from_maybe_impl(
self._sync(self._impl_obj.wait_for(timeout=timeout, state=state))
)
宏哥还是按之前toast的消息那个demo来演示,这里就不写demo的HTML代码,不知道的可以看宏哥之前的文章:传送门
3.1.1代码设计
3.1.2参考代码
# coding=utf-8 # 1.先设置编码,utf-8可支持中英文,如上,一般放在第一行 # 2.注释:包括记录创建时间,创建人,项目名称。
'''
Created on 2024-07-16
@author: 北京-宏哥
北京宏哥(微信搜索:北京宏哥,关注宏哥,提前解锁更多测试干货!)
Project: 《最新出炉》系列小成篇-Python+Playwright自动化测试-66 - 等待元素至指定状态
''' # 3.导入模块
from playwright.sync_api import Playwright, sync_playwright, expect def run(playwright: Playwright) -> None: browser = playwright.chromium.launch(headless=False)
context = browser.new_context()
page = context.new_page()
page.goto("E:/Desktop/test/toast.html")
# 点击 点击关注 按钮
page.locator("#hongge").click()
# 等待元素出现在dom
page.locator('//html/body/div').wait_for(state="attached")
# 获取元素文本
print(page.locator('//html/body/div').inner_text())
page.locator('//html/body/div').wait_for(state="detached")
print("元素已经从DOM移除")
page.wait_for_timeout(1000)
context.close()
browser.close() with sync_playwright() as playwright:
run(playwright)
3.1.3运行代码
1.运行代码,右键Run'Test',就可以看到控制台输出,如下图所示:
2.运行代码后电脑端的浏览器的动作。如下图所示:
3.2wait_for_selector()
page.wait_for_selector()
是 Playwright 中的一个方法,用于等待与指定 CSS 选择器匹配的元素出现在页面中。
这个方法接受一个选择器参数和一个可选的选项参数。常用的选项参数包括:
visible
:指定元素必须可见,默认为False
。hidden
:指定元素必须隐藏,默认为False
。state
:可以设置为visible
、hidden
、attached
或detached
,用于等待元素达到特定的状态。timeout
:设置等待的超时时间,以毫秒为单位。如果在指定的时间内元素未达到等待的状态,则会抛出超时异常。
官方定义的函数如下:
def wait_for_selector(
self,
selector: str,
*,
state: typing.Optional[
Literal["attached", "detached", "hidden", "visible"]
] = None,
timeout: typing.Optional[float] = None,
strict: typing.Optional[bool] = None
) -> typing.Optional["ElementHandle"]:
"""ElementHandle.wait_for_selector Returns element specified by selector when it satisfies `state` option. Returns `null` if waiting for `hidden` or
`detached`. Wait for the `selector` relative to the element handle to satisfy `state` option (either appear/disappear from dom,
or become visible/hidden). If at the moment of calling the method `selector` already satisfies the condition, the
method will return immediately. If the selector doesn't satisfy the condition for the `timeout` milliseconds, the
function will throw. **Usage** ```py
await page.set_content(\"<div><span></span></div>\")
div = await page.query_selector(\"div\")
# waiting for the \"span\" selector relative to the div.
span = await div.wait_for_selector(\"span\", state=\"attached\")
``` ```py
page.set_content(\"<div><span></span></div>\")
div = page.query_selector(\"div\")
# waiting for the \"span\" selector relative to the div.
span = div.wait_for_selector(\"span\", state=\"attached\")
``` **NOTE** This method does not work across navigations, use `page.wait_for_selector()` instead. Parameters
----------
selector : str
A selector to query for.
state : Union["attached", "detached", "hidden", "visible", None]
Defaults to `'visible'`. Can be either:
- `'attached'` - wait for element to be present in DOM.
- `'detached'` - wait for element to not be present in DOM.
- `'visible'` - wait for element to have non-empty bounding box and no `visibility:hidden`. Note that element
without any content or with `display:none` has an empty bounding box and is not considered visible.
- `'hidden'` - wait for element to be either detached from DOM, or have an empty bounding box or
`visibility:hidden`. This is opposite to the `'visible'` option.
timeout : Union[float, None]
Maximum time in milliseconds. Defaults to `30000` (30 seconds). Pass `0` to disable timeout. The default value can
be changed by using the `browser_context.set_default_timeout()` or `page.set_default_timeout()` methods.
strict : Union[bool, None]
When true, the call requires selector to resolve to a single element. If given selector resolves to more than one
element, the call throws an exception. Returns
-------
Union[ElementHandle, None]
""" return mapping.from_impl_nullable(
self._sync(
self._impl_obj.wait_for_selector(
selector=selector, state=state, timeout=timeout, strict=strict
)
)
)
1.等待元素出现在DOM中
page.wait_for_selector("定位方法", state='attached')
2.等待从DOM中移除
page.wait_for_selector("定位方法", state='detached')
3.等待元素可见
page.wait_for_selector("定位方法", state="visible")
4.等待元素不可见(隐藏)
page.wait_for_selector("定位方法", state='hidden')
如果没有传 state 参数,默认情况下是等待元素可见 visible
page.wait_for_selector("定位方法")
3.2.1等待元素出现和移除
默认情况下,在HTML页面的DOM节点里面是没有这个元素的,通过某些操作(点击【点击关注】按钮),这个元素才出现,如下图所示:
宏哥还是按之前toast的消息那个demo来演示,这里就不写demo的HTML代码,不知道的可以看宏哥之前的文章:传送门
3.2.1.1代码设计
3.2.1.2参考代码
# coding=utf-8 # 1.先设置编码,utf-8可支持中英文,如上,一般放在第一行 # 2.注释:包括记录创建时间,创建人,项目名称。
'''
Created on 2024-07-16
@author: 北京-宏哥
北京宏哥(微信搜索:北京宏哥,关注宏哥,提前解锁更多测试干货!)
Project: 《最新出炉》系列小成篇-Python+Playwright自动化测试-66 - 等待元素至指定状态
''' # 3.导入模块
from playwright.sync_api import Playwright, sync_playwright, expect def run(playwright: Playwright) -> None: browser = playwright.chromium.launch(headless=False)
context = browser.new_context()
page = context.new_page()
page.goto("E:/Desktop/test/toast.html")
# 点击 点击关注 按钮
page.locator("#hongge").click()
# 等待元素出现在dom
loc_msg = page.wait_for_selector('//html/body/div', state="attached")
# 获取元素文本
print(loc_msg.inner_text())
page.wait_for_selector('//html/body/div', state="detached")
print("元素已经从DOM移除")
page.wait_for_timeout(1000)
context.close()
browser.close() with sync_playwright() as playwright:
run(playwright)
3.2.1.3运行代码
1.运行代码,右键Run'Test',就可以看到控制台输出,如下图所示:
2.运行代码后电脑端的浏览器的动作。如下图所示:
3.2.2等待元素显示和隐藏
默认情况下,在HTML页面的元素本身就在DOM里,只是通过某些操作,状态发生改变:隐藏和显示。如下提示语本来就在DOM里,只是默认是隐藏状态。宏哥还在之前的演示demo找到了一个这样的场景,刚好用来演示。
3.2.2.1代码设计
3.2.2.2参考代码
# coding=utf-8 # 1.先设置编码,utf-8可支持中英文,如上,一般放在第一行 # 2.注释:包括记录创建时间,创建人,项目名称。
'''
Created on 2024-07-16
@author: 北京-宏哥
北京宏哥(微信搜索:北京宏哥,关注宏哥,提前解锁更多测试干货!)
Project: 《最新出炉》系列小成篇-Python+Playwright自动化测试-66 - 等待元素至指定状态
''' # 3.导入模块
from playwright.sync_api import Playwright, sync_playwright, expect def run(playwright: Playwright) -> None: browser = playwright.chromium.launch(headless=False)
context = browser.new_context()
page = context.new_page()
page.goto("https://sahitest.com/demo/visible.htm")
#点击隐藏按钮
page.locator("//html/body/form/input[4]").click()
page.wait_for_selector("#uv", state="hidden")
print("元素已经隐藏")
page.wait_for_timeout(1000)
# 点击显示按钮
page.locator("//html/body/form/input[5]").click()
loc_msg = page.wait_for_selector("#uv", state="visible")
print("元素已经显示")
# 获取元素文本
print(loc_msg.inner_text())
page.wait_for_timeout(1000)
context.close()
browser.close() with sync_playwright() as playwright:
run(playwright)
3.2.2.3运行代码
1.运行代码,右键Run'Test',就可以看到控制台输出,如下图所示:
2.运行代码后电脑端的浏览器的动作(注意:using visibility显示和隐藏,可以加长等待时间,看的更清楚)。如下图所示:
3.3 wait_for_element_state()
wait_for_load_state(),等待事件被触发。等待前面按钮触发的事件加载完成,才进行下面的操作。
在Python的Playwright库中,wait_for_load_state()
方法用于等待页面达到特定的加载状态。该方法接受三个参数:
state:页面应该达到的加载状态,可以是
load
、domcontentloaded
或networkidle
。这些状态分别代表页面的不同加载程度,其中load
表示页面完全加载,domcontentloaded
表示文档内容已经加载,而networkidle
则表示网络几乎无连接,即页面加载已完成。timeout:等待的最长时间,单位为毫秒。默认值为30 * 1000,即30秒。这个参数用于设置等待操作的最大超时时间,以避免程序长时间等待而无法继续执行。
wait_until:等待的事件类型,可以是
load
、domcontentloaded
、networkidle0
或networkidle2
中的一个。这个参数用于指定等待的具体事件类型,以便更精确地控制等待的条件。
通过使用wait_for_load_state()
方法,可以确保在继续执行后续操作之前,页面已经完全加载完成,从而避免因页面元素未完全加载而导致的操作失败或错误。
官方定义的函数如下:
def wait_for_load_state(
self,
state: typing.Optional[
Literal["domcontentloaded", "load", "networkidle"]
] = None,
*,
timeout: typing.Optional[float] = None
) -> None:
"""Page.wait_for_load_state Returns when the required load state has been reached. This resolves when the page reaches a required load state, `load` by default. The navigation must have been
committed when this method is called. If current document has already reached the required state, resolves
immediately. **Usage** ```py
await page.get_by_role(\"button\").click() # click triggers navigation.
await page.wait_for_load_state() # the promise resolves after \"load\" event.
``` ```py
page.get_by_role(\"button\").click() # click triggers navigation.
page.wait_for_load_state() # the promise resolves after \"load\" event.
``` ```py
async with page.expect_popup() as page_info:
await page.get_by_role(\"button\").click() # click triggers a popup.
popup = await page_info.value
# Wait for the \"DOMContentLoaded\" event.
await popup.wait_for_load_state(\"domcontentloaded\")
print(await popup.title()) # popup is ready to use.
``` ```py
with page.expect_popup() as page_info:
page.get_by_role(\"button\").click() # click triggers a popup.
popup = page_info.value
# Wait for the \"DOMContentLoaded\" event.
popup.wait_for_load_state(\"domcontentloaded\")
print(popup.title()) # popup is ready to use.
``` Parameters
----------
state : Union["domcontentloaded", "load", "networkidle", None]
Optional load state to wait for, defaults to `load`. If the state has been already reached while loading current
document, the method resolves immediately. Can be one of:
- `'load'` - wait for the `load` event to be fired.
- `'domcontentloaded'` - wait for the `DOMContentLoaded` event to be fired.
- `'networkidle'` - **DISCOURAGED** wait until there are no network connections for at least `500` ms. Don't use
this method for testing, rely on web assertions to assess readiness instead.
timeout : Union[float, None]
Maximum operation time in milliseconds, defaults to 30 seconds, pass `0` to disable timeout. The default value can
be changed by using the `browser_context.set_default_navigation_timeout()`,
`browser_context.set_default_timeout()`, `page.set_default_navigation_timeout()` or
`page.set_default_timeout()` methods.
""" return mapping.from_maybe_impl(
self._sync(self._impl_obj.wait_for_load_state(state=state, timeout=timeout))
)
宏哥在这个网站:https://www.jq22.com/ 找了一个demo,只有加载完成才会出现文字,然后对其进行定位打印文本。
3.3.1代码设计
3.3.2参考代码
# coding=utf-8 # 1.先设置编码,utf-8可支持中英文,如上,一般放在第一行 # 2.注释:包括记录创建时间,创建人,项目名称。
'''
Created on 2024-07-16
@author: 北京-宏哥
北京宏哥(微信搜索:北京宏哥,关注宏哥,提前解锁更多测试干货!)
Project: 《最新出炉》系列小成篇-Python+Playwright自动化测试-66 - 等待元素至指定状态
''' # 3.导入模块
from playwright.sync_api import Playwright, sync_playwright, expect def run(playwright: Playwright) -> None: browser = playwright.chromium.launch(headless=False)
context = browser.new_context()
page = context.new_page()
page.goto("https://www.jq22.com/demo/jquery-jdt20160820/")
page.wait_for_load_state()
print(page.locator('//*[@id="progress_content"]/i[4]/span').inner_text())
context.close()
browser.close() with sync_playwright() as playwright:
run(playwright)
3.3.3运行代码
1.运行代码,右键Run'Test',就可以看到控制台输出,如下图所示:
2.运行代码后电脑端的浏览器的动作。如下图所示:
敲黑板!!!1.注意自动化测试的加载的时间不要超过此方法的默认时间,超时就会报错了哈!!!这个网站需要加载40S才会出现文字,如下图所示:
3.3.4代码设计
3.3.5参考代码
# coding=utf-8 # 1.先设置编码,utf-8可支持中英文,如上,一般放在第一行 # 2.注释:包括记录创建时间,创建人,项目名称。
'''
Created on 2024-07-16
@author: 北京-宏哥
北京宏哥(微信搜索:北京宏哥,关注宏哥,提前解锁更多测试干货!)
Project: 《最新出炉》系列小成篇-Python+Playwright自动化测试-66 - 等待元素至指定状态
''' # 3.导入模块
from playwright.sync_api import Playwright, sync_playwright, expect def run(playwright: Playwright) -> None: browser = playwright.chromium.launch(headless=False)
context = browser.new_context()
page = context.new_page()
page.goto("https://sahitest.com/demo/php/delayedLoadInner.php") page.wait_for_load_state() print(page.locator("//html/body/div").inner_text())
print(page.locator("//html/body/span").inner_text())
context.close()
browser.close() with sync_playwright() as playwright:
run(playwright)
3.3.6运行代码
1.运行代码,右键Run'Test',就可以看到控制台输出(.运行代码控制台报错,因为加载这个页面需要40s,而此方法默认30000ms=30s,超时报错),如下图所示:
2.运行代码后电脑端的浏览器的动作。如下图所示:
4.小结
4.1wait_for() 和 wait_for_selector()使用区别
wait_for() 方法 和 wait_for_selector()使用区别:
page.locator('定位元素').wait_for() 返回的是None,后面不能继续操作元素
page.wait_for_selector("定位方法") 返回的是locator 对象,后面可以继续操作元素
好了,今天时间也不早了,宏哥就讲解和分享到这里,感谢您耐心的阅读,希望对您有所帮助。
《最新出炉》系列小成篇-Python+Playwright自动化测试-66 - 等待元素至指定状态(出现、移除、显示和隐藏)的更多相关文章
- 深入学习jQuery选择器系列第八篇——过滤选择器之伪子元素选择器
× 目录 [1]通用形式 [2]反向形式 [3]首尾元素 [4]唯一元素 前面的话 本文是子元素选择器的续篇,主要介绍关于nth-of-type()选择器的内容.该部分内容并非没有出现在<锋利的 ...
- python接口自动化测试--数据分离读取Excal指定单元格数据
上一篇博客讲了怎么批量读取Excal单元格数据,现在咱们说一下怎么读取Excal指定单元格数据. 一.首先建一个Test_Main类 #!/usr/bin/python # -*- coding: U ...
- appium+python搭建自动化测试框架_Appium元素定位(二)
Appium元素定位: 工具:Android\android-sdk\tools uiautomatorviewer.bat 1. id定位: self.driver.find_element_ ...
- Python+Appium自动化测试(5)-appium元素定位常用方法
对于Android而言,查找appUI界面元素属性的工具有三种:appium desktop,uiautomatorviewer.bat,weditor.之前已经介绍过了weditor的使用,这里我将 ...
- 手牵手,使用uni-app从零开发一款视频小程序 (系列上 准备工作篇)
系列文章 手牵手,使用uni-app从零开发一款视频小程序 (系列上 准备工作篇) 手牵手,使用uni-app从零开发一款视频小程序 (系列下 开发实战篇) 前言 好久不见,很久没更新博客了,前段时间 ...
- Python系列之入门篇——HDFS
Python系列之入门篇--HDFS 简介 HDFS (Hadoop Distributed File System) Hadoop分布式文件系统,具有高容错性,适合部署在廉价的机器上.Python ...
- Python系列之入门篇——MYSQL
Python系列之入门篇--MYSQL 简介 python提供了两种mysql api, 一是MySQL-python(不支持python3),二是PyMYSQL(支持python2和python3) ...
- 看完100篇Python技术精华文章,平均涨薪30%!
一个以技术为立身根基的教育机构做出来的微信号,干货程度会有多高? 马哥Linux运维公众号运营五年,从一开始的定位就是给技术人分享加薪干货的地方.这五年里,公众号运营最重的任务就是做内容.内容并不好做 ...
- 第五篇.python进阶
目录 第五篇.python进阶 1. 异常处理 2. 数字类型内置方法 2.定义: 3.常用操作+内置方法: 4.存一个值or多个值: 5.有序or无序: 6.可变和不可变 1.用途: 2.定义: 3 ...
- 【Windows编程】系列第三篇:文本字符输出
上一篇我们展示了如何使用Windows SDK创建基本控件,本篇来讨论如何输出文本字符. 在使用Win32编程时,我们常常要输出文本到窗口上,Windows所有的文本字符或者图形输出都是通过图形设备接 ...
随机推荐
- Task - lmdeploy
基础作业: 使用 LMDeploy 以本地对话.网页Gradio.API服务中的一种方式部署 InternLM-Chat-7B 模型,生成 300 字的小故事(需截图
- C# 8字节byte数组转int
对方是协议 对于整型.长整型等数据类型,Big endian 认为第一个字节是最高位字节(按照从低地址到高地址的顺序存放数据的高位字节到低位字节):而 Little endian 则相反,它认为第一个 ...
- 09-CentOS软件包管理
简介 CentOS7使用rpm和yum来管理软件包. CentOS 8附带YUM包管理器v4.0.4版本,该版本现在使用DNF (Dandified YUM)技术作为后端.DNF是新一代的YUM,新的 ...
- .net core SM2加密+PKCS8实现
前阵子在对接银行接口,对方给出的加密方式是SM2,在网上找了不少教程,都是使用Portable.BouncyCastle实现的,功能实现后发现对方给出的密钥格式是PKCS8,下面代码记录一下PKCS8 ...
- hbase第一课:hbase-2.2.7分布式搭建
hbase-2.2.7分布式搭建文档 1.上传解压配置环境变量 # 1.解压 tar -xvf hbase-2.2.7-bin.tar.gz.gz # 2.配置环境变量 vim /etc/profil ...
- selenium验证码识别,超级鹰干超级鹰
from selenium.webdriver import Edge from selenium.webdriver.common.by import By # 在这里导入浏览器设置相关的类 fro ...
- 【点云检测】OpenPCDet 教程系列 [1] 安装 与 ROS运行
前言与参考 主要是介绍库的使用,做笔记区 首先搜索的时候有个问题 一直在我脑子里 hhh 就是MMlab其实还有一个叫mmdetection3d 的库,然后搜的时候发现 hhh 有网友和我一样的疑惑: ...
- GUI测试
标签(空格分隔): GUI 我要用到 Chrome 浏览器,所以需要先下载 Chrome Driver 并将其放入环境变量.接下来,你可以用自己熟悉的方式建立一个空的 Maven 项目,然后在 POM ...
- Top cluster 树分块
写点基础的东西.随便写的,勿喷. top cluster 一个 cluster 是一个联通子图,且至多有两个点与其他部分连接 这两个点被称为 boundary node 其余点被称为 internal ...
- CF372C
思路 根据题意可以得到dp转移方程是 \(f_{i,j}=\max\{f_{i-1,k}+b_i-|a_i-j|\}\) 而且 \(j-(t_{i}-t_{i-1})\times d\le k\le ...