Playwright之录制脚本转Page Object类

Playwright之录制脚本转Page Object类

设计思路 : 我们今天UI自动化设计的时候,通常会遵循一些设计模式,例如Page Object模式。但是自己找元素再去填写有一些麻烦,所以我们可以通过拆解录制的脚本,将其中的元素提取出来,然后放到我们的页面中。

一、文件目录如下

在这里插入图片描述

  • auto_myself(名字瞎起的) : 执行文件,主要功能为获取我们脚本存放的地址,读取信息,然后将其写入py文件,创建object,并添加其属性。
  • page_template : 生成的类的模板,将录制的脚本转为这种格式。
  • scripts_record_file : 录制的脚本存放文件。

二、操作步骤

1.使用playwright脚本录制命令,启动脚本录制功能,进行操作,录制自动化脚本

playwright安装过程就不说了,都是一样的。

playwright codegen
2.将录制的脚本复制到txt文件中

直接用录制器自带的复制,复制粘贴就行啦,很方便。
在这里插入图片描述

3.修改auto_myself文件中的类名称和脚本地址

如果在同一个文件夹下,只修改类名和保存文件的信息就可以。
在这里插入图片描述

4. 执行auto_myself的方法

执行后我们可以得到一个文件名为playwright_element_page,类为class_name的py文件。
在这里插入图片描述

在这里插入图片描述

三、auto_myself文件代码

文件的逻辑如下:

  1. 定义好object的属性
  2. 获取录制的脚本文件
  3. 根据元素特点进行分离,将元素的定位方式保存并重命名
  4. 将获取到的元素进行到我们的模板文件中
  5. 文件替换和去重等处理
 -*- coding: utf-8 -*-
import os.path
from playwright_element_page.page_template import page_base_text
# 获取文件执行目录
root_path = os.path.dirname(os.path.abspath(__file__))
print(root_path)

class AutoMyself(object):
    """
    脚本自动创建类
    """

    _button = 0
    _input = 0
    _select = 0
    _switch = 0
    _frame = 0
    _label = 0
    _link = 0
    _total = 0
    _deduplication = 0

    def __init__(self, record_scripts_base_path: str = '', output_file_path: str = '', output_file_name: str = ''):
        self.base_path = record_scripts_base_path
        self.output_path = root_path + output_file_path + '/' + output_file_name + '.py'
        self.element_dict = {}

    def scripts_to_page(self, page_name: str):
        """
        录制脚本转 page 结构文件
        :param page_name:创建文件名称
        :return:
        """
        if self.__get_element_for_page():
            self.__set_element_to_page(page_name)

    def __get_element_for_page(self):
        """
        获取文件内容
        :return:
        """
        try:
            with open(self.base_path, 'r', encoding='gbk') as f:
                for line in f:
                    line = line.strip().replace("\n", "")
                    tags = ('page.', 'page1.')
                    if any(tag if tag in line else False for tag in tags):
                        self.__create_element_for_page(line)
                        self._total += 1
        except UnicodeDecodeError as ude:
            print(f'*****文件读取失败!文件编码异常:{ude},请检查文件内容!*****')
        except Exception as e:
            print(f'*****执行异常:{e}*****')
        finally:
            print(f'***** 元素数量:{self._total} *****')
            return self.element_dict

    def __set_element_to_page(self, page_name: str):
        """
        保存元素信息到文件
        :return:
        """
        # 元素去重
        self.__element_deduplication()
        try:

            with open(self.output_path, 'w', encoding='utf-8') as f:
                class_name = page_name.title()
                f.write(page_base_text.format(class_name.replace('_', '')))
                for name, locator in self.element_dict.items():
                    f.write(f'\t\tself.{name} = {locator}\n')
        except UnicodeDecodeError as ude:
            print(f"***** __set_element_to_page文件写入异常,字符格式错误:{ude} *****")
        except Exception as e:
            print(f'***** 文件写入异常,{e} *****')
        finally:
            print(f'***** 已去除重复元素数量:{self._deduplication} *****')
            print('***** 文件写入操作完成! *****')

    def __create_element_for_page(self, element):
        """
        创建页面元素
        :return:
        """
        element_types = ('select_option',)
        if 'get_by_role' in element:
            self.__element_filter_by_role(element)
        elif any(element_type if element_type else False for element_type in element_types):
            self.__element_filter_by_type(element)
        else:
            self.__element_filter_by_operate(element)

    def __element_filter_by_role(self, element):
        """
        根据元素角色的定位方式,添加元素信息
        :param element:元素信息
        :return:
        """
        role = element.split('get_by_role("')[1].split('"')[0]
        if role == 'button':
            self.element_dict[f'button_{self._button}'] = element.split('.click')[0]
            self._button += 1
        elif role == 'label':
            self.element_dict[f'label_{self._label}'] = element.split('.click')[0]
            self._label += 1
        elif role == 'link':
            self.element_dict[f'link_{self._link}'] = element.split('.click')[0]
            self._link += 1
        else:
            self.__element_filter_by_operate(element)

    def __element_filter_by_type(self, element):
        """
        根据元素角色的定位方式,添加元素信息
        :param element:元素信息
        :return:
        """
        if 'select_option' in element.split('.')[-1]:
            self.element_dict[f'select_{self._select}'] = element.split('.click')[0]
            self._select += 1
        else:
            self.__element_filter_by_operate(element)

    def __element_filter_by_operate(self, element):
        """
        根据操作方式,判断元素类型
        :param element:
        :return:
        """
        if '.click()' in element:
            self.element_dict[f'button_{self._button}'] = element.split('.click')[0]
            self._button += 1
        elif '.fill(' in element:
            self.element_dict[f'input_{self._input}'] = element.split('.fill')[0]
            self._input += 1
        else:
            print(f'当前元素识别方式未补充:{element}')

    def __element_deduplication(self):
        """
        元素去重
        :return:
        """
        new_dict = {value: key for key, value in self.element_dict.items()}
        self.element_dict = {value: key for key, value in new_dict.items()}
        self._deduplication = self._total - len(self.element_dict)


if __name__ == '__main__':
    am = AutoMyself(record_scripts_base_path='scripts_record_file.txt', output_file_name='playwright_element_page')
    am.scripts_to_page('class_name')

四、page_template文件代码

其实这个文件不用py用txt也可以,只要可以获取到我们想要的类结构,然后按行写入文件就能满足我们的需求。

# -*- coding: utf-8 -*-
# page模板内容
page_base_text = '''# -*- coding: utf-8 -*-
from serve.base_page import BasePage
from playwright.sync_api import Page


class {}(BasePage):
\t"""
\t页面描述
\t"""

\tdef __init__(self, page: Page):
\t\tsuper().__init__(page)
'''

其他

转换的思路其实比较简单,就是将元素提取出来,然后将其写入另一个文件。脚本内容还有很多需要完善的地方,大家可以提出修改意见,我会根据大家的意见进行完善。大家有其他问题也可以提出一起修改~

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/774654.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

vue3中pinia使用持久化管理

安装插件 npm install pinia pinia-plugin-persistpinia进行注册 创建index.ts import { createPinia } from pinia; //对外暴露大仓库 export default createPinia(); 在mian.ts //引入pinpa import { createApp } from vue //引入根组件 import App from ./App.vue const…

class类和style内联样式的绑定

这里的绑定其实就是v-bind的绑定,如代码所示,div后面的引号就是v-bind绑定,然后大括号将整个对象括起来,对象内先是属性,属性后接的是变量,这个变量是定义在script中的,后通过这个变量&#xff…

CAN转PN网关模块连接激光切割机的配置方法

激光切割机在工业生产中被广泛应用,而激光发射器与控制设备常以不同的协议存在两者之间,CAN总线和Profinet以各自的特点被广泛用于设备当中。本文将介绍介绍兴达易控CAN转Profinet网关模块(XD-PN_CAN20)连接 CAN 激光切割机的使用…

【算法 - 哈希表】两数之和

这里写自定义目录标题 两数之和题目解析思路解法一 :暴力枚举 依次遍历解法二 :使用哈希表来做优化 核心逻辑为什么之前的暴力枚举策略不太好用了?所以,这就是 这道题选择 固定一个数,再与其前面的数逐一对比完后&…

如何在 Ubuntu上搭建 LAMP

远程登录 Ubuntu系统环境 ssh (User)(IP) # 比如:ssh lennlouis192.168.207.128 为安全起见,建议你使用 root 登录 VPS 后创建一个具有 sudo 权限的帐号。 安装和配置 Apache 2 Apache Http Server 是一个开源的,非常流行,使用…

RAG 为什么需要文本分割(Chunking)

Picone上的一个博客,翻译过来学习一下,其中加入了一些个人的理解和调整,有兴趣更深入研究的可以看一下文章的原文。 为什么需要文本分割(Chunking) 在构建与LLM相关的应用程序时,Chunking是将大量文本分解…

anaconda命令大全

目录 查看所有虚拟环境查看某虚拟环境安装的包创建虚拟环境激活创建好的虚拟环境回到之前的环境删除创建的虚拟环境查看conda所在的位置、虚拟环境位置等信息conda修改虚拟环境所在的位置 查看所有虚拟环境 conda env list查看某虚拟环境安装的包 激活要查看的虚拟环境之后&a…

【黑马头条】 article微服务编译失败,包com.heima.model.common.article.dtos 不存在

解决办法, 将 model微服务重新打包编译下载 然后在service的pom文件里面加上版本号 这样编译就不会找不到啦

SQL注入【1】——通用漏洞/SQL注入/mysql跨库/ACCESS偏移

一、知识点: 1、脚本代码与数据库前置知识 2、Access数据库注入-简易&偏移 3、MYSQL数据库注入-简易:权限跨库 二、前置知识: (一)SQL注入漏洞产生原理分析 SQL注入产生条件:根本条件:可控变量、特定函数。 脚本代码在实现…

数学建模MATLAB绘图大全

最近快要开始一年一度的数学建模竞赛啦,接下来争取每天更一篇数学建模算法!(当然这是理想状态下),今天就先更一些MATLAB常用的绘图吧,论文赏心悦目的关键就在于丰富多彩的图,好看的图一定会成为…

MySql主从同步延迟怎么办?

文章目录 什么是MySQL主从架构主从架构的组成工作原理主从复制的步骤主从架构的优点主从架构的缺点 什么是主从同步延迟为什么会导致主从延迟主从延时的排查和解决如果发现主从数据不一致怎么办? 我们常说的业务量越来越大,I/O访问频率过高,单…

2021-06-15 protues(ISIS)脉冲发生器仿真仪表使用

缘由这个脉冲发生器怎么连线_编程语言-CSDN问答

​埃文科技受邀出席2024 “数据要素×”生态大会​

2024“数据要素”生态大会(以下简称“大会”)于2024年6月30日在河南省郑州市举办,大会主题为“加快数据要素化进程 推动新质生产力发展”。 本次大会旨在搭建高水平交流合作平台、分享前沿观点、展示先进技术、交流实践经验,共同探…

开放式蓝牙耳机推荐,开放式耳机选购小技巧大公开!

跑步是我们生活中最常见的运动方式。在跑步中佩戴耳机往往能达到“事半功倍”的效果,如何去选择一款好的运动耳机便需要精挑细选了。作为一个开放式耳机资深玩家兼马拉松参与者,我个人觉得开放式耳机是最适合跑步的了,其开放式的设计更加适合…

数据结构之算法的时间复杂度

1.时间复杂度的定义 在计算机科学中,算法的时间复杂度是一个函数,它定量描述了算法的运行时间。一个算法所花费的时间与其中语句的执行次数成正比列,算法中的基本操作的执行次数,为算法的时间复杂度 例1: 计算Func1…

鸿蒙‘ohpm‘ 不是内部或外部命令,也不是可运行的程序-解决方案

🔥 博客主页: 小韩本韩! ❤️ 感谢大家点赞👍收藏⭐评论✍️ 在鸿蒙的DevEco Studio的终端下输入 onpm -v 或者 你需要下载第三方ohpm包的时候提示‘ohpm‘ 不是内部或外部命令,也不是可运行的程序- 主要是因为我们…

【基于R语言群体遗传学】-6-表型计算等位基因频率、最大似然估计方法

到目前为止,我们主要讨论了等位基因和基因型频率,以及我们如何可以从一个推断出另一个。但是,如果我们不知道等位基因频率,只知道种群中存在哪些表型呢?如果我们足够幸运,知道哪些表型对应哪些基因型&#…

网络-calico问题分析

项目场景: calico-node日志提示 Failed to auto-detect host MTU - no interfaces matched the MTU interface pattern. To use auto-MTU, set mtuifacePattern to match your hosts’s interfaes. 同时,cali开头网卡的mtu是1440大小 原因分析&#xff…

扁鹊三兄弟的启示,探寻系统稳定的秘诀

一、稳定性的重要性 1. 公司收益的角度 从公司收益的视角审视,系统不稳定可能会引发直接损失。例如,当系统突然出现故障导致交易中断时,可能造成交易款项的紊乱、资金的滞留或损失,这不但会阻碍当前交易的顺利完成,还…

web安全的会议室管理系统-计算机毕业设计源码50331

目 录 摘要 1 绪论 1.1 开发背景与意义 1.2国内外研究现状 1.3 相关技术、工具简介 1.3.1 MySQL数据库的介绍 1.3.2 B/S架构的介绍 1.3.3 Java语言 1.3.4 SpringBoot框架 1.4论文结构与章节安排 2 会议室管理系统需求分析 2.1 可行性分析 2.1.1 技术可行性分析 2…