首页 星云 工具 资源 星选 资讯 热门工具
:

PDF转图片 完全免费 小红书视频下载 无水印 抖音视频下载 无水印 数字星空

《最新出炉》系列小成篇-Python+Playwright自动化测试-66 - 等待元素至指定状态(出现、移除、显示和隐藏)

编程知识
2024年08月08日 07:16

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 对象,后面可以继续操作元素

好了,今天时间也不早了,宏哥就讲解和分享到这里,感谢您耐心的阅读,希望对您有所帮助。

From:https://www.cnblogs.com/du-hong/p/18303190
本文地址: http://www.shuzixingkong.net/article/894
0评论
提交 加载更多评论
其他文章 升级JDK时涉及的工作任务
JDK版本升级,通常引入新的语言特性、新的API,废弃一些API,从而导致一些不兼容的现象。 因此在升级产品使用的JDK版本时,通常有如下考虑: 新产品包括新建设的项目以及刚启动不久的项目,使用高版本的JDK。 对于生命周期中间的产品,依据人力预算和团队的技能,决策是否升级。 对于进入生命周期尾部的
Golang在整洁架构基础上实现事务
这篇文章在 go-kratos 官方的 layout 项目的整洁架构基础上,在微服务架构下,实现优雅的数据库事务操作。
Golang在整洁架构基础上实现事务 Golang在整洁架构基础上实现事务 Golang在整洁架构基础上实现事务
使用触发器来审计表的DML、DDL操作
最近帮客户排查某问题时,因为怀疑应用对某张配置表有变更,所以需要对这张表的所有操作进行审计。 原本Oracle对某张表的审计是非常方便的,一条命令就可以实现,也不需要费心自定义审计表。 -- 启用对表DEPT的插入、更新和删除操作的审计 AUDIT INSERT, UPDATE, DELETE ON
使用触发器来审计表的DML、DDL操作
七牛云私有空间图片上传、下载
导航 引言 总体思路 七牛云相关的配置文件 获取七牛云上传token 相关类定义 核心代码实现 获取七牛云图片下载链接 公开空间 私有空间 核心代码实现 结语 参考 引言 我们在成长,代码也要成长。 多媒体图片在各种网站、小程序和app中应用广泛,同时也大大增强了用户体验。 随着云服务的兴起,越来越
七牛云私有空间图片上传、下载 七牛云私有空间图片上传、下载
博客园自救之产品开发小建议
继上次 博客园直播方向运营建议之后,我又冒出了一个小建议, 毕竟作为博客园精神股东,开动我脑洞,我也义不容辞责任 博客园的产品形式是博客文章, 拓展路径有两条,一条是 文章的分类,一条的是文章的内容 分类的控制权在博客园,可拓展性强 内容的控制权在文章作者,可获站性弱 所以更多的拓展方向在分类 软件
介绍一款新奇的开源操作系统:GodoOS
在快节奏的现代办公环境中,一款高效、集成化的操作系统无疑是提升工作效率的利器。今天,我们要为您隆重介绍 ——GodoOS,一款专为内网办公环境设计的全能操作系统。它不仅仅是一个工具,更是您团队协作与文件管理的得力助手,将彻底改变您的工作方式,带来前所未有的便捷体验! 【全能办公套件,一应俱全】 Go
介绍一款新奇的开源操作系统:GodoOS
神经网络之卷积篇:详解更多边缘检测内容(More edge detection)
详解更多边缘检测内容 已经见识到用卷积运算实现垂直边缘检测,在本博客中,将看到如何区分正边和负边,这实际就是由亮到暗与由暗到亮的区别,也就是边缘的过渡。还能了解到其他类型的边缘检测以及如何去实现这些算法,而不要总想着去自己编写一个边缘检测程序。 这张6&#215;6的图片,左边较亮,而右边较暗,将它
神经网络之卷积篇:详解更多边缘检测内容(More edge detection) 神经网络之卷积篇:详解更多边缘检测内容(More edge detection) 神经网络之卷积篇:详解更多边缘检测内容(More edge detection)
快速基于 ClickHouse + Grafana 搭建可观测性解决方案 - 日志篇(ClickHouse 官方博客)
引言 作为一款高性能的 OLAP 数据库,ClickHouse 被用于多种应用场景,包括 时间序列(time series)数据的实时分析。其多样化的应用场景推动了大量分析函数的发展,这些函数有助于查询大多数类型的数据。这些查询特性加上高压缩率使得越来越多的用户开始利用 ClickHouse 来存储
快速基于 ClickHouse + Grafana 搭建可观测性解决方案 - 日志篇(ClickHouse 官方博客) 快速基于 ClickHouse + Grafana 搭建可观测性解决方案 - 日志篇(ClickHouse 官方博客) 快速基于 ClickHouse + Grafana 搭建可观测性解决方案 - 日志篇(ClickHouse 官方博客)