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文件代码
文件的逻辑如下:
- 定义好object的属性
- 获取录制的脚本文件
- 根据元素特点进行分离,将元素的定位方式保存并重命名
- 将获取到的元素进行到我们的模板文件中
- 文件替换和去重等处理
-*- 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)
'''
其他
转换的思路其实比较简单,就是将元素提取出来,然后将其写入另一个文件。脚本内容还有很多需要完善的地方,大家可以提出修改意见,我会根据大家的意见进行完善。大家有其他问题也可以提出一起修改~