UI界面自动化BagePage

常用basepage模块代码

python 复制代码
# -*- coding: utf-8 -*-
# @Desc: UI自动化测试的一些基础浏览器操作方法

# 第三方库导入
import time
from logging import config
import random

import allure
from selenium.webdriver.common.alert import Alert
from selenium.webdriver.remote.webelement import WebElement
from selenium.webdriver.support.select import Select

import config
from common.utils.ReturnTime import ReturnTime
from jc_log.setting import get_logger
import pyautogui
from pywinauto.keyboard import send_keys
from selenium.common.exceptions import NoSuchElementException, InvalidSelectorException, TimeoutException
from selenium.webdriver import ActionChains
from selenium.webdriver.support import expected_conditions as ec
from selenium.webdriver.support.wait import WebDriverWait

logger = get_logger(__name__)
g_timeout = 10
g_poll_frequency = 0.2


class BasePage:
    """
    UI自动化基础操作封装
    """

    def __init__(self, driver):
        self.driver = driver
        self.__img_dir = config.REPORT_DIR

    def refresh(self):
        """刷新网页"""
        self.driver.refresh()

    def get_url(self, url):
        """
        访问指定地址
        """
        self.driver.get(url=url)
        return self.driver.current_url

    def get_current_url(self):
        """
        获取当前浏览器驱动的地址
        """
        return self.driver.current_url

    def force_click(self, locator: tuple, mode: str = "click", force=False):
        """鼠标点击,当元素不可点击的时候,使用强制点击

        :param locator: 元素定位,元祖类型
        :param mode: visible(元素可见),notvisible(元素消失不可见), exist(元素存在),click(元素可点击)
        :param force: 强制点击,默认false
        """
        try:
            elem = self.find_element(locator=locator, mode=mode)
            if not force:
                self.driver.execute_script("arguments[0].click()", elem)
            else:
                elem.click()
                self.driver.execute_script("arguments[0].click({force: true})", elem)
        except Exception as e:
            print("未找到元素:{}".format(e))
            raise e

    def wait_element_visibility(self, locator: tuple, timeout=20, poll_frequency=g_poll_frequency):
        """
        显性等待: 等待元素可见

        :param locator: 元素定位,元祖类型
        :param timeout
        :param poll_frequency
        :return:
        """
        page = self.get_current_url()
        logger.debug(f"-开始-等待页面{page}的元素:{locator}可见")
        try:
            # 获取等待开始时间的时间戳
            __start_time = ReturnTime.get_timestamp()
            rtn = WebDriverWait(self.driver, timeout, poll_frequency).until(ec.visibility_of_element_located(locator))
            # 计算元素等待的时间
            __wait_time = ReturnTime.get_timestamp() - __start_time
            logger.debug(f"页面:{page}上的元素{locator}已可见,共计等待{__wait_time:0.2f}秒")
        except TimeoutException:
            logger.error(f"页面:{page},等待元素{locator}超时")
            self.set_error_img()
            raise TimeoutException('元素等待超时')
        except InvalidSelectorException as e:
            logger.error(f"页面:{page},元素不可见或定位表达式:{locator}异常\n {e}")
            raise InvalidSelectorException('元素定位异常')
        return rtn

    def wait_element_clickable(self, locator: tuple, timeout=g_timeout, poll_frequency=g_poll_frequency):
        """
        显性等待: 等待元素可点击

        :param locator: 元素定位,元祖类型
        :param timeout:
        :param poll_frequency
        :return:
        """

        page = self.get_current_url()
        logger.debug(f"-开始-等待页面{page}的元素:{locator}可点击")
        try:
            # 获取等待开始时间的时间戳
            __start_time = ReturnTime.get_timestamp()
            rtn = WebDriverWait(self.driver, timeout, poll_frequency).until(
                ec.element_to_be_clickable(locator))

            # 计算元素等待的时间
            __wait_time = ReturnTime.get_timestamp() - __start_time
            logger.debug(f"页面:{page}上的元素{locator}已可点击,共计等待{__wait_time:0.2f}秒")
        except TimeoutException as e:
            logger.error(f"页面:{page},等待元素{locator}超时")
            self.set_error_img()
            raise e
        except InvalidSelectorException as e:
            logger.error(f"页面:{page},元素不可点击或定位表达式:{locator}异常\n {e}")
            raise e
        return rtn

    def wait_element_presence(self, locator: tuple, timeout=g_timeout, poll_frequency=g_poll_frequency):
        """
        显性等待: 等待元素被加载出来

        :param locator: 元素定位,元祖类型
        :param timeout
        :param poll_frequency
        :return:
        """
        page = self.get_current_url()
        logger.debug(f"-开始-等待页面{page}的元素:{locator}存在")
        try:
            # 获取等待开始时间的时间戳
            __start_time = ReturnTime.get_timestamp()
            rtn = WebDriverWait(self.driver, timeout, poll_frequency).until(
                ec.presence_of_all_elements_located(locator))
            # 计算元素等待的时间
            __wait_time = ReturnTime.get_timestamp() - __start_time
            logger.debug(f"页面:{page}上的元素{locator}已存在,共计等待{__wait_time:0.2f}秒")
        except TimeoutException as e:
            logger.error(f"页面:{page},等待元素{locator}超时")
            self.set_error_img()
            raise e
        except InvalidSelectorException as e:
            logger.error(f"页面:{page},元素不存在或定位表达式:{locator}异常\n {e}")
            raise e
        return rtn

    def wait_element_not_visible(self, locator: tuple, timeout=g_timeout, poll_frequency=g_poll_frequency):
        """
        等待元素不可见

        :param locator: 元素定位表达式
        :param timeout
        :param poll_frequency
        :return:
        :return: 无返回值
        """
        page = self.get_current_url()
        logger.debug(f"-开始-等待页面{page}的元素:{locator}存在")
        try:
            # 获取等待开始时间的时间戳
            __start_time = ReturnTime.get_timestamp()
            time.sleep(1)
            rtn = WebDriverWait(self.driver, timeout, poll_frequency).until(
                ec.invisibility_of_element_located(locator))
            # 计算元素等待的时间
            __wait_time = ReturnTime.get_timestamp() - __start_time
            logger.debug(f"页面:{page}上的元素{locator}已经不可见,共计等待{__wait_time:0.2f}秒")
        except TimeoutException as e:
            logger.error(f"页面:{page},等待元素{locator}不可见超时")
            self.set_error_img()
            raise e
        except InvalidSelectorException as e:
            logger.error(f"页面:{page},元素不存在或定位表达式:{locator}异常\n {e}")
            raise e
        return rtn

    def get_element_attribute(self, locator: tuple, attr_name):
        """
        获取元素属性值

        :param locator: 元素定位,元祖类型
        :param attr_name
        :return: 元素属性值
        """
        try:
            return self.driver.find_element(*locator).get_attribute(attr_name)
        except NoSuchElementException as e:
            print("未找到元素:{}".format(e))
            raise e

    def get_name(self, locator: tuple):
        """
        获取元素的name属性值
        """
        return self.get_element_attribute(locator, "name")

    def get_title(self, locator: tuple):
        """
        获取元素的title属性值
        """
        return self.get_element_attribute(locator, "title")

    def get_class(self, locator: tuple):
        """
        获取元素的class属性值
        """
        return self.get_element_attribute(locator, "class")

    def switch_to_frame(self, reference=None, timeout=g_timeout, poll=g_poll_frequency):
        """
        iframe切换

        :param reference: 可以是id, name,索引或者元素定位(元祖)
        :param timeout:
        :param poll:
        :return:
        """
        if not reference:
            return self.driver.switch_to.default_content()
        return WebDriverWait(self.driver, timeout, poll).until(
            ec.frame_to_be_available_and_switch_to_it(reference)
        )

    def __get_title_handle(self, title):
        handles = self.driver.window_handles
        for handle in handles:
            self.driver.switch_to.window(handle)
            if self.driver.title == title:
                return handle

    def switch_to_window(self, title):
        """切换到指定窗口"""
        self.__get_title_handle(title)
        return self

    def switch_next_window(self):
        """切换到另一个窗口"""
        # 获取所有的窗口
        windows = self.driver.window_handles
        if len(windows) >= 2:
            # 切换窗口
            self.driver.switch_to.window(self.driver.window_handles[-1])
        return self

    def open_new_window(self, url):
        """打开一个新窗口"""
        # 获取所有的窗口
        start_window = self.driver.window_handls
        # 打开新窗口
        js = "window.open({})".format(url)
        self.driver.execute_script(js)
        # 等待新窗口出现,进行切换
        WebDriverWait(self.driver, 5, 0.5).until(
            ec.new_window_is_opened(start_window)
        )
        # 切换窗口
        self.driver.switch_to.window(self.driver.window_handls[-1])
        return self

    def __select_wait_method(self, locator: tuple, mode: str = "visible") -> None:
        """
        选择元素定位的等待方式

        :param locator: 元素的定位表达式 例:(By.xx,'定位表达式')
        :param mode: visible(元素可见), exist(元素存在),click(元素可点击)
        :return: 无返回值
        """
        page = self.get_current_url()
        if mode == "visible":
            self.wait_element_visibility(locator=locator)
        elif mode == "exist":
            self.wait_element_presence(locator=locator)
        elif mode == "click":
            self.wait_element_clickable(locator=locator)
        else:
            logger.error(f"定位{page}页面的元素:{locator},mode参数传值异常,入参值为:{mode}")

    def find_element(self, locator: tuple, mode: str = "visible") -> WebElement:
        """
        定位元素,支持所有定位单个元素的定位表达式

        :param locator: 元素的定位表达式 例:(By.xx,'定位表达式')
        :param mode: visible(元素可见), exist(元素存在),click(元素可点击)
        :return: 定位到的元素对象
        """
        page = self.get_current_url()
        self.__select_wait_method(locator=locator, mode=mode)
        try:
            logger.debug(f"正在定位{page}页面的: {locator} 的元素")
            element = self.driver.find_element(*locator)
            self.element_dyeing(element=element)
            return element
        except TimeoutException:
            logger.error(f"页面:{page},定位元素:{locator}定位超时")
            self.set_error_img()
            raise TimeoutException("元素定位超时请检查")
        except Exception:
            logger.error(f"页面:{page},定位元素:{locator}定位失败")
            self.set_error_img()
            raise Exception("元素定位失败请检查")

    def find_elements(self, locator: tuple, mode: str = "visible") -> list:
        """
        定位一组元素,返回一个列表

        :param locator: 元素的定位表达式 例:(By.xx,'定位表达式')
        :param mode: visible(元素可见),notvisible(元素消失不可见), exist(元素存在)
        :return: 返回一组元素是一个列表
        """
        page = self.get_current_url()
        self.__select_wait_method(locator=locator, mode=mode)
        try:
            logger.debug(f"正在定位{page}页面的: {locator} 的元素")
            element_list = self.driver.find_elements(*locator)
            return element_list
        except NoSuchElementException as e:
            logger.error(f"页面:{page},定位元素:{locator}定位失败")
            self.set_error_img()
            raise e

    def __move_element_visible(self, locator: tuple, element: WebElement, alignment: bool = False) -> None:
        """
         将元素移动到页面可见区域

        :param locator: 元素的定位表达式 例:(By.xx,'定位表达式')
        :param alignment 默认对齐方式是元素和当前页面的底部对齐,可以传 alignment=''表示和顶部对齐
        :param element 需要可见的元素
        :return: 无返回值
        """
        page = self.get_current_url()
        logger.debug(f'将{page}页面的元素:{locator}移动至浏览器可见区域')
        try:
            # 代码执行比页面渲染速度快 这里放0.5秒等待页面渲染
            time.sleep(0.5)
            self.driver.execute_script('arguments[0].scrollIntoView({0});'.format(alignment), element)
            # 休眠1秒让页面可以正常滚动到对应的位置再执行下去
            time.sleep(1)
        except Exception as e:
            logger.error(f"{page}页面的元素:{locator}移动失败\n{e}")
            self.set_error_img()
            raise e

    def click(self, locator: tuple, mode: str = "click", alignment: bool = False, move_element: bool = False,
              is_double_click: bool = False) -> None:
        """
        点击元素

        :param locator: 元素的定位表达式 例:(By.xx,'定位表达式')
        :param mode: visible(元素可见),notvisible(元素消失不可见), exist(元素存在),click(元素可点击)
        :param alignment: 默认对齐方式是元素和当前页面的底部对齐,可以传 alignment=''表示和顶部对齐
        :param move_element: 这里是布尔值 传入True 表示需要让元素滚动到页面可见区域 False 表示不用
        :param is_double_click: False单击元素,传入True 双击元素
        :return: 无返回值
        """
        page = self.get_current_url()
        element = self.find_element(locator=locator, mode=mode)
        if move_element is True:
            self.__move_element_visible(locator=locator, element=element, alignment=alignment)
        try:
            logger.debug(f"点击:{page}页面,属性为{locator}的元素")
            if is_double_click:
                ActionChains(self.driver).double_click(element).perform()
            else:
                element.click()
        except Exception as e:
            logger.error(f"页面{page}的元素: {locator} 点击失败")
            self.set_error_img()
            raise e

    def click_elements(self, locator: tuple, mode: str = "click", alignment: bool = False, move_element: bool = False,
                       is_double_click: bool = False) -> None:
        """
        点击一组元素

        :param locator: 元素的定位表达式 例:(By.xx,'定位表达式')
        :param mode: visible(元素可见),notvisible(元素消失不可见), exist(元素存在),click(元素可点击)
        :param alignment: 默认对齐方式是元素和当前页面的底部对齐,可以传 alignment=''表示和顶部对齐
        :param move_element: 这里是布尔值 传入True 表示需要让元素滚动到页面可见区域 False 表示不用
        :param is_double_click: False单击元素,传入True 双击元素
        :return: 无返回值
        """
        page = self.get_current_url()
        elements = self.find_elements(locator=locator, mode=mode)
        if move_element is True:
            self.__move_element_visible(locator=locator, element=elements[0], alignment=alignment)
        try:
            logger.debug(f"点击:{page}页面,属性为{locator}的元素")
            for element in elements:
                if is_double_click:
                    ActionChains(self.driver).double_click(element).perform()
                else:
                    element.click()
        except Exception as e:
            logger.error(f"页面{page}的元素: {locator} 点击失败")
            self.set_error_img()
            raise e

    def random_click_element(self, locator: tuple, num: int, mode: str = "click", alignment: bool = False,
                             move_element: bool = False) -> str:
        """
        随机点击一个元素

        :param locator: 元素的定位表达式 例:(By.xx,'定位表达式')
        :param num: 从第几位元素开始点击
        :param mode: visible(元素可见), exist(元素存在),click(元素可点击)
        :param alignment: 默认对齐方式是元素和当前页面的底部对齐,可以传 alignment=''表示和顶部对齐
        :param move_element: 这里是布尔值 传入True 表示需要让元素滚动到页面可见区域 False 表示不用
        :return: 点击的元素的文本
        """
        page = self.get_current_url()
        elements = self.find_elements(locator=locator, mode=mode)
        click_num: int = random.randint(num, len(elements) - 1)
        try:
            element = elements[click_num]
            if move_element is True:
                self.__move_element_visible(locator=locator, element=element, alignment=alignment)
            self.element_dyeing(element)
            logger.debug(f"点击:{page}页面,属性为{locator}的元素中的{click_num}位")
            element.click()
        except Exception as e:
            logger.error(f"页面{page}的元素: {locator} 中的第{click_num}位元素点击失败")
            self.set_error_img()
            raise e
        return element.text

    def input_text(self, locator: tuple, content: str or int, mode: str = "visible", alignment: bool = False,
                   move_element: bool = False) -> WebElement:
        """
        输入文本内容

        :param locator: 传入元素定位表达式
        :param content: 传入输入的文本内容
        :param mode:  visible(元素可见), exist(元素存在)
        :param alignment: 默认对齐方式是元素和当前页面的底部对齐,可以传 alignment=''表示和顶部对齐
        :param move_element: 这里是布尔值 传入True 表示需要让元素滚动到页面可见区域 False 表示不用
        :return: 无返回值
        """
        page = self.get_current_url()
        element = self.find_element(locator=locator, mode=mode)
        if move_element is True:
            self.__move_element_visible(locator=locator, element=element, alignment=alignment)
        try:
            self.clear_contents(locator=locator, mode=mode, alignment=alignment)
            logger.debug(f"输入操作:{page}页面下的属性为:{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_error_img()
            logger.error(f"页面{page}的属性: {locator} 输入操作失败")
            raise e
        return element

    def clear_contents(self, locator: tuple, mode: str = "visible", alignment: bool = False,
                       move_element: bool = False) -> None:
        """
        清除文本内容

        :param locator: 传入元素定位表达式
        :param mode:  visible(元素可见), exist(元素存在)
        :param alignment: 默认对齐方式是元素和当前页面的底部对齐,可以传 alignment=''表示和顶部对齐
        :param move_element: 这里是布尔值 传入True 表示需要让元素滚动到页面可见区域 False 表示不用
        :return: 无返回值
        """
        page = self.get_current_url()
        element = self.find_element(locator=locator, mode=mode)
        if move_element is True:
            self.__move_element_visible(locator=locator, element=element, alignment=alignment)
        try:
            logger.debug(f"输入操作:{page}页面下的属性为:{locator}的元素,清除内容")
            # 保证正常清除
            time.sleep(0.2)
            element.clear()
        except Exception as e:
            self.set_error_img()
            logger.error(f"页面{page}的属性: {locator} 清除操作失败")
            raise e

    def get_element_text(self, locator: tuple, mode: str = 'visible', alignment: bool = False,
                         move_element: bool = False) -> str:
        """
        获取元素的文本内容

        :param locator:  传入元素定位表达式
        :param mode: visible(元素可见), exist(元素存在)
        :param alignment: 默认对齐方式是元素和当前页面的底部对齐,可以传 alignment=''表示和顶部对齐
        :param move_element: 这里是布尔值 传入True 表示需要让元素滚动到页面可见区域 False 表示不用
        :return: 返回获取到的元素文本内容
        """
        page = self.get_current_url()
        element = self.find_element(locator=locator, mode=mode)
        if move_element is True:
            self.__move_element_visible(locator=locator, element=element, alignment=alignment)
        try:
            logger.debug(f"文本获取操作:获取{page}页面下的属性为:{locator}的元素的文本内容")
            return element.text
        except Exception as e:
            logger.error(f"页面{page}的元素:{locator}获取文本操作失败")
            self.set_error_img()
            raise e

    def click_radios(self, locator: tuple, method: str, amount: int = None, mode: str = 'visible',
                     alignment: bool = False, move_element: bool = False) -> WebElement:
        """
        复选框内容点击

        :param locator: 传入元素定位表达式
        :param mode:  visible(元素可见), exist(元素存在)
        :param amount: 传入复选项的数量 例子如果是3个选项就传入3
        :param method: 选择对应的内容选择方式 all 点击复选框的全部内容 random 随机点击复选框的中的某一个选项 assign点击指定的某个复选项
        :param alignment: 默认对齐方式是元素和当前页面的底部对齐,可以传 alignment=''表示和顶部对齐
        :param move_element: 这里是布尔值 传入True 表示需要让元素滚动到页面可见区域 False 表示不用
        :return: 全部点击时无返回,其他返回被点击的元素
        """
        # 定位到复选框一定是一组元素
        page = self.get_current_url()
        elements: list[WebElement] = self.find_elements(locator=locator, mode=mode)
        try:
            logger.debug('点击方式为:{}'.format(method))
            if method == 'all':
                # 点击复选项中每一个元素
                for ele in elements:
                    if move_element is True:
                        self.__move_element_visible(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_element is True:
                    self.__move_element_visible(locator=locator, element=element, alignment=alignment)
                element.click()
                # 返回被点击的元素
                return element
            # 点击复选框中指定位置的选项
            elif method == 'assign':
                # 因为从0开始计数,所以传入的 amount-1
                element = elements[amount - 1]
                if move_element is True:
                    self.__move_element_visible(locator=locator, element=element, alignment=alignment)
                element.click()
                return element
            else:
                logger.error('点击方式输入错误,请检查')
        except Exception as e:
            logger.error(f"页面{page}的元素:{locator}复选框点击操作失败")
            self.set_error_img()
            raise e

    @staticmethod
    def element_is_selected(element: WebElement):
        """
        判断元素是否勾选

        :param element: 需要校验是否勾选的元素
        :return: 选中是Ture 没有选择是False
        """
        return element.is_selected()

    def select_contents_menu(self, locator: tuple, text: str, mode: str = 'visible', alignment: bool = False,
                             move_element: bool = False) -> None:

        """
        选择下拉菜单中的内容

        :param locator: 传入元素定位表达式
        :param text: 出入下拉列表需要选择的内容
        :param mode: visible(元素可见), exist(元素存在)
        :param alignment:  默认对齐方式是元素和当前页面的底部对齐,可以传 alignment=''表示和顶部对齐
        :param move_element: 这里是布尔值 传入True 表示需要让元素滚动到页面可见区域 False 表示不用
        """
        page = self.get_current_url()
        element = self.find_element(locator=locator, mode=mode)
        # 定义一个存储菜单内容的空列表
        option = []
        if move_element is True:
            self.__move_element_visible(locator=locator, element=element, alignment=alignment)
        try:
            # 获取下拉列表的内容
            options = element.find_elements_by_tag_name("option")
            for value in options:
                option.append(value)
            if text in option:
                Select(element).select_by_visible_text(text)
            else:
                logger.error(f"选项:{text}不在下拉列表之中请检查")
        except Exception as e:
            self.set_error_img()
            logger.error(f"页面{page}的元素:{locator}下拉框操作失败请检查")
            raise e

    def dispose_alert(self, action: str) -> str:
        """
        处理页面alert

        :param action: 参数为 accept 点击alert的确定 dismiss点击alert的取消
        :return: 返回alert的文本内容 可能有些用例需要用这个参数去校验
        """
        # 等待alert出现再去操作
        WebDriverWait(self.driver, 5, 0.5).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:
                logger.error('alert 处理参数错误请检查')
            return alert.text
        except Exception as e:
            logger.error('alert处理异常')
            raise e

    def get_text(self, locator: tuple):
        """
        获取元素的文本值

        :param locator: 元素定位
        :return:
        """
        try:
            elem = self.driver.find_element(*locator)
            value = elem.text
            return value
        except NoSuchElementException as e:
            print(f"get未找到元素{e}")
            raise e

    def element_dyeing(self, element) -> None:
        """
        将被操作的元素染色

        :return: None
        """
        self.driver.execute_script("arguments[0].setAttribute('style', 'background: yellow; border: 2px solid red;');",
                                   element)

    def set_error_img(self) -> None:
        """
        截图

        :return: None
        """
        __time_tag = ReturnTime.get_timestamp()
        __img_path = self.__img_dir + f"/{__time_tag}.png"
        try:
            # 进行截图
            self.driver.save_screenshot(filename=__img_path)
            logger.error(f"截图成功文件名称为:{__time_tag}.png")
            __file = open(__img_path, "rb").read()
            allure.attach(__file, "用例执行失败截图", allure.attachment_type.PNG)
        except Exception as e:
            logger.error(f"执行失败截图未能正确添加进入测试报告:{e}")
            raise e

    def set_case_img(self) -> None:
        """
        用例执行完毕截图,并且将截图加入allure测试报告中

        :return: 无返回值
        """
        with allure.step("关键步骤截图"):
            __img_name = ReturnTime.get_timestamp()
            __img_path = self.__img_dir + f"/{__img_name}.png"
            try:
                # 截图前等待1秒防止图片没有正常加载
                time.sleep(1)
                self.driver.save_screenshot(filename=__img_path)
                logger.debug(f"用例执行完成,截图成功,文件名称为{__img_name}.png")
                # 读取图片信息
                __file = open(file=__img_path, mode="rb").read()
                allure.attach(__file, "关键步骤截图", allure.attachment_type.PNG)
            except Exception as e:
                logger.error(f"测试结果截图,未能正确添加进入测试报告:{e}")
                raise e

    # ------------------------ START: JS事件 ------------------------ #
    def execute_js(self, js, *args):
        """
        执行javascript脚本
        js: 元组形式参数
        """
        self.driver.execute_script(js, *args)
        return self

    def upload_file_pywinauto(self, file_path):
        """
        使用pywinauto来上传
            缺点:只能在windows上使用。
            优点:可以选择多个文件,路径中有中文也可以。
            安装:pip install pywinauto -i https://mirrors.aliyun.com/pypi/simple/
        :param file_path: 文件绝对路径,支持传数组
        """
        if isinstance(file_path, list):
            for path in file_path:
                # 上传文件
                send_keys(path)
        else:
            # 上传文件
            send_keys(file_path)
        # 点击回车
        send_keys("{VK_RETURN}")
        return self

    def upload_file_pyautogui(self, file_path):
        """
        使用pyautogui来上传
            缺点:只能选择一个文件,路径中有中文会出问题。
            优点:跨平台。Linux, mac,windows都可以。
            安装:pip install pyautogui -i https://mirrors.aliyun.com/pypi/simple/
        :param file_path: 文件绝对路径,支持传数组
        """
        if isinstance(file_path, list):
            print("只能选择一个文件,默认选择第一个")
            file_path = file_path[0]

        # 上传文件
        pyautogui.write(file_path)
        # 点击回车
        pyautogui.press("enter", 2)
        return self

    # ------------------------ END: JS事件 ------------------------ #

    # ------------------------ START: 鼠标事件:双击,悬停,拖动 ------------------------ #

    def double_click(self, locator):
        """
        鼠标双击
        :param locator:
        :return:
        """
        try:
            elem = self.driver.find_element(*locator)
            action = ActionChains(self.driver)
            action.double_click(elem).perform()
            return self
        except NoSuchElementException as e:
            print("未找到元素:{}".format(e))
            raise e

    def drag_and_drop(self, start_locator, end_locator):
        """鼠标拖动"""
        elem_start = self.driver.find_element(*start_locator)
        elem_end = self.driver.find_element(*end_locator)
        action = ActionChains(self.driver)
        action.double_click((elem_start, elem_end)).perform()
        return self

    def hover(self, locator):
        """鼠标悬停"""
        el = self.driver.find_element(*locator)
        action = ActionChains(self.driver)
        action.move_to_element(el).perform()
        return self
相关推荐
黄公子学安全2 小时前
Java的基础概念(一)
java·开发语言·python
程序员一诺2 小时前
【Python使用】嘿马python高级进阶全体系教程第10篇:静态Web服务器-返回固定页面数据,1. 开发自己的静态Web服务器【附代码文档】
后端·python
小木_.3 小时前
【Python 图片下载器】一款专门为爬虫制作的图片下载器,多线程下载,速度快,支持续传/图片缩放/图片压缩/图片转换
爬虫·python·学习·分享·批量下载·图片下载器
Jiude3 小时前
算法题题解记录——双变量问题的 “枚举右,维护左”
python·算法·面试
唐小旭3 小时前
python3.6搭建pytorch环境
人工智能·pytorch·python
是十一月末4 小时前
Opencv之对图片的处理和运算
人工智能·python·opencv·计算机视觉
爱学测试的李木子4 小时前
Python自动化测试的2种思路
开发语言·软件测试·python
kitsch0x975 小时前
工具学习_Conan 安装第三方库
开发语言·python·学习
梦幻精灵_cq5 小时前
《点点之歌》“意外”诞生记
python
张狂年少5 小时前
电力通信规约-104实战
java·开发语言·python