class ReleaseNoticePage(IndexPage): """ 考情综合管理-->发布通知 """ title = El("通知标题", css="input.ant-input") range = Els("接收范围", css=".gwj-InfoPub-checkbox.ant-checkbox-wrapper input") content = El("通知内容", css=".w-e-text") commit = El("发送", css="button.ant-btn.ant-btn-primary") dismiss = El("取消", css=".iconfont.icon-quxiao") recommit = El("确认发送", x="//*[text()='确 定']/..", mode="I") def choice_range(self, *args): index = { "全部": 0, "市级": 1, "区县级": 2, "考点级": 3, } for choice in args: self.range[index[choice]].click() def send_notice(self, title, range_, content): self.title.send_keys(title) self.choice_range(range_) self.content.send_keys(content) self.screenshot_in_allure("发送通知") self.commit.click() sleep(0.5) self.recommit.click() return self.pm("MyNoticePage")(self)
class SiteBuildingmManagement(IndexPage): """场所建筑管理""" save_btn = El("保存按钮", x='//button[string()="保 存"]') com_btn = El( "确定按钮", css='#layui-layer1 > div.layui-layer-btn.layui-layer-btn- > a') back_btn = El("返回按钮", lt='返 回') _table = El("建筑表", css="table") @property def table(self): sleep(1) return Table(self._table) def __get_input(self, label_name): return self.find_element( x=f"(//label[contains(string(),'{label_name}')]/following-sibling::div/*)[1]" ) def add_build(self, build_info): """ 添加建筑 :type build_info: list or dict :param build_info: {"建筑名称":"","楼层总数":""} or [{"建筑名称":"","楼层总数":""}, {"建筑名称":"","楼层总数":""}] :return: """ def _add_build(_build_info): """ 添加一个建筑 :param _build_info: {"建筑名称":"","楼层总数":""} :return: """ for k, v in _build_info.items(): el = self.__get_input(k) el.clear() el.send_keys(v) self.save_btn.click() self.com_btn.click() if isinstance(build_info, list): for info in build_info: _add_build(info) elif isinstance(build_info, dict): _add_build(build_info) else: raise TypeError( f"add_build only use dict or list, not type:{type(build_info)}:{build_info}" ) return self def back(self): self.back_btn.click() return LocationManagePage(self)
class UserInfoBox(Page): """ 个人信息 右上角点击后 # fixme 2020年5月30日 """ close_button = El(describe="关闭按钮", css=".ant-modal-close-x") base_info_box = El(describe="基本信息框", css="#uinfo_form .ant-col.ant-col-14") submit_button = El(describe="保存按钮", css="#uinfo_form button") # 界面问题导致的代码问题 other_info_box_title = El(describe="其他信息框标题", css="#uinfo_form .ant-row.xt-uinfo-header") other_info_box_info = El(describe="其他信息框内容", css="#uinfo_form .ant-row.xt-uinfo-text") _cell = Els(describe="内容", css="div.ant-col") @property def base_info(self) -> dict: """ 通过对innerHTML的读取,将内容作为字典返回 fixme 如果改变页面布局可能需要该改代码 :return: info_ """ raw_info = self.base_info_box.get_attribute('innerHTML') _ = [ re.sub("[\u3000(: ]", "", info) for info in re.findall(">(.*?)<", raw_info) if info ] # _ = ['姓名', '王华', '性别', '男', '民族', '汉族', '验证状态', '已认证', '身份验证', '通过', '照片合规', '通过', # '人脸比对', '通过', ')', '办公电话', '联系电话', '邮箱'] div_info = _[:-4] info_ = dict(zip(div_info[::2], div_info[1::2])) # info_ = {'姓名': '王华', '性别': '男', '民族': '汉族', '验证状态': '已认证', # '身份验证': '通过', '照片合规': '通过', '人脸比对': '通过'} input_info = re.findall("value=\"(.*?)\"", raw_info) # input_info = ['07715320540', '18100771469', ''] info_.update(dict(zip(_[-3:], input_info))) return info_ @property def other_info(self) -> dict: titles = [el.text for el in self._cell(self.other_info_box_title)] info = [el.text for el in self._cell(self.other_info_box_title)] return dict(zip(titles, info)) def close_box(self): """ 关闭弹出框 @return: """ self.close_button.click() return IndexPage(self)
class LocationManagePage(IndexPage): """场所管理主界面""" __page_name = "物理场所管理" site_building_management_button = El("场所建筑管理按钮", lt='场所建筑管理') add_site_button = El("新增场所按钮", lt='新增场所') def click_site_building_management_button(self): """点击场所建筑管理按钮""" self.site_building_management_button.click() return SiteBuildingmManagement(self) def click_add_site_button(self): """新增场所按钮""" self.add_site_button.click() return SiteManagement(self)
class HomePage(Page): examination_management_system = El('考务综合管理平台', xpath="//font[text()='考务综合管理平台']") logout_button = El('登出按钮', xpath="//font[text()='安全退出']") sys_search_input_box = El('系统搜索框输入框', xpath="//input[@placeholder='系统名称']") sys_search_button = El("系统搜索框搜索按钮", css="svg.icon.yh-search-svg > use") def search_sys(self, sys_name): self.sys_search_input_box.clear() self.sys_search_input_box.send_keys(sys_name) self.sys_search_button.click() return self def click_system(self, sys_name): css = f'span[title="{sys_name}"]' el = self.driver.find_element_by_css_selector(css) el.click()
class PWDChangeBox(Page): box = El("修改密码框体", css=".ant-modal-content") close_button = El("关闭按钮", css=".ant-modal-close-x") new_pwd = El("新密码", css="#resetpwd_form_newPwd") confirm_pwd = El("确认密码", css="#resetpwd_form_confirmPwd") commit_button = El("确认密码", css="button.ant-btn.ant-btn-primary") def change_pwd(self, new_pwd, confirm_pwd=None): if confirm_pwd is None: confirm_pwd = new_pwd self.new_pwd.send_keys(new_pwd) self.confirm_pwd.send_keys(confirm_pwd) self.commit_button.click() def close(self): self.close_button.click() return LoginPage(self)
class NoticeDetailPage(IndexPage): back_btn = El("返回按钮", xpath="//span[text()='返回']") detail_title = El("详情标题", css=".info-detail-title") detail_content = El("详情内容", css=".info-detail-content") comment = El("评论", css=".ant-input") commit = El("发表评论", xpath="//span[text()='发表']") comment_content = Els("评论内容", css=".info-detail-comBox") def comment_notice(self, context): self.comment.send_keys(context) self.commit.click() def back(self, page_name): if page_name not in ["MyNoticePage", "AllNoticePage"]: raise ValueError self.back_btn.click() return self.pm(page_name)(self)
class AllNoticePage(IndexPage): """ 考情综合管理-->全部通知 """ all_notice_table = El("通知表格", css="table") notice_search_box = El("通知搜索", css="div.hf-ai-serBox input") def search_notice(self, arg): self.notice_search_box.send_keys(arg) self.notice_search_box.send_keys(Keys.ENTER) return self @property def table(self): return Table(self.all_notice_table) def check_detail(self, notice): self.click(x=f"//div[@title='{notice}']") return self.pm("NoticeDetailPage")(self)
class UserAddPage(IndexPage): """用户添加框弹出""" _table = El("表格", css='.ws-table-box') save_btn = El("保存按钮", x='//button[string()="保存"]') cancel_btn = El("取消按钮", x='//button[string()="取消"]') @property def table(self): return DivTable(self._table, {"css": "p>span"}, {"css": ".gwj-table-box-tableItem"}, {"x": "./div"}) def select_row_by_name(self, name): """通过名称选择表格中对应行的label框""" if name == "全部": self.click(el=self._table.find_element_by_xpath( './/*[text()="姓名"]/parent::p//input')) else: self.click(el=self._table.find_element_by_xpath( f'.//*[text()="{name}"]/parent::div//input')) return self def select_check_box_by_index(self, index): """通过index选择label框,index为0时选择全部""" els = self._table.find_elements_by_css_selector( ".ant-checkbox-input") self.click(el=els[index]) return self def select_role_by_name(self, name, role_name): """通过用户名字选择角色类型""" tr = None for tr in getattr(self.table, "_trs"): if name in tr.get_attribute("innerText"): break else: logger.error(f"没有找到>>>{name}>>>对应的人员") if tr: _select_something( self, tr.find_element_by_xpath("(.//div[@aria-controls])[1]"), role_name)
class PassWordChangeBox(Page): """ 修改密码框 """ old_password_box = El(describe="旧密码", id="resetpwd_form_oldPwd") new_password_box = El(describe="新密码", id="resetpwd_form_newPwd") confirm_password_box = El(describe="确认新密码", id="resetpwd_form_confirmPwd") change_password_submit_button = El( describe="提交", xpath='//button[contains(string(),"提")]') change_password_cancel_button = El( describe="取消", xpath='//button[contains(string(),"消")]') close_button = El(describe="关闭按钮", css='button[aria-label="Close"]') def change_password(self, old, new, confirm_password=None): """ 重置密码 :param old: 旧密码 :param new: 新密码 :param confirm_password: 确认密码为空时为新密码 :return: """ self.old_password_box.clear() self.old_password_box.send_keys(old) self.new_password_box.clear() self.old_password_box.send_keys(new) self.confirm_password_box.clear() if confirm_password is None: self.confirm_password_box.send_keys(new) else: self.confirm_password_box.send_keys(confirm_password) self.change_password_submit_button.click() def close_box(self): self.close_button.click() return IndexPage(self)
class MyNoticePage(AllNoticePage): del_btn = El("删除按钮", xpath="//span[text()='删除']") del_selector = Els("删除选择项", css="input.ant-checkbox-input") accept_btn = El("确认删除", css=".ant-btn") def select_to_del(self, *index): """ :param index: 0:当前页全选,1-21为个数 :return: """ if 0 in index: self.del_selector[0].click() else: for i in index: self.del_selector[i].click() def do_del(self): if self.del_btn.is_enabled(): self.del_btn.click() self.accept_btn.click() return self
class NewDepartment(Page): department_name = El("部门名称", mode="I", css="#Name") department_type = El("部门类型下拉框", css=".dropdown-menu.open") department_type_opener = El("部门类型下拉框激活", css="button[data-id]") exam_projects = Els("分管考试项目", css="#dv_EtId label") submit_btn = El("保存", css="button[type='submit']") msg = El("信息框内容", css="div.layui-layer-padding") confirm_btn = El("确认按钮", css=".layui-layer-btn0") def add_department(self, info): """ 添加部门 :param info = { "部门名称":部门名称, "部门类别":部门类别, "部门分管考试项目":[部门分管考试项目] } department_name: 部门名称 department_type: 部门类别 ["管理部门","业务部门","技术部门","综合部门","后勤部门"] exam_projects: 部门分管考试项目 ["普通高考", "成人高考", "研究生考试", "自考", "学业水平考试", "计算机等级考试", "英语四六级B级考试", "中小学教师资格考试", "英语等级考试(PETS)", "书画等级考试(CCPT)", "高校教师技能考试", "高校自主选拔测试", "高校教师理论考试", "剑桥少儿英语(YLE)"] :return: DepartmentInfoMaintainPage """ department_name = info["部门名称"] department_type = info["部门类别"] exam_projects = info["部门分管考试项目"] self.switch_to_frame(locator="main-body", switch_out=False) with allure.step(f"添加部门:部门信息>>>{info}"): self.click(self.department_name) self.department_name.send_keys(department_name) DropDownBox( self.department_type, self.department_type_opener).select(department_type) if exam_projects: for exam_project in exam_projects: el = select_el(self.exam_projects, exam_project) self.click(el=el) self.screenshot_in_allure() self.click(el=self.submit_btn) logger.info(f"提示信息:{self.msg.text}") self.screenshot_in_allure() self.click(el=self.confirm_btn) self.switch_to_frame() # 加载信息过慢 sleep(2) return DepartmentInfoMaintainPage(self)
class AddDevicePage(IndexPage): """新增设备页面""" save_btn = El('保存按钮', x="//*[text()='保 存']") com_btn = El('确定按钮', mode='I', x="//*[text()='确定']") fast_add_btn = El('快速新增', mode='V', x="//*[text()='快速新增']") def add_dev(self, info, fast=False): """ 添加设备 :param info: { "基础信息":{}, "其他信息":{}, } :param fast: 快速新增 :return: """ self._input_base_info(info["基础信息"]) self._input_other_info(info["其他信息"]) if fast: self.fast_add_btn.click() else: self.save_btn.click() self.com_btn.click() return self if fast else DeviceInfoManageTab(self) def __get_control(self, label_name): """ 选择页面控件 :param label_name: :return: """ val = f"(//label[contains(string(),'{label_name}')]/following-sibling::div/*)[1]" el = self.find_element(x=val) if el.tag_name == "div": return DropDownBox(el.find_element_by_xpath('./div'), el) else: return el def _input_base_info(self, info): """ 基础信息录入 :param info: { "设备类别": "", "设备编号": "", "设备名称": "", "设备状态": "", "设备厂商": "" } :return: """ with allure.step("基础信息录入"): logger.info(f"录入设备基础信息:>>>{info}") self.__get_control("设备类别").select(info["设备类别"]) if info.get("设备编号", ""): self.__get_control("设备编号").send_keys(info["设备编号"]) self.__get_control("设备名称").select(info["设备名称"]) self.__get_control("设备状态").select(info["设备状态"]) self.__get_control("设备厂商").select(info["设备厂商"]) return self def _input_other_info(self, info): """ 输入其他信息 :param info: :return: """ with allure.step("其他信息录入"): logger.info(f"录入设备其他信息:>>>{info}") for key, val in info.items(): self.__get_control(key).send_keys(val) return self
class MaxInTab(IndexPage): exam_items_select_opener = El( "考试项目", css='#div_ExamProject button[data-id="cboExamProject"]') exam_items_selects = El( "考试项目菜单", mode="V", x='//button[@data-id="cboExamProject"]/parent::div//div') # 搜索框 query_org_drop_box = El("管理机构下拉列表", css="#orgtree_value_layer") query_org_drop_box_opener = El("管理机构下拉列表激活框", css="#orgtree_name") query_org_type_drop_box = El("机构类型下拉列表", css="#orgtypetree_value_layer") query_org_type_drop_box_opener = El("机构类型下拉列表", css="#orgtypetree_name") _table = El("资质表格", css='table') @property def table(self): """资质表格""" return Table(self._table) @property def _org_type_tree(self): """机构-类型-树形下拉框""" return TreeDropDownBox(self.query_org_type_drop_box, self.query_org_type_drop_box_opener) @property def _org_name_tree(self): """机构-名称-树形下拉框""" return TreeDropDownBox(self.query_org_drop_box, self.query_org_drop_box_opener) @property def org_type(self): """机构类型""" return self._org_type_tree.value @property def org_name(self): """机构名称""" return self._org_name_tree.value def select_exam_item(self, item_name): """ 选择考试项目名称 :param item_name: 考试项目名称 :return: """ self.exam_items_select_opener.click() el = self.exam_items_selects.find_element_by_xpath( f".//a[text()='{item_name}']") self.click(el=el) return self @property def exam_item(self): """考试项目""" return self.exam_items_select_opener.get_attribute("title") def select_management_org(self, org_name): pass
class PeopleManagePage(IndexPage): __page_name = "人员管理" org_select_open = El('部门选择', css='#select .ant-select-selection') com_select_open = El('编制类型', css='#compile .ant-select-selection') job_select_open = El('工作状态', css='#jobtype .ant-select-selection') search_input = El('人员查询输入框', css='[placeholder="查询姓名或身份证号"]') search_btn = El('查询按钮', x="//*[text()='查询']/parent::button") _table = El("人员表格", css=".fyl-rygl-table") add_people_btn = El("人员新增", x='//button[string()="人员新增"]') def query_people(self, info): """ 查询人员 :param info: { "部门":"","编制类型":"", "工作状态":"","人员":"" } :return: """ with allure.step(f"查询人员:查询条件>>>{info}"): _select_something(self, self.org_select_open, info.get("部门")) _select_something(self, self.com_select_open, info.get("编制类型")) _select_something(self, self.job_select_open, info.get("工作状态")) # todo 身份证校验,目前只有名字校验 self.search_input.send_keys(info.get("人员", "")) self.search_btn.click() self.screenshot_in_allure(f"查询人员:查询条件>>>{info}") return self def click_add_people_btn(self): """ 点击新增人员 :return: NewPeoplePage obj """ self.add_people_btn.click() return NewPeoplePage(self) def del_people(self, name): """ 删除人员 :param name: 人员名称 :return: """ logger.info("删除人员:>>>" + name) with allure.step("删除人员"): self.find_element(x=f'//div[text()="{name}"][2]/..//button[string()="删 除"]').click() self.click(x='//button[contains(string(),"确认")]') return self @property def table(self): return DivTable(self._table, {"x": "./div[1]/div"}, {"x": ".//*[@class='fyl-rygl-table-list']"}, {"x": "./div"}) @property def info_compliance(self): """ 表格中数据合规 即部门对应,编制类型对应,工作状态对应,人员对应 :return: """ result = self._department_name_same and self._com_type_same and self._job_type_same and self._search_input_same if not result: logger.error(f"结果不同表中信息为:\n {self.table.info}") self.screenshot_in_allure("结果不同") return result @property def _department_name_same(self): """部门名称与表格中相同""" if self.org_select_open.text == "全部": return True else: for dep in self.table["部门名称"]: if self.org_select_open.text != dep: return False else: return True @property def _com_type_same(self): """编制类型与表格中相同""" if self.com_select_open.text == "全部": return True else: for dep in self.table["编制类型"]: if self.com_select_open.text != dep: return False else: return True @property def _job_type_same(self): """工作状态与表格中相同""" if self.job_select_open.text == "全部": return True else: for dep in self.table["工作状态"]: if self.job_select_open.text != dep: return False else: return True @property def _search_input_same(self): """搜索框与表格中相同""" val = self.search_input.get_attribute("value") if val == "": return True else: for i in self.table["姓名"]: if val not in i: return False else: return True
class NewPeoplePage(IndexPage): com_type_box = El("编制类型", x='//*[contains(text(),"编制类型")]/parent::div') fullname = El("姓名输入框", x=_label_xpath_input("姓名")) id_num = El("身份证号输入框", x=_label_xpath_input("身份证号")) gender_box = El("性别选择框", x='//*[contains(text(),"性别")]/parent::div') marriage_box = El("婚否选择框", x='//*[contains(text(),"婚否")]/parent::div') bth_input_open = El("生日输入框激活器", mode="I", css=".ant-calendar-picker-input") ethnic_open = El("民族选择框", x=_label_xpath_drop("民族")) email_input = El("邮箱", x=_label_xpath_input("邮箱")) office_phone = El("办公电话", x=_label_xpath_input("办公电话")) contact_phone = El("联系电话", x=_label_xpath_input("联系电话")) uploadimg_input = El("上传照片框", css="#uploadimg") # 其他信息 # 在编、聘用 department_box = El("正式_借调_临时_部门选择框", x=_label_xpath_drop("部门")) position_box = El("职务输入框", x=_label_xpath_input("职务")) education_box = El("学历选择框", x=_label_xpath_drop("学历")) degree_box = El("学位选择框", x=_label_xpath_drop('学位')) job_title_box = El("职称选择框", x=_label_xpath_drop('职称')) political_status_box = El("政治面貌选择框", x=_label_xpath_drop('政治面貌')) # 临时、借调 original_work_unit_box = El("原工作单位输入框", x=_label_xpath_input('原工作单位')) secondment_validity = El("借调有效期输入框激活器", x=_label_xpath_input("借调有效期")) # 保存按钮 save_btn = El("保存按钮", x='//button[string()="保 存"]') def choose_compilation_type(self, c_name): """选择编制类型""" LabelGroup(self.com_type_box).select_label(c_name) return self @property def compilation_type(self): """选择的编制类型""" return self.com_type_box.find_element_by_css_selector(".ant-radio-wrapper-checked").text def upload_img(self, img_path): """上传照片""" self.uploadimg_input.send_keys(img_path) def input_base_info(self, info_dict): """ 填写基本信息 :param info_dict: { "姓名": "", "身份证号": "", "性别": "", "婚否": "", "出生日期": "", "民族": "", "邮箱": "", "办公电话": "", "联系电话": "", "上传头像图片地址":"" } :return: self """ with allure.step("填写基本信息"): self.fullname.send_keys(info_dict["姓名"]) self.id_num.send_keys(info_dict["身份证号"]) # 前端做了自动识别 性别 出生日期不需要手动填写,如果需要改的话传值需符合规范 LabelGroup(self.gender_box).select_label(info_dict["性别"]) LabelGroup(self.marriage_box).select_label(info_dict["婚否"]) self.bth_input_open.click() self._input_time(info_dict["出生日期"]) _select_something(self, self.ethnic_open, info_dict["民族"]) self.email_input.send_keys(info_dict["邮箱"]) self.office_phone.send_keys(info_dict["办公电话"]) self.contact_phone.send_keys(info_dict["联系电话"]) self.upload_img(info_dict["上传头像图片地址"]) self.screenshot_in_allure("填写基本信息") return self def _input_time(self, t): """当前页面的输入时间实现""" el = self.find_element(css=".ant-calendar-date-input-wrap input") el.clear() el.send_keys(t + Keys.ENTER) def input_other_info(self, info_dict): """ 输入其他信息 :param info_dict: { "部门": "", "学历": "", "职务": "", "学位": "", "职称": "", "政治面貌": "", # 借调、临时人员独有 "原工作单位": "", "借调有效期": "", } :return: """ with allure.step("填写其他信息"): _select_something(self, self.department_box, info_dict["部门"]) _select_something(self, self.education_box, info_dict["学历"]) self.position_box.send_keys(info_dict["职务"]) _select_something(self, self.degree_box, info_dict["学位"]) _select_something(self, self.job_title_box, info_dict["职称"]) _select_something(self, self.political_status_box, info_dict["政治面貌"]) if self.compilation_type in ["在编", "聘用"]: pass elif self.compilation_type in ["借调"]: self.original_work_unit_box.send_keys(info_dict["原工作单位"]) self.secondment_validity.click() self._input_time(info_dict["借调有效期"]) elif self.compilation_type in ["临时"]: self.original_work_unit_box.send_keys(info_dict["原工作单位"]) self.screenshot_in_allure("填写其他信息") try: # 高分辨率适配 self.action.scroll_by(0, 1000, el=self.find_element(css=".scrollbar-container.ps.ps--active-y")) except NoSuchElementException: logger.info("不需要滑动屏幕") self.save_btn.click() return PeopleManagePage(self)
class SiteManagement(IndexPage): """场所管理页面""" room_information_input_box = El("房间信息输入框", css='#Name') test_room_capacity_input_box = El("考场容量输入框", css='#RoomCap') duty_phone_input_box = El("值班电话输入框", css='#ContactTel') save_btn = El("保存按钮", x='//button[text()="保 存"]') back_btn = El("返回按钮", lt='返 回') fast_add_btn = El("快速新增", x="//*[text()='快速新增']") # 提示框 msg = El("弹出框信息", css=".layui-layer-content") confirm_btn = El("确定按钮", mode="I", lt='确定') cancel_btn = El("取消按钮", css='.layui-layer-close') def add_site(self, site_info, fast=False): """ 添加场所 :param fast: 快速添加 :param site_info: { "场所类型":"","场所名称":"","楼层":"","房间信息":"", "考场容量":"","值班电话":"" "默认座次":"" } 场所类型: 请选择场所类型, 标准化考场, 试卷保管室, 考务办公室, 视频监考室, 语音播放室, 试卷流转通道, 普通考场, 试卷保密室, 考务指挥中心, 其他, :return: """ with allure.step("快速添加场所" if fast else "添加场所"): # 必填 self._drop_dwon_box_select_by("PtCode", site_info["场所类型"]) self._drop_dwon_box_select_by("BuildingId", site_info["场所名称"]) self._drop_dwon_box_select_by("BuildingFloors", site_info["楼层"]) self.room_information_input_box.send_keys(site_info["房间信息"]) # 普通考场-考场容量 if site_info["场所类型"] == "普通考场": self.test_room_capacity_input_box.send_keys( str(site_info.get("考场容量", 30))) # 值班电话 if site_info["场所类型"] in [ "试卷保管室", "考务办公室", "视频监考室", "语音播放室", "试卷保密室", "考务指挥中心", "其他" ]: tel = str(site_info.get("值班电话", "")) self.duty_phone_input_box.send_keys(tel) # 标准化考场-默认座次 if site_info["场所类型"] == "标准化考场": self._drop_dwon_box_select_by('DefaultseattingWay', site_info.get("默认座次", 8877)) if fast: self.fast_add_btn.click() logger.info(f"弹出框信息为:{self.msg.text}") self.confirm_btn.click() return self else: self.save_btn.click() logger.info(f"弹出框信息为:{self.msg.text}") self.confirm_btn.click() return self def _drop_dwon_box_select_by(self, drop_dwon_box_name, by_val): """ 此界面下拉框选择框实现 :param drop_dwon_box_name: 下拉框的data-id属性对应的值 :param by_val: li标签的值 :return: """ _el = self.find_element( mode="V", x=f"//button[@data-id='{drop_dwon_box_name}']/parent::div") _el.click() _el.find_element_by_xpath(f".//li[string()='{by_val}']").click()
class NewOrgPage(Page): """新增机构弹出界面""" frame_el = El("弹出框定位", css="#main-body") org_type_select = El("机构类型选择", x='//*[@data-id="OrgType"]/following::div[1]') org_type_select_opener = El("机构类型选择激活器", css='[data-id="OrgType"]') school_type_select = El( "学校类型选择", x='//*[@data-id="SchoolType"]/following::div[1]') school_type_opener = El("学校类型选择激活器", css='[data-id="SchoolType"]') org_code_input = El("机构代码输入框", css="#OrgDisplayCode") org_name_input = El("机构名称输入框", css="#OrgName") org_alias_input = El("机构简称输入框", css="#OrgAlias") org_area_input = El("考区名称", mode="V", css="#GLKQMC") submit_btn = El("保存按钮", css='[type="submit"]') confirm_btn = El("确认按钮", x='//*[text()="确定"]') _org_account = El("机构账号", css="#label_account") @property def org_account(self): return self._org_account.text def add_org_school(self, school_type, org_num, org_name, org_ab, area_name=""): """ 添加学校类型的机构 :param school_type: 学校类型 :param org_num: 机构编号 :param org_name: 机构名称 :param org_ab:机构简称 :param area_name:区域名称 || 大学才有 :return: """ with allure.step("添加学校类型的机构"): self.switch_to_frame(self.frame_el, switch_out=False) self.select_org_type("学校") assert school_type in school_org_list DropDownBox(self.school_type_select, self.school_type_opener).select(school_type) self.org_code_input.send_keys(org_num) self.org_name_input.send_keys(org_name) self.org_alias_input.send_keys(org_ab) if area_name and school_type == "大学": self.org_area_input.send_keys(area_name) self.click(el=self.submit_btn) self.click(el=self.confirm_btn) self.switch_to_frame() return SubOrgManagePage(self) def select_org_type(self, val): DropDownBox(self.org_type_select, self.org_type_select_opener).select(val)
class DeviceInfoManageTab(DeviceInfoManagePage): """设备信息管理tab页""" _table = El("设备表格", css="table") device_category_selection_box_opener = El("设备类别选择框触发", css='//*[@data-id="DtCode"]') device_category_selection_box = El( "设备类别选择框", css='//*[@data-id="DtCode"]/following-sibling::div/ul') association_status_opener = El("关联状态触发", css='//*[@data-id="RelationStatus"]') association_status_selection_box = El( "关联状态选择框", css='//*[@data-id="RelationStatus"]/following-sibling::div/ul') query_btn = El("查询按钮", css="#btnQuery") search_input = El("搜索框", css="#deviceSearch") search_btn = El("搜索按钮", css="#btnSearch") add_dev_btn = El("添加设备按钮", x="//*[text()='新增设备']") @property def info_compliance(self): """ 信息合规 :return: bool """ dev_type = self._device_category_selection.value status = self._association_status_selection.value table_status = set(self.table["关联状态"]) table_types = set(self.table["设备类别"]) logger.info(f"选择的设备类别:{dev_type}") logger.info(f"选择的关联状态:{status}") logger.info(f"表格中的设备类别set:{table_status}") logger.info(f"表格中的设备类别set:{table_types}") # 192.168.170.160 if dev_type == "全部" and status == "全部": return True elif dev_type == "全部": return status in table_status elif status == "全部": return dev_type in table_types else: return status in table_status and dev_type in table_types def search_dev(self, dev_name): """ 搜索设备代码/设备名称 :type dev_name: str :param dev_name: :return: self """ if dev_name: with allure.step(f"搜索设备代码/设备名称:{dev_name}"): self.search_input.send_keys(dev_name) self.search_btn.click() return self def query_dev(self, dev_info): """ :type dev_info: dict :param dev_info: { "设备类别":"", "关联状态":"", } :return: self """ dev_type = dev_info.get("设备类别", "") association_status = dev_info.get("关联状态", "") with allure.step(f"查询设备>>>设备类别:{dev_type},关联状态:{association_status}"): if dev_type: self._device_category_selection.select(dev_type) if association_status: self._association_status_selection.select(association_status) if dev_type or association_status: self.query_btn.click() return self @property def _device_category_selection(self): """设备类别""" return DropDownBox(self.device_category_selection_box, self.device_category_selection_box_opener) @property def _association_status_selection(self): """关联状态""" return DropDownBox(self.association_status_selection_box, self.association_status_opener) @property def table(self): """设备表格""" return Table(self._table) def click_add_dev_btn(self): self.add_dev_btn.click() return self.AddDevicePage(self) class AddDevicePage(IndexPage): """新增设备页面""" save_btn = El('保存按钮', x="//*[text()='保 存']") com_btn = El('确定按钮', mode='I', x="//*[text()='确定']") fast_add_btn = El('快速新增', mode='V', x="//*[text()='快速新增']") def add_dev(self, info, fast=False): """ 添加设备 :param info: { "基础信息":{}, "其他信息":{}, } :param fast: 快速新增 :return: """ self._input_base_info(info["基础信息"]) self._input_other_info(info["其他信息"]) if fast: self.fast_add_btn.click() else: self.save_btn.click() self.com_btn.click() return self if fast else DeviceInfoManageTab(self) def __get_control(self, label_name): """ 选择页面控件 :param label_name: :return: """ val = f"(//label[contains(string(),'{label_name}')]/following-sibling::div/*)[1]" el = self.find_element(x=val) if el.tag_name == "div": return DropDownBox(el.find_element_by_xpath('./div'), el) else: return el def _input_base_info(self, info): """ 基础信息录入 :param info: { "设备类别": "", "设备编号": "", "设备名称": "", "设备状态": "", "设备厂商": "" } :return: """ with allure.step("基础信息录入"): logger.info(f"录入设备基础信息:>>>{info}") self.__get_control("设备类别").select(info["设备类别"]) if info.get("设备编号", ""): self.__get_control("设备编号").send_keys(info["设备编号"]) self.__get_control("设备名称").select(info["设备名称"]) self.__get_control("设备状态").select(info["设备状态"]) self.__get_control("设备厂商").select(info["设备厂商"]) return self def _input_other_info(self, info): """ 输入其他信息 :param info: :return: """ with allure.step("其他信息录入"): logger.info(f"录入设备其他信息:>>>{info}") for key, val in info.items(): self.__get_control(key).send_keys(val) return self
class LoginPage(Page): __page_name = "登陆页面" username = El("用户名输入框", name="myuser") password = El("密码输入框", css="input[placeholder='请输入密码']") login_button = El("登录按钮", css="div.yh-login-btn > button", time_out=1) message_box = El("登录提示信息", css=".ant-message", mode="V") verify_box = El("验证码输入框", x="//*[@placeholder='请输入验证码']") verify_img = El("验证码图片", css="img[alt]") test_flag = El("登陆页面的测试条", css=".xt-flag-test") def login(self, username, password): logger.info("登录用户名:>>>{},登录密码>>>{}".format(username, password)) self.username.send_keys(username) self.password.send_keys(password) self.verify() if self.is_login: logger.info("登录成功返回主页") return self.pm("IndexPage")(self) else: return self def logout(self): return self.pm("IndexPage")(self).logout() def login_as_role(self, role_name): """通过配置的角色名登陆""" info = WEB_ROLE_CONF[role_name] return self.login(*info) def verify(self, max_time=10): """ 验证码验证实现 """ if max_time == 0: raise RuntimeError("验证码重试次数过多") if self.is_login: return True tmp_png_name = os.path.join(STATIC_DIR, "tmp", "tmp.png") # 智能识别验证码逻辑 verify_code = "" while len(verify_code) != 5: self.verify_img.click() self.verify_img.screenshot(tmp_png_name) verify_code = get_verify_code(tmp_png_name) self.verify_box.send_keys(verify_code) self.login_button.click() sleep(0.5) if self.is_login: return True max_time -= 1 return self.verify(max_time) @property def error_message(self): msg = self.message_box.text logger.info("登录提示信息为>>>{}".format(msg)) return msg @property def is_login(self): """ 判断是否登录成功 :return: """ try: self.login_button except NoSuchElementException: return True return False class PWDChangeBox(Page): box = El("修改密码框体", css=".ant-modal-content") close_button = El("关闭按钮", css=".ant-modal-close-x") new_pwd = El("新密码", css="#resetpwd_form_newPwd") confirm_pwd = El("确认密码", css="#resetpwd_form_confirmPwd") commit_button = El("确认密码", css="button.ant-btn.ant-btn-primary") def change_pwd(self, new_pwd, confirm_pwd=None): if confirm_pwd is None: confirm_pwd = new_pwd self.new_pwd.send_keys(new_pwd) self.confirm_pwd.send_keys(confirm_pwd) self.commit_button.click() def close(self): self.close_button.click() return LoginPage(self)
class IndexPage(Page): """ 对主页主要位置的封装,包括顶部菜单,用户信息,左侧菜单,个人信息框,修改密码框 --------------------------------------------- | ----------------------------------------| | | | | | | | | | <非封装区域> | | | | | | | | | | --------------------------------------------- """ __page_name = "导航页" # 顶部 title = El(describe="标题框", css="div.xt-title span") top_menu = Els(describe="顶部菜单栏", css="header .ant-menu-item.ant-menu-item-only-child") user_info_box = El(describe="用户信息框体", css=".xt-uinfo-name") user_info_drop_down = Els( describe="下拉菜单", mode="V", css=".ant-dropdown.ant-dropdown-placement-bottomCenter li") # 侧边 aside_menu = Els(describe="侧边栏菜单栏", css="aside li") # 主页面定位 index_iframe = El(describe="iframe定位器", css="iframe.xt-mainIframe") def select_top_menu(self, by): """ 通过输入的顶部菜单名称或者index来选择菜单 :param by: @return: """ self.driver.switch_to.default_content() el = select_el(self.top_menu, by) el.click() return self def select_aside_menu(self, by): """ 通过传入的名称列表选择对应侧边菜单 :param by: :return: """ self.driver.switch_to.default_content() if isinstance(by, list): for _by in by: self.click(x=f"//*[text()='{_by}']") else: self.click(x=f"//*[text()='{by}']") self._switch_in() if by in self.pm.pages: return self.pm(by)(self) return self def logout(self): """退出登录""" try: self.driver.switch_to.default_content() return self._choice_user_drop_down_menu("安全退出") except WebDriverException: return self def _choice_user_drop_down_menu(self, by): """ 通过菜单名或者index来选择右上角的下拉菜单 :param by: :return: """ self.hover(self.user_info_box) el = select_el(self.user_info_drop_down, by) el.click() if by in ["个人信息", 0]: return UserInfoBox(self) elif by in ["修改密码", 1]: return PassWordChangeBox(self) elif by in ["安全退出", 2]: return self.pm("LoginPage")(self) def _switch_in(self): try: self.switch_to_frame() except Exception as exc: logger.error(exc) pass
class UserManagePage(IndexPage): __page_name = "用户管理" department_drop = El("部门下拉框", x='(//div[@aria-controls])[1]') preparation_type_drop = El("编制类型下拉框", x='(//div[@aria-controls])[2]') query_button = El("查询按钮", x='//button[string()="查询"]') user_add_button = El("新增用户按钮", x='//button[string()="新增用户"]') _table = El("表格", css='.yh-userlist-wrap') @property def table(self): return DivTable(self._table, {"x": './div[@class="yh-userlist-header"]//span'}, {"css": ".yh-userlist-info.yh-border-bottom"}, {"x": "./span"}) def query_user(self, info): """ 查询用户 :param info: {"部门":"","编制类型":""} :return: """ with allure.step(f"查询用户:查询条件>>>{info}"): _select_something(self, self.department_drop, info.get("部门")) _select_something(self, self.preparation_type_drop, info.get("编制类型")) self.query_button.click() return self def click_user_add_btn(self): """点击新增人员按钮""" self.user_add_button.click() return self.UserAddPage(self) @property def info_complite(self): """结果与搜索条件相同""" result = self._department_complite and self._preparation_type_complite if not result: logger.error(f"结果不同表中信息为:\n {self.table.info}") self.screenshot_in_allure("结果不同") return result @property def _department_complite(self): """部门信息相同""" t = self.department_drop.text if t == "全部": return True for info in self.table.info["部门名称"]: if t != info: return False else: return True @property def _preparation_type_complite(self): """编制类型相同""" t = self.preparation_type_drop.text if t == "全部": return True for info in self.table.info["编制类型"]: if t != info: return False else: return True class UserAddPage(IndexPage): """用户添加框弹出""" _table = El("表格", css='.ws-table-box') save_btn = El("保存按钮", x='//button[string()="保存"]') cancel_btn = El("取消按钮", x='//button[string()="取消"]') @property def table(self): return DivTable(self._table, {"css": "p>span"}, {"css": ".gwj-table-box-tableItem"}, {"x": "./div"}) def select_row_by_name(self, name): """通过名称选择表格中对应行的label框""" if name == "全部": self.click(el=self._table.find_element_by_xpath( './/*[text()="姓名"]/parent::p//input')) else: self.click(el=self._table.find_element_by_xpath( f'.//*[text()="{name}"]/parent::div//input')) return self def select_check_box_by_index(self, index): """通过index选择label框,index为0时选择全部""" els = self._table.find_elements_by_css_selector( ".ant-checkbox-input") self.click(el=els[index]) return self def select_role_by_name(self, name, role_name): """通过用户名字选择角色类型""" tr = None for tr in getattr(self.table, "_trs"): if name in tr.get_attribute("innerText"): break else: logger.error(f"没有找到>>>{name}>>>对应的人员") if tr: _select_something( self, tr.find_element_by_xpath("(.//div[@aria-controls])[1]"), role_name)
class OrgInfoMaintainPage(OrgManagePage): """机构信息维护页面""" # 基本信息 org_name = El("机构名称", css="#OrgName") org_code = El("机构代码", css=".form-control-static") org_type = El( "机构类型", x='//label[contains(text(),"机构类型")]/following-sibling::div/p') area = El("行政区划", x='//label[contains(text(),"行政区划")]/following-sibling::div/p') org_count = El("编制人数", css="#EditCount") org_alias = El("机构简称", css="#OrgAlias") glkqmc = El("考区名称", css="#GLKQMC") duty_tel = El("联系电话", css="#DutyTel") address = El("地址", css="#Address") # 其他信息 contact_name = El("机构联系人", css="#tempSearch_ContactName") contact_tel = El("机构联系人电话", css="#p_contacTel") technician_name = El("技术负责人", css="#tempSearch_TechnicianName") technician_tel = El("技术负责人电话", css="#p_TechnicianTel") longitude = El("经度", css="#Longitude") latitude = El("维度", css="#Latitude") search_technician_name = El( "机构联系人搜索按钮", css='#demo-tabs-box-1 span.input-group-addon-ContactName') search_technician_name_box = El( "机构联系人搜索框", mode="V", x='(//*[contains(@class,"panel combo-p")])[1]') search_contact_name = El( "技术负责人搜索按钮", css='#demo-tabs-box-1 span.input-group-addon-TechnicianName') search_contact_name_box = El( "技术负责人搜索框", mode="V", x='(//*[contains(@class,"panel combo-p")])[2]') save_btn = El("保存按钮", css="#orgEditSave") def search_contact(self, name): """搜索机构联系人""" with allure.step(f"搜索机构联系人:{name}"): self.contact_name.clear() self.contact_name.send_keys(name) info = Table(self.search_contact_name_box).info logger.info(info) self.screenshot_in_allure() return info def search_technician(self, name): """搜索机构负责人""" with allure.step(f"搜索机构负责人:{name}"): self.technician_name.clear() self.search_technician_name.click() self.technician_name.send_keys(name) logger.info(Table(self.search_technician_name_box).info) self.screenshot_in_allure() @property def base_info(self): """基础信息""" _info = dict() _info["机构名称"] = self.org_name.get_attribute("value") _info["机构代码"] = self.org_code.text _info["机构类别"] = self.org_type.text _info["行政区划"] = self.area.text _info["编制人数"] = self.org_count.get_attribute("value") _info["机构简称"] = self.org_alias.get_attribute("value") _info["考区名称"] = self.glkqmc.get_attribute("value") _info["联系电话"] = self.duty_tel.get_attribute("value") _info["地址"] = self.address.get_attribute("value") return _info @property def other_info(self): """其他信息""" _info = dict() _info["机构联系人"] = self.contact_name.get_attribute("value") _info["机构联系人电话"] = self.contact_tel.text _info["技术负责人"] = self.technician_name.get_attribute("value") _info["技术负责人电话"] = self.technician_tel.text _info["经度"] = self.longitude.get_attribute("value") _info["维度"] = self.latitude.get_attribute("value") return _info
class DepartmentInfoMaintainPage(OrgManagePage): """部门信息维护""" add_department_btn = El("新增部门按钮", css="#btnAddDepartment") info_table = El("信息表", css="#divTemplate table") def del_department(self, d_name): with allure.step(f"删除{d_name}部门"): val = f'//*[text()="{d_name}"]/parent::tr//*[text()="删 除"]' self.click(x=val) self.click(x='//a[text()="删除"]') return self def click_add_department_btn(self): with allure.step("点击新增部门按钮"): self.click(el=self.add_department_btn) return self.NewDepartment(self) def get_tr(self, info): return Table(self.info_table).get_row(info) @property def table_info(self): return Table(self.info_table).info class NewDepartment(Page): department_name = El("部门名称", mode="I", css="#Name") department_type = El("部门类型下拉框", css=".dropdown-menu.open") department_type_opener = El("部门类型下拉框激活", css="button[data-id]") exam_projects = Els("分管考试项目", css="#dv_EtId label") submit_btn = El("保存", css="button[type='submit']") msg = El("信息框内容", css="div.layui-layer-padding") confirm_btn = El("确认按钮", css=".layui-layer-btn0") def add_department(self, info): """ 添加部门 :param info = { "部门名称":部门名称, "部门类别":部门类别, "部门分管考试项目":[部门分管考试项目] } department_name: 部门名称 department_type: 部门类别 ["管理部门","业务部门","技术部门","综合部门","后勤部门"] exam_projects: 部门分管考试项目 ["普通高考", "成人高考", "研究生考试", "自考", "学业水平考试", "计算机等级考试", "英语四六级B级考试", "中小学教师资格考试", "英语等级考试(PETS)", "书画等级考试(CCPT)", "高校教师技能考试", "高校自主选拔测试", "高校教师理论考试", "剑桥少儿英语(YLE)"] :return: DepartmentInfoMaintainPage """ department_name = info["部门名称"] department_type = info["部门类别"] exam_projects = info["部门分管考试项目"] self.switch_to_frame(locator="main-body", switch_out=False) with allure.step(f"添加部门:部门信息>>>{info}"): self.click(self.department_name) self.department_name.send_keys(department_name) DropDownBox( self.department_type, self.department_type_opener).select(department_type) if exam_projects: for exam_project in exam_projects: el = select_el(self.exam_projects, exam_project) self.click(el=el) self.screenshot_in_allure() self.click(el=self.submit_btn) logger.info(f"提示信息:{self.msg.text}") self.screenshot_in_allure() self.click(el=self.confirm_btn) self.switch_to_frame() # 加载信息过慢 sleep(2) return DepartmentInfoMaintainPage(self)
class SubOrgManagePage(OrgManagePage): """下级机构管理""" # 搜索框 query_org_drop_box = El("管理机构下拉列表", css="#orgtree_value_layer") query_org_drop_box_opener = El("管理机构下拉列表激活框", css="#orgtree_name") query_org_type_drop_box = El("机构类型下拉列表", css="#orgtypetree_value_layer") query_org_type_drop_box_opener = El("机构类型下拉列表", css="#orgtypetree_name") query_org_btn = El("查询按钮", css="#btnQuery") search_org_name_input = El("机构名称搜索输入框", css="#orgSearch") search_org_name_btn = El("机构名称搜索按钮", css="#btnSearch") # 内容 info_table = El("机构管理表", css="#divOrgContent") # 新增机构 add_org_btn = El("新增机构按钮", id="btnAddOrg") def click_add_org_btn(self): self.add_org_btn.click() return SubOrgManagePage.NewOrgPage(self) @property def org_name_compliance(self): """ 判断机构名称是否合规,通过机构名称前的标号进行判断 :return: """ i = self.table.info s_org_names = self.table.info["机构名称"] org_nums = list(map(lambda s: re.findall(r"\d+", s)[0], s_org_names)) org_num = re.findall(r"\d+", self.org_name)[0] for item in org_nums: if not item.startswith(org_num): return False else: return True @property def org_type_compliance(self): """判断机构类型是否合规""" if self.org_type == "全部": # 若选择为全部,则直接返回True return True org_types = self.table.info["机构类型"] if len(org_types) == 0: # 判断没有搜索到,则直接返回True return True if self.org_type == "学校": # 搜索为学校,判断表中类型是否为c_list中的值 for org_type in org_types: if org_type not in school_org_list: return False else: return True else: # 搜索为固定 if len(set(org_types)) != 1: # 不止一种返回False return False return self.org_type == org_types[0] @property def table(self): return Table(self.info_table) @property def _org_type_tree(self): """机构-类型-树形下拉框""" return TreeDropDownBox(self.query_org_type_drop_box, self.query_org_type_drop_box_opener) @property def _org_name_tree(self): """机构-名称-树形下拉框""" return TreeDropDownBox(self.query_org_drop_box, self.query_org_drop_box_opener) @property def org_type(self): """机构类型""" return self._org_type_tree.value @property def org_name(self): """机构名称""" return self._org_name_tree.value def select_org(self, *org_names): tree = TreeDropDownBox(self.query_org_drop_box, self.query_org_drop_box_opener) tree.select_by_list(org_names) return self def select_org_type(self, *org_types): tree = TreeDropDownBox(self.query_org_type_drop_box, self.query_org_type_drop_box_opener) tree.select_by_list(org_types) return self def search_org(self, org_name): """按机构名称搜索""" self.search_org_name_input.clear() self.search_org_name_input.send_keys(org_name) self.search_org_name_btn.click() return self class NewOrgPage(Page): """新增机构弹出界面""" frame_el = El("弹出框定位", css="#main-body") org_type_select = El("机构类型选择", x='//*[@data-id="OrgType"]/following::div[1]') org_type_select_opener = El("机构类型选择激活器", css='[data-id="OrgType"]') school_type_select = El( "学校类型选择", x='//*[@data-id="SchoolType"]/following::div[1]') school_type_opener = El("学校类型选择激活器", css='[data-id="SchoolType"]') org_code_input = El("机构代码输入框", css="#OrgDisplayCode") org_name_input = El("机构名称输入框", css="#OrgName") org_alias_input = El("机构简称输入框", css="#OrgAlias") org_area_input = El("考区名称", mode="V", css="#GLKQMC") submit_btn = El("保存按钮", css='[type="submit"]') confirm_btn = El("确认按钮", x='//*[text()="确定"]') _org_account = El("机构账号", css="#label_account") @property def org_account(self): return self._org_account.text def add_org_school(self, school_type, org_num, org_name, org_ab, area_name=""): """ 添加学校类型的机构 :param school_type: 学校类型 :param org_num: 机构编号 :param org_name: 机构名称 :param org_ab:机构简称 :param area_name:区域名称 || 大学才有 :return: """ with allure.step("添加学校类型的机构"): self.switch_to_frame(self.frame_el, switch_out=False) self.select_org_type("学校") assert school_type in school_org_list DropDownBox(self.school_type_select, self.school_type_opener).select(school_type) self.org_code_input.send_keys(org_num) self.org_name_input.send_keys(org_name) self.org_alias_input.send_keys(org_ab) if area_name and school_type == "大学": self.org_area_input.send_keys(area_name) self.click(el=self.submit_btn) self.click(el=self.confirm_btn) self.switch_to_frame() return SubOrgManagePage(self) def select_org_type(self, val): DropDownBox(self.org_type_select, self.org_type_select_opener).select(val)