[py] Raise InvalidSelectorException for compound class names (#16291)
NOKEYCHECK=True
GitOrigin-RevId: 0ff768a2229f23fcb9fec84978a146bf2acb07b9
diff --git a/selenium/webdriver/remote/locator_converter.py b/selenium/webdriver/remote/locator_converter.py
index e924d7f..ceb05c4 100644
--- a/selenium/webdriver/remote/locator_converter.py
+++ b/selenium/webdriver/remote/locator_converter.py
@@ -14,6 +14,8 @@
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
+
+from selenium.common.exceptions import InvalidSelectorException
from selenium.webdriver.common.by import By
@@ -23,6 +25,8 @@
if by == By.ID:
return By.CSS_SELECTOR, f'[id="{value}"]'
elif by == By.CLASS_NAME:
+ if value and any(char.isspace() for char in value.strip()):
+ raise InvalidSelectorException("Compound class names are not allowed.")
return By.CSS_SELECTOR, f".{value}"
elif by == By.NAME:
return By.CSS_SELECTOR, f'[name="{value}"]'
diff --git a/selenium/webdriver/remote/shadowroot.py b/selenium/webdriver/remote/shadowroot.py
index 9603770..f23f5c4 100644
--- a/selenium/webdriver/remote/shadowroot.py
+++ b/selenium/webdriver/remote/shadowroot.py
@@ -17,6 +17,7 @@
from hashlib import md5 as md5_hash
+from selenium.common.exceptions import InvalidSelectorException
from selenium.webdriver.common.by import By
from selenium.webdriver.remote.command import Command
@@ -74,6 +75,8 @@
by = By.CSS_SELECTOR
value = f'[id="{value}"]'
elif by == By.CLASS_NAME:
+ if value and any(char.isspace() for char in value.strip()):
+ raise InvalidSelectorException("Compound class names are not allowed.")
by = By.CSS_SELECTOR
value = f".{value}"
elif by == By.NAME:
@@ -112,6 +115,8 @@
by = By.CSS_SELECTOR
value = f'[id="{value}"]'
elif by == By.CLASS_NAME:
+ if value and any(char.isspace() for char in value.strip()):
+ raise InvalidSelectorException("Compound class names are not allowed.")
by = By.CSS_SELECTOR
value = f".{value}"
elif by == By.NAME:
diff --git a/selenium/webdriver/remote/webdriver.py b/selenium/webdriver/remote/webdriver.py
index 84cc7c5..cb8d08b 100644
--- a/selenium/webdriver/remote/webdriver.py
+++ b/selenium/webdriver/remote/webdriver.py
@@ -14,6 +14,7 @@
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
+
"""The WebDriver implementation."""
import base64
diff --git a/test/selenium/webdriver/common/driver_element_finding_tests.py b/test/selenium/webdriver/common/driver_element_finding_tests.py
index cfdca06..42df9ff 100644
--- a/test/selenium/webdriver/common/driver_element_finding_tests.py
+++ b/test/selenium/webdriver/common/driver_element_finding_tests.py
@@ -20,7 +20,7 @@
from selenium.common.exceptions import InvalidSelectorException, NoSuchElementException
from selenium.webdriver.common.by import By
-# By.id positive
+# By.ID positive
def test_should_be_able_to_find_asingle_element_by_id(driver, pages):
@@ -53,7 +53,7 @@
assert len(elements) == 8
-# By.id negative
+# By.ID negative
def test_should_not_be_able_to_locate_by_id_asingle_element_that_does_not_exist(driver, pages):
@@ -99,7 +99,7 @@
driver.find_element(By.ID, "non_Existent_Button")
-# By.name positive
+# By.NAME positive
def test_should_be_able_to_find_asingle_element_by_name(driver, pages):
@@ -120,7 +120,7 @@
assert element.get_attribute("name") == "div1"
-# By.name negative
+# By.NAME negative
def test_should_not_be_able_to_locate_by_name_asingle_element_that_does_not_exist(driver, pages):
@@ -159,7 +159,7 @@
assert len(elements) == 0
-# By.tag_Name positive
+# By.TAG_NAME positive
def test_should_be_able_to_find_asingle_element_by_tag_name(driver, pages):
@@ -174,7 +174,7 @@
assert len(elements) > 1
-# By.tag_Name negative
+# By.TAG_NAME negative
def test_should_not_be_able_to_locate_by_tag_name_asingle_element_that_does_not_exist(driver, pages):
@@ -189,22 +189,18 @@
assert len(elements) == 0
-@pytest.mark.xfail_firefox(reason="https://github.com/mozilla/geckodriver/issues/2007")
-@pytest.mark.xfail_remote(reason="https://github.com/mozilla/geckodriver/issues/2007")
+@pytest.mark.xfail_firefox(reason="unlike chrome, firefox raises NoSuchElementException")
+@pytest.mark.xfail_remote(reason="unlike chrome, firefox raises NoSuchElementException")
@pytest.mark.xfail_safari(reason="unlike chrome, safari raises NoSuchElementException")
-@pytest.mark.xfail_chrome(reason="https://bugs.chromium.org/p/chromedriver/issues/detail?id=4743")
-@pytest.mark.xfail_edge(reason="https://bugs.chromium.org/p/chromedriver/issues/detail?id=4743")
def test_finding_asingle_element_by_empty_tag_name_should_throw(driver, pages):
pages.load("formPage.html")
with pytest.raises(InvalidSelectorException):
driver.find_element(By.TAG_NAME, "")
-@pytest.mark.xfail_firefox(reason="https://github.com/mozilla/geckodriver/issues/2007")
-@pytest.mark.xfail_remote(reason="https://github.com/mozilla/geckodriver/issues/2007")
+@pytest.mark.xfail_firefox(reason="unlike chrome, firefox returns an empty list")
+@pytest.mark.xfail_remote(reason="unlike chrome, firefox returns an empty list")
@pytest.mark.xfail_safari(reason="unlike chrome, safari returns an empty list")
-@pytest.mark.xfail_chrome(reason="https://bugs.chromium.org/p/chromedriver/issues/detail?id=4743")
-@pytest.mark.xfail_edge(reason="https://bugs.chromium.org/p/chromedriver/issues/detail?id=4743")
def test_finding_multiple_elements_by_empty_tag_name_should_throw(driver, pages):
pages.load("formPage.html")
with pytest.raises(InvalidSelectorException):
@@ -223,7 +219,7 @@
assert len(elements) == 0
-# By.class_Name positive
+# By.CLASS_NAME positive
def test_should_be_able_to_find_asingle_element_by_class(driver, pages):
@@ -269,7 +265,7 @@
assert elements[0].text == "Spaced out"
-# By.class_Name negative
+# By.CLASS_NAME negative
def test_should_not_find_element_by_class_when_the_name_queried_is_shorter_than_candidate_name(driver, pages):
@@ -279,8 +275,6 @@
@pytest.mark.xfail_safari(reason="unlike chrome, safari raises TimeoutException")
-@pytest.mark.xfail_chrome(reason="https://bugs.chromium.org/p/chromedriver/issues/detail?id=4743")
-@pytest.mark.xfail_edge(reason="https://bugs.chromium.org/p/chromedriver/issues/detail?id=4743")
def test_finding_asingle_element_by_empty_class_name_should_throw(driver, pages):
pages.load("xhtmlTest.html")
msg = r"\/errors#invalidselectorexception"
@@ -289,8 +283,6 @@
@pytest.mark.xfail_safari(reason="unlike chrome, safari raises TimeoutException")
-@pytest.mark.xfail_chrome(reason="https://bugs.chromium.org/p/chromedriver/issues/detail?id=4743")
-@pytest.mark.xfail_edge(reason="https://bugs.chromium.org/p/chromedriver/issues/detail?id=4743")
def test_finding_multiple_elements_by_empty_class_name_should_throw(driver, pages):
pages.load("xhtmlTest.html")
with pytest.raises(InvalidSelectorException):
@@ -299,13 +291,11 @@
def test_finding_asingle_element_by_compound_class_name_should_throw(driver, pages):
pages.load("xhtmlTest.html")
- with pytest.raises(NoSuchElementException):
+ with pytest.raises(InvalidSelectorException):
driver.find_element(By.CLASS_NAME, "a b")
@pytest.mark.xfail_safari(reason="unlike chrome, safari raises TimeoutException")
-@pytest.mark.xfail_chrome(reason="https://bugs.chromium.org/p/chromedriver/issues/detail?id=4743")
-@pytest.mark.xfail_edge(reason="https://bugs.chromium.org/p/chromedriver/issues/detail?id=4743")
def test_finding_asingle_element_by_invalid_class_name_should_throw(driver, pages):
pages.load("xhtmlTest.html")
with pytest.raises(InvalidSelectorException):
@@ -313,15 +303,13 @@
@pytest.mark.xfail_safari(reason="unlike chrome, safari raises TimeoutException")
-@pytest.mark.xfail_chrome(reason="https://bugs.chromium.org/p/chromedriver/issues/detail?id=4743")
-@pytest.mark.xfail_edge(reason="https://bugs.chromium.org/p/chromedriver/issues/detail?id=4743")
def test_finding_multiple_elements_by_invalid_class_name_should_throw(driver, pages):
pages.load("xhtmlTest.html")
with pytest.raises(InvalidSelectorException):
driver.find_elements(By.CLASS_NAME, "!@#$%^&*")
-# By.xpath positive
+# By.XPATH positive
def test_should_be_able_to_find_asingle_element_by_xpath(driver, pages):
@@ -388,7 +376,7 @@
assert "baz" in element.text
-# By.xpath negative
+# By.XPATH negative
def test_should_throw_an_exception_when_there_is_no_link_to_click(driver, pages):
@@ -398,8 +386,6 @@
@pytest.mark.xfail_safari(reason="unlike chrome, safari raises TimeoutException")
-@pytest.mark.xfail_chrome(reason="https://bugs.chromium.org/p/chromedriver/issues/detail?id=4743")
-@pytest.mark.xfail_edge(reason="https://bugs.chromium.org/p/chromedriver/issues/detail?id=4743")
def test_should_throw_invalid_selector_exception_when_xpath_is_syntactically_invalid_in_driver_find_element(
driver, pages
):
@@ -409,8 +395,6 @@
@pytest.mark.xfail_safari(reason="unlike chrome, safari raises TimeoutException")
-@pytest.mark.xfail_chrome(reason="https://bugs.chromium.org/p/chromedriver/issues/detail?id=4743")
-@pytest.mark.xfail_edge(reason="https://bugs.chromium.org/p/chromedriver/issues/detail?id=4743")
def test_should_throw_invalid_selector_exception_when_xpath_is_syntactically_invalid_in_driver_find_elements(
driver, pages
):
@@ -420,8 +404,6 @@
@pytest.mark.xfail_safari(reason="unlike chrome, safari raises TimeoutException")
-@pytest.mark.xfail_chrome(reason="https://bugs.chromium.org/p/chromedriver/issues/detail?id=4743")
-@pytest.mark.xfail_edge(reason="https://bugs.chromium.org/p/chromedriver/issues/detail?id=4743")
def test_should_throw_invalid_selector_exception_when_xpath_is_syntactically_invalid_in_element_find_element(
driver, pages
):
@@ -432,8 +414,6 @@
@pytest.mark.xfail_safari(reason="unlike chrome, safari raises TimeoutException")
-@pytest.mark.xfail_chrome(reason="https://bugs.chromium.org/p/chromedriver/issues/detail?id=4743")
-@pytest.mark.xfail_edge(reason="https://bugs.chromium.org/p/chromedriver/issues/detail?id=4743")
def test_should_throw_invalid_selector_exception_when_xpath_is_syntactically_invalid_in_element_find_elements(
driver, pages
):
@@ -444,8 +424,6 @@
@pytest.mark.xfail_safari(reason="unlike chrome, safari raises TimeoutException")
-@pytest.mark.xfail_chrome(reason="https://bugs.chromium.org/p/chromedriver/issues/detail?id=4743")
-@pytest.mark.xfail_edge(reason="https://bugs.chromium.org/p/chromedriver/issues/detail?id=4743")
def test_should_throw_invalid_selector_exception_when_xpath_returns_wrong_type_in_driver_find_element(driver, pages):
pages.load("formPage.html")
with pytest.raises(InvalidSelectorException):
@@ -453,8 +431,6 @@
@pytest.mark.xfail_safari(reason="unlike chrome, safari raises TimeoutException")
-@pytest.mark.xfail_chrome(reason="https://bugs.chromium.org/p/chromedriver/issues/detail?id=4743")
-@pytest.mark.xfail_edge(reason="https://bugs.chromium.org/p/chromedriver/issues/detail?id=4743")
def test_should_throw_invalid_selector_exception_when_xpath_returns_wrong_type_in_driver_find_elements(driver, pages):
pages.load("formPage.html")
with pytest.raises(InvalidSelectorException):
@@ -462,8 +438,6 @@
@pytest.mark.xfail_safari(reason="unlike chrome, safari raises TimeoutException")
-@pytest.mark.xfail_chrome(reason="https://bugs.chromium.org/p/chromedriver/issues/detail?id=4743")
-@pytest.mark.xfail_edge(reason="https://bugs.chromium.org/p/chromedriver/issues/detail?id=4743")
def test_should_throw_invalid_selector_exception_when_xpath_returns_wrong_type_in_element_find_element(driver, pages):
pages.load("formPage.html")
body = driver.find_element(By.TAG_NAME, "body")
@@ -472,8 +446,6 @@
@pytest.mark.xfail_safari(reason="unlike chrome, safari raises TimeoutException")
-@pytest.mark.xfail_chrome(reason="https://bugs.chromium.org/p/chromedriver/issues/detail?id=4743")
-@pytest.mark.xfail_edge(reason="https://bugs.chromium.org/p/chromedriver/issues/detail?id=4743")
def test_should_throw_invalid_selector_exception_when_xpath_returns_wrong_type_in_element_find_elements(driver, pages):
pages.load("formPage.html")
body = driver.find_element(By.TAG_NAME, "body")
@@ -481,7 +453,7 @@
body.find_elements(By.XPATH, "count(//input)")
-# By.css_Selector positive
+# By.CSS_SELECTOR positive
def test_should_be_able_to_find_asingle_element_by_css_selector(driver, pages):
@@ -530,7 +502,7 @@
assert element.get_attribute("value") == "two"
-# By.css_Selector negative
+# By.CSS_SELECTOR negative
def test_should_not_find_element_by_css_selector_when_there_is_no_such_element(driver, pages):
@@ -546,8 +518,6 @@
@pytest.mark.xfail_safari(reason="unlike chrome, safari raises TimeoutException")
-@pytest.mark.xfail_chrome(reason="https://bugs.chromium.org/p/chromedriver/issues/detail?id=4743")
-@pytest.mark.xfail_edge(reason="https://bugs.chromium.org/p/chromedriver/issues/detail?id=4743")
def test_finding_asingle_element_by_empty_css_selector_should_throw(driver, pages):
pages.load("xhtmlTest.html")
with pytest.raises(InvalidSelectorException):
@@ -555,8 +525,6 @@
@pytest.mark.xfail_safari(reason="unlike chrome, safari raises TimeoutException")
-@pytest.mark.xfail_chrome(reason="https://bugs.chromium.org/p/chromedriver/issues/detail?id=4743")
-@pytest.mark.xfail_edge(reason="https://bugs.chromium.org/p/chromedriver/issues/detail?id=4743")
def test_finding_multiple_elements_by_empty_css_selector_should_throw(driver, pages):
pages.load("xhtmlTest.html")
with pytest.raises(InvalidSelectorException):
@@ -564,8 +532,6 @@
@pytest.mark.xfail_safari(reason="unlike chrome, safari raises TimeoutException")
-@pytest.mark.xfail_chrome(reason="https://bugs.chromium.org/p/chromedriver/issues/detail?id=4743")
-@pytest.mark.xfail_edge(reason="https://bugs.chromium.org/p/chromedriver/issues/detail?id=4743")
def test_finding_asingle_element_by_invalid_css_selector_should_throw(driver, pages):
pages.load("xhtmlTest.html")
with pytest.raises(InvalidSelectorException):
@@ -573,15 +539,13 @@
@pytest.mark.xfail_safari(reason="unlike chrome, safari raises TimeoutException")
-@pytest.mark.xfail_chrome(reason="https://bugs.chromium.org/p/chromedriver/issues/detail?id=4743")
-@pytest.mark.xfail_edge(reason="https://bugs.chromium.org/p/chromedriver/issues/detail?id=4743")
def test_finding_multiple_elements_by_invalid_css_selector_should_throw(driver, pages):
pages.load("xhtmlTest.html")
with pytest.raises(InvalidSelectorException):
driver.find_elements(By.CSS_SELECTOR, "//a/b/c[@id='1']")
-# By.link_Text positive
+# By.LINK_TEXT positive
def test_should_be_able_to_find_alink_by_text(driver, pages):
@@ -632,7 +596,7 @@
assert link.text == "link with trailing space"
-# By.link_Text negative
+# By.LINK_TEXT negative
def test_should_not_be_able_to_locate_by_link_text_asingle_element_that_does_not_exist(driver, pages):
@@ -647,7 +611,7 @@
assert len(elements) == 0
-# By.partial_Link_Text positive
+# By.PARTIAL_LINK_TEXT positive
def test_should_be_able_to_find_multiple_elements_by_partial_link_text(driver, pages):