Menu: 文件上传弹框处理

文件上传、弹框处理文件上传:input标签可以直接使用send_keys(文件地址)上传文件
用法:el = driver.find_element_by_id('上传按钮id')el.send_keys("文件路径+文件名")文件上传案例:打开百度图片网址:https://image.baidu.com识别上传按钮点击上传按钮将本地的图片文件上传
import time
from selenium_file_alert.base import Baseclass TestFile(Base):                   #继承Base()方法,不需要初始化driver'''打开百度图片网址:https://image.baidu.com识别上传按钮点击上传按钮将本地的图片文件上传'''def test_file_upload(self):self.driver.get("https://image.baidu.com/")#点击打开文件上传弹框self.driver.find_element_by_css_selector('.st_camera_off').click()el = self.driver.find_element_by_id('stfile')# el.send_keys("C:/Users/Banana/Desktop/dog.jpg")el.send_keys(r"C:\Users\Banana\Desktop\dog.jpg")        #复制的本地路径使用r参数防止字符转义time.sleep(5)
弹框处理机制在页面操作中有时会碰到JavaScript所生成的alert、confirm以及prompt弹框,
可以使用swith_to.alert()方法定位到。然后用text/accept/dismiss/send_keys等
方法进行操作。参考分辨alert(F12 console: window.alert("hello"))、
window(点击某个链接新打开window窗口)、div模态框(例如百度页面的登录,
div页面会非常复杂有很多渲染和链接),以及操作。操作alert常用的方法:switch_to.alert()      #获取当前页面上的警告框text                 #返回alert/confirm/prompt中的文字信息accept()              #接受现有警告框,也就是点击确定按钮dismiss()                #取消现有警告框,也就是点击取消按钮send_keys(keysToSend) #发送文本至警告框。keyToSend:将文本发送至警告框。alert窗口处理案例:打开网页https://www.runoob.com/try/try.php?filename=jqueryui-api-droppable操作窗口右侧页面,将元素1拖拽到元素2 这时候会有一个alert弹框,点击弹框中的‘确定’然后再点击‘点击运行’关闭网页
import time
from selenium.webdriver import ActionChains
from selenium_file_alert.base import Baseclass TestAlert(Base):          #继承Base()方法,不需要初始化driver'''打开网页https://www.runoob.com/try/try.php?filename=jqueryui-api-droppable操作窗口右侧页面,将元素1拖拽到元素2这时候会有一个alert弹框,点击弹框中的‘确定’然后再点击‘点击运行’关闭网页'''def test_alert(self):self.driver.get("https://www.runoob.com/try/try.php?filename=jqueryui-api-droppable")#切换frameself.driver.switch_to.frame('iframeResult')dragele = self.driver.find_element_by_id('draggable')dropele = self.driver.find_element_by_id('droppable')action = ActionChains(self.driver)#拖拽后记得perform()action.drag_and_drop(dragele,dropele).perform()time.sleep(3)#获取页面警告框,点击 【确定】 按钮self.driver.switch_to_alert().accept()#切换到父节点frameself.driver.switch_to.parent_frame()#点击 【点击运行】按钮self.driver.find_element_by_id("submitBTN").click()

Menu:Page Object设计模式

案例抽象化操作细节结果验证操作细节结果验证
↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
PageObject测试:操作细节、验证如果case中存在大量的find_element 界面发生变更,case需要重写 为此我们需要采用PO模式
如果采用PO模式,比如登录,登录的按钮变了,只用在登录对应的地方修改,所有的case是不需要修改的https://github.com/SeleniumHQ/selenium/wiki/PageObjects
PO六大原则
The public methods represent the services that the page offers   公共方法代表页面提供的服务
Try not to expose the internals of the page                      不要暴露页面的内部细节
Generally don't make assertions                                  通常不做断言
Methods return other PageObjects                                 方法返回其他PageObjects
Need not represent an entire page                                不需要将整个页面功能全部设计出来
Different results for the same action are modelled as different methods    相同动作的不同结果被建模为不同的方法

Menu:Page Object原则

https://github.com/SeleniumHQ/selenium/wiki/PageObjects
PO六大原则
The public methods represent the services that the page offers             #公共方法代表页面提供的服务#栗子:#百度页面很多功能,一个方法click()代表搜索,一个方法sendkeys()代表输入框
Try not to expose the internals of the page                                #不要暴露页面的内部细节
Generally don't make assertions                                            #通常不做断言
Methods return other PageObjects                                            #方法返回其他PageObjects#栗子:#百度点一个页面弹出一个页面,那么这个页面就应该return弹出的页面#如果页面A导航到页面B,Page A应当return Page B
Need not represent an entire page                                          #不需要将整个页面功能全部设计出来
Different results for the same action are modelled as different methods    #相同动作的不同结果被建模为不同的方法#栗子:#404err 和200 设计俩个方法,分别代表正确的页面和错误的页面。不要把正确的页面和错误的页面写在一个页面里

Menu:企业微信的自动化登录

一、使用remote复用已有的浏览器 主要功能也是调试使用
二、使用cookie登录一、使用remote复用已有的浏览器:对当前页面进行测试,不希望重新打开浏览器,不希望进行前面的所有步骤后再执行该页面的操作。通过chromedriver开启debug模式即可实现1.在已有chrome浏览器上打开调试2.修改selenium代码,适应该调试详细步骤:1.环境变量加入chrome可执行文件地址,也就是chrome运行文件加入到环境变量          #加入到环境变量后,cmd输入chrome(可执行文件名称),如果可运行证明添加成功#注意添加环境变量是将文件所在目录添加到环境变量,不是将文件可执行路径加入到环境变量,例如 C:\Program Files\Google\Chrome\Application\chrome.exe 只需要将  C:\Program Files\Google\Chrome\Application 加入到path环境变量即可2.chrome --remote-debugging-port=9222               #命令行运行,打开浏览器调试时,一定要关闭所有chrome浏览器,这时运行后会打开一个9222的chrome窗口3.代码也需要加入 9222 debug的调试地址                   #和浏览器打开的调试端口进行通信,实现已有浏览器的复用
#使用remote复用已有的浏览器
# Generated by Selenium IDE
import timefrom selenium import webdriver
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.common.by import Byclass Test():def setup_method(self):options = Options()#和浏览器打开的调试端口进行通信#浏览器要使用 --remote-debugging-port=9222 开启调试options.debugger_address = "127.0.0.1:9222"self.driver = webdriver.Chrome(options=options)         #和浏览器打开的调试端口进行通信,实现已有浏览器的复用def tear_down(self):#self.driver.quit()                                      #可不写,以防将通信浏览器窗口关掉passdef test_baidu(self):self.driver.get("https://www.baidu.com/")self.driver.find_element(By.ID, "kw").send_keys("霍格沃兹测试学院")self.driver.find_element(By.ID, "su").click()time.sleep(2)self.driver.find_element(By.PARTIAL_LINK_TEXT, "软件自动化测试开发培训_接口性能测试").click()

Menu:企业微信的自动化登录2

二、使用cookie登录driver.get(url)driver.delete_all_cookies()for cookie in cookies:driver.add_cookie(cookie)driver.refresh()shelve    #python自带的小型数据库
db = shelve.open("cookies")     #如果本地没有cookies数据库,会创建一个名称为cookies的小型数据库。如果本地有cookies数据库,那么就会直接读取小型数据库如何更新数据?将数据库的key重新赋值即可,对整体进行更新====================
1.先通过复用浏览器获取登录的cookies,进行打印。通过变量保存登录的cookies
2.将获取的cookies通过小型数据库shelve进行保存后,保存完成关闭小型数据库
3.取消使用复用浏览器,用新窗口打开需要访问的网址(给定url),打开小型数据库shelve,读取数据,
移除cookies中的expiry后,将剩下的cookie注入到浏览器cookie上。关闭小型数据库shelve。
====================#参考链接:https://ceshiren.com/t/topic/3832
# Generated by Selenium IDE
import shelve
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.common.by import Byclass Test():def setup_method(self):options = Options()#和浏览器打开的调试端口进行通信#浏览器要使用 --remote-debugging-port=9222 开启调试options.debugger_address = "127.0.0.1:9222"# self.driver = webdriver.Chrome(options=options)         #和浏览器打开的调试端口进行通信,实现已有浏览器的复用self.driver = webdriver.Chrome()        #使用cookies,不使用复用浏览器def test_wework(self):'''1.先通过复用浏览器获取登录的cookies, 进行打印。通过变量保存登录的cookies2.将获取的cookies通过小型数据库shelve进行保存后,保存完成关闭小型数据库3.取消使用复用浏览器,用新窗口打开需要访问的网址(给定url),打开小型数据库shelve, 读取数据,移除cookies中的expiry后,将剩下的cookie注入到浏览器cookie上。关闭小型数据库shelve。'''# self.driver.get("https://work.weixin.qq.com/wework_admin/frame#index")#复用浏览器时,识别的是当前打开的窗口页面,类似于句柄,识别的是当前句柄# self.driver.find_element(By.ID,'menu_contacts').click()     #复用浏览器,浏览器当前窗口为企业微信登录主页,此时复用浏览器也不需要指定访问页面链接,给定元素定位方式即可操作#print(self.driver.get_cookies())        #使用复用的浏览器打印页面的cookies#打印的cookies结果如下:#注意查看domain是否是当前页面domain# cookies = [{'domain': '.work.weixin.qq.com', 'httpOnly': True, 'name': 'wwrtx.vst', 'path': '/', 'secure': False, 'value': 'QHVVs-2wzIL4rJjmY3wob1l0ig6tXr57X2AUVnqy_kkxyBdA4VdupnL4gIKgMVXKTuw2beIgPe5lO8FuK5_orfnF97CrZekiYltq5uDTEJSjs-fUY5bqqqZ3uDtdGdETj39cRnXsVnX0pBjl-vhkt0X4fBR_cWKOhkMAiXH6OaxUrrkhT4pxuyccuzLjIF0_Zi9HusVw1XLEca5EEdy8sLP_bjAMxsJN6OlcyS8tf-Z7lK8wvl_hSe0k71ZwUxG74fzL6CduIkr5KvnqHeDOvw'}, {'domain': '.work.weixin.qq.com', 'httpOnly': False, 'name': 'wwrtx.cs_ind', 'path': '/', 'secure': False, 'value': ''}, {'domain': '.work.weixin.qq.com', 'httpOnly': False, 'name': 'wwrtx.vid', 'path': '/', 'secure': False, 'value': '1688851169374160'}, {'domain': '.work.weixin.qq.com', 'httpOnly': False, 'name': 'wxpay.vid', 'path': '/', 'secure': False, 'value': '1688851169374160'}, {'domain': '.work.weixin.qq.com', 'httpOnly': False, 'name': 'wxpay.corpid', 'path': '/', 'secure': False, 'value': '1970325082099192'}, {'domain': '.work.weixin.qq.com', 'httpOnly': True, 'name': 'wwrtx.sid', 'path': '/', 'secure': False, 'value': 'BgQbApgB5Cv3-0pB0wUKylNi9zU150nDOwRQiIWnTnr6ZM6OY5YuUWSccsk0f0WJ'}, {'domain': '.work.weixin.qq.com', 'httpOnly': False, 'name': 'wwrtx.d2st', 'path': '/', 'secure': False, 'value': 'a3875345'}, {'domain': '.qq.com', 'expiry': 1683389247, 'httpOnly': False, 'name': '_ga', 'path': '/', 'secure': False, 'value': 'GA1.2.1823337344.1620312436'}, {'domain': '.work.weixin.qq.com', 'httpOnly': False, 'name': 'Hm_lpvt_9364e629af24cb52acc78b43e8c9f77d', 'path': '/', 'secure': False, 'value': '1620312435'}, {'domain': '.work.weixin.qq.com', 'httpOnly': True, 'name': 'wwrtx.refid', 'path': '/', 'secure': False, 'value': '22550649492593767'}, {'domain': '.qq.com', 'expiry': 1620403647, 'httpOnly': False, 'name': '_gid', 'path': '/', 'secure': False, 'value': 'GA1.2.329605108.1620312436'}, {'domain': 'work.weixin.qq.com', 'expiry': 1620343967, 'httpOnly': True, 'name': 'ww_rtkey', 'path': '/', 'secure': False, 'value': '4u2d0gs'}, {'domain': '.work.weixin.qq.com', 'expiry': 1651848431, 'httpOnly': False, 'name': 'wwrtx.c_gdpr', 'path': '/', 'secure': False, 'value': '0'}, {'domain': '.qq.com', 'expiry': 2147483864, 'httpOnly': False, 'name': 'ptcz', 'path': '/', 'secure': False, 'value': '404395857d0956cd67e5dc882ce36fa983ffc0e12868c7bb44551137c04ea0c0'}, {'domain': '.work.weixin.qq.com', 'httpOnly': True, 'name': 'wwrtx.ltype', 'path': '/', 'secure': False, 'value': '1'}, {'domain': '.qq.com', 'expiry': 2147385600, 'httpOnly': False, 'name': 'pgv_pvid', 'path': '/', 'secure': False, 'value': '1892346730'}, {'domain': '.work.weixin.qq.com', 'expiry': 1651848435, 'httpOnly': False, 'name': 'Hm_lvt_9364e629af24cb52acc78b43e8c9f77d', 'path': '/', 'secure': False, 'value': '1620312435'}, {'domain': '.work.weixin.qq.com', 'httpOnly': True, 'name': 'wwrtx.ref', 'path': '/', 'secure': False, 'value': 'direct'}, {'domain': '.qq.com', 'expiry': 1646627414, 'httpOnly': True, 'name': '_tc_unionid', 'path': '/', 'secure': False, 'value': '4221d27e-d471-4076-9915-90cf48cab78c'}, {'domain': '.qq.com', 'expiry': 2147483864, 'httpOnly': False, 'name': 'RK', 'path': '/', 'secure': False, 'value': 'KcAo+ePfWz'}, {'domain': '.qq.com', 'expiry': 1622302027, 'httpOnly': False, 'name': 'ptui_loginuin', 'path': '/', 'secure': False, 'value': '857552341'}, {'domain': '.work.weixin.qq.com', 'expiry': 1622909251, 'httpOnly': False, 'name': 'wwrtx.i18n_lan', 'path': '/', 'secure': False, 'value': 'zh'}]self.driver.get("https://work.weixin.qq.com/")      #不通过复用浏览器,需要给定url# # 创建或者打开一个数据库db = shelve.open("auth_cookie")          #如果本地没有auth_cookie数据库,会创建一个名称为auth_cookie的小型数据库,会生成相应的二进制文件。如果本地有auth_cookie数据库,那么就会直接读取# 将数据存储到 shelve 中# db["auth_cookie"] = cookies           #将cookies保存一次后,即可进行注释# 取出数据cookies = db["auth_cookie"]for cookie in cookies:if "expiry" in cookie.keys():#移除cookie中的expiry,expiry也是类似于get、post这种规范命名cookie.pop("expiry")# 把字典加入到 driver 的 cookie 中self.driver.add_cookie(cookie)self.driver.get("https://work.weixin.qq.com/wework_admin/frame")self.driver.find_element(By.XPATH, "//*[@id='menu_contacts']").click()db.close()                          #使用完数据库数据关闭数据库

Menu:Page Object演练1

首页pageobject1.立即注册点击立即注册return立即注册pageobject2.企业登录点击企业登录return企业登录PageObject企业登录pageobject1.扫码用手机扫描二维码2.立即注册点击企业注册return立即注册pageobject注册页pageobject1.填表输入文本点击下拉框点击确定
#见下面详情图

#案例一:上面的流程图演练 实现链式调用
#案例二:企业微信首页(首页包含添加成员功能)和通讯录添加成员页面
复用浏览器,跳过登录操作,使用企业微信首页(首页包含添加成员功能)和通讯录添加成员页面
实现链式调用,同时
1.引进base_page初始化driver判断driver是否存在,如果不存在就进行新建
2.driver的操作都封装在base_page,例如find_element封装在base_page中
3.对改造1里面的driver进行处理,直接判断是否进行了复用      #属于优化代码,待后续补充注意:1.跳转到的页面不用每次都初始化driver,将上一个页面的driver进行传递,跳转的页面直接__init__初始化使用即可2.跳转的页面使用上一个页面driver时,查找元素没有提示,此时我们需要在__init__方法里面给个标识即可,相当于告诉编译器这个注释表达意思是个WebDriver#Pycharm使用技巧
Pycharm进行全局搜索:Edit->Find->Find in Path...所有PO页面都继承basepage这个基类
self._driver        #私有变量,保护属性,注意单个下划线开头和俩个下划线开头的区别所有子类实现自己的构造方法,调用自己的方法时,都会主动去调用父类的__init__方法。如果子类自己写了__init__方法会覆盖掉父类的__init__方法
#add_member里面没有__init__方法,但是它继承了base_page,所以会调用base_page的__init__方法上面的案例:所有子类PO共用了一个driver,如果一个子类PO修改了driver,那么依靠上面的单例模式就无法正常进行链式调用
存在潜在隐患:子类PO修改了driver,单例模式就无法正常进行链式调用改进:所有关于driver的操作都封装在base_page上例如find_element封装在base_page中,其他页面直接调用find方法即可isReuse = False       #对driver进行改造,待后面进行处理

Menu:Page Object演练2

改造:1.所有PO页面都继承basepage这个基类,共用basepage里面的driver所有子类再实现自己的构造方法,调用自己的方法时,都会主动去调用父类的__init__方法。如果子类自己写了__init__方法会覆盖掉父类的__init__方法2.所有关于driver的操作都封装在base_page上上面的案例:所有子类PO共用了一个driver,如果一个子类PO修改了driver,那么依靠上面的单例模式就无法正常进行链式调用
存在潜在隐患:子类PO修改了driver,单例模式就无法正常进行链式调用改进:所有关于driver的操作都封装在base_page上例如find_element封装在base_page中,其他页面直接调用find方法即可3.对改造1里面的driver进行处理,直接判断是否进行了复用        #属于优化代码,待后续补充isReuse = False                                     #对driver进行改造,待后面进行处理

33min

#案例一:上面的流程图演练   实现链式调用
#index.py文件内容           #index PO
from selenium import webdriver
from web.test_wework_login.login import Login
from web.test_wework_login.register import Registerclass Index:##案例一:上面的流程图演练    实现链式调用#首页POdef __init__(self):self.driver = webdriver.Chrome()self.driver.get("https://work.weixin.qq.com/")self.driver.implicitly_wait(3)def goto_register(self):'''1.立即注册点击立即注册return立即注册pageobject:return:'''self.driver.find_element_by_css_selector('.index_head_info_pCDownloadBtn').click()return Register(self.driver)       #跳转页面时将driver传递过去,实现下一个页面复用driverdef goto_login(self):'''2.企业登录点击企业登录return企业登录PageObject:return:'''self.driver.find_element_by_css_selector('.index_top_operation_loginBtn').click()return Login(self.driver)           #跳转页面时将driver传递过去,实现下一个页面复用driver
#案例一:上面的流程图演练   实现链式调用
#login.py文件内容           #login PO
from selenium import webdriver
from selenium.webdriver.remote.webdriver import WebDriver
from web.test_wework_login.register import Registerclass Login:#跳转的页面使用上一个页面driver时,查找元素没有提示,此时我们需要在__init__方法里面给个标识即可,相当于告诉编译器这个注释表达意思是个WebDriver#注意WebDriver的书写方式,不要写成全小写def __init__(self,driver:WebDriver):#跳转到的页面不用每次都初始化driver,将上一个页面的driver进行传递,跳转的页面直接__init__初始化使用即可self.driver = driver#登录POdef scan(self):'''1.扫码用手机扫描二维码:return:'''passdef goto_register(self):'''2.立即注册点击企业注册return立即注册pageobject:return:'''self.driver.find_element_by_css_selector('.login_registerBar_link').click()return Register(self.driver)
#案例一:上面的流程图演练   实现链式调用
#register.py文件内容        #register PO
from selenium.webdriver.remote.webdriver import WebDriverclass Register:# 跳转的页面使用上一个页面driver时,查找元素没有提示,此时我们需要在__init__方法里面给个标识即可,相当于告诉编译器这个注释表达意思是个WebDriver# 注意WebDriver的书写方式,不要写成全小写def __init__(self,driver:WebDriver):#跳转到的页面不用每次都初始化driver,将上一个页面的driver进行传递,跳转的页面直接__init__初始化使用即可self.driver = driverdef register(self):'''1.填表输入文本点击下拉框点击确定:return:'''self.driver.find_element_by_id("corp_name").send_keys("goodjob")self.driver.find_element_by_id("manager_name").send_keys("Mrs zhang")self.driver.find_element_by_id("register_tel").send_keys("13000000000")self.driver.find_element_by_id("iagree").click()return True         #只是用于举例,此处省略表单部分字段填写,直接返回True,保证文件运行通过
#  实现测试
#案例一:上面的流程图演练    实现链式调用
#test_login.py文件内容          #新建一个测试py文件测试login页面
from web.test_wework_login.index import Index#新建一个测试py文件测试login页面
class TestLogin:# def __init__(self):##     self.index = Index()#注意这里使用的是setup方法,不是__init__方法def setup(self):self.index = Index()def test_login(self):result = self.index.goto_login().goto_register().register()assert result
#案例二:企业微信首页(首页包含添加成员功能)和通讯录添加成员页面
#复用浏览器,跳过登录操作,使用企业微信首页(首页包含添加成员功能)和通讯录添加成员页面
#base_page.py文件内容
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.remote.webdriver import WebDriverclass BasePage:_driver = None_base_url = ""def __init__(self, driver: WebDriver = None):if driver is None:chrome_options = Options()# 和浏览器打开的调试端口进行通信# 浏览器要使用 --remote-debugging-port=9222 开启调试chrome_options.debugger_address = "127.0.0.1:9222"self._driver = webdriver.Chrome(options=chrome_options)self._driver.implicitly_wait(3)else:self._driver = driverif self._base_url != "":self._driver.get(self._base_url)#find_element封装在base_page中def find(self,by,locator):      #一个是定位方式by,一个是元素内容locatorreturn self._driver.find_element(by,locator)
'''
#案例二:企业微信首页(首页包含添加成员功能)和通讯录添加成员页面
复用浏览器,跳过登录操作,使用企业微信首页(首页包含添加成员功能)和通讯录添加成员页面
实现链式调用,同时
1.引进base_page初始化driver判断driver是否存在,如果不存在就进行新建
2.driver的操作都封装在base_page,例如find_element封装在base_page中
3.对改造1里面的driver进行处理,直接判断是否进行了复用      #属于优化代码,待后续补充
'''
#index.py文件内容from web.test_wework.base_page import BasePage
from web.test_wework.contact import Contactclass Index(BasePage):_base_url = "https://work.weixin.qq.com/wework_admin/frame#index"def goto_contact(self):self._driver.find_element_by_css_selector('.index_service_cnt_itemWrap:nth-child(1)').click()return Contact(self._driver)            #和Contact.py文件内容有关,需要注意
#案例二:企业微信首页(首页包含添加成员功能)和通讯录添加成员页面
#复用浏览器,跳过登录操作,使用企业微信首页(首页包含添加成员功能)和通讯录添加成员页面
#contact.py文件内容
import time
from web.test_wework.base_page import BasePageclass Contact(BasePage):#为啥这里还需要进行定义 _base_url?#该页面不需要定义 _base_url 内容,之前页面报错‘ElementNotInteractableException#’是由于 首页点击添加成员直接到了添加成员表单页面,故不需要点击 添加成员 元素定位,这样会找不到元素#恰好指定的url链接里面有 添加成员 的元素定位,正好跳过了此问题# _base_url = "https://work.weixin.qq.com/wework_admin/frame#contacts"'''添加成员'''def add_member(self):#通过css定位查找到多个元素,默认点击第一个元素# time.sleep(3)#首页点击添加成员直接到了添加成员表单页面,故不需要点击元素 添加成员,这样会找不到元素,会报错‘ElementNotInteractableException’#‘ElementNotInteractableException’ 元素不可交互,元素定位错了#self._driver.find_element_by_css_selector('.ww_operationBar .js_add_member').click()        #注释掉即可self._driver.find_element_by_id('username').send_keys("Mrs zhang")self._driver.find_element_by_id('memberAdd_acctid').send_keys("1818168")self._driver.find_element_by_id("memberAdd_phone").send_keys("18516131349")# 通过css定位查找到多个元素,默认点击第一个元素self._driver.find_element_by_css_selector('.js_btn_save').click()
#案例二:企业微信首页(首页包含添加成员功能)和通讯录添加成员页面
#复用浏览器,跳过登录操作,使用企业微信首页(首页包含添加成员功能)和通讯录添加成员页面
#实现测试  test_index.py文件内容from web.test_wework.index import Indexclass TestIndex:def setup(self):self.index = Index()def test_index(self):self.index.goto_contact().add_member()
一、隐式等待、显示等待
隐式等待:对全局有效。当某些元素不出现的时候,我们判断页面该元素不出现时进行处理,那么隐式等待就不好处理了#以下报错请注意:
1、元素不可交互 ‘ElementNotInteractableException’      #元素定位错了
2、元素能被点击,被点击过后仍然报错,主逻辑没加载出来,所以仍然报错。这时候我们需要使用显式等待。
3、当某些元素不出现的时候,我们判断页面该元素不出现时进行处理,那么隐式等待就不好处理了,这时候我们需要使用显式等待。#请注意:
css定位class属性时取一段即可进行定位,而采用XPath进行定位时,需要使用整个Class属性进行定位哦
#该案例可参考企业微信,首页进入通讯录页面,点击【添加成员】时# ‘ElementNotInteractableException’ 定位【添加成员】元素时 ,元素定位错了,第一个元素定位错了#修复元素定位错误后执行,元素能被点击,被点击过后仍然报错,主逻辑没加载出来#定位【添加成员】元素时,使用css定位和XPath定位,css定位class属性时取一段即可进行定位,而采用XPath进行定位时,需要使用整个Class属性进行定位哦

8.企业微信web端自动化测试实战

base_page页面的显式等待方法  传一个元组(既包含了定位方式,又包含了定位内容)WebDriverWait里面有个方法属性是元素能被点击:需要满足    1.元素出现2.元素可被点击该元素已经出现,也可被点击,但是点击了没有生效。        # 使用WebDriverWait定位addmember页面姓名元素提示no such element 是因为加载过慢,selenium对添加成员元素进行点击,添加成员 元素已经出现,并且可以进行点击,于是selenium认为对添加成员元素进行了点击。但是真实情况是虽然点击了 添加成员 元素,但是没有弹出添加成员表单。但是selenium不知道表单没有弹出,此时还是停留在通讯录列表页面,姓名元素是不可能有的,所以会出现姓名元素是不可能有的。解决方案:改写显式等待,满足添加成员的条件。等待addmember页面姓名元素, 姓名元素是在下一个页面出现,判断姓名元素的长度,如果元素长度>=1 则表示新的页面已经出现。判断元素长度请使用find_elements
#改造
#base_page.py文件内容
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.chrome.webdriver import WebDriver
from selenium.webdriver.support import expected_conditions
from selenium.webdriver.support.wait import WebDriverWaitclass BasePage:_driver = None_base_url = ""def __init__(self, driver: WebDriver = None):if driver is None:chrome_options = Options()# 和浏览器打开的调试端口进行通信# 浏览器要使用 --remote-debugging-port=9222 开启调试chrome_options.debugger_address = "127.0.0.1:9222"self._driver = webdriver.Chrome(options=chrome_options)self._driver.implicitly_wait(3)else:self._driver = driverif self._base_url != "":self._driver.get(self._base_url)def find(self, by, locator):return self._driver.find_element(by, locator)def finds(self, by, locator):return self._driver.find_elements(by, locator)def wait_for_click(self, locator):# 显示等待, 传一个元组,既包含了定位方式,又包含了定位内容WebDriverWait(self._driver, 10).until(expected_conditions.element_to_be_clickable(locator))def wait_for_condition(self, condition):# 满足 condition 的显示等待WebDriverWait(self._driver, 10).until(condition)
#改造
#index.py文件内容
from selenium.webdriver.common.by import By
from test_selenium1.test_wework.add_member import AddMember
from test_selenium1.test_wework.base_page import BasePageclass Index(BasePage):_base_url = "https://work.weixin.qq.com/wework_admin/frame#index"def goto_add_member(self):#案例一演示内容:    #通过首页,点击 常用入口-添加成员 ,跳转通讯录添加成员表单提交页面,此处演示改造内容不用该方式直接进入添加成员表单页面# self._driver.find_element_by_css_selector('.index_service_cnt_itemWrap:nth-child(1)').click()'''1.采取 首页 点击 通讯录 进入通讯录页面2.通讯录页面点击 添加成员 进入 通讯录添加成员表单提交页面:return:'''self.find(By.CSS_SELECTOR,'#menu_contacts').click()# 情形1: 直接点击 添加成员 元素,no such element: Unable to locate element: {"method":"css selector","selector":"[id="username"]"}# self.find(By.CSS_SELECTOR,".js_has_member>div:nth-child(1)>a:nth-child(2)")'''# 使用WebDriverWait定位addmember页面姓名元素提示no such element 是因为加载过慢,selenium对添加成员元素进行点击,添加成员 元素已经出现,并且可以进行点击,于是selenium认为对添加成员元素进行了点击。但是真实情况是虽然点击了 添加成员 元素,但是没有弹出添加成员表单。但是selenium不知道表单没有弹出,此时还是停留在通讯录列表页面,姓名元素是不可能有的,所以会出现姓名元素是不可能有的.'''# 情形2: 使用WebDriverWait 在该情况下也不能使用   no such element: Unable to locate element: {"method":"css selector","selector":"[id="username"]"}# 该元素已经出现,也可被点击,但是点击了没有生效。# 请注意wait_for_click方法传递的是元组(By.CSS_SELECTOR,".js_has_member>div:nth-child(1)>a:nth-child(2)"),既包含了定位方式,又包含了定位内容# self.wait_for_click((By.CSS_SELECTOR,".js_has_member>div:nth-child(1)>a:nth-child(2)"))#情形3,也就是解决方案改写显式等待,满足添加成员的条件。def add_member_condition(x):  # base_page里面定义的 wait_for_condition 方法 有参数,所以调用需要给个参数"""改写显示等待条件等待addmember页面姓名元素, 姓名元素是在下一个页面出现,判断姓名元素的长度,如果元素长度>=1 则表示新的页面已经出现。判断元素长度请使用find_elements"""#判断元素长度请使用find_elements,不要弄成find_element啦。请注意elements_len = len(self.finds(By.ID, "username"))if elements_len <= 0:# 如果添加成员表单姓名元素没有出现,一直点击 添加成员 元素self.find(By.CSS_SELECTOR, ".js_has_member>div:nth-child(1)>a:nth-child(2)").click()# 如果 username 不存在,就会触发 until 中的列循环return elements_len > 0#请注意调用条件add_member_condition时作为属性传进去,而不是作为方法,不要带括号self.wait_for_condition(add_member_condition)return AddMember(self._driver)
#改造
#add_member.py文件内容:
import time
from selenium.webdriver.common.by import By
from test_selenium1.test_wework.base_page import BasePageclass AddMember(BasePage):def add_member(self):"""添加成员页面,实现成员添加:return:"""self.find(By.ID, "username").send_keys("MrDong23456")self.find(By.ID, "memberAdd_acctid").send_keys("MrDong23456")self.find(By.ID, "memberAdd_phone").send_keys("11111111112")self.find(By.CSS_SELECTOR, ".js_btn_save").click()'''self._driver.find_element_by_id("username").send_keys("Mrsdong")self._driver.find_element_by_id("memberAdd_acctid").send_keys("MrDong234567")self._driver.find_element_by_id("memberAdd_phone").send_keys("11111111112")self._driver.find_element_by_css_selector(".js_btn_save").click()'''
#测试文件
#test_add_member.py文件内容
from test_selenium1.test_wework.index import Indexclass TestAddMember:def setup(self):self.index = Index()def test_add_member(self):self.index.goto_add_member().add_member()

Web自动化测试(二)相关推荐

  1. Web自动化测试二:selenium打开和登录浏览器(火狐、IE、chrome)

    案例1:打开火狐浏览器,登录OutLook网页版 public class Test1 { WebDriver driver=null; String url="https://exchan ...

  2. Web自动化测试 (Selenium+Python)测试环境搭建

    目录 一.什么样的项目适合做Web自动化测试 二.Python+Selenium环境搭建 三.八大元素定位 一.什么样的项目适合做Web自动化测试 1.软件需求不会频繁的变更 2.项目周期比较长 3. ...

  3. Web自动化测试怎么做?Web自动化测试的详细流程和步骤

    一.什么是web自动化测试 自动化(Automation)是指机器设备.系统或过程(生产.管理过程)在没有人或较少人的直接参与下,按照人的要求,经过自动检测.信息处理.分析判断.操纵控制,实现预期的目 ...

  4. 【Web自动化测试】(二)使用selenium编写测试用例

    相关文章链接: [Web自动化测试](一)Selenium介绍及安装部署说明 [Web自动化测试](三)Selenium中控件定位方法 [Web自动化测试](四)Selenium中WEB控件交互的方法 ...

  5. 基于python的界面自动化测试-基于Selenium+Python的web自动化测试框架

    一.什么是Selenium? Selenium是一个基于浏览器的自动化测试工具,它提供了一种跨平台.跨浏览器的端到端的web自动化解决方案.Selenium主要包括三部分:Selenium IDE.S ...

  6. web自动化测试常见面试题

    一.找不到元素可能出现的原因: 1.元素表达式错误 2.不在指定的frame 3.等待时间短,页面加载速度慢 4.执行脚本打开了新的页面,不在指定的窗口中 二.优化web自动化测试效率 避免使用强制等 ...

  7. python selenium po_python+selenium基于po模式的web自动化测试框架

    一.什么是Selenium? Selenium是一个基于浏览器的自动化测试工具,它提供了一种跨平台.跨浏览器的端到端的web自动化解决方案.Selenium主要包括三部分:Selenium IDE.S ...

  8. java web典型模块大全_python+selenium基于po模式的web自动化测试框架

    一.什么是Selenium? Selenium是一个基于浏览器的自动化测试工具,它提供了一种跨平台.跨浏览器的端到端的web自动化解决方案.Selenium主要包括三部分:Selenium IDE.S ...

  9. Web自动化测试中使用groovy实现页面的对象化

    一. 现状 在自动化的过程中, 我们知道web自动化测试的开发和维护成本是比较高的,能否采用技术以及流程改进等手段来降低web自动化测试的成本呢? 我们先看看目前的实现方式,通常,实现步骤如下:(1) ...

  10. 使用 Python+Selenium + 第三方库实现的简单的 web 自动化测试框架 源码

    使用 Python+Selenium + 第三方库实现简单的 web 自动化测试框架,为 web 自动化测试编写更加便利和可维护. 一.配置(config) 1.1 说明 设置自动化案例运行时的属性值 ...

最新文章

  1. 用python客户画像代码_客户画像与标签体系-Python数据科学技术详解与商业项目实战精讲 - Python学习网...
  2. Linux磁盘挂载和docker安装
  3. 如何用java创建超链接_Java如何在PPT中的幻灯片上创建超链接?
  4. 学习 WCF (4)--学会使用配置文件
  5. Android中获取手机电量信息
  6. 访问修饰符(C# 编程指南)
  7. java连接imserver_java后端IM消息推送服务开发——协议
  8. 游戏软件性能测试怎么做?常规测试知识要点总结
  9. java file文件删除_Java File.delete 删除文件
  10. 怎么用计算机直接截图,电脑怎样截图又快又方便 1分钟教你如何快速截图
  11. 关于locale的设定
  12. 分布式数据一致性的探讨
  13. 初中学历程序员面试被HR吐槽,初中学历还有要月薪3万5,到底是学历重要还是能力重要?...
  14. html上传动态图片不显示图片,解决 viewer.js 动态更新图片导致无法预览的问题
  15. 康奈尔大学计算机系教授,独家解析康奈尔大学EE专业的五大方向
  16. 北京市基本医疗保险A类定点医疗机构名单(2010-09-29)
  17. 商品搜索引擎--商品推荐
  18. 【C语言】C语言外部变量和内部变量
  19. 【其他】用ps切片处理素材
  20. Qt QDialog更换图标icon

热门文章

  1. vue3使用Pinia进行全局状态管理,Pinia安装和使用,Pinia 和 Vuex的对比
  2. 商务英语与计算机思维,商务英语技巧的优势
  3. 数据结构与算法A实验六图论---7-2 哈利·波特的考试(Flody算法)
  4. CAD画家具学习笔记
  5. 老男孩31期郜鹏飞决心书
  6. VirtualBox 安装 Ubuntu16.04服务器版系统
  7. 应用内版本更新库UpdateVersion
  8. SqlServer复习
  9. Linux 之父自传《just for fun》读书笔记
  10. Spark源码阅读(五) --- Spark的支持的join方式以及join策略