鼠标键盘操作之Selenium
在测试的时候,我们不可避免地需要用到鼠标键盘操作,那么在自动化测试中如何编写对应的代码呢?这就不得不提到Selenium中的ActionChains模块。ActionChains,顾名思义就是动作链的意思。通常我们可以用这样的格式去进行鼠标的单击左键操作:ActionChains(driver).click(element).perform()
要注意的是,一定要在操作后面加上perform()方法——执行动作链,否则操作不会执行。那么ActionChains都有哪些主要的属性和方法呢?首先毫无疑问的是我们需要引入ActionChains和Keys模块,Keys中包含一些特殊的键盘按键,可以让我们引用,比如:Ctrl、F1~F12,A~Z等等。引入这两个模块的代码如下:
from selenium.webdriver.common.keys import Keys
from selenium.webdriver import ActionChains
(一)click点击
主要包括 click 单击鼠标左键、double_click 双击鼠标左键、context_click 单击鼠标右键 这三个方法,这里我分别用三个例子来一一对他们进行代码验证:
1.单击鼠标左键百度首页的“新闻”,打开新闻标签页。
2.双击鼠标左键百度首页的 “地图”,打开地图标签页。
3.单击鼠标右键百度首页的“视频”,并且按照弹出的菜单框,键盘点击“T”,打开视频标签页。
1、click(on_element=None) 单击鼠标左键
(1)具体代码操作
单击鼠标左键 百度首页的“新闻”,打开新闻标签页,通过for循环切换到新闻页,验证标题中是否包含特定内容“新闻”,打印结果。
from selenium import webdriver
from time import sleep
from selenium.webdriver.common.keys import Keys
from selenium.webdriver import ActionChains
class TestCase(object):
def __init__(self):
self.driver = webdriver.Chrome()
self.url = 'http://www.baidu.com'
self.driver.maximize_window()
self.driver.get(self.url)
self.mainWindow = self.driver.current_window_handle
def test_click(self):
news = self.driver.find_element_by_css_selector('#s-top-left > a') #“新闻”元素
ActionChains(self.driver).click(news).perform() #在元素上单击鼠标左键,打开新闻网页
sleep(2)
self.test_open_page('新闻')
self.driver.switch_to.window(self.mainWindow) #切回百度首页
#用来判断是否打开特定标签页
def test_open_page(self, title_in):
for handle in self.driver.window_handles:
self.driver.switch_to.window(handle)
if title_in in self.driver.title:
print('It is true, open page', self.driver.title)
break
if __name__ == '__main__':
test = TestCase() #实例化TestCase类
test.test_click() #调用测试方法
(2)注意事项及附加知识点
要注意的是,在上面的代码中,用到了一个test_open_page()方法,大家肯定觉得奇怪,点击“新闻”元素后,新闻标签页不是已经打开了也显示在最前面了,为什么还要使用switch_to.window()去切换窗口呢?
这是因为哪怕我们在点击某个元素后,重新生成了一个新的标签页,但此时我们的操作仍然在原先的窗口当中。也就是说,这时候我们的self.driver.title还会是百度首页的,不相信的大家可以试试。所以当我们要在新的窗口继续操作元素或者验证标题网址什么的,就要用到handle窗口切换的方法进行了窗口的切换。
2、click_and_hold(self, on_element=None) 点击某个元素不松开 、release(on_element=None) 在某个元素位置上方松开。
(1)具体代码操作
点击百度首页的学术元素不松开,判断是否打开了学术标签页,松开后,再次判断是否打开标签页。
def test_click_hold_release(self):
subject = self.driver.find_element_by_css_selector('#s-top-left > a:nth-last-child(2)')#“学术”元素
ActionChains(self.driver).click_and_hold(subject).perform()
sleep(2)
handles = self.driver.window_handles
print('未松开之前', handles)
ActionChains(self.driver).release(subject).perform()
sleep(2)
handles = self.driver.window_handles
print('松开之后', handles)
self.test_open_page('学术')
print('url = ', self.driver.current_url)
self.driver.switch_to.window(self.mainWindow)# 切回百度首页
(2)控制台结果
松开之前的标签页只有一个,而松开后有两个,另外一个的url就是学术标签页的,如下图所示:
http://www.51testing.com/attachments/2023/05/15326880_202305041455031UIMU.png
3、double_click(on_element=None) 双击鼠标左键
(1)具体代码操作
双击鼠标左键 百度首页的“地图”,打开地图标签页,通过for循环切换到地图页,验证标题中是否包含特定内容“地图”,打印结果。(有些代码是重复的,所以这里只贴了主要代码,后面同上)
def test_double_click(self):
map = self.driver.find_element_by_css_selector('#s-top-left > a:nth-child(3)') #“地图”元素
ActionChains(self.driver).double_click(map).perform() #双击地图,跳转到地图页
sleep(2)
self.test_open_page('地图')
self.driver.switch_to.window(self.mainWindow) #切回百度首页
2)控制台结果
已打开地图标签页,如下图所示:
http://www.51testing.com/attachments/2023/05/15326880_202305041455061Dssp.png
4、context_click(on_element=None) 单击鼠标右键
(1)具体代码操作
单击鼠标右键 百度首页的“视频”,打开菜单选择框。根据菜单选择框中的提示,发送“t”键给“视频”元素,通过for循环切换到视频页,验证标题中是否包含特定内容“视频”,打印结果。
def test_context_click(self):
mainWindow = self.driver.current_window_handle
video = self.driver.find_element_by_css_selector('#s-top-left > a:nth-child(4)')# “视频”元素
ActionChains(self.driver).context_click(video).perform()# 右击视频
self.driver.execute_script("arguments.focus();", video)# 注意,一定要加这一步:否则焦点会在输入框那里,后面的send_keys('t')会失效,变成在输入框中输入“t”
sleep(2)
ActionChains(self.driver).send_keys_to_element(video, 't').perform()# 根据提示发送“t”给视频元素,打开“视频”标签页
sleep(2)
self.test_open_page('视频')
self.driver.switch_to.window(mainWindow)
(2)控制台结果
已打开视频标签页,如下图所示:
http://www.51testing.com/attachments/2023/05/15326880_202305041455091KmPI.png
(3)注意事项及附加知识点
在上面的代码中,使用到了selenium中运行js代码的方法:execute_script(),那一整行的代码表示我切换焦点给“视频”元素。为什么要有这一步操作呢?
因为在百度首页,有一个搜索的输入框,所以焦点一直在输入框上面,如果我没有切换焦点给“视频”元素,那么无论是使用键盘操作的send_keys()还是send_keys_to_element()方法,“t”这个值都会变成输入到搜索框中,跟我想要的测试执行情况不一致,这可能也是一个bug吧,具体的大家也可以尝试一下。
(二)drag拖拽
包括两个方法:drag_and_drop 拖拽到某个元素再松开、 drag_and_drop_by_offset 拖拽到某个坐标再松开。
1、drag_and_drop(source, target) 拖拽到某个元素再松开
(1)具体代码操作
拖拽 某网站上的小块元素到大块元素上方,通过获取弹出对话框来判断是否执行了此次拖拽操作,打印结果。
def test_drag_and_drop(self):
kw = self.driver.find_element_by_id('kw')
qrcode = self.driver.find_element_by_id('s_side_wrapper')
img_url = self.driver.find_element_by_css_selector('#s_side_wrapper .icon-hover').get_attribute('src')#获取二维码图片地址
print(img_url)
ActionChains(self.driver).drag_and_drop(qrcode, kw).perform()
self.driver.switch_to.window(self.mainWindow)
(2)控制台结果
结果显示了对话框的文字内容——dropped,说明拖拽成功,如下图所示:
http://www.51testing.com/attachments/2023/05/15326880_202305041455121yI0a.pnghttp://www.51testing.com/attachments/2023/05/15326880_202305041455151sfeJ.png
2、 drag_and_drop_by_offset(source, xoffset, yoffset) 拖拽到某个坐标再松开
(1)具体代码操作
拖拽 百度首页右下角的二维码图片元素到搜索框的坐标中,通过判断搜索框中是否显示了该图片的网址来判断是否执行了此次拖拽操作,打印结果。
def test_drag_and_drop2_by_offset(self):
self.driver.get('https://www.runoob.com/try/try.php?filename=jqueryui-api-droppable')
# 切换到目标元素所在的frame
self.driver.switch_to.frame("iframeResult")
source = self.driver.find_element_by_id("draggable") # 确定拖拽目标的起点
target = self.driver.find_element_by_id("droppable") # 确定拖拽目标的终点
xoffset = target.location.get('x') # 获取拖拽目标终点的x坐标
yoffset = target.location.get('y') # 确定拖拽目标终点的y坐标
ActionChains(self.driver).drag_and_drop_by_offset(source, xoffset, yoffset).perform()
sleep(5)
alert = self.driver.switch_to.alert()
print(alert.text)
alert.accept()
self.driver.switch_to.window(self.mainWindow)# 切回百度首页
(2)控制台结果
结果和上面drag_and_drop方法是一样的,这里就不贴图了。
(3)注意事项及附加知识点
从上面的代码可以看到我们使用了location()方法拿到元素的坐标,元素的坐标返回的是一个json字符串{'x':123,'y':456} 。通过get('x')和get('y')分别拿到x坐标和y坐标(这个坐标是相对于浏览器左上角的偏移量)。
(三)Key 发送键
1、send_keys(*keys_to_send) 发送某个键到当前焦点元素
(1)具体代码操作
在百度首页搜索框中输入“selenium”,复制之后,清空搜索框,再把北荣复制进去右下角的二维码图片元素到搜索框的坐标中,通过判断搜索框中是否显示了该图片的网址来判断是否执行了此次拖拽操作,打印结果。
def test_send_keys(self):
# ctrl + c 复制、clear 清空、ctrl + v 粘贴
kw = self.driver.find_element_by_id('kw')
kw.send_keys('selenium')
sleep(2)
kw.send_keys(Keys.CONTROL, 'a') #ctrl + a 复制
sleep(2)
kw.send_keys(Keys.CONTROL, 'c') #ctrl + c 复制
sleep(2)
kw.clear()
sleep(2)
print('清空后:', kw.get_attribute('value'))
kw.send_keys(Keys.CONTROL, 'v')#ctrl + v 复制
sleep(2)
print('粘贴后:', kw.get_attribute('value'))
self.driver.switch_to.window(self.mainWindow)# 切回百度首页
(2)控制台结果
结果显示清空后,搜索框内容为空,粘贴后,搜索框内容为selenium,说明复制粘贴成功,如下图所示:
http://www.51testing.com/attachments/2023/05/15326880_2023050414552010fQB.png
2、send_keys_to_element(element, *keys_to_send) 发送某个键到某个元素
和send_keys不同的是,前者是直接表示发给焦点元素,参数值可以进行组合键的使用,而后者则是有一个参数去决定发送给特定的哪个元素,另外这个send_keys_to_element在使用到非焦点元素上时,会有bug,前面有提到,这里我就不细说了。
3、key_down(value, element=None) 按下某个键、key_up (value, element=None) 松开某个键
(1)具体代码操作
当我们使用组合键,例如:Ctrl+、Shift+的时候,通常是先按下ctrl或shift键,再按下其他键,然后再松开,而字母键通常我们是使用send_keys方法去发送键值给到元素。
这里我还是以百度搜索为例,复制搜索框中的内容后,再清空搜索框,最后又把该内容粘贴到搜索框,即“复制+清空+粘贴”操作,具体操作代码如下:
def test_key_down_up(self):
# ctrl + c 复制、clear 清空、ctrl + v 粘贴
kw = self.driver.find_element_by_id('kw')
kw.clear()
sleep(2)
kw.send_keys('python')
action = ActionChains(self.driver)
action.key_down(Keys.CONTROL).send_keys('a').key_up(Keys.CONTROL).perform()# ctrl+a
sleep(2)
action.key_down(Keys.CONTROL).send_keys('c').key_up(Keys.CONTROL).perform()# ctrl+c
sleep(2)
kw.clear()
print('清空后:', kw.get_attribute('value'))
sleep(2)
kw.click()
action.key_down(Keys.CONTROL).send_keys('v').key_up(Keys.CONTROL).perform()# 松开ctrl键
sleep(3)
print('粘贴后:', kw.get_attribute('value'))
self.driver.switch_to.window(self.mainWindow)# 切回百度首页
(2)控制台结果
结果显示清空后,搜索框内容为空,粘贴后,搜索框内容为python,说明复制粘贴成功,如下图所示:
http://www.51testing.com/attachments/2023/05/15326880_202305041455231S6Xq.png
(四)move 移动
1、move_to_element 移动到某个元素上方
(1)具体代码操作
移动到百度首页右下角的二维码元素上方,等待三秒看是否会弹出悬浮框,打印结果。
def test_move_to_element(self):
qrcode = self.driver.find_element_by_css_selector('div#s_side_wrapper')
ActionChains(self.driver).move_to_element(qrcode).perform()
sleep(3)
qrcode_hide_window = self.driver.find_element_by_css_selector('#s_qrcode_nologin> .tooltip')
print(qrcode_hide_window)
(2)控制台结果
悬浮窗正常显示,打印了该元素对象的信息,如下图所示:
http://www.51testing.com/attachments/2023/05/15326880_202305041455261P7t9.png
2、move_by_offset(xoffset, yoffset) 移动到某个坐标
具体代码操作 :
移动到百度首页右下角的二维码元素所在的坐标位置,等待三秒看是否会弹出悬浮框,打印结果。
http://www.51testing.com/attachments/2023/05/15326880_202305041455301IdKL.png
3、move_to_element_with_offset(to_element, xoffset, yoffset) 移动到距离某个元素(左上角坐标)多少距离的位置。
(1)具体代码操作:
通过计算百度首页搜索框与“更多”元素之间的距离,移动鼠标到“更多”元素的坐标位置,判断是否显示了更多的悬浮框,打印结果。
def test_move_to_element_with_offset(self):
kw = self.driver.find_element_by_id('kw')
kw_x = kw.location.get('x')
kw_y = kw.location.get('y')
more = self.driver.find_element_by_css_selector('#s-top-left > .s-top-more-btn > a') #“更多”元素
more_x = more.location.get('x') #“更多”元素的x坐标
more_y = more.location.get('y') #“更多”元素的宽
more_w = more.size.get('width')#“更多”元素的宽
more_h = more.size.get('height') #“更多”元素的高
xoffset = kw_x - more_x - more_w / 2
yoffset = kw_y - more_y - more_h / 2
ActionChains(self.driver).move_to_element_with_offset(more, xoffset, yoffset).perform()
sleep(3)
more_hide_window = self.driver.find_element_by_id('s-top-more')
print(more_hide_window)
(2)控制台结果
悬浮窗正常显示,打印了该元素对象的信息,如下图所示:
http://www.51testing.com/attachments/2023/05/15326880_202305041455331Uiwv.png
页:
[1]