Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
SeleniumHQ
GitHub Repository: SeleniumHQ/Selenium
Path: blob/trunk/py/test/selenium/webdriver/common/interactions_tests.py
4005 views
1
# Licensed to the Software Freedom Conservancy (SFC) under one
2
# or more contributor license agreements. See the NOTICE file
3
# distributed with this work for additional information
4
# regarding copyright ownership. The SFC licenses this file
5
# to you under the Apache License, Version 2.0 (the
6
# "License"); you may not use this file except in compliance
7
# with the License. You may obtain a copy of the License at
8
#
9
# http://www.apache.org/licenses/LICENSE-2.0
10
#
11
# Unless required by applicable law or agreed to in writing,
12
# software distributed under the License is distributed on an
13
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14
# KIND, either express or implied. See the License for the
15
# specific language governing permissions and limitations
16
# under the License.
17
18
"""Tests for advanced user interactions."""
19
20
import pytest
21
22
from selenium.common.exceptions import MoveTargetOutOfBoundsException
23
from selenium.webdriver.common.action_chains import ActionChains
24
from selenium.webdriver.common.actions import interaction
25
from selenium.webdriver.common.actions.wheel_input import ScrollOrigin
26
from selenium.webdriver.common.by import By
27
from selenium.webdriver.common.keys import Keys
28
from selenium.webdriver.support.ui import WebDriverWait
29
30
31
def perform_drag_and_drop_with_mouse(driver, pages):
32
"""Copied from org.openqa.selenium.interactions.TestBasicMouseInterface."""
33
pages.load("draggableLists.html")
34
dragReporter = driver.find_element(By.ID, "dragging_reports")
35
toDrag = driver.find_element(By.ID, "rightitem-3")
36
dragInto = driver.find_element(By.ID, "sortable1")
37
38
holdItem = ActionChains(driver).click_and_hold(toDrag)
39
moveToSpecificItem = ActionChains(driver).move_to_element(driver.find_element(By.ID, "leftitem-4"))
40
moveToOtherList = ActionChains(driver).move_to_element(dragInto)
41
drop = ActionChains(driver).release(dragInto)
42
assert "Nothing happened." == dragReporter.text
43
44
holdItem.perform()
45
moveToSpecificItem.perform()
46
moveToOtherList.perform()
47
assert "Nothing happened. DragOut" == dragReporter.text
48
49
drop.perform()
50
51
52
@pytest.mark.xfail_safari
53
def test_dragging_element_with_mouse_moves_it_to_another_list(driver, pages):
54
"""Copied from org.openqa.selenium.interactions.TestBasicMouseInterface."""
55
perform_drag_and_drop_with_mouse(driver, pages)
56
dragInto = driver.find_element(By.ID, "sortable1")
57
assert 6 == len(dragInto.find_elements(By.TAG_NAME, "li"))
58
59
60
@pytest.mark.xfail_safari
61
def test_dragging_element_with_mouse_fires_events(driver, pages):
62
"""Copied from org.openqa.selenium.interactions.TestBasicMouseInterface."""
63
perform_drag_and_drop_with_mouse(driver, pages)
64
dragReporter = driver.find_element(By.ID, "dragging_reports")
65
assert "Nothing happened. DragOut DropIn RightItem 3" == dragReporter.text
66
67
68
def _is_element_available(driver, id):
69
"""Copied from org.openqa.selenium.interactions.TestBasicMouseInterface."""
70
try:
71
driver.find_element(By.ID, id)
72
return True
73
except Exception:
74
return False
75
76
77
@pytest.mark.xfail_safari
78
def test_drag_and_drop(driver, pages):
79
"""Copied from org.openqa.selenium.interactions.TestBasicMouseInterface."""
80
element_available_timeout = 15
81
wait = WebDriverWait(driver, element_available_timeout)
82
pages.load("droppableItems.html")
83
wait.until(lambda dr: _is_element_available(driver, "draggable"))
84
85
if not _is_element_available(driver, "draggable"):
86
raise AssertionError("Could not find draggable element after 15 seconds.")
87
88
toDrag = driver.find_element(By.ID, "draggable")
89
dropInto = driver.find_element(By.ID, "droppable")
90
91
holdDrag = ActionChains(driver).click_and_hold(toDrag)
92
move = ActionChains(driver).move_to_element(dropInto)
93
drop = ActionChains(driver).release(dropInto)
94
95
holdDrag.perform()
96
move.perform()
97
drop.perform()
98
99
dropInto = driver.find_element(By.ID, "droppable")
100
text = dropInto.find_element(By.TAG_NAME, "p").text
101
assert "Dropped!" == text
102
103
104
@pytest.mark.xfail_safari
105
def test_double_click(driver, pages):
106
"""Copied from org.openqa.selenium.interactions.TestBasicMouseInterface."""
107
pages.load("javascriptPage.html")
108
toDoubleClick = driver.find_element(By.ID, "doubleClickField")
109
110
dblClick = ActionChains(driver).double_click(toDoubleClick)
111
112
dblClick.perform()
113
assert "DoubleClicked" == toDoubleClick.get_attribute("value")
114
115
116
def test_context_click(driver, pages):
117
"""Copied from org.openqa.selenium.interactions.TestBasicMouseInterface."""
118
pages.load("javascriptPage.html")
119
toContextClick = driver.find_element(By.ID, "doubleClickField")
120
121
contextClick = ActionChains(driver).context_click(toContextClick)
122
123
contextClick.perform()
124
assert "ContextClicked" == toContextClick.get_attribute("value")
125
126
127
def test_move_and_click(driver, pages):
128
"""Copied from org.openqa.selenium.interactions.TestBasicMouseInterface."""
129
pages.load("javascriptPage.html")
130
toClick = driver.find_element(By.ID, "clickField")
131
132
click = ActionChains(driver).move_to_element(toClick).click()
133
134
click.perform()
135
assert "Clicked" == toClick.get_attribute("value")
136
137
138
def test_cannot_move_to_anull_locator(driver, pages):
139
"""Copied from org.openqa.selenium.interactions.TestBasicMouseInterface."""
140
pages.load("javascriptPage.html")
141
142
with pytest.raises(AttributeError):
143
move = ActionChains(driver).move_to_element(None)
144
move.perform()
145
146
147
@pytest.mark.xfail_safari
148
def test_clicking_on_form_elements(driver, pages):
149
"""Copied from org.openqa.selenium.interactions.CombinedInputActionsTest."""
150
pages.load("formSelectionPage.html")
151
options = driver.find_elements(By.TAG_NAME, "option")
152
selectThreeOptions = (
153
ActionChains(driver).click(options[1]).key_down(Keys.SHIFT).click(options[3]).key_up(Keys.SHIFT)
154
)
155
selectThreeOptions.perform()
156
157
showButton = driver.find_element(By.NAME, "showselected")
158
showButton.click()
159
160
resultElement = driver.find_element(By.ID, "result")
161
assert "roquefort parmigiano cheddar" == resultElement.text
162
163
164
@pytest.mark.xfail_firefox
165
@pytest.mark.xfail_safari
166
def test_selecting_multiple_items(driver, pages):
167
"""Copied from org.openqa.selenium.interactions.CombinedInputActionsTest."""
168
pages.load("selectableItems.html")
169
reportingElement = driver.find_element(By.ID, "infodiv")
170
assert "no info" == reportingElement.text
171
172
listItems = driver.find_elements(By.TAG_NAME, "li")
173
selectThreeItems = (
174
ActionChains(driver)
175
.key_down(Keys.CONTROL)
176
.click(listItems[1])
177
.click(listItems[3])
178
.click(listItems[5])
179
.key_up(Keys.CONTROL)
180
)
181
selectThreeItems.perform()
182
183
assert "#item2 #item4 #item6" == reportingElement.text
184
185
# Now click on another element, make sure that's the only one selected.
186
actionsBuilder = ActionChains(driver)
187
actionsBuilder.click(listItems[6]).perform()
188
assert "#item7" == reportingElement.text
189
190
191
@pytest.mark.xfail_safari
192
def test_sending_keys_to_active_element_with_modifier(driver, pages):
193
pages.load("formPage.html")
194
e = driver.find_element(By.ID, "working")
195
e.click()
196
197
ActionChains(driver).key_down(Keys.SHIFT).send_keys("abc").key_up(Keys.SHIFT).perform()
198
199
assert "ABC" == e.get_attribute("value")
200
201
202
def test_sending_keys_to_element(driver, pages):
203
pages.load("formPage.html")
204
e = driver.find_element(By.ID, "working")
205
206
ActionChains(driver).send_keys_to_element(e, "abc").perform()
207
208
assert "abc" == e.get_attribute("value")
209
210
211
def test_can_send_keys_between_clicks(driver, pages):
212
"""Ensure W3C sends correct pause count to other input devices."""
213
pages.load("javascriptPage.html")
214
keyup = driver.find_element(By.ID, "keyUp")
215
keydown = driver.find_element(By.ID, "keyDown")
216
ActionChains(driver).click(keyup).send_keys("foobar").click(keydown).perform()
217
218
assert "foobar" == keyup.get_attribute("value")
219
220
221
def test_can_reset_interactions(driver):
222
actions = ActionChains(driver)
223
actions.click()
224
actions.key_down("A")
225
assert all(len(device.actions) > 0 for device in actions.w3c_actions.devices if device.type != interaction.WHEEL)
226
227
actions.reset_actions()
228
229
assert all(len(device.actions) == 0 for device in actions.w3c_actions.devices)
230
231
232
def test_can_pause(driver, pages):
233
from time import time
234
235
pages.load("javascriptPage.html")
236
237
pause_time = 2
238
toClick = driver.find_element(By.ID, "clickField")
239
toDoubleClick = driver.find_element(By.ID, "doubleClickField")
240
241
pause = ActionChains(driver).click(toClick).pause(pause_time).click(toDoubleClick)
242
243
start = time()
244
pause.perform()
245
end = time()
246
247
assert pause_time < end - start
248
assert "Clicked" == toClick.get_attribute("value")
249
assert "Clicked" == toDoubleClick.get_attribute("value")
250
251
252
@pytest.mark.xfail_firefox
253
@pytest.mark.xfail_remote
254
@pytest.mark.xfail_safari
255
def test_can_scroll_to_element(driver, pages):
256
pages.load("scrolling_tests/frame_with_nested_scrolling_frame_out_of_view.html")
257
iframe = driver.find_element(By.TAG_NAME, "iframe")
258
259
assert not _in_viewport(driver, iframe)
260
261
ActionChains(driver).scroll_to_element(iframe).perform()
262
263
assert _in_viewport(driver, iframe)
264
265
266
@pytest.mark.xfail_firefox
267
@pytest.mark.xfail_remote
268
@pytest.mark.xfail_safari
269
def test_can_scroll_from_element_by_amount(driver, pages):
270
pages.load("scrolling_tests/frame_with_nested_scrolling_frame_out_of_view.html")
271
iframe = driver.find_element(By.TAG_NAME, "iframe")
272
scroll_origin = ScrollOrigin.from_element(iframe)
273
274
ActionChains(driver).scroll_from_origin(scroll_origin, 0, 200).pause(0.2).perform()
275
276
driver.switch_to.frame(iframe)
277
checkbox = driver.find_element(By.NAME, "scroll_checkbox")
278
assert _in_viewport(driver, checkbox)
279
280
281
@pytest.mark.xfail_firefox
282
@pytest.mark.xfail_remote
283
@pytest.mark.xfail_safari
284
def test_can_scroll_from_element_with_offset_by_amount(driver, pages):
285
pages.load("scrolling_tests/frame_with_nested_scrolling_frame_out_of_view.html")
286
footer = driver.find_element(By.TAG_NAME, "footer")
287
scroll_origin = ScrollOrigin.from_element(footer, 0, -50)
288
289
ActionChains(driver).scroll_from_origin(scroll_origin, 0, 200).pause(0.2).perform()
290
291
iframe = driver.find_element(By.TAG_NAME, "iframe")
292
driver.switch_to.frame(iframe)
293
checkbox = driver.find_element(By.NAME, "scroll_checkbox")
294
assert _in_viewport(driver, checkbox)
295
296
297
def test_errors_when_element_offset_not_in_viewport(driver, pages):
298
pages.load("scrolling_tests/frame_with_nested_scrolling_frame_out_of_view.html")
299
footer = driver.find_element(By.TAG_NAME, "footer")
300
scroll_origin = ScrollOrigin.from_element(footer, 0, 50)
301
302
with pytest.raises(MoveTargetOutOfBoundsException):
303
ActionChains(driver).scroll_from_origin(scroll_origin, 0, 200).pause(0.2).perform()
304
305
306
@pytest.mark.xfail_firefox
307
@pytest.mark.xfail_remote
308
def test_can_scroll_from_viewport_by_amount(driver, pages):
309
pages.load("scrolling_tests/frame_with_nested_scrolling_frame_out_of_view.html")
310
footer = driver.find_element(By.TAG_NAME, "footer")
311
delta_y = footer.rect["y"]
312
313
ActionChains(driver).scroll_by_amount(0, delta_y).pause(0.2).perform()
314
315
assert _in_viewport(driver, footer)
316
317
318
@pytest.mark.xfail_safari
319
def test_can_scroll_from_viewport_with_offset_by_amount(driver, pages):
320
pages.load("scrolling_tests/frame_with_nested_scrolling_frame.html")
321
scroll_origin = ScrollOrigin.from_viewport(10, 10)
322
323
ActionChains(driver).scroll_from_origin(scroll_origin, 0, 200).pause(0.2).perform()
324
325
iframe = driver.find_element(By.TAG_NAME, "iframe")
326
driver.switch_to.frame(iframe)
327
checkbox = driver.find_element(By.NAME, "scroll_checkbox")
328
assert _in_viewport(driver, checkbox)
329
330
331
def test_errors_when_origin_offset_not_in_viewport(driver, pages):
332
pages.load("scrolling_tests/frame_with_nested_scrolling_frame.html")
333
scroll_origin = ScrollOrigin.from_viewport(-10, -10)
334
335
with pytest.raises(MoveTargetOutOfBoundsException):
336
ActionChains(driver).scroll_from_origin(scroll_origin, 0, 200).pause(0.2).perform()
337
338
339
def _get_events(driver):
340
"""Return list of key events recorded in the test_keys_page fixture."""
341
events = driver.execute_script("return allEvents.events;") or []
342
# `key` values in `allEvents` may be escaped (see `escapeSurrogateHalf` in
343
# test_keys_wdspec.html), so this converts them back into unicode literals.
344
for e in events:
345
# example: turn "U+d83d" (6 chars) into u"\ud83d" (1 char)
346
if "key" in e and e["key"].startswith("U+"):
347
key = e["key"]
348
hex_suffix = key[key.index("+") + 1 :]
349
e["key"] = chr(int(hex_suffix, 16))
350
351
# WebKit sets code as 'Unidentified' for unidentified key codes, but
352
# tests expect ''.
353
if "code" in e and e["code"] == "Unidentified":
354
e["code"] = ""
355
return events
356
357
358
def _in_viewport(driver, element):
359
script = (
360
"for(var e=arguments[0],f=e.offsetTop,t=e.offsetLeft,o=e.offsetWidth,n=e.offsetHeight;\n"
361
"e.offsetParent;)f+=(e=e.offsetParent).offsetTop,t+=e.offsetLeft;\n"
362
"return f<window.pageYOffset+window.innerHeight&&t<window.pageXOffset+window.innerWidth&&f+n>\n"
363
"window.pageYOffset&&t+o>window.pageXOffset"
364
)
365
return driver.execute_script(script, element)
366
367