Skip to content

Commit 6ff3693

Browse files
committed
[py] update implementation for submitting forms
1 parent 7c77d06 commit 6ff3693

2 files changed

Lines changed: 78 additions & 45 deletions

File tree

py/selenium/webdriver/remote/webelement.py

Lines changed: 60 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -26,13 +26,12 @@
2626
from io import BytesIO
2727
from typing import Union
2828

29-
from selenium.common.exceptions import WebDriverException
29+
from selenium.common.exceptions import WebDriverException, JavascriptException
3030
from selenium.webdriver.common.by import By
3131
from selenium.webdriver.common.utils import keys_to_typing
3232
from .command import Command
3333
from .shadowroot import ShadowRoot
3434

35-
3635
# TODO: When moving to supporting python 3.9 as the minimum version we can
3736
# use built in importlib_resources.files.
3837
getAttribute_js = None
@@ -91,11 +90,20 @@ def click(self) -> None:
9190

9291
def submit(self):
9392
"""Submits a form."""
94-
form = self.find_element(By.XPATH, "./ancestor-or-self::form")
95-
self._parent.execute_script(
96-
"var e = arguments[0].ownerDocument.createEvent('Event');"
97-
"e.initEvent('submit', true, true);"
98-
"if (arguments[0].dispatchEvent(e)) { arguments[0].submit() }", form)
93+
script = "var form = arguments[0];\n" \
94+
"while (form.nodeName != \"FORM\" && form.parentNode) {\n" \
95+
" form = form.parentNode;\n" \
96+
"}\n" \
97+
"if (!form) { throw Error('Unable to find containing form element'); }\n" \
98+
"if (!form.ownerDocument) { throw Error('Unable to find owning document'); }\n" \
99+
"var e = form.ownerDocument.createEvent('Event');\n" \
100+
"e.initEvent('submit', true, true);\n" \
101+
"if (form.dispatchEvent(e)) { HTMLFormElement.prototype.submit.call(form) }\n"
102+
103+
try:
104+
self._parent.execute_script(script, self)
105+
except JavascriptException:
106+
raise WebDriverException("To submit an element, it must be nested inside a form element")
99107

100108
def clear(self) -> None:
101109
"""Clears the text if it's a text entry element."""
@@ -280,9 +288,10 @@ def find_element_by_link_text(self, link_text):
280288
281289
element = element.find_element_by_link_text('Sign In')
282290
"""
283-
warnings.warn("find_element_by_link_text is deprecated. Please use find_element(by=By.LINK_TEXT, value=link_text) instead",
284-
DeprecationWarning,
285-
stacklevel=2)
291+
warnings.warn(
292+
"find_element_by_link_text is deprecated. Please use find_element(by=By.LINK_TEXT, value=link_text) instead",
293+
DeprecationWarning,
294+
stacklevel=2)
286295
return self.find_element(by=By.LINK_TEXT, value=link_text)
287296

288297
def find_elements_by_link_text(self, link_text):
@@ -300,9 +309,10 @@ def find_elements_by_link_text(self, link_text):
300309
301310
elements = element.find_elements_by_link_text('Sign In')
302311
"""
303-
warnings.warn("find_elements_by_link_text is deprecated. Please use find_elements(by=By.LINK_TEXT, value=text) instead",
304-
DeprecationWarning,
305-
stacklevel=2)
312+
warnings.warn(
313+
"find_elements_by_link_text is deprecated. Please use find_elements(by=By.LINK_TEXT, value=text) instead",
314+
DeprecationWarning,
315+
stacklevel=2)
306316
return self.find_elements(by=By.LINK_TEXT, value=link_text)
307317

308318
def find_element_by_partial_link_text(self, link_text):
@@ -322,9 +332,10 @@ def find_element_by_partial_link_text(self, link_text):
322332
323333
element = element.find_element_by_partial_link_text('Sign')
324334
"""
325-
warnings.warn("find_element_by_partial_link_text is deprecated. Please use find_element(by=By.PARTIAL_LINK_TEXT, value=link_text) instead",
326-
DeprecationWarning,
327-
stacklevel=2)
335+
warnings.warn(
336+
"find_element_by_partial_link_text is deprecated. Please use find_element(by=By.PARTIAL_LINK_TEXT, value=link_text) instead",
337+
DeprecationWarning,
338+
stacklevel=2)
328339
return self.find_element(by=By.PARTIAL_LINK_TEXT, value=link_text)
329340

330341
def find_elements_by_partial_link_text(self, link_text):
@@ -342,9 +353,10 @@ def find_elements_by_partial_link_text(self, link_text):
342353
343354
elements = element.find_elements_by_partial_link_text('Sign')
344355
"""
345-
warnings.warn("find_elements_by_partial_link_text is deprecated. Please use find_elements(by=By.PARTIAL_LINK_TEXT, value=link_text) instead",
346-
DeprecationWarning,
347-
stacklevel=2)
356+
warnings.warn(
357+
"find_elements_by_partial_link_text is deprecated. Please use find_elements(by=By.PARTIAL_LINK_TEXT, value=link_text) instead",
358+
DeprecationWarning,
359+
stacklevel=2)
348360
return self.find_elements(by=By.PARTIAL_LINK_TEXT, value=link_text)
349361

350362
def find_element_by_tag_name(self, name):
@@ -364,9 +376,10 @@ def find_element_by_tag_name(self, name):
364376
365377
element = element.find_element_by_tag_name('h1')
366378
"""
367-
warnings.warn("find_element_by_tag_name is deprecated. Please use find_element(by=By.TAG_NAME, value=name) instead",
368-
DeprecationWarning,
369-
stacklevel=2)
379+
warnings.warn(
380+
"find_element_by_tag_name is deprecated. Please use find_element(by=By.TAG_NAME, value=name) instead",
381+
DeprecationWarning,
382+
stacklevel=2)
370383
return self.find_element(by=By.TAG_NAME, value=name)
371384

372385
def find_elements_by_tag_name(self, name):
@@ -384,9 +397,10 @@ def find_elements_by_tag_name(self, name):
384397
385398
elements = element.find_elements_by_tag_name('h1')
386399
"""
387-
warnings.warn("find_elements_by_tag_name is deprecated. Please use find_elements(by=By.TAG_NAME, value=name) instead",
388-
DeprecationWarning,
389-
stacklevel=2)
400+
warnings.warn(
401+
"find_elements_by_tag_name is deprecated. Please use find_elements(by=By.TAG_NAME, value=name) instead",
402+
DeprecationWarning,
403+
stacklevel=2)
390404
return self.find_elements(by=By.TAG_NAME, value=name)
391405

392406
def find_element_by_xpath(self, xpath):
@@ -455,9 +469,10 @@ def find_elements_by_xpath(self, xpath):
455469
elements = element.find_elements_by_xpath("//div[contains(@class, 'foo')]")
456470
457471
"""
458-
warnings.warn("find_elements_by_xpath is deprecated. Please use find_elements(by=By.XPATH, value=xpath) instead",
459-
DeprecationWarning,
460-
stacklevel=2)
472+
warnings.warn(
473+
"find_elements_by_xpath is deprecated. Please use find_elements(by=By.XPATH, value=xpath) instead",
474+
DeprecationWarning,
475+
stacklevel=2)
461476
return self.find_elements(by=By.XPATH, value=xpath)
462477

463478
def find_element_by_class_name(self, name):
@@ -477,9 +492,10 @@ def find_element_by_class_name(self, name):
477492
478493
element = element.find_element_by_class_name('foo')
479494
"""
480-
warnings.warn("find_element_by_class_name is deprecated. Please use find_element(by=By.CLASS_NAME, value=name) instead",
481-
DeprecationWarning,
482-
stacklevel=2)
495+
warnings.warn(
496+
"find_element_by_class_name is deprecated. Please use find_element(by=By.CLASS_NAME, value=name) instead",
497+
DeprecationWarning,
498+
stacklevel=2)
483499
return self.find_element(by=By.CLASS_NAME, value=name)
484500

485501
def find_elements_by_class_name(self, name):
@@ -497,7 +513,9 @@ def find_elements_by_class_name(self, name):
497513
498514
elements = element.find_elements_by_class_name('foo')
499515
"""
500-
warnings.warn("find_elements_by_class_name is deprecated. Please use find_elements(by=By.CLASS_NAME, value=name) instead", DeprecationWarning)
516+
warnings.warn(
517+
"find_elements_by_class_name is deprecated. Please use find_elements(by=By.CLASS_NAME, value=name) instead",
518+
DeprecationWarning)
501519
return self.find_elements(by=By.CLASS_NAME, value=name)
502520

503521
def find_element_by_css_selector(self, css_selector):
@@ -517,9 +535,10 @@ def find_element_by_css_selector(self, css_selector):
517535
518536
element = element.find_element_by_css_selector('#foo')
519537
"""
520-
warnings.warn("find_element_by_css_selector is deprecated. Please use find_element(by=By.CSS_SELECTOR, value=css_selector) instead",
521-
DeprecationWarning,
522-
stacklevel=2)
538+
warnings.warn(
539+
"find_element_by_css_selector is deprecated. Please use find_element(by=By.CSS_SELECTOR, value=css_selector) instead",
540+
DeprecationWarning,
541+
stacklevel=2)
523542
return self.find_element(by=By.CSS_SELECTOR, value=css_selector)
524543

525544
def find_elements_by_css_selector(self, css_selector):
@@ -537,9 +556,10 @@ def find_elements_by_css_selector(self, css_selector):
537556
538557
elements = element.find_elements_by_css_selector('.foo')
539558
"""
540-
warnings.warn("find_elements_by_css_selector is deprecated. Please use find_elements(by=By.CSS_SELECTOR, value=css_selector) instead",
541-
DeprecationWarning,
542-
stacklevel=2)
559+
warnings.warn(
560+
"find_elements_by_css_selector is deprecated. Please use find_elements(by=By.CSS_SELECTOR, value=css_selector) instead",
561+
DeprecationWarning,
562+
stacklevel=2)
543563
return self.find_elements(by=By.CSS_SELECTOR, value=css_selector)
544564

545565
def send_keys(self, *value) -> None:
@@ -593,7 +613,8 @@ def shadow_root(self) -> ShadowRoot:
593613
- NoSuchShadowRoot - if no shadow root was attached to element
594614
"""
595615
browser_main_version = int(self._parent.caps["browserVersion"].split(".")[0])
596-
assert self._parent.caps["browserName"].lower() not in ["firefox", "safari"], "This only currently works in Chromium based browsers"
616+
assert self._parent.caps["browserName"].lower() not in ["firefox",
617+
"safari"], "This only currently works in Chromium based browsers"
597618
assert not browser_main_version <= 95, f"Please use Chromium based browsers with version 96 or later. Version used {self._parent.caps['browserVersion']}"
598619
return self._execute(Command.GET_SHADOW_ROOT)['value']
599620

py/test/selenium/webdriver/common/form_handling_tests.py

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -41,28 +41,40 @@ def test_should_be_able_to_click_image_buttons(driver, pages):
4141
WebDriverWait(driver, 3).until(EC.title_is("We Arrive Here"))
4242

4343

44-
def test_should_be_able_to_submit_forms(driver, pages):
44+
def test_should_submit_input_in_form(driver, pages):
4545
pages.load("formPage.html")
4646
driver.find_element(By.NAME, "login").submit()
4747
WebDriverWait(driver, 3).until(EC.title_is("We Arrive Here"))
4848

4949

50-
def test_should_submit_aform_when_any_input_element_within_that_form_is_submitted(driver, pages):
50+
def test_should_submit_any_input_element_within_form(driver, pages):
5151
pages.load("formPage.html")
5252
driver.find_element(By.ID, "checky").submit()
5353
WebDriverWait(driver, 3).until(EC.title_is("We Arrive Here"))
5454

5555

56-
def test_should_submit_aform_when_any_element_within_that_form_is_submitted(driver, pages):
56+
def test_should_submit_any_element_within_form(driver, pages):
5757
pages.load("formPage.html")
5858
driver.find_element(By.XPATH, "//form/p").submit()
5959
WebDriverWait(driver, 5).until(EC.title_is("We Arrive Here"))
6060

6161

62-
def test_should_not_be_able_to_submit_aform_that_does_not_exist(driver, pages):
62+
def test_should_submit_element_with_id_submit(driver, pages):
6363
pages.load("formPage.html")
64-
with pytest.raises(NoSuchElementException):
65-
driver.find_element(By.NAME, "there is no spoon").submit()
64+
driver.find_element(By.ID, "submit").submit()
65+
WebDriverWait(driver, 5).until(EC.title_is("We Arrive Here"))
66+
67+
68+
def test_should_submit_element_with_name_submit(driver, pages):
69+
pages.load("formPage.html")
70+
driver.find_element(By.NAME, "submit").submit()
71+
WebDriverWait(driver, 5).until(EC.title_is("We Arrive Here"))
72+
73+
74+
def test_should_not_submit_button_outside_form(driver, pages):
75+
pages.load("formPage.html")
76+
with pytest.raises(WebDriverException):
77+
driver.find_element(By.NAME, "SearchableText").submit()
6678

6779

6880
def test_should_be_able_to_enter_text_into_atext_area_by_setting_its_value(driver, pages):

0 commit comments

Comments
 (0)