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、‌domcontentloadednetworkidle。‌这些状态分别代表页面的不同加载程度,‌其中load表示页面完全加载,‌domcontentloaded表示文档内容已经加载,‌而networkidle则表示网络几乎无连接,‌即页面加载已完成。‌

  • timeout:‌等待的最长时间,‌单位为毫秒。‌默认值为30 * 1000,‌即30秒。‌这个参数用于设置等待操作的最大超时时间,‌以避免程序长时间等待而无法继续执行。‌

  • wait_until:‌等待的事件类型,‌可以是load、‌domcontentloaded、‌networkidle0networkidle2中的一个。‌这个参数用于指定等待的具体事件类型,‌以便更精确地控制等待的条件。‌

通过使用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 - 等待元素至指定状态(出现、移除、显示和隐藏)的更多相关文章

  1. 深入学习jQuery选择器系列第八篇——过滤选择器之伪子元素选择器

    × 目录 [1]通用形式 [2]反向形式 [3]首尾元素 [4]唯一元素 前面的话 本文是子元素选择器的续篇,主要介绍关于nth-of-type()选择器的内容.该部分内容并非没有出现在<锋利的 ...

  2. python接口自动化测试--数据分离读取Excal指定单元格数据

    上一篇博客讲了怎么批量读取Excal单元格数据,现在咱们说一下怎么读取Excal指定单元格数据. 一.首先建一个Test_Main类 #!/usr/bin/python # -*- coding: U ...

  3. appium+python搭建自动化测试框架_Appium元素定位(二)

    Appium元素定位: 工具:Android\android-sdk\tools    uiautomatorviewer.bat 1. id定位: self.driver.find_element_ ...

  4. Python+Appium自动化测试(5)-appium元素定位常用方法

    对于Android而言,查找appUI界面元素属性的工具有三种:appium desktop,uiautomatorviewer.bat,weditor.之前已经介绍过了weditor的使用,这里我将 ...

  5. 手牵手,使用uni-app从零开发一款视频小程序 (系列上 准备工作篇)

    系列文章 手牵手,使用uni-app从零开发一款视频小程序 (系列上 准备工作篇) 手牵手,使用uni-app从零开发一款视频小程序 (系列下 开发实战篇) 前言 好久不见,很久没更新博客了,前段时间 ...

  6. Python系列之入门篇——HDFS

    Python系列之入门篇--HDFS 简介 HDFS (Hadoop Distributed File System) Hadoop分布式文件系统,具有高容错性,适合部署在廉价的机器上.Python ...

  7. Python系列之入门篇——MYSQL

    Python系列之入门篇--MYSQL 简介 python提供了两种mysql api, 一是MySQL-python(不支持python3),二是PyMYSQL(支持python2和python3) ...

  8. 看完100篇Python技术精华文章,平均涨薪30%!

    一个以技术为立身根基的教育机构做出来的微信号,干货程度会有多高? 马哥Linux运维公众号运营五年,从一开始的定位就是给技术人分享加薪干货的地方.这五年里,公众号运营最重的任务就是做内容.内容并不好做 ...

  9. 第五篇.python进阶

    目录 第五篇.python进阶 1. 异常处理 2. 数字类型内置方法 2.定义: 3.常用操作+内置方法: 4.存一个值or多个值: 5.有序or无序: 6.可变和不可变 1.用途: 2.定义: 3 ...

  10. 【Windows编程】系列第三篇:文本字符输出

    上一篇我们展示了如何使用Windows SDK创建基本控件,本篇来讨论如何输出文本字符. 在使用Win32编程时,我们常常要输出文本到窗口上,Windows所有的文本字符或者图形输出都是通过图形设备接 ...

随机推荐

  1. Task - lmdeploy

    基础作业: 使用 LMDeploy 以本地对话.网页Gradio.API服务中的一种方式部署 InternLM-Chat-7B 模型,生成 300 字的小故事(需截图

  2. C# 8字节byte数组转int

    对方是协议 对于整型.长整型等数据类型,Big endian 认为第一个字节是最高位字节(按照从低地址到高地址的顺序存放数据的高位字节到低位字节):而 Little endian 则相反,它认为第一个 ...

  3. 09-CentOS软件包管理

    简介 CentOS7使用rpm和yum来管理软件包. CentOS 8附带YUM包管理器v4.0.4版本,该版本现在使用DNF (Dandified YUM)技术作为后端.DNF是新一代的YUM,新的 ...

  4. .net core SM2加密+PKCS8实现

    前阵子在对接银行接口,对方给出的加密方式是SM2,在网上找了不少教程,都是使用Portable.BouncyCastle实现的,功能实现后发现对方给出的密钥格式是PKCS8,下面代码记录一下PKCS8 ...

  5. 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 ...

  6. selenium验证码识别,超级鹰干超级鹰

    from selenium.webdriver import Edge from selenium.webdriver.common.by import By # 在这里导入浏览器设置相关的类 fro ...

  7. 【点云检测】OpenPCDet 教程系列 [1] 安装 与 ROS运行

    前言与参考 主要是介绍库的使用,做笔记区 首先搜索的时候有个问题 一直在我脑子里 hhh 就是MMlab其实还有一个叫mmdetection3d 的库,然后搜的时候发现 hhh 有网友和我一样的疑惑: ...

  8. GUI测试

    标签(空格分隔): GUI 我要用到 Chrome 浏览器,所以需要先下载 Chrome Driver 并将其放入环境变量.接下来,你可以用自己熟悉的方式建立一个空的 Maven 项目,然后在 POM ...

  9. Top cluster 树分块

    写点基础的东西.随便写的,勿喷. top cluster 一个 cluster 是一个联通子图,且至多有两个点与其他部分连接 这两个点被称为 boundary node 其余点被称为 internal ...

  10. 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 ...