#!/usr/bin/env python # -*- coding: utf-8 -*- ''' @File : head_page.py @Time : 2024/11/07 15:19:33 @Author : dulip3ng @Version : 1.0 @Desc : None ''' import re from playwright.sync_api import expect, Error, Page from pages.base_page import BasePage from common.field_type import FieldType class HeadPage(BasePage): def __init__(self, page:Page, locator): super().__init__(page) self.locator = locator def click_button(self, button_name:str, sub_button_name:str=None): """ 点击单据头按钮 :param button_name: 按钮名称 :param sub_button_name: 子按钮名称 :return: None """ if not sub_button_name: self.page.locator(self.locator.BUTTON_ARGS_LOC % button_name).click() else: self.page.locator(self.locator.BUTTON_ARROW_ARGS_LOC % button_name).hover() self.page.locator(self.locator.SUB_BUTTON_ARGS_LOC % sub_button_name).click() def change_sheet(self, sheet_name:str): """ 点击单据头页签 :param sheet_name: 页签名称 :return: None """ self.page.locator(self.locator.SHEET_ARGS_LOC % sheet_name).click() def _set_text(self, field_name:str, value:str): """ 单据头文本字段赋值 :param field_name: 字段名 :param value: 字段值 :return: None """ locator = self.page.locator(self.locator.TEXT_FIELD_ARGS_LOC % field_name) locator.clear() locator.fill(value) def _set_base(self, field_name:str, value:str): """ 单据头基础资料字段赋值 :param field_name: 字段名 :param value: 字段值 :return: None """ # 直接点击BASE_FIELD_ARGS_LOC input元素可操作性检查不通过,被BASE_FIELD_SPAN_ARGS_LOC span劫持,这里直接对span进行点击 self.page.locator(self.locator.BASE_FIELD_SPAN_ARGS_LOC % field_name).click() locator = self.page.locator(self.locator.BASE_FIELD_ARGS_LOC % field_name) locator.clear() locator.fill(value) # 输入空格弹出基础资料选项,fill方法会覆盖当前输入内容,使用press_sequentially方法模拟输入 locator.press_sequentially(" ") locator.press("Backspace") self.page.locator(self.locator.BASE_ITEM_ARGS_LOC % value).nth(0).click() def _set_select(self, field_name:str, item_value:str): """ 单据头下拉列表字段赋值 :param field_name: 字段名 :param item_value: 字段值 :return: None """ # Locator.click()普通点击无法弹出下拉选项值,使用force强制点击 # 注意:force=True强制点击不执行非必要的元素可操作性检查 self.page.locator(self.locator.SELECT_FIELD_ARGS_LOC % field_name).click() self.page.locator(self.locator.SELECT_ITEM_ARGS_LOC % (item_value,item_value)).click() def _set_textarea(self, field_name:str, value:str): """ 单据头大文本框字段赋值 :param field_name: 字段名 :param value: 字段值 :return: None """ locator = self.page.locator(self.locator.TEXTAREA_FIELD_ARGS_LOC % field_name) locator.clear() locator.fill(value) def _set_multiselect(self, field_name:str, values:str): """ 单据头多选下拉列表字段赋值 :param field_name: 字段名 :param values: 字段值 :return: None """ self.page.locator(self.locator.MULTISELECT_FIELD_ARGS_LOC % field_name).click() for item_value in values: self.page.locator(self.locator.MULTISELECT_ITEM_ARGS_LOC % item_value).click() self.page.locator(self.locator.MULTISELECT_OK_BTN_LOC).click() def set_value(self, field_name:str, *values:str, field_type: FieldType = None): """ 单据头字段赋值统一方法,根据给定或自动识别的字段类型调用不同方法完成赋值 :param field_name: 字段名 :param value: 字段值 :param field_type: 可选参数,字段类型,不填时自动识别字段类型 :return: None """ if not field_type: field_type = self._parse_field_type(field_name) match field_type: case FieldType.TEXT: self._set_text(field_name, values[0]) case FieldType.SELECT: self._set_select(field_name, values[0]) case FieldType.BASE: self._set_base(field_name, values[0]) case FieldType.TEXTAREA: self._set_textarea(field_name, values[0]) case FieldType.MULTISELECT: self._set_multiselect(field_name, *values) def set_checked(self, field_name:str): """ 单据头勾选复选框 :param field_name: 复选框名 :return: None """ self.page.locator(self.locator.CHECKBOX_FIELD_ARGS_LOC % field_name).click() def set_text_in_head_body(self, row:int, field_name:str, value:str): """ 单据头中的单据体文本字段赋值 如样品通知单-接收人页签 :param field_name: 字段名 :param value: 字段值 :param row: 行号,从1开始 :return: None """ self.page.locator(self.locator.TRIGGER_IN_HEAD_BODY_FIELD_ARGS_LOC % (field_name, row-1)).click() locator = self.page.locator(self.locator.TEXT_FIELD_IN_HEAD_BODY_ARGS_LOC % (field_name, row-1)) locator.clear() locator.fill(value) def set_base_in_head_body(self, row:int, field_name:str, value:str): """ 单据头中的单据体基础资料字段赋值 如样品通知单-接收人页签 :param field_name: 字段名 :param value: 字段值 :param row: 行号,从1开始 :return: None """ self.page.locator(self.locator.TRIGGER_IN_HEAD_BODY_FIELD_ARGS_LOC % (field_name, row - 1)).click() locator = self.page.locator(self.locator.BASE_FIELD_IN_HEAD_BODY_ARGS_LOC % (field_name, row - 1)) locator.click() locator.fill(value) # 输入空格弹出基础资料选项,fill方法会覆盖当前输入内容,使用press_sequentially方法模拟输入 locator.press_sequentially(" ") locator.press("Backspace") self.page.locator(self.locator.BASE_ITEM_ARGS_LOC % value).nth(0).click() def _get_text_value(self, field_name:str) -> str: """ 单据头文本字段取值 文本字段有两种形式,一种是可编辑状态,值存放在input元素中,另一种是锁定状态值存放在span元素中, 默认取input值,500ms超时未取到时取span中的值 :param field_name: 字段名 :return: 字段值 """ try: locator_input = self.page.locator(self.locator.TEXT_VALUE_INPUT_ARGS_LOC % field_name) expect(locator_input).to_be_visible(timeout=500) return locator_input.input_value() except AssertionError: locator_span = self.page.locator(self.locator.TEXT_VALUE_SPAN_ARGS_LOC % field_name) expect(locator_span).to_be_visible(timeout=500) return locator_span.inner_text() def _get_select_value(self, field_name:str) -> str: """ 单据头下拉列表字段取值 下拉列表字段有两种形式,一种是可编辑状态,值存放在input元素中,另一种是锁定状态值存放在span元素中, 默认取input值,未找到时立即去span中的值 与取text不同的是text由两个xpath语句获取值,select由一个通用的xpath取值,所以判断方式不同 :param field_name: 字段名 :return: 字段值 """ try: locator = self.page.locator(self.locator.SELECT_VALUE_ARGS_LOC % field_name) return locator.input_value() except Error: return locator.inner_text() def _get_base_value(self, field_name:str) -> str: """ 获取单据头基础资料字段值 :param field_name: 字段名 :return: 字段值 """ return self.page.locator(self.locator.BASE_VALUE_ARGS_LOC % field_name).inner_text() def _get_textarea_value(self, field_name:str): """ 单据头大文本字段取值 :param field_name: 字段名 :return: 字段值 """ return self.page.locator(self.locator.TEXTAREA_FIELD_ARGS_LOC % field_name).input_value() def _get_multiselect_value(self, field_name:str): """ 单据头多选下拉列表字段取值 :param field_name: 字段名 :return: 字段值 """ return self.page.locator(self.locator.MULTISELECT_VALUE_ARGS_LOC % field_name).inner_text() def get_value(self, field_name:str, field_type: FieldType=None) -> str: """ 单据头字段取值统一方法,根据给定或自动识别的字段类型调用不同取值方法取值 :param field_name: 字段名 :param field_type: 可选参数,字段类型 :return: 字段值 """ if not field_type: field_type = self._parse_field_type(field_name) match field_type: case FieldType.TEXT: return self._get_text_value(field_name) case FieldType.SELECT: return self._get_select_value(field_name) case FieldType.BASE: return self._get_base_value(field_name) case FieldType.MULTISELECT: return self._get_multiselect_value(field_name) case FieldType.TEXTAREA: return self._get_textarea_value(field_name) case _: return "" def _parse_field_type(self, field_name:str) -> FieldType: """ 分析字段类型,set_value(), get_value()中调用的核心方法 注意:金蝶版本升级后可能不同字段类型判断依据有变化,字段类型是根据元素"data-attdata"属性值判断, 定位器可用性检查通过不代表分析字段类型可正常使用 :param field_name: 字段名 :return: 字段类型 FieldType """ data_role = self.page.locator(self.locator.PARSE_FIELD_TYPE_ARGS_LOC % field_name).get_attribute("data-attdata") pattern = "xtype\":\"([a-zA-Z0-9]+)" match_strs = re.findall(pattern, data_role) if match_strs: match match_strs[0]: case "bosf7field": return FieldType.BASE case "kdeditcombo" | "kdcombo": return FieldType.SELECT case "kdmulticombo": return FieldType.MULTISELECT case "kdtextarea" | "kdlangtextarea" | "kdtabpage": return FieldType.TEXTAREA case _: return FieldType.TEXT return FieldType.UNKNOWN def click_button_in_head_body(self, button_name:str, sub_button_name:str=None): """ 点击单据头中单据体按钮或子按钮 如:新增行 **用法:** HeadPage.click_button_in_head_body("新增行") HeadPage.click_button_in_head_body("新增行", "复制行") :param button_name: 按钮名称 :param sub_button_name: 可选参数,子按钮名称 :return: None """ if not sub_button_name: self.page.locator(self.locator.BUTTON_IN_HEAD_BODY_ARGS_LOC % button_name).click() else: self.page.locator(self.locator.BUTTON_ARROW_IN_HEAD_BODY_ARGS_LOC % button_name).hover() self.page.locator(self.locator.SUB_BUTTON_IN_HEAD_BODY_ARGS_LOC % sub_button_name).click() self._click_blank()