Files
WebAutoTest/commons/driver.py
CNWei 92d06dd9cf init: 初始化项目
- 创建了基本的项目结构
- 添加了 .gitignore 文件
- 配置了基本的开发环境
- 添加清华镜像源
- 设置了基础的文件夹和文件(如 commons, utils, POM, pytest.ini)

项目说明:
- [项目名称]:Web自动化测试
- [项目描述]:基于pytest,selenium的自动化测试工具
- [开发环境]:Python
2025-04-14 23:05:39 +08:00

342 lines
11 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env python
# coding=utf-8
"""
@author: CNWei
@Software: PyCharm
@contact: t6i888@163.com
@file: key_driver
@date: 2025/4/2 21:59
@desc:
"""
import logging
from time import sleep
import secrets # 原生库,用于生成安全的随机数
from typing import Optional, Callable, Union, Literal, Any, TypeVar
from urllib.parse import urljoin
from selenium.webdriver import Chrome, Edge, Firefox, Safari, Ie
from selenium.webdriver.common.by import By
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.support.ui import Select
from selenium.webdriver.remote.webdriver import WebDriver
from selenium.webdriver.remote.webdriver import WebElement
from commons.assert_functions import custom_asserts
from commons.custom_expected_condition import EC, custom_ec
from commons.modules import Browser, Locator
from commons.settings import configs, EXPLICIT_WAIT_TIMEOUT, SCREENSHOT_DIR
logger = logging.getLogger(__name__)
WebDriverOrWebElement = Union[WebDriver, WebElement]
D = TypeVar("D", bound=Union[WebDriver, WebElement])
T = TypeVar("T")
# 触发器 trigger
# 浏览器 Browser
# 执行器 actuator
# 筛选器 Filters
# 查找器 finder
# 转换器 converter
def webdriver_finder(browser: str | Browser = Browser.CHROME) -> WebDriver:
match browser:
case Browser.CHROME:
return Chrome()
case Browser.FIREFOX:
return Firefox()
case Browser.IE:
return Ie()
case Browser.SAFARI:
return Safari()
case Browser.EDGE:
return Edge()
case _:
return Chrome() # 默认情况
def by_converter(by_value: str | Locator):
try:
# 统一处理输入
if isinstance(by_value, str):
by = Locator(by_value.lower().replace(' ', ''))
# 创建对应的浏览器实例
by = {
Locator.ID: By.ID,
Locator.NAME: By.NAME,
Locator.CLASS: By.CLASS_NAME,
Locator.TAG: By.TAG_NAME,
Locator.LINK_TEXT: By.LINK_TEXT,
Locator.PARTIAL_LINK_TEXT: By.PARTIAL_LINK_TEXT,
Locator.CSS: By.CSS_SELECTOR,
Locator.XPATH: By.XPATH,
}.get(by_value, By.XPATH)
return by
except ValueError:
return By.XPATH
class KeyWordDriver:
# def __init__(self, browser: str | Browser):
# self.driver = self.webdriver_finder(browser)
def __init__(self):
self.driver: WebDriver | None = None
self._url: str | None = None
# self.temp_value = None
def base_url(self, url: str, *args, **kwargs):
logger.info(f"前置URL: {url}")
self._url = url
# return url
def browser(self, browser_name: str | Browser = Browser.CHROME, *args, **kwargs):
browser_name = Browser(browser_name.lower().replace(' ', '')) if isinstance(browser_name, str) else browser_name
match browser_name:
case Browser.CHROME:
logger.info(f"启动{Browser.CHROME}浏览器")
self.driver = Chrome()
# return Chrome()
case Browser.FIREFOX:
logger.info(f"启动{Browser.FIREFOX}浏览器")
self.driver = Firefox()
case Browser.IE:
logger.info(f"启动{Browser.IE}浏览器")
self.driver = Ie()
case Browser.SAFARI:
logger.info(f"启动{Browser.SAFARI}浏览器")
self.driver = Safari()
case Browser.EDGE:
logger.info(f"启动{Browser.EDGE}浏览器")
self.driver = Edge()
case _:
logger.info(f"启动默认浏览器: {Browser.CHROME}")
self.driver = Chrome() # 默认情况
def find_element(self, by: str = By.XPATH, value: Optional[str] = None, *args, **kwargs) -> WebElement:
by = by_converter(by)
return self.driver.find_element(by, value)
def delay(self, timeout: int | float):
sleep(timeout)
return self
def implicit_wait(self, timeout: float, *args, **kwargs) -> None:
"""
隐式等待
:param timeout: 超时时间
:param args:
:param kwargs:
:return:
"""
self.driver.implicitly_wait(timeout)
def explicit_wait(self, method: T, timeout: float = EXPLICIT_WAIT_TIMEOUT, *args, **kwargs):
"""
显示等待
:param method: 可调用对象名
:param timeout: 超时时间
:param args:
:param kwargs:
:return:
"""
try:
if isinstance(method, str):
method = custom_ec.get(method, (lambda _: False))
logger.info(f"预期条件: {method.__name__}")
return WebDriverWait(self.driver, timeout).until(method)
except TypeError as te:
logger.error(f"显示等待异常: {te}")
# self.driver.quit()
raise te
def page_load_timeout(self, timeout: float, *args, **kwargs) -> None:
self.driver.set_page_load_timeout(timeout)
def get(self, url, *args, **kwargs):
if self.driver is None:
self.browser(*args, **kwargs)
if not url.startswith("http"):
# 自动添加baseurl
url = urljoin(self._url, url)
logger.info(f"网址: {url}")
print(url)
self.driver.get(url)
def maximize_window(self):
self.driver.maximize_window()
def click(self, by, value, *args, **kwargs):
by = by_converter(by)
mark = (by, value)
method = EC.element_to_be_clickable(mark)
self.explicit_wait(method).click()
# self.find_element(by, value).click()
def clear(self, by, value, *args, **kwargs):
by = by_converter(by)
mark = (by, value)
method = EC.visibility_of_element_located(mark)
self.explicit_wait(method).clear()
# self.driver.find_element(by, value).clear()
def input(self, by, value, content: str | None = None, *args, **kwargs):
by = by_converter(by)
mark = (by, value)
method = EC.visibility_of_element_located(mark)
self.explicit_wait(method).send_keys(content)
# self.find_element(by, value).send_keys(content)
def get_text(self, by, value, *args, **kwargs):
"""
获取元素文本
:param by:
:param value:
:param args:
:param kwargs:
:return:
"""
by = by_converter(by)
mark = (by, value)
method = EC.visibility_of_element_located(mark)
text = self.explicit_wait(method).text
# print(text)
return text
def get_attribute(self, by, value, attributes: str, *args, **kwargs):
"""
获取元素属性值(classtypevalue,...)
:param by:
:param value:
:param attributes:
:param args:
:param kwargs:
:return:
"""
by = by_converter(by)
mark = (by, value)
method = EC.presence_of_element_located(mark)
text = self.explicit_wait(method).get_attribute(attributes)
# print(text)
return text
def enter_iframe(self, by, value, *args, **kwargs):
by = by_converter(by)
element = self.find_element(by, value)
self.driver.switch_to.frame(element)
def exit_iframe(self, *args, **kwargs):
self.driver.switch_to.default_content()
def get_cookie(self, name, *args, **kwargs) -> Optional[dict]:
return self.driver.get_cookie(name)
def add_cookie(self, cookie_dict, *args, **kwargs) -> None:
self.driver.add_cookie(cookie_dict)
def screenshot_png(self, by, value, name: str | None = None, *args, **kwargs) -> None:
by = by_converter(by)
# mark = (by, value)
# method = EC.visibility_of_element_located(mark)
if name is not None:
path = (configs.SCREENSHOT_DIR / f"{name}.png").as_posix()
else:
# 生成 8 个随机字节,然后转为 16 个字符的十六进制字符串
random_hex = secrets.token_hex(8) # n=8 表示生成 8 字节
path = (configs.SCREENSHOT_DIR / f"{random_hex}.png").as_posix()
logger.warning(f"截图存放路径: {path}")
# self.explicit_wait(method).screenshot(path)
self.find_element(by, value).screenshot(path)
def select(self, by, value, text, func_name, *args, **kwargs):
# 未完成
by = by_converter(by)
mark = (by, value)
method = EC.visibility_of_element_located(mark)
self.explicit_wait(method)
def run_javascript(self, by, value, code: str, *args, **kwargs) -> Any:
# 还需打磨
by = by_converter(by)
element = self.find_element(by, value)
return self.driver.execute_script(code, element)
# def assert_text_equals(self, by, value,method, text, msg=None):
# by = by_converter(by)
# # _text = self.get_text(by, value)
# _text = getattr(self,method)(by, value)
#
# assert _text == text, msg
# def until(self, method: Callable[[D], Union[Literal[False], T]], message: str = "") -> T:
# try:
# value = method(self.driver)
# if value:
# return value
# except AssertionError as e:
# logger.error(e)
#
# def assert_text_equals(self, method, text, msg=""):
# if isinstance(method, str):
# method = custom_asserts.get(method, (lambda _: False))
# logger.info(f"{method=}")
# # _text = self.until(method)
# _text = method(self.driver)
# logger.info(_text)
# assert _text == text, msg
def assert_text_equals(self, by, value, text):
by = by_converter(by)
_text = self.get_text(by, value)
assert _text == text, f"断言“{_text}”与“{text}”相等失败!!"
logger.info(f"断言: {_text} == {text}")
def assert_text_not_equals(self, by, value, text):
by = by_converter(by)
_text = self.get_text(by, value)
assert _text != text, f"断言“{_text}”与“{text}”不相等失败!!"
def assert_text_contains(self, by, value, text, msg=None):
by = by_converter(by)
_text = self.get_text(by, value)
assert _text in text, f"断言“{_text}”包含于“{text}”中失败!!"
def assert_text_not_contains(self, by, value, text, msg=None):
by = by_converter(by)
_text = self.get_text(by, value)
assert _text not in text, f"断言“{_text}”不包含于“{text}”中失败!!"
if __name__ == '__main__':
from commons.settings import configs
el = KeyWordDriver()
el.base_url(configs.base_url)
# el.browser("chrome")
el.browser(Browser.EDGE)
el.get("/users/login")
el.input("", '//*[@id="email"]', configs.username)
el.input("", '//*[@id="pass"]', configs.password)
el.get_text("", '//*[@id="root"]/div[1]/div/div/form/div[1]/label')
el.click("", '//*[@id="root"]/div[1]/div/div/form/div[3]/button')
type_value = el.get_attribute("", '//*[@id="root"]/div[1]/div/div/form/div[3]/button', "type")
print(type_value)
el.assert_text_equals("", '//*[@id="root"]/div[1]/div/div/form/div[3]/button', "登录")