class Gitlab_Client: def __init__(self, url: str, access_token: str): self.url = url self.access_token = access_token self.url = urljoin(self.url, '/api/v4') self.doRequest = DoRequest(self.url) self.doRequest.updateHeaders({'PRIVATE-TOKEN': self.access_token}) def get_projects(self, page: int = 1, per_page: int = 100, search='', simple=True): params = {'page': page, 'per_page': per_page} httpResponseResult = self.doRequest.get( '/projects?simple=%s&search=%s' % (simple, search), params=params) return ujson.loads(httpResponseResult.body) def _get_project_id(self, project_name: str): projects = self.get_projects(search=project_name) for project_info in projects: if project_info['name'] == project_name.strip(): return project_info['id'] def get_project_file(self, project_name, ref, file_path): """ @param project_name: @param ref: 分支名、tag名、commit @param file_path: @return: """ project_id = self._get_project_id(project_name) params = {'ref': ref} httpResponsResult = self.doRequest.get( '/projects/%s/repository/files/%s' % (project_id, file_path), params=params) return ujson.loads(httpResponsResult.body) def update_project_file(self, project_name: str, branch_name: str, file_path: str, content: str, commit_message: str): """ @param project_name: @param branch_name: @param file_path: @param content: @param commit_message: @return: """ project_id = self._get_project_id(project_name) params = { 'branch': branch_name, 'content': content, 'commit_message': commit_message } httpResponsResult = self.doRequest.put( '/projects/%s/repository/files/%s' % (project_id, file_path), params=params) return ujson.loads(httpResponsResult.body)
class DemoProjectClient(object): __instance = None __inited = None def __new__(cls, *args, **kwargs): if cls.__instance is None: cls.__instance = object.__new__(cls) return cls.__instance def __init__(self): if self.__inited is None: self.demoProjectConfig = DemoProjectReadConfig().config self.demoProjectDBClients = DemoProjectDBClients() self.doRequest = DoRequest(self.demoProjectConfig.url) self.csrftoken = self._initCsrftoken() self.__inited = True def _initCsrftoken(self): # 测试接口如果都需要先授权,可以在再次操作,将授权信息放到httpclient的headers或者cookies httpResponseResult = self.doRequest.get( "/horizon/auth/login/?next=/horizon/") cookies = httpResponseResult.cookies csrftoken = StrTool.getStringWithLBRB(cookies, 'csrftoken=', ' for') return csrftoken
class DemoProjectClient(): def __init__(self): self.demoProjectConfig=DemoProjectInit().getDemoProjectConfig() self.doRequest=DoRequest(self.demoProjectConfig.url) self.csrftoken=None self._initCsrftoken() def _initCsrftoken(self): # 测试接口如果都需要先授权,可以在再次操作,将授权信息放到httpclient的headers或者cookies httpResponseResult = self.doRequest.get("/horizon/auth/login/?next=/horizon/") cookies = httpResponseResult.cookies csrftoken = StrTool.getStringWithLBRB(cookies, 'csrftoken=', ' for') self.csrftoken = csrftoken
def start_app_device_test(index,device_info,keyword,dir,markexpr,capture,reruns,lf): for path, dirs, files in os.walk('config/app_ui_tmp'): for file in files: if(int(file)==index): os.rename(os.path.join(path,file),os.path.join(path,str(os.getpid()))) print('开始检测appium server是否可用......') try: doRquest = DoRequest('http://'+device_info['server_ip']+':%s/wd/hub'%device_info['server_port'].strip()) httpResponseResult = doRquest.get('/status') result = ujson.loads(httpResponseResult.body) if result['status'] == 0: print('appium server状态为可用......') else: sys.exit('appium server状态为不可用') except: sys.exit('appium server状态为不可用') a_devices_desired_capabilities = device_info['capabilities'] print('开始设备' + device_info['device_desc'] + '测试......') for desired_capabilities in a_devices_desired_capabilities: FileTool.writeObjectIntoFile(desired_capabilities, 'config/app_ui_tmp/' + str(os.getpid()) + '_current_desired_capabilities') if desired_capabilities['appPackage']: desired_capabilities_desc = desired_capabilities['appPackage'] else: desired_capabilities_desc = os.path.basename(desired_capabilities['app']) print('当前设备开始测试的desired_capabilities为:%s' % desired_capabilities) # 执行pytest前的参数准备 pytest_execute_params = ['-c', 'config/pytest.ini', '-v', '--alluredir', 'output/app_ui/' + device_info['device_desc'] + '/' + desired_capabilities_desc] # 判断目录参数 if not dir: dir = 'cases/app_ui/' # 判断关键字参数 if keyword: pytest_execute_params.append('-k') pytest_execute_params.append(keyword) # 判断markexpr参数 if markexpr: pytest_execute_params.append('-m') pytest_execute_params.append(markexpr) # 判断是否输出日志 if capture: if int(capture): pytest_execute_params.append('-s') # 判断是否失败重跑 if reruns: if int(reruns): pytest_execute_params.append('--reruns') pytest_execute_params.append(reruns) # 判断是否只运行上一次失败的用例 if lf: if int(lf): pytest_execute_params.append('--lf') pytest_execute_params.append(dir) # 构建孙进程 process = multiprocessing.Process(target=pytest_main, args=(pytest_execute_params,)) process.start() process.join() print('当前设备结束测试的desired_capabilities为:%s' % desired_capabilities) print('结束设备' + device_info['device_desc'] + '测试......')
parser.add_argument('-r', '--reruns', help='失败重跑次数,默认为0', type=str) parser.add_argument('-lf', '--lf', help='是否运行上一次失败的用例,1:是、0:否,默认为0', type=str) parser.add_argument('-clr', '--clr', help='是否清空已有测试结果,1:是、0:否,默认为0', type=str) args = parser.parse_args() print('%s开始初始化......' % DateTimeTool.getNowTime()) print('%s开始检测selenium server是否可用......' % DateTimeTool.getNowTime()) try: doRquest = DoRequest(Read_WEB_UI_Config().web_ui_config.selenium_hub) httpResponseResult = doRquest.get('/status') result = ujson.loads(httpResponseResult.body) if result['status'] == 0: print('%sselenium server状态为可用......' % DateTimeTool.getNowTime()) else: sys.exit('%sselenium server状态为不可用' % DateTimeTool.getNowTime()) except: sys.exit('%sselenium server状态为不可用' % DateTimeTool.getNowTime()) # 处理pytest文件 deal_pytest_ini_file() # 初始化java依赖的libs java_maven_init() print('%s初始化基础数据......' % DateTimeTool.getNowTime())
def start_app_device_test(index,device_info,keyword,dir,markexpr,capture,reruns,lf,clr): for path, dirs, files in os.walk('config/app_ui_tmp'): for file in files: if(int(file)==index): os.rename(os.path.join(path,file),os.path.join(path,str(os.getpid()))) print('%s开始检测appium server是否可用......'%DateTimeTool.getNowTime()) try: doRquest = DoRequest('http://'+device_info['server_ip']+':%s/wd/hub'%device_info['server_port'].strip()) httpResponseResult = doRquest.get('/status') result = ujson.loads(httpResponseResult.body) if result['status'] == 0: print('%sappium server状态为可用......'%DateTimeTool.getNowTime()) else: sys.exit('%sappium server状态为不可用'%DateTimeTool.getNowTime()) except: print('%sappium server状态为不可用'%DateTimeTool.getNowTime()) raise Exception('%sappium server状态为不可用'%DateTimeTool.getNowTime()) a_devices_desired_capabilities = device_info['capabilities'] print('%s开始设备%s测试......'%(DateTimeTool.getNowTime(),device_info['device_desc'])) print('%s当前设备所需测试的desired_capabilities为:%s'%(DateTimeTool.getNowTime(),a_devices_desired_capabilities)) for desired_capabilities in a_devices_desired_capabilities: FileTool.writeObjectIntoFile(desired_capabilities,'config/app_ui_tmp/'+str(os.getpid())+'_current_desired_capabilities') desired_capabilities_desc=None if 'appPackage' in desired_capabilities.keys(): desired_capabilities_desc = desired_capabilities['appPackage'] elif 'app' in desired_capabilities.keys(): desired_capabilities_desc = desired_capabilities['app'].split('/')[-1] elif 'bundleId' in desired_capabilities.keys(): desired_capabilities_desc = desired_capabilities['bundleId'] print('%s当前设备开始测试的desired_capabilities为:%s'%(DateTimeTool.getNowTime(),desired_capabilities)) # 执行pytest前的参数准备 pytest_execute_params = ['-c', 'config/pytest.ini', '-v', '--alluredir', 'output/app_ui/%s/%s/report_data/'%(device_info['device_desc'],desired_capabilities_desc)] # 判断目录参数 if not dir: dir = 'cases/app_ui/' # 判断关键字参数 if keyword: pytest_execute_params.append('-k') pytest_execute_params.append(keyword) # 判断markexpr参数 if markexpr: pytest_execute_params.append('-m') pytest_execute_params.append(markexpr) # 判断是否输出日志 if capture: if int(capture): pytest_execute_params.append('-s') # 判断是否失败重跑 if reruns: if int(reruns): pytest_execute_params.append('--reruns') pytest_execute_params.append(reruns) # 判断是否只运行上一次失败的用例 if lf: if int(lf): pytest_execute_params.append('--lf') # 判断是否清空已有测试结果 if clr: if int(clr): pytest_execute_params.append('--clean-alluredir') pytest_execute_params.append(dir) # 构建孙进程 process = multiprocessing.Process(target=pytest_main,args=(pytest_execute_params,)) process.start() process.join() print('%s当前设备结束测试的desired_capabilities为:%s' % (DateTimeTool.getNowTime(),desired_capabilities)) print('%s结束设备%s测试......'%(DateTimeTool.getNowTime(),device_info['device_desc']))
class Gitlab_Client: def __init__(self, url: str, username: str, password: str): self.url = url self.username = username self.password = password self.url = urljoin(self.url, '/api/v3') self.doRequest = DoRequest(self.url) self.private_token = self._get_private_token() self._path_private_token = '?private_token=%s' % self.private_token def _login(self): httpResponseResult = self.doRequest.post_with_form( '/session?login=%s&password=%s' % (self.username, self.password)) return httpResponseResult def _get_private_token(self): user_info = self._login().body user_info = ujson.loads(user_info) return user_info['private_token'] def get_user(self): return ujson.loads(self._login().body) def get_projects(self, page: int = 1, per_page: int = 100): params = {'page': 1, 'per_page': 100} httpResponseResult = self.doRequest.get('/projects%s' % self._path_private_token, params=params) return ujson.loads(httpResponseResult.body) def _get_project_id(self, project_name: str): projects = self.get_projects() for project_info in projects: if project_info['name'] == project_name.strip(): return project_info['id'] def get_project_tree(self, project_name: str): project_id = self._get_project_id(project_name) httpResponsResult = self.doRequest.get( '/projects/%s/repository/tree%s' % (project_id, self._path_private_token)) return ujson.loads(httpResponsResult.body) def get_project_file(self, project_name, ref, file_path): """ @param project_name: @param ref: 分支名、tag名、commit @param file_path: @return: """ project_id = self._get_project_id(project_name) params = {'file_path': file_path, 'ref': ref} httpResponsResult = self.doRequest.get( '/projects/%s/repository/files%s' % (project_id, self._path_private_token), params=params) return ujson.loads(httpResponsResult.body) def update_project_file(self, project_name: str, branch_name: str, file_path: str, content: str, commit_message: str): """ @param project_name: @param branch_name: @param file_path: @param content: @param commit_message: @return: """ project_id = self._get_project_id(project_name) params = { 'file_path': file_path, 'branch_name': branch_name, 'content': content, 'commit_message': commit_message } httpResponsResult = self.doRequest.put( '/projects/%s/repository/files%s' % (project_id, self._path_private_token), params=params) return ujson.loads(httpResponsResult.body)
class AppOperator: """ 类中的element参数可以有appium.webdriver.webelement.WebElement和pojo.elementInfo.ElementInfo类型 """ def __init__(self, driver): self._config = Read_APP_UI_Config().app_ui_config self._doRequest = DoRequest(self._config.appium_hub) self._doRequest.setHeaders({'Content-Type': 'application/json'}) self._driver = driver self._session_id = driver.session_id # 获得设备支持的性能数据类型 self._performance_types = json.loads( self._doRequest.post_with_form( '/session/' + self._session_id + '/appium/performanceData/types').body)['value'] # 获取当前窗口大小 self._windows_size = self.get_window_size() def _change_element_to_webElement_type(self, element): if isinstance(element, ElementInfo): webElement = self.getElement(element) elif isinstance(element, WebElement): webElement = element else: return None return webElement def get(self, url): self._driver.get(url) def get_current_url(self): return self._driver.current_url def getTitle(self): return self._driver.title def getText(self, element): webElement = self._change_element_to_webElement_type(element) if webElement: return webElement.text def click(self, element): webElement = self._change_element_to_webElement_type(element) if webElement: webElement.click() def submit(self, element): webElement = self._change_element_to_webElement_type(element) if webElement: webElement.submit() def sendText(self, element, text): webElement = self._change_element_to_webElement_type(element) if webElement: webElement.clear() webElement.send_keys(text) def is_displayed(self, element): webElement = self._change_element_to_webElement_type(element) if webElement: flag = webElement.is_displayed() return flag def is_enabled(self, element): webElement = self._change_element_to_webElement_type(element) if webElement: flag = webElement.is_enabled() return flag def is_selected(self, element): webElement = self._change_element_to_webElement_type(element) if webElement: flag = webElement.is_selected() return flag def select_dropDownBox_by_value(self, element, value): """ 适用单选下拉框 :param element: :param value: :return: """ webElement = self._change_element_to_webElement_type(element) if webElement: webElement = Select(webElement) webElement.select_by_value(value) def select_dropDownBox_by_text(self, element, text): """ 适用单选下拉框 :param element: :param text: :return: """ webElement = self._change_element_to_webElement_type(element) if webElement: webElement = Select(webElement) webElement.select_by_visible_text(text) def select_dropDownBox_by_index(self, element, index): """ 适用单选下拉框,下标从0开始 :param element: :param index: :return: """ webElement = self._change_element_to_webElement_type(element) if webElement: webElement = Select(webElement) webElement.select_by_index(index) def select_dropDownBox_by_values(self, element, values): """ 适用多选下拉框 :param element: :param values:以数组传参 :return: """ webElement = self._change_element_to_webElement_type(element) if webElement: webElement = Select(webElement) webElement.deselect_all() for value in values: webElement.select_by_value(value) def select_dropDownBox_by_texts(self, element, texts): """ 适用多选下拉框 :param element: :param texts:以数组传参 :return: """ webElement = self._change_element_to_webElement_type(element) if webElement: webElement = Select(webElement) webElement.deselect_all() for text in texts: webElement.select_by_visible_text(text) def select_dropDownBox_by_indexs(self, element, indexs): """ 适用多选下拉框,下标从0开始 :param element: :param indexs: 以数组传参 :return: """ webElement = self._change_element_to_webElement_type(element) if webElement: webElement = Select(webElement) webElement.deselect_all() for index in indexs: webElement.select_by_index(index) def switch_to_window(self, window_name): """ 仅使用web :param window_name: :return: """ self._driver.switch_to.window(window_name) def switch_to_frame(self, frame_name): """ 仅使用web :param frame_name: :return: """ self._driver.switch_to.frame(frame_name) def page_forward(self): """ 仅使用web :return: """ self._driver.forward() def pag_back(self): """ 仅使用web :return: """ self._driver.back() def dismiss_alert(self): """ 仅使用web :return: """ alert = self._driver.switch_to.alert alert.dismiss() def accept_alert(self): """ 仅使用web :return: """ alert = self._driver.switch_to.alert alert.accept() def get_alert_text(self): """ 仅使用web :return: """ alert = self._driver.switch_to.alert return alert.text def get_screenshot(self, fileName): fileName = DateTimeTool.getNowTime('%Y%m%d%H%M%S%f_') + fileName allure.attach(name=fileName, body=self._driver.get_screenshot_as_png(), attachment_type=allure.attachment_type.PNG) def refresh(self): self._driver.refresh() def uploadFile(self, element, filePath): """ 仅适用于web 适用于元素为input且type="file"的文件上传 :param element: :param filePath: :return: """ webElement = self._change_element_to_webElement_type(element) if webElement: webElement.send_keys(os.path.abspath(filePath)) def switch_to_parent_frame(self): """ 切换到父frame(仅使用web) :return: """ self._driver.switch_to.parent_frame() def get_property(self, element, property_name): webElement = self._change_element_to_webElement_type(element) if webElement: return webElement.get_property(property_name) def get_attribute(self, element, attribute_name): webElement = self._change_element_to_webElement_type(element) if webElement: return webElement.get_attribute(attribute_name) def get_element_outer_html(self, element): return self.get_attribute(element, 'outerHTML') def get_element_inner_html(self, element): return self.get_attribute(element, 'innerHTML') def get_page_source(self): return self._driver.page_source def get_captcha(self, element, language='eng'): """ 识别图片验证码 :param element: 验证码图片元素 :param language: eng:英文,chi_sim:中文 :return: """ # 为防止截图包含高亮影响识别,元素不进行高亮 captcha_webElement = self._change_element_to_webElement_type(element) left = captcha_webElement.location['x'] top = captcha_webElement.location['y'] right = captcha_webElement.location['x'] + captcha_webElement.size[ 'width'] bottom = captcha_webElement.location['y'] + captcha_webElement.size[ 'height'] # 首先进行屏幕截图 captcha_image_file_name = DateTimeTool.getNowTime( '%Y%m%d%H%M%S%f_') + 'captcha.png' captcha_image_file_name = os.path.abspath('output/' + captcha_image_file_name) self._driver.get_screenshot_as_file(captcha_image_file_name) img = Image.open(captcha_image_file_name) # 验证码图片裁切并保存 img = img.crop((left, top, right, bottom)) img.save(captcha_image_file_name) # 识别图片验证码 captcha = CaptchaRecognitionTool.captchaRecognition( captcha_image_file_name, language) captcha = captcha.strip() captcha = captcha.replace(' ', '') return captcha def get_table_data(self, element, data_type='text'): """ 以二维数组返回表格每一行的每一列的数据[[row1][row2][colume1,clume2]] :param element: :param data_type: text-返回表格文本内容,html-返回表格html内容,webElement-返回表格元素 :return: """ if isinstance(element, ElementInfo): # 由于表格定位经常会出现【StaleElementReferenceException: Message: stale element reference: element is not attached to the page document 】异常错误, # 解决此异常只需要用显示等待,保证元素存在即可,显示等待类型中visibility_of_all_elements_located有实现StaleElementReferenceException异常捕获, # 所以强制设置表格定位元素时使用VISIBILITY_OF element.wait_type = Wait_By.VISIBILITY_OF webElement = self.getElement(element) elif isinstance(element, WebElement): webElement = element else: return None table_data = [] table_trs = webElement.find_elements_by_tag_name('tr') try: for tr in table_trs: tr_data = [] tr_tds = tr.find_elements_by_tag_name('td') if data_type.lower() == 'text': for td in tr_tds: tr_data.append(td.text) elif data_type.lower() == 'html': for td in tr_tds: tr_data.append(td.get_attribute('innerHTML')) elif data_type.lower() == 'webelement': tr_data = tr_tds table_data.append(tr_data) except StaleElementReferenceException as e: print('获取表格内容异常:' + e.msg) return table_data def get_window_size(self): return self._driver.get_window_size() def get_geolocation(self): """ 返回定位信息,纬度/经度/高度 :return: """ httpResponseResult = self._doRequest.get('/session/' + self._session_id + '/location') return httpResponseResult.body def set_geolocation(self, latitude, longitude, altitude): """ 设置定位信息 :param latitude: 纬度 -90 ~ 90 :param longitude: 精度 ~180 ~ 180 :param altitude: 高度 :return: """ geolocation = {} location = {} location.update({'latitude': latitude}) location.update({'longitude': longitude}) location.update({'altitude': altitude}) geolocation.update({'location': location}) self._doRequest.post_with_form('/session/' + self._session_id + '/location', params=json.dumps(geolocation)) def get_current_activity(self): """ 获得Android的activity :return: """ return self._driver.current_activity def get_current_package(self): """ 获得Android的package :return: """ return self._driver.current_package def execute_javascript(self, script): """ 仅适用于web :param script: :return: """ self._driver.execute_script(script) def install_app(self, filePath): self._driver.install_app(os.path.abspath(filePath)) def remove_app(self, app_id): self._driver.remove_app(app_id) def launch_app(self): self._driver.launch_app() def reset_app(self): """ 重置app,可以进入下一轮app测试 :return: """ return self._driver.reset() def close_app(self): self._driver.close_app() def background_app(self, seconds): """ 后台运行 :param seconds: :return: """ self._driver.background_app(seconds) def push_file_to_device(self, device_filePath, local_filePath): """ 上传文件设备 :param device_filePath: :param local_filePath: :return: """ local_filePath = os.path.abspath(local_filePath) with open(local_filePath, 'rb') as f: data = base64.b64encode(f.read()) f.close() self._driver.push_file(device_filePath, data) def pull_file_from_device(self, device_filePath, local_filePath): """ 从设备上下载文件 :param device_filePath: :param local_filePath: :return: """ local_filePath = os.path.abspath(local_filePath) data = self._driver.pull_file(device_filePath) with open(local_filePath, 'wb') as f: f.write(base64.b64decode(data)) f.close() def shake_device(self): """ 仅支持IOS,详见https://github.com/appium/appium/blob/master/docs/en/commands/device/interactions/shake.md :return: """ self._driver.shake() def lock_screen(self, seconds=None): self._driver.lock(seconds) def unlock_screen(self): self._driver.unlock() def press_keycode(self, keycode): """ 按键盘按键 :param keycode: 键盘上每个按键的ascii :return: """ self._driver.press_keycode(keycode) def long_press_keycode(self, keycode): """ 长按键盘按键 :param keycode: :return: """ self._driver.long_press_keycode(keycode) def hide_keyboard(self, key_name=None, key=None, strategy=None): """ 隐藏键盘,ios需要指定key_name或strategy,Android无需参数 :param key_name: :param key: :param strategy: :return: """ self._driver.hide_keyboard(key_name, key, strategy) def toggle_airplane_mode(self): """ 切换飞行模式(开启关闭),仅支持Android :return: """ self._doRequest.post_with_form('/session/' + self._session_id + '/appium/device/toggle_airplane_mode') def toggle_data(self): """ 切换蜂窝数据模式(开启关闭),仅支持Android :return: """ self._doRequest.post_with_form('/session/' + self._session_id + '/appium/device/toggle_data') def toggle_wifi(self): """ 切换wifi模式(开启关闭),仅支持Android :return: """ self._doRequest.post_with_form('/session/' + self._session_id + '/appium/device/toggle_wifi') def toggle_location_services(self): """ 切换定位服务模式(开启关闭),仅支持Android :return: """ self._driver.toggle_location_services() def get_performance_date(self, data_type, package_name=None, data_read_timeout=10): """ 获得设备性能数据 :param package_name: :param data_type: cpuinfo、batteryinfo、networkinfo、memoryinfo :param data_read_timeout: :return: """ if data_type in self._performance_types: params = {} if not package_name: package_name = self.get_current_package() params.update({'packageName': package_name}) params.update({'dataType': data_type}) params.update({'dataReadTimeout': data_read_timeout}) httpResponseResult = self._doRequest.post_with_form( '/session/' + self._session_id + '/appium/getPerformanceData', params=json.dumps(params)) return httpResponseResult.body else: return None def start_recording_screen(self): """ 默认录制为3分钟,android最大只能3分钟,ios最大只能10分钟。如果录制产生的视频文件过大无法放到手机内存里会抛异常,所以尽量录制短视频 :return: """ self._driver.start_recording_screen(forcedRestart=True) def stop_recording_screen(self, fileName=''): """ 停止录像并将视频附加到报告里 :param fileName: :return: """ fileName = DateTimeTool.getNowTime('%Y%m%d%H%M%S%f_') + fileName data = self._driver.stop_recording_screen() allure.attach(name=fileName, body=base64.b64decode(data), attachment_type=allure.attachment_type.MP4) def get_device_time(self): """ 获得设备时间 :return: """ return self._driver.device_time def get_element_location(self, element): """ 获得元素在屏幕的位置,x、y坐标 :param element: :return: """ webElement = self._change_element_to_webElement_type(element) if webElement: return webElement.location def get_element_size_in_pixels(self, element): """ 返回元素的像素大小 :param element: :return: """ webElement = self._change_element_to_webElement_type(element) if webElement: return webElement.size def get_all_contexts(self): """ 获得能够自动化测所有上下文(混合应用中的原生应用和web应用) :return: """ return self._driver.contexts def get_current_context(self): """ 获得当前appium中正在运行的上下文(混合应用中的原生应用和web应用) :return: """ return self._driver.current_context def switch_context(self, context_name): """ 切换上下文(混合应用中的原生应用和web应用) :param context_name: :return: """ context = {} context.update({'name': context_name}) self._doRequest.post_with_form('/session/' + self._session_id + '/context', params=json.dumps(context)) def mouse_move_to(self, element, xoffset=None, yoffset=None): """ 移动鼠标到指定位置(仅适用于Windows、mac) 1、如果xoffset和yoffset都None,则鼠标移动到指定元素的正中间 2、如果element、xoffset和yoffset都不为None,则根据元素的左上角做x和y的偏移移动鼠标 :param element: :param xoffset: :param yoffset: :return: """ webElement = self._change_element_to_webElement_type(element) if element: actions = ActionChains(self._driver) if xoffset and yoffset: actions.move_to_element_with_offset(webElement, xoffset, yoffset) actions.move_to_element(webElement) actions.perform() def mouse_click(self): """ 点击鼠标当前位置(仅适用于Windows、mac) :return: """ actions = ActionChains(self._driver) actions.click() actions.perform() def mouse_double_click(self): """ 双击鼠标当前位置(仅适用于Windows、mac) :return: """ actions = ActionChains(self._driver) actions.double_click() actions.perform() def mouse_click_and_hold(self): """ 长按鼠标(仅适用于Windows、mac) :return: """ actions = ActionChains(self._driver) actions.click_and_hold() actions.perform() def mouse_release_click_and_hold(self): """ 停止鼠标长按(仅适用于Windows、mac) :return: """ actions = ActionChains(self._driver) actions.release() actions.perform() def touch_tap(self, element, xoffset=None, yoffset=None, count=1, is_perfrom=True): """ 触屏点击 1、如果xoffset和yoffset都None,则在指定元素的正中间进行点击 2、如果element、xoffset和yoffset都不为None,则根据元素的左上角做x和y的偏移然后进行点击 :param element: :param xoffset: :param yoffset: :param count: 点击次数 :param is_perfrom 是否马上执行动作,不执行可以返回动作给多点触控执行 :return: """ webElement = self._change_element_to_webElement_type(element) if webElement: actions = TouchAction(self._driver) actions.tap(element, xoffset, yoffset, count) if is_perfrom: actions.perform() return actions def touch_long_press(self, element, xoffset=None, yoffset=None, duration_sconds=10, is_perfrom=True): """ 触屏长按 1、如果xoffset和yoffset都None,则在指定元素的正中间进行长按 2、如果element、xoffset和yoffset都不为None,则根据元素的左上角做x和y的偏移然后进行长按 :param element: :param xoffset: :param yoffset: :param duration_sconds: 长按秒数 :param is_perfrom 是否马上执行动作,不执行可以返回动作给多点触控执行 :return: """ webElement = self._change_element_to_webElement_type(element) if webElement: actions = TouchAction(self._driver) actions.long_press(webElement, xoffset, yoffset, duration_sconds * 1000) if is_perfrom: actions.perform() return actions def multi_touch_actions_perform(self, touch_actions): """ 多点触控执行 :param touch_actions: :return: """ multiActions = MultiAction(self._driver) for actions in touch_actions: multiActions.add(actions) multiActions.perform() def touch_slide(self, start_element=None, start_x=None, start_y=None, end_element=None, end_x=None, end_y=None, duration=None): """ 滑动屏幕,在指定时间内从一个位置滑动到另外一个位置 1、如果start_element不为None,则从元素的中间位置开始滑动 2、如果end_element不为None,滑动结束到元素的中间位置 :param start_element: :param end_element: :param start_x: :param start_y: :param end_x: :param end_y: :param duration: 毫秒 :return: """ start_webElement = self._change_element_to_webElement_type( start_element) end_webElement = self._change_element_to_webElement_type(end_element) if start_webElement: start_webElement_location = self.get_element_location( start_webElement) start_x = start_webElement_location['x'] start_y = start_webElement_location['y'] if end_webElement: end_webElement_location = self.get_element_location(end_webElement) end_x = end_webElement_location['x'] end_y = end_webElement_location['y'] self._driver.swipe(start_x, start_y, end_x, end_y, duration) def touch_left_slide(self, duration=500): """ 从屏幕正中间进行左滑 :return: """ start_x = self._windows_size['width'] * 0.45 start_y = self._windows_size['height'] * 0.45 end_x = 0 end_y = start_y self._driver.swipe(start_x, start_y, end_x, end_y, duration) def touch_right_slide(self, duration=500): """ 从屏幕正中间进行右滑 :return: """ start_x = self._windows_size['width'] * 0.45 start_y = self._windows_size['height'] * 0.45 end_x = self._windows_size['width'] * 0.9 end_y = start_y self._driver.swipe(start_x, start_y, end_x, end_y, duration) def touch_up_slide(self, duration=500): """ 从屏幕正中间进行上滑 :return: """ start_x = self._windows_size['width'] * 0.45 start_y = self._windows_size['height'] * 0.45 end_x = start_x end_y = 0 self._driver.swipe(start_x, start_y, end_x, end_y, duration) def touch_down_slide(self, duration=500): """ 从屏幕正中间进行下滑 :return: """ start_x = self._windows_size['width'] * 0.45 start_y = self._windows_size['height'] * 0.45 end_x = start_x end_y = self._windows_size['height'] * 0.9 self._driver.swipe(start_x, start_y, end_x, end_y, duration) def getElement(self, elementInfo): """ 定位单个元素 :param elementInfo: :return: """ webElement = None locator_type = elementInfo.locator_type locator_value = elementInfo.locator_value wait_type = elementInfo.wait_type wait_seconds = elementInfo.wait_seconds wait_expected_value = elementInfo.wait_expected_value if wait_expected_value: wait_expected_value = wait_expected_value # 查找元素,为了保证元素被定位,都进行显式等待 if wait_type == Wait_By.TITLE_IS: webElement = WebDriverWait(self._driver, wait_seconds).until( expected_conditions.title_is(wait_expected_value)) elif wait_type == Wait_By.TITLE_CONTAINS: webElement = WebDriverWait(self._driver, wait_seconds).until( expected_conditions.title_contains(wait_expected_value)) elif wait_type == Wait_By.PRESENCE_OF_ELEMENT_LOCATED: webElement = WebDriverWait(self._driver, wait_seconds).until( expected_conditions.presence_of_element_located( (locator_type, locator_value))) elif wait_type == Wait_By.ELEMENT_TO_BE_CLICKABLE: webElement = WebDriverWait(self._driver, wait_seconds).until( expected_conditions.element_to_be_clickable( (locator_type, locator_value))) elif wait_type == Wait_By.ELEMENT_LOCATED_TO_BE_SELECTED: webElement = WebDriverWait(self._driver, wait_seconds).until( expected_conditions.element_located_to_be_selected( (locator_type, locator_value))) elif wait_type == Wait_By.VISIBILITY_OF: webElements = WebDriverWait(self._driver, wait_seconds).until( (expected_conditions.visibility_of_all_elements_located( (locator_type, locator_value)))) if len(webElements) > 0: webElement = webElements[0] else: if locator_type == By.ID: webElement = WebDriverWait(self._driver, wait_seconds).until( lambda driver: driver.find_element_by_id(locator_value)) elif locator_type == By.NAME: webElement = WebDriverWait(self._driver, wait_seconds).until( lambda driver: driver.find_element_by_name(locator_value)) elif locator_type == By.LINK_TEXT: webElement = WebDriverWait(self._driver, wait_seconds).until( lambda driver: driver.find_element_by_link_text( locator_value)) elif locator_type == By.XPATH: webElement = WebDriverWait(self._driver, wait_seconds).until( lambda driver: driver.find_element_by_xpath(locator_value)) elif locator_type == By.PARTIAL_LINK_TEXT: webElement = WebDriverWait(self._driver, wait_seconds).until( lambda driver: driver.find_element_by_partial_link_text( locator_value)) elif locator_type == By.CSS_SELECTOR: webElement = WebDriverWait(self._driver, wait_seconds).until( lambda driver: driver.find_element_by_css_selector( locator_value)) elif locator_type == By.CLASS_NAME: webElement = WebDriverWait(self._driver, wait_seconds).until( lambda driver: driver.find_element_by_class_name( locator_value)) elif locator_type == By.TAG_NAME: webElement = WebDriverWait(self._driver, wait_seconds).until( lambda driver: driver.find_element_by_tag_name( locator_value)) elif locator_type == Locator_Type.ACCESSIBILITY_ID: webElement = WebDriverWait(self._driver, wait_seconds).until( lambda driver: driver.find_element_by_accessibility_id( locator_value)) elif locator_type == Locator_Type.IMAGE: webElement = WebDriverWait(self._driver, wait_seconds).until( lambda driver: driver.find_element_by_image(locator_type)) return webElement def getElements(self, elementInfo): """ 定位多个元素 :param elementInfo: :return: """ webElements = None locator_type = elementInfo.locator_type locator_value = elementInfo.locator_value wait_type = elementInfo.wait_type wait_seconds = elementInfo.wait_seconds # 查找元素,为了保证元素被定位,都进行显式等待 if wait_type == Wait_By.PRESENCE_OF_ELEMENT_LOCATED: webElements = WebDriverWait(self._driver, wait_seconds).until( expected_conditions.presence_of_all_elements_located( (locator_type, locator_value))) elif wait_type == Wait_By.VISIBILITY_OF: webElements = WebDriverWait(self._driver, wait_seconds).until( expected_conditions.visibility_of_all_elements_located( (locator_type, locator_value))) else: if locator_type == By.ID: webElements = WebDriverWait(self._driver, wait_seconds).until( lambda driver: driver.find_elements_by_id(locator_value)) elif locator_type == By.NAME: webElements = WebDriverWait(self._driver, wait_seconds).until( lambda driver: driver.find_elements_by_name(locator_value)) elif locator_type == By.LINK_TEXT: webElements = WebDriverWait(self._driver, wait_seconds).until( lambda driver: driver.find_elements_by_link_text( locator_value)) elif locator_type == By.XPATH: webElements = WebDriverWait( self._driver, wait_seconds).until(lambda driver: driver. find_elements_by_xpath(locator_value)) elif locator_type == By.PARTIAL_LINK_TEXT: webElements = WebDriverWait(self._driver, wait_seconds).until( lambda driver: driver.find_elements_by_partial_link_text( locator_value)) elif locator_type == By.CSS_SELECTOR: webElements = WebDriverWait(self._driver, wait_seconds).until( lambda driver: driver.find_elements_by_css_selector( locator_value)) elif locator_type == By.CLASS_NAME: webElements = WebDriverWait(self._driver, wait_seconds).until( lambda driver: driver.find_elements_by_class_name( locator_value)) elif locator_type == By.TAG_NAME: webElements = WebDriverWait(self._driver, wait_seconds).until( lambda driver: driver.find_elements_by_tag_name( locator_value)) elif locator_type == Locator_Type.ACCESSIBILITY_ID: webElements = WebDriverWait(self._driver, wait_seconds).until( lambda driver: driver.find_elements_by_accessibility_id( locator_value)) elif locator_type == Locator_Type.IMAGE: webElements = WebDriverWait(self._driver, wait_seconds).until( lambda driver: driver.find_elements_by_image(locator_type)) return webElements def getSubElement(self, parent_element, sub_elementInfo): """ 获得元素的单个子元素 :param parent_element: 父元素 :param sub_elementInfo: 子元素,只能提供pojo.elementInfo.ElementInfo类型 :return: """ webElement = self._change_element_to_webElement_type(parent_element) if not webElement: return None if not isinstance(sub_elementInfo, ElementInfo): return None # 通过父元素查找子元素 locator_type = sub_elementInfo.locator_type locator_value = sub_elementInfo.locator_value wait_seconds = sub_elementInfo.wait_seconds # 查找元素,为了保证元素被定位,都进行显式等待 if locator_type == By.ID: subWebElement = WebDriverWait( webElement, wait_seconds).until(lambda webElement: webElement. find_element_by_id(locator_value)) elif locator_type == By.NAME: subWebElement = WebDriverWait( webElement, wait_seconds).until(lambda webElement: webElement. find_element_by_name(locator_value)) elif locator_type == By.LINK_TEXT: subWebElement = WebDriverWait( webElement, wait_seconds).until(lambda webElement: webElement. find_element_by_link_text(locator_value)) elif locator_type == By.XPATH: subWebElement = WebDriverWait( webElement, wait_seconds).until(lambda webElement: webElement. find_element_by_xpath(locator_value)) elif locator_type == By.PARTIAL_LINK_TEXT: subWebElement = WebDriverWait(webElement, wait_seconds).until( lambda webElement: webElement. find_element_by_partial_link_text(locator_value)) elif locator_type == By.CSS_SELECTOR: subWebElement = WebDriverWait(webElement, wait_seconds).until( lambda webElement: webElement.find_element_by_css_selector( locator_value)) elif locator_type == By.CLASS_NAME: subWebElement = WebDriverWait( webElement, wait_seconds).until(lambda webElement: webElement. find_element_by_class_name(locator_value)) elif locator_type == By.TAG_NAME: subWebElement = WebDriverWait( webElement, wait_seconds).until(lambda webElement: webElement. find_element_by_tag_name(locator_value)) elif locator_type == Locator_Type.ACCESSIBILITY_ID: subWebElement = WebDriverWait(webElement, wait_seconds).until( lambda webElement: webElement.find_element_by_accessibility_id( locator_value)) elif locator_type == Locator_Type.IMAGE: subWebElement = WebDriverWait( webElement, wait_seconds).until(lambda webElement: webElement. find_element_by_image(locator_type)) else: return None return subWebElement def getSubElements(self, parent_element, sub_elementInfo): """ 获得元素的多个子元素 :param parent_element: 父元素 :param sub_elementInfo: 子元素,只能提供pojo.elementInfo.ElementInfo类型 :return: """ webElement = self._change_element_to_webElement_type(parent_element) if not webElement: return None if not isinstance(sub_elementInfo, ElementInfo): return None # 通过父元素查找多个子元素 locator_type = sub_elementInfo.locator_type locator_value = sub_elementInfo.locator_value wait_seconds = sub_elementInfo.wait_seconds # 查找元素,为了保证元素被定位,都进行显式等待 if locator_type == By.ID: subWebElements = WebDriverWait( webElement, wait_seconds).until(lambda webElement: webElement. find_elements_by_id(locator_value)) elif locator_type == By.NAME: subWebElements = WebDriverWait( webElement, wait_seconds).until(lambda webElement: webElement. find_elements_by_name(locator_value)) elif locator_type == By.LINK_TEXT: subWebElements = WebDriverWait( webElement, wait_seconds).until(lambda webElement: webElement. find_elements_by_link_text(locator_value)) elif locator_type == By.XPATH: subWebElements = WebDriverWait( webElement, wait_seconds).until(lambda webElement: webElement. find_elements_by_xpath(locator_value)) elif locator_type == By.PARTIAL_LINK_TEXT: subWebElements = WebDriverWait(webElement, wait_seconds).until( lambda webElement: webElement. find_elements_by_partial_link_text(locator_value)) elif locator_type == By.CSS_SELECTOR: subWebElements = WebDriverWait(webElement, wait_seconds).until( lambda webElement: webElement.find_elements_by_css_selector( locator_value)) elif locator_type == By.CLASS_NAME: subWebElements = WebDriverWait( webElement, wait_seconds).until(lambda webElement: webElement. find_elements_by_class_name(locator_value)) elif locator_type == By.TAG_NAME: subWebElements = WebDriverWait( webElement, wait_seconds).until(lambda webElement: webElement. find_elements_by_tag_name(locator_value)) elif locator_type == Locator_Type.ACCESSIBILITY_ID: subWebElements = WebDriverWait(webElement, wait_seconds).until( lambda webElement: webElement. find_elements_by_accessibility_id(locator_value)) elif locator_type == Locator_Type.IMAGE: subWebElements = WebDriverWait( webElement, wait_seconds).until(lambda webElement: webElement. find_elements_by_image(locator_type)) else: return None return subWebElements def explicit_wait_page_title(self, elementInfo): """ 仅适用于web 显式等待页面title :param elementInfo: :return: """ self.getElement(elementInfo) def getDriver(self): return self._driver
class Disconf_Client: def __init__(self, url: str, username: str, password: str, is_verify_ssl_cer=True): self.url = url self.username = username self.password = password self.doRequest = DoRequest(self.url) self.doRequest.setVerify(is_verify_ssl_cer) self._login() def _login(self): params = { 'name': 'admin_test', 'password': '******', 'remember': '1' } httpResponseResult = self.doRequest.post_with_form( '/api/account/signin', params) return ujson.loads(httpResponseResult.body) def get_app_list(self): httpResponseResult = self.doRequest.get('/api/app/list') app_list = ujson.loads(httpResponseResult.body) app_list = app_list['page']['result'] return app_list def get_app_id(self, app_name: str): app_list = self.get_app_list() for app_info in app_list: if app_info['name'] == app_name: return app_info['id'] def get_env_list(self): httpResponseResult = self.doRequest.get('/api/env/list') env_list = ujson.loads(httpResponseResult.body) env_list = env_list['page']['result'] return env_list def get_env_id(self, env_name: str): env_list = self.get_env_list() for env_info in env_list: if env_info['name'] == env_name: return env_info['id'] def get_version_list(self, app_id: int, env_id: int): params = {'appId': app_id, 'envid': env_id} httpResponseResult = self.doRequest.get('/api/web/config/versionlist', params) version_list = ujson.loads(httpResponseResult.body) version_list = version_list['page']['result'] return version_list def get_config_list(self, app_id: int, env_id: int, version: str, pageSize: int = 50, pageNo: int = 1): params = { 'appId': app_id, 'envId': env_id, 'version': version, "page.pageSize": pageSize, "page.pageNo": pageNo } httpResponseResult = self.doRequest.get('/api/web/config/list', params) config_list = ujson.loads(httpResponseResult.body) config_list = config_list['page']['result'] return config_list def get_config_id(self, app_name: str, env_name: str, version: str, config_name: str): now_page = 1 # 最多从500个文件获取 while (not now_page > 10): config_list = self.get_config_list(self.get_app_id(app_name), self.get_env_id(env_name), version, pageSize=50, pageNo=now_page) for config_info in config_list: if config_info['key'] == config_name: return config_info['configId'] now_page += 1 def get_config_info(self, config_id: int): httpResponseResult = self.doRequest.get('/api/web/config/%s' % config_id) config_info = ujson.loads(httpResponseResult.body) config_info = config_info['result']['value'] return config_info def update_config_info(self, config_id: int, content: str): params = {'fileContent': content} httpResponseResult = self.doRequest.put( '/api/web/config/filetext/%s' % config_id, params) config_info = ujson.loads(httpResponseResult.body) return config_info