616 lines
28 KiB
Python
616 lines
28 KiB
Python
# -*- coding: utf-8 -*-
|
||
# -------------------------------
|
||
# @文件:basic_page.py
|
||
# @时间:2024/4/12 15:12
|
||
# @作者:caiweichao
|
||
# @功能描述:路径常量
|
||
# -------------------------------
|
||
import random
|
||
import time
|
||
|
||
import allure
|
||
from selenium import webdriver
|
||
from selenium.common.exceptions import *
|
||
from selenium.common.exceptions import TimeoutException
|
||
from selenium.webdriver.common.action_chains import ActionChains
|
||
from selenium.webdriver.common.alert import Alert
|
||
from selenium.webdriver.remote.webelement import WebElement
|
||
from selenium.webdriver.support import expected_conditions as ec
|
||
from selenium.webdriver.support.wait import WebDriverWait
|
||
|
||
from util.basic.log import Log, LogStoragerPocess
|
||
from util.basic.analysis_yaml import AnalysisYaml
|
||
from util.basic.times import Times
|
||
|
||
|
||
class BasicPage:
|
||
# 图片文件夹路径
|
||
__img_dir = LogStoragerPocess().get_log_dir()
|
||
conf: dict = AnalysisYaml().get_date('SELENIUM_CONFIG')
|
||
|
||
def __init__(self, driver):
|
||
self.driver: webdriver.Chrome = driver
|
||
self.wait: WebDriverWait = WebDriverWait(
|
||
driver=self.driver,
|
||
timeout=self.conf.get("WAIT_ELEMENT"),
|
||
poll_frequency=self.conf.get("POLL_ELEMENT")
|
||
)
|
||
|
||
def get_url(self, url: str) -> None:
|
||
"""
|
||
进入指定连接
|
||
:param url: 链接地址
|
||
:return: None
|
||
"""
|
||
self.driver.get(url=url)
|
||
|
||
def get_current_url_path(self) -> str:
|
||
"""
|
||
获取当前页面的url的路径
|
||
:return: url路径
|
||
"""
|
||
current_url = self.driver.current_url
|
||
return current_url
|
||
|
||
def set_img_error(self) -> None:
|
||
"""
|
||
用例执行失败截图,并且加入allure测试报告中
|
||
:return: 无返回值
|
||
"""
|
||
# 获取图片存储的文件夹
|
||
__time_tag = Times.timestamp()
|
||
__img_path = self.__img_dir + f"/{__time_tag}.png"
|
||
try:
|
||
# 进行截图
|
||
self.driver.save_screenshot(filename=__img_path)
|
||
Log.error(f"截图成功文件名称为:{__time_tag}.png")
|
||
__file = open(__img_path, "rb").read()
|
||
allure.attach(__file, "用例执行失败截图", allure.attachment_type.PNG)
|
||
except Exception as e:
|
||
Log.error(f"执行失败截图未能正确添加进入测试报告:{e}")
|
||
raise e
|
||
|
||
def set_img_case(self) -> None:
|
||
"""
|
||
用例执行完毕截图,并且将截图加入allure测试报告中
|
||
:return: 无返回值
|
||
"""
|
||
with allure.step("关键步骤截图"):
|
||
__img_name = Times.timestamp()
|
||
__img_path = self.__img_dir + f"/{__img_name}.png"
|
||
try:
|
||
# 截图前等待1秒防止图片没有正常加载
|
||
time.sleep(1)
|
||
self.driver.save_screenshot(filename=__img_path)
|
||
Log.debug(f"用例执行完成,截图成功,文件名称为{__img_name}.png")
|
||
# 读取图片信息
|
||
__file = open(file=__img_path, mode="rb").read()
|
||
allure.attach(__file, "关键步骤截图", allure.attachment_type.PNG)
|
||
except Exception as e:
|
||
Log.error(f"测试结果截图,未能正确添加进入测试报告:{e}")
|
||
raise e
|
||
|
||
def element_dyeing(self, element) -> None:
|
||
"""
|
||
将被操作的元素染色
|
||
:rollback: 是否将元素回滚
|
||
:return: None
|
||
"""
|
||
try:
|
||
self.driver.execute_script(
|
||
"arguments[0].setAttribute('style', 'background: green;');",
|
||
element)
|
||
except Exception as e:
|
||
Log.info(f"无法染色染色失效:{e}")
|
||
pass
|
||
|
||
def __wait_element_visible(self, model: str, locator: tuple[str, str]) -> None:
|
||
"""
|
||
等待元素可见
|
||
:param model: 元素所处的页面
|
||
:param locator: 元素定位表达式
|
||
:return: 无返回值
|
||
"""
|
||
Log.debug(f"-开始-等待页面{model}的元素:{locator}可见")
|
||
try:
|
||
# 获取等待开始时间的时间戳
|
||
__start_time = Times.timestamp()
|
||
self.wait.until(ec.visibility_of_element_located(locator))
|
||
# 计算元素等待的时间
|
||
__wait_time = Times.timestamp() - __start_time
|
||
Log.debug(f"页面:{model}上的元素{locator}已可见,共计等待{__wait_time:0.2f}秒")
|
||
except TimeoutException:
|
||
Log.error(f"页面:{model},等待元素{locator}超时")
|
||
self.set_img_error()
|
||
raise TimeoutException('元素等待超时')
|
||
except InvalidSelectorException as e:
|
||
Log.error(f"页面:{model},元素不可见或定位表达式:{locator}异常\n {e}")
|
||
raise InvalidSelectorException('元素定位异常')
|
||
|
||
def __wait_element_clickable(self, model: str, locator: tuple[str, str]) -> None:
|
||
"""
|
||
等待元素点击
|
||
:param model: 元素所处的页面
|
||
:param locator: 元素定位表达式
|
||
:return: 无返回值
|
||
"""
|
||
Log.debug(f"-开始-等待页面{model}的元素:{locator}可点击")
|
||
try:
|
||
# 获取等待开始时间的时间戳
|
||
__start_time = Times.timestamp()
|
||
self.wait.until(ec.element_to_be_clickable(locator))
|
||
# 计算元素等待的时间
|
||
__wait_time = Times.timestamp() - __start_time
|
||
Log.debug(f"页面:{model}上的元素{locator}已可点击,共计等待{__wait_time:0.2f}秒")
|
||
except TimeoutException as e:
|
||
Log.error(f"页面:{model},等待元素{locator}超时")
|
||
self.set_img_error()
|
||
raise e
|
||
except InvalidSelectorException as e:
|
||
Log.error(f"页面:{model},元素不可点击或定位表达式:{locator}异常\n {e}")
|
||
raise e
|
||
|
||
def __wait_element_exit(self, model: str, locator: tuple[str, str]) -> None:
|
||
"""
|
||
等待元素存在
|
||
:param model: 元素所处的页面
|
||
:param locator: 元素定位表达式
|
||
:return: 无返回值
|
||
"""
|
||
Log.debug(f"-开始-等待页面{model}的元素:{locator}存在")
|
||
try:
|
||
# 获取等待开始时间的时间戳
|
||
__start_time = Times.timestamp()
|
||
self.wait.until(ec.presence_of_element_located(locator))
|
||
# 计算元素等待的时间
|
||
__wait_time = Times.timestamp() - __start_time
|
||
Log.debug(f"页面:{model}上的元素{locator}已存在,共计等待{__wait_time:0.2f}秒")
|
||
except TimeoutException as e:
|
||
Log.error(f"页面:{model},等待元素{locator}超时")
|
||
self.set_img_error()
|
||
raise e
|
||
except InvalidSelectorException as e:
|
||
Log.error(f"页面:{model},元素不存在或定位表达式:{locator}异常\n {e}")
|
||
raise e
|
||
|
||
def wait_element_not_visible(self, model: str, locator: tuple[str, str]) -> None:
|
||
"""
|
||
等待元素不可见
|
||
:param model: 元素所处的页面
|
||
:param locator: 元素定位表达式
|
||
:return: 无返回值
|
||
"""
|
||
Log.debug(f"-开始-等待页面{model}的元素:{locator}存在")
|
||
try:
|
||
# 获取等待开始时间的时间戳
|
||
__start_time = Times.timestamp()
|
||
time.sleep(1)
|
||
self.wait.until(ec.invisibility_of_element_located(locator))
|
||
# 计算元素等待的时间
|
||
__wait_time = Times.timestamp() - __start_time
|
||
Log.debug(f"页面:{model}上的元素{locator}已经不可见,共计等待{__wait_time:0.2f}秒")
|
||
except TimeoutException as e:
|
||
Log.error(f"页面:{model},等待元素{locator}不可见超时")
|
||
self.set_img_error()
|
||
raise e
|
||
except InvalidSelectorException as e:
|
||
Log.error(f"页面:{model},元素不存在或定位表达式:{locator}异常\n {e}")
|
||
raise e
|
||
|
||
def __select_wait_method(self, model: str, locator: tuple[str, str], mode: str = "visible") -> None:
|
||
"""
|
||
选择元素定位的等待方式
|
||
:param model: 传参定位的是哪个页面 字符串形式
|
||
:param locator: 元素的定位表达式 例:(By.xx,'定位表达式')
|
||
:param mode: visible(元素可见), exist(元素存在),click(元素可点击)
|
||
:return: 无返回值
|
||
"""
|
||
if mode == "visible":
|
||
self.__wait_element_visible(model=model, locator=locator)
|
||
elif mode == "exist":
|
||
self.__wait_element_exit(model=model, locator=locator)
|
||
elif mode == "click":
|
||
self.__wait_element_clickable(model=model, locator=locator)
|
||
else:
|
||
Log.error(f"定位{model}页面的元素:{locator},mode参数传值异常,入参值为:{mode}")
|
||
|
||
def find_element(self, locator: tuple[str, str], mode: str = "visible", model: str = None) -> WebElement:
|
||
"""
|
||
定位元素,支持所有定位单个元素的定位表达式
|
||
:param model: 传参定位的是哪个页面 字符串形式
|
||
:param locator: 元素的定位表达式 例:(By.xx,'定位表达式')
|
||
:param mode: visible(元素可见), exist(元素存在)
|
||
:return: 定位到的元素对象
|
||
"""
|
||
self.__select_wait_method(model=model, locator=locator, mode=mode)
|
||
try:
|
||
Log.debug(f"正在定位{model}页面的: {locator} 的元素")
|
||
element = self.driver.find_element(*locator)
|
||
self.element_dyeing(element=element)
|
||
return element
|
||
except TimeoutException:
|
||
Log.error(f"页面:{model},定位元素:{locator}定位超时")
|
||
self.set_img_error()
|
||
raise TimeoutException("元素定位超时请检查")
|
||
except Exception:
|
||
Log.error(f"页面:{model},定位元素:{locator}定位失败")
|
||
self.set_img_error()
|
||
raise Exception("元素定位失败请检查")
|
||
|
||
def find_elements(self, locator: tuple[str, str], mode: str = "visible") -> list:
|
||
"""
|
||
定位一组元素,返回一个列表
|
||
:param locator: 元素的定位表达式 例:(By.xx,'定位表达式')
|
||
:param mode: visible(元素可见),notvisible(元素消失不可见), exist(元素存在)
|
||
:return: 返回一组元素是一个列表
|
||
"""
|
||
model = self.get_current_url_path()
|
||
self.__select_wait_method(model=model, locator=locator, mode=mode)
|
||
try:
|
||
Log.debug(f"正在定位{model}页面的: {locator} 的元素")
|
||
element_list = self.driver.find_elements(*locator)
|
||
return element_list
|
||
except Exception as e:
|
||
Log.error(f"页面:{model},定位元素:{locator}定位失败")
|
||
self.set_img_error()
|
||
raise e
|
||
|
||
def __move_element_visible(self, model: str, locator: tuple, element: WebElement, alignment: bool = False) -> None:
|
||
"""
|
||
将元素移动到页面可见区域
|
||
:param model: 传参定位的是哪个页面 字符串形式
|
||
:param locator: 元素的定位表达式 例:(By.xx,'定位表达式')
|
||
:param alignment 默认对其方式是元素和当前页面的底部对齐,可以传 alignment=''表示和顶部对齐
|
||
:param element 需要可见的元素
|
||
:return: 无返回值
|
||
"""
|
||
Log.debug(f'将{model}页面的元素:{locator}移动至浏览器可见区域')
|
||
try:
|
||
# 代码执行比页面渲染速度快 这里放0.5秒等待页面渲染
|
||
time.sleep(0.5)
|
||
alignment = 'false' if alignment else 'true'
|
||
self.driver.execute_script(f'arguments[0].scrollIntoView({alignment});', element)
|
||
# 休眠1秒让页面可以正常滚动到对应的位置再执行下去
|
||
time.sleep(1)
|
||
except Exception as e:
|
||
Log.error(f"{model}页面的元素:{locator}移动失败\n{e}")
|
||
self.set_img_error()
|
||
raise e
|
||
|
||
def click_element(self, locator: tuple[str, str], mode: str = "click", alignment: bool = False,
|
||
move_elemnet: bool = False,
|
||
is_double_click: bool = False) -> None:
|
||
"""
|
||
点击元素
|
||
:param locator: 元素的定位表达式 例:(By.xx,'定位表达式')
|
||
:param mode: visible(元素可见),notvisible(元素消失不可见), exist(元素存在),click(元素可点击)
|
||
:param alignment: 默认对其方式是元素和当前页面的底部对齐,可以传 alignment=''表示和顶部对齐
|
||
:param move_elemnet: 这里是布尔值 传入True 表示需要让元素滚动到页面可见区域 False 表示不用
|
||
:param is_double_click: False单击元素,传入True 双击元素
|
||
:return: 无返回值
|
||
"""
|
||
model = self.get_current_url_path()
|
||
element = self.find_element(model=model, locator=locator, mode=mode)
|
||
if move_elemnet is True:
|
||
self.__move_element_visible(model=model, locator=locator, element=element, alignment=alignment)
|
||
try:
|
||
Log.debug(f"点击:{model}页面,属性为{locator}的元素")
|
||
if is_double_click:
|
||
ActionChains(self.driver).double_click(element).perform()
|
||
else:
|
||
element.click()
|
||
except Exception as e:
|
||
Log.error(f"页面{model}的元素: {locator} 点击失败")
|
||
self.set_img_error()
|
||
raise e
|
||
|
||
def click_elements(self, locator: tuple[str, str], mode: str = "click", alignment: bool = False,
|
||
move_elemnet: bool = False,
|
||
is_double_click: bool = False) -> None:
|
||
"""
|
||
点击一组元素
|
||
:param locator: 元素的定位表达式 例:(By.xx,'定位表达式')
|
||
:param mode: visible(元素可见),notvisible(元素消失不可见), exist(元素存在),click(元素可点击)
|
||
:param alignment: 默认对其方式是元素和当前页面的底部对齐,可以传 alignment=''表示和顶部对齐
|
||
:param move_elemnet: 这里是布尔值 传入True 表示需要让元素滚动到页面可见区域 False 表示不用
|
||
:param is_double_click: False单击元素,传入True 双击元素
|
||
:return: 无返回值
|
||
"""
|
||
model = self.get_current_url_path()
|
||
elements = self.find_elements(locator=locator, mode=mode)
|
||
if move_elemnet is True:
|
||
self.__move_element_visible(model=model, locator=locator, element=elements[0], alignment=alignment)
|
||
try:
|
||
Log.debug(f"点击:{model}页面,属性为{locator}的元素")
|
||
for element in elements:
|
||
if is_double_click:
|
||
ActionChains(self.driver).double_click(element).perform()
|
||
else:
|
||
element.click()
|
||
except Exception as e:
|
||
Log.error(f"页面{model}的元素: {locator} 点击失败")
|
||
self.set_img_error()
|
||
raise e
|
||
|
||
def random_click_element(self, locator: tuple[str, str], num: int, mode: str = "click", alignment: bool = False,
|
||
move_elemnet: bool = False) -> str:
|
||
"""
|
||
随机点击一个元素
|
||
:param locator: 元素的定位表达式 例:(By.xx,'定位表达式')
|
||
:param num: 从第几位元素开始点击
|
||
:param mode: visible(元素可见), exist(元素存在),click(元素可点击)
|
||
:param alignment: 默认对其方式是元素和当前页面的底部对齐,可以传 alignment=''表示和顶部对齐
|
||
:param move_elemnet: 这里是布尔值 传入True 表示需要让元素滚动到页面可见区域 False 表示不用
|
||
:return: 点击的元素的文本
|
||
"""
|
||
model = self.get_current_url_path()
|
||
elements = self.find_elements(locator=locator, mode=mode)
|
||
click_num: int = random.randint(num, len(elements) - 1)
|
||
try:
|
||
element = elements[click_num]
|
||
if move_elemnet is True:
|
||
self.__move_element_visible(model=model, locator=locator, element=element, alignment=alignment)
|
||
self.element_dyeing(element)
|
||
Log.debug(f"点击:{model}页面,属性为{locator}的元素中的{click_num}位")
|
||
element.click()
|
||
except Exception as e:
|
||
Log.error(f"页面{model}的元素: {locator} 中的第{click_num}位元素点击失败")
|
||
self.set_img_error()
|
||
raise e
|
||
return element.text
|
||
|
||
def input_text(self, locator: tuple[str, str], content: str or int, mode: str = "visible", alignment: bool = False,
|
||
move_elemnet: bool = False) -> WebElement:
|
||
"""
|
||
输入文本内容
|
||
:param locator: 传入元素定位表达式
|
||
:param content: 传入输入的文本内容
|
||
:param mode: visible(元素可见), exist(元素存在)
|
||
:param alignment: 默认对其方式是元素和当前页面的底部对齐,可以传 alignment=''表示和顶部对齐
|
||
:param move_elemnet: 这里是布尔值 传入True 表示需要让元素滚动到页面可见区域 False 表示不用
|
||
:return: 无返回值
|
||
"""
|
||
model = self.get_current_url_path()
|
||
element = self.find_element(model=model, locator=locator, mode=mode)
|
||
if move_elemnet is True:
|
||
self.__move_element_visible(model=model, locator=locator,
|
||
element=element, alignment=alignment)
|
||
try:
|
||
Log.debug(f"输入操作:{model}页面下的属性为:{locator}的元素,输入内容为{content}")
|
||
element.send_keys(content)
|
||
self.driver.execute_script(
|
||
"arguments[0].setAttribute('style', 'background: write; border: 1px solid black;');", element)
|
||
except Exception as e:
|
||
self.set_img_error()
|
||
Log.error(f"页面{model}的属性: {locator} 输入操作失败")
|
||
raise e
|
||
return element
|
||
|
||
def clear_contents(self, locator: tuple[str, str], mode: str = "visible", alignment: bool = False,
|
||
move_elemnet: bool = False) -> None:
|
||
"""
|
||
清除文本内容
|
||
:param locator: 传入元素定位表达式
|
||
:param mode: visible(元素可见), exist(元素存在)
|
||
:param alignment: 默认对其方式是元素和当前页面的底部对齐,可以传 alignment=''表示和顶部对齐
|
||
:param move_elemnet: 这里是布尔值 传入True 表示需要让元素滚动到页面可见区域 False 表示不用
|
||
:return: 无返回值
|
||
"""
|
||
model = self.get_current_url_path()
|
||
element = self.find_element(model=model, locator=locator, mode=mode)
|
||
if move_elemnet is True:
|
||
self.__move_element_visible(model=model, locator=locator, element=element, alignment=alignment)
|
||
try:
|
||
Log.debug(f"输入操作:{model}页面下的属性为:{locator}的元素,清除内容")
|
||
# 保证正常清除
|
||
time.sleep(0.2)
|
||
element.clear()
|
||
except Exception as e:
|
||
self.set_img_error()
|
||
Log.error(f"页面{model}的属性: {locator} 清除操作失败")
|
||
raise e
|
||
|
||
def get_element_text(self, locator: tuple[str, str], mode: str = 'visible', alignment: bool = False,
|
||
move_elemnet: bool = False) -> str:
|
||
"""
|
||
获取元素的文本内容
|
||
:param locator: 传入元素定位表达式
|
||
:param mode: visible(元素可见), exist(元素存在)
|
||
:param alignment: 默认对其方式是元素和当前页面的底部对齐,可以传 alignment=''表示和顶部对齐
|
||
:param move_elemnet: 这里是布尔值 传入True 表示需要让元素滚动到页面可见区域 False 表示不用
|
||
:return: 返回获取到的元素文本内容
|
||
"""
|
||
model = self.get_current_url_path()
|
||
element = self.find_element(model=model, locator=locator, mode=mode)
|
||
if move_elemnet is True:
|
||
self.__move_element_visible(model=model, locator=locator, element=element, alignment=alignment)
|
||
try:
|
||
Log.debug(f"文本获取操作:获取{model}页面下的属性为:{locator}的元素的文本内容")
|
||
return element.text
|
||
except Exception as e:
|
||
Log.error(f"页面{model}的元素:{locator}获取文本操作失败")
|
||
self.set_img_error()
|
||
raise e
|
||
|
||
def click_radios(self, locator: tuple[str, str], method: str, amount: int = None, mode: str = 'visible',
|
||
alignment: bool = False, move_elemnet: bool = False) -> WebElement:
|
||
"""
|
||
复选框内容点击
|
||
:param locator: 传入元素定位表达式
|
||
:param mode: visible(元素可见), exist(元素存在)
|
||
:param amount: 传入复选项的数量 例子如果是3个选项就传入3
|
||
:param method: 选择对应的内容选择方式 all 点击复选框的全部内容 random 随机点击复选框的中的某一个选项 assign点击指定的某个复选项
|
||
:param alignment: 默认对其方式是元素和当前页面的底部对齐,可以传 alignment=''表示和顶部对齐
|
||
:param move_elemnet: 这里是布尔值 传入True 表示需要让元素滚动到页面可见区域 False 表示不用
|
||
:return: 全部点击时无返回,其他返回被点击的元素
|
||
"""
|
||
# 定位到复选框一定是一组元素
|
||
model = self.get_current_url_path()
|
||
elements: list[WebElement] = self.find_elements(locator=locator, mode=mode)
|
||
try:
|
||
Log.debug('点击方式为:{}'.format(method))
|
||
if method == 'all':
|
||
# 点击复选项中每一个元素
|
||
for ele in elements:
|
||
if move_elemnet is True:
|
||
self.__move_element_visible(model=model, locator=locator, element=ele, alignment=alignment)
|
||
ele.click()
|
||
# 随机点击复选项中的某一个内容
|
||
elif method == 'random':
|
||
# 导入随机数包
|
||
import random
|
||
# 生成指定范围之内的随机数作为需要点击的radio
|
||
num = random.randint(0, amount - 1)
|
||
element = elements[num]
|
||
if move_elemnet is True:
|
||
self.__move_element_visible(model=model, locator=locator, element=element, alignment=alignment)
|
||
element.click()
|
||
# 返回被点击的元素
|
||
return element
|
||
# 点击复选框中指定位置的选项
|
||
elif method == 'assign':
|
||
# 因为从0开始计数,所以传入的 amount-1
|
||
element = elements[amount - 1]
|
||
if move_elemnet is True:
|
||
self.__move_element_visible(model=model, locator=locator, element=element, alignment=alignment)
|
||
element.click()
|
||
return element
|
||
else:
|
||
Log.error('点击方式输入错误,请检查')
|
||
except Exception as e:
|
||
Log.error(f"页面{model}的元素:{locator}复选框点击操作失败")
|
||
self.set_img_error()
|
||
raise e
|
||
|
||
@staticmethod
|
||
def element_is_selected(elenmet: WebElement):
|
||
"""
|
||
判断元素是否勾选
|
||
:param elenmet: 需要校验是否勾选的元素
|
||
:return: 选中是Ture 没有选择是False
|
||
"""
|
||
return elenmet.is_selected()
|
||
|
||
def dispose_alert(self, action: str) -> str:
|
||
"""
|
||
处理页面alert
|
||
:param action: 参数为 accept 点击alert的确定 dismiss点击alert的取消
|
||
:return: 返回alert的文本内容 可能有些用例需要用这个参数去校验
|
||
"""
|
||
# 等待alert出现再去操作
|
||
self.wait.until(ec.alert_is_present())
|
||
alert: Alert = self.driver.switch_to.alert
|
||
# 尝试点击alert
|
||
try:
|
||
if action == 'accept':
|
||
alert.accept()
|
||
elif action == 'dismiss':
|
||
alert.dismiss()
|
||
else:
|
||
Log.error('alert 处理参数错误请检查')
|
||
return alert.text
|
||
except Exception as e:
|
||
Log.error('alert处理异常')
|
||
raise e
|
||
|
||
def get_handles(self):
|
||
"""
|
||
获取当前页面的句柄
|
||
:return: 方法返回值当前获取到的句柄值
|
||
"""
|
||
# 获取当前页面的句柄
|
||
handles = self.driver.window_handles
|
||
return handles
|
||
|
||
def swich_window(self, old_handle) -> None:
|
||
"""
|
||
浏览器页面切换--通过切换句柄实现切换到正在使用的页面上
|
||
:param old_handle: 传入之前获取的句柄的值
|
||
:return: None
|
||
"""
|
||
# 等待最新的窗口出现
|
||
self.wait.until(ec.new_window_is_opened(old_handle))
|
||
# 调用获取句柄的方法拿到最新打开的标签页的句柄
|
||
new_handle = self.get_handles()
|
||
# 切换到最新页面因为时最新所以直接使用下标 -1 就行
|
||
self.driver.switch_to.window(new_handle[-1])
|
||
|
||
def is_element_exist(self, locator: tuple[str, str], timeout: int = 10) -> bool:
|
||
"""
|
||
判断单元素是否存在
|
||
:param timeout: 默认超时时间
|
||
:param locator: 传入元素定位表达式
|
||
:return: 返回布尔值 true表示元素存在 false表示元素不存在
|
||
"""
|
||
model = self.get_current_url_path()
|
||
try:
|
||
Log.debug(f'判断{model}页面的元素{locator}是否存在')
|
||
WebDriverWait(self.driver, timeout=timeout, poll_frequency=0.1).until(
|
||
ec.visibility_of_element_located(locator))
|
||
return True
|
||
except Exception:
|
||
return False
|
||
|
||
# 判断元素是否已经消失不见了
|
||
def element_whether_invisibility(self, locator: tuple[str, str]) -> bool:
|
||
"""
|
||
判断元素是否已经消失不见了
|
||
:param locator: 传入元素定位表达式
|
||
:return:
|
||
"""
|
||
model = self.get_current_url_path()
|
||
try:
|
||
# 主要用于处理loading页面加载完成后1秒再去判断保证被判断的元素正常展示
|
||
# time.sleep(1)
|
||
# 获取等待开始时间的时间戳
|
||
__start_time = Times.timestamp()
|
||
Log.debug(f'判断{model}页面的元素{locator}是否消失了')
|
||
WebDriverWait(self.driver, timeout=60, poll_frequency=0.1).until(
|
||
ec.invisibility_of_element_located(locator))
|
||
# 计算元素等待的时间
|
||
__wait_time = Times.timestamp() - __start_time
|
||
Log.debug(f"页面:{model}上的元素{locator}已消失,共计等待{__wait_time:0.2f}秒")
|
||
return True
|
||
except Exception:
|
||
return False
|
||
|
||
def switch_ifram(self, locator: tuple[str, str]) -> None:
|
||
"""
|
||
判切换ifram,部分页面的元素在ifram里需要切换后定位
|
||
:param locator: 传入元素定位表达式
|
||
"""
|
||
model = self.get_current_url_path()
|
||
try:
|
||
Log.debug(f'切换{model}页面的ifram{locator}')
|
||
self.driver.switch_to.frame(frame_reference=self.find_element(model=model, locator=locator))
|
||
except Exception:
|
||
Log.error(f'{model}页面的ifram切换失败')
|
||
|
||
def mouse_over(self, locator: tuple[str, str], times: int) -> None:
|
||
"""
|
||
鼠标悬停功能
|
||
:param locator: 元素定位表达式
|
||
:param times: 悬停N秒
|
||
:return: None
|
||
"""
|
||
model = self.get_current_url_path()
|
||
element = self.find_element(model=model, locator=locator)
|
||
ActionChains(self.driver).move_to_element(to_element=element).perform()
|
||
time.sleep(times)
|
||
|
||
def refresh_page(self) -> None:
|
||
"""
|
||
刷新当前页面
|
||
:return: None
|
||
"""
|
||
Log.info(f"刷新页面: {self.get_current_url_path()}")
|
||
self.driver.refresh()
|
||
|
||
def execute_script(self, script_str, *args) -> None:
|
||
"""
|
||
执行script脚本
|
||
:param script_str: 元素定位表达式
|
||
"""
|
||
Log.info(f"页面脚本执行: {script_str}")
|
||
self.driver.execute_script(script_str, *args)
|