Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Strip and collapse spaces from element text should be #1749

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
18 changes: 18 additions & 0 deletions atest/acceptance/keywords/content_assertions.robot
Expand Up @@ -162,14 +162,26 @@ Element Should Not Contain
Element Text Should Be
Element Text Should Be some_id This text is inside an identified element
Element Text Should Be some_id This TEXT IS INSIDE AN IDENTIFIED ELEMENT ignore_case=True
Element Text Should Be some_id This text is inside an identified element${SPACE} strip_spaces=True
Element Text Should Be some_id ${SPACE}This text is inside an identified element strip_spaces=LEADING
Element Text Should Be some_id This text is inside an identified element${SPACE} strip_spaces=TRAILING
Element Text Should Be some_id This${SPACE}${SPACE} text is inside an identified element collapse_spaces=True
Run Keyword And Expect Error
... The text of element 'some_id' should have been 'inside' but it was 'This text is inside an identified element'.
... Element Text Should Be some_id inside
Run Keyword And Expect Error
... The text of element 'some_id' should have been 'This text is inside an identified element ' but it was 'This text is inside an identified element'.
... Element Text Should Be some_id This text is inside an identified element${SPACE} strip_spaces=False
Run Keyword And Expect Error
... The text of element 'some_id' should have been 'This${SPACE}${SPACE} text is inside an identified element' but it was 'This text is inside an identified element'.
... Element Text Should Be some_id This${SPACE}${SPACE} text is inside an identified element collapse_spaces=False

Element Text Should Not Be
Element Text Should Not Be some_id Foo This text is inside an identified element
Element Text Should Not Be some_id This TEXT IS INSIDE AN IDENTIFIED ELEMENT ignore_case=False
Element Text Should Not Be some_id FOO This text is inside an identified element ignore_case=True
Element Text Should Not Be some_id This text is inside an identified element${SPACE} strip_spaces=False
Element Text Should Not Be some_id This text${SPACE}${SPACE} is inside an identified element collapse_spaces=False
Run Keyword And Expect Error
... The text of element 'some_id' was not supposed to be 'This text is inside an identified element'.
... Element Text Should Not Be some_id This text is inside an identified element
Expand All @@ -179,6 +191,12 @@ Element Text Should Not Be
Run Keyword And Expect Error
... The text of element 'some_id' was not supposed to be 'THIS TEXT is inside an identified element'.
... Element Text Should Not Be some_id THIS TEXT is inside an identified element ignore_case=True
Run Keyword And Expect Error
... The text of element 'some_id' was not supposed to be 'This text is inside an identified element '.
... Element Text Should Not Be some_id This text is inside an identified element${SPACE} strip_spaces=True
Run Keyword And Expect Error
... The text of element 'some_id' was not supposed to be 'This text${SPACE}${SPACE} is inside an identified element'.
... Element Text Should Not Be some_id This text${SPACE}${SPACE} is inside an identified element collapse_spaces=True

Get Text
${str} = Get Text some_id
Expand Down
4 changes: 4 additions & 0 deletions src/SeleniumLibrary/__init__.pyi
Expand Up @@ -163,13 +163,17 @@ class SeleniumLibrary:
expected: Union[None, str],
message: Optional[str] = None,
ignore_case: bool = False,
strip_spaces: Union[bool, str] = False,
collapse_spaces: bool = False,
): ...
def element_text_should_not_be(
self,
locator: Union[selenium.webdriver.remote.webelement.WebElement, str],
not_expected: Union[None, str],
message: Optional[str] = None,
ignore_case: bool = False,
strip_spaces: Union[bool, str] = False,
collapse_spaces: bool = False,
): ...
def execute_async_javascript(
self, *code: Union[selenium.webdriver.remote.webelement.WebElement, str]
Expand Down
60 changes: 58 additions & 2 deletions src/SeleniumLibrary/keywords/element.py
Expand Up @@ -13,12 +13,14 @@
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import re

from collections import namedtuple
from typing import List, Optional, Tuple, Union

from SeleniumLibrary.utils import is_noney
from SeleniumLibrary.utils.events.event import _unwrap_eventfiring_element
from robot.utils import plural_or_not, is_truthy
from robot.utils import plural_or_not, is_truthy, is_string
from selenium.webdriver.common.action_chains import ActionChains
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.remote.webelement import WebElement
Expand Down Expand Up @@ -329,6 +331,8 @@ def element_text_should_be(
expected: Union[None, str],
message: Optional[str] = None,
ignore_case: bool = False,
strip_spaces: Union[bool, str] = False,
collapse_spaces: bool = False,
):
"""Verifies that element ``locator`` contains exact the text ``expected``.

Expand All @@ -341,7 +345,19 @@ def element_text_should_be(
The ``ignore_case`` argument can be set to True to compare case
insensitive, default is False.

If ``strip_spaces`` is given a true value (see `Boolean arguments`)
and both arguments are strings, the comparison is done without leading
and trailing spaces. If ``strip_spaces`` is given a string value
``LEADING`` or ``TRAILING`` (case-insensitive), the comparison is done
without leading or trailing spaces, respectively.

If ``collapse_spaces`` is given a true value (see `Boolean arguments`) and both
arguments are strings, the comparison is done with all white spaces replaced by
a single space character.

``ignore_case`` argument is new in SeleniumLibrary 3.1.
``strip_spaces`` is new in SeleniumLibrary 5.x.x and
``collapse_spaces`` is new in SeleniumLibrary 5.x.x.

Use `Element Should Contain` if a substring match is desired.
"""
Expand All @@ -350,6 +366,12 @@ def element_text_should_be(
if ignore_case:
text = text.lower()
expected = expected.lower()
if strip_spaces:
text = self._strip_spaces(text, strip_spaces)
expected = self._strip_spaces(expected, strip_spaces)
if collapse_spaces:
text = self._collapse_spaces(text)
expected = self._collapse_spaces(expected)
if text != expected:
if message is None:
message = (
Expand All @@ -365,6 +387,8 @@ def element_text_should_not_be(
not_expected: Union[None, str],
message: Optional[str] = None,
ignore_case: bool = False,
strip_spaces: Union[bool, str] = False,
collapse_spaces: bool = False,
):
"""Verifies that element ``locator`` does not contain exact the text ``not_expected``.

Expand All @@ -377,7 +401,19 @@ def element_text_should_not_be(
The ``ignore_case`` argument can be set to True to compare case
insensitive, default is False.

New in SeleniumLibrary 3.1.1
If ``strip_spaces`` is given a true value (see `Boolean arguments`)
and both arguments are strings, the comparison is done without leading
and trailing spaces. If ``strip_spaces`` is given a string value
``LEADING`` or ``TRAILING`` (case-insensitive), the comparison is done
without leading or trailing spaces, respectively.

If ``collapse_spaces`` is given a true value (see `Boolean arguments`) and both
arguments are strings, the comparison is done with all white spaces replaced by
a single space character.

``ignore_case`` is new in SeleniumLibrary 3.1.1
``strip_spaces`` is new in SeleniumLibrary 5.x.x and
``collapse_spaces`` is new in SeleniumLibrary 5.x.x.
"""
self.info(
f"Verifying element '{locator}' does not contain exact text '{not_expected}'."
Expand All @@ -387,11 +423,31 @@ def element_text_should_not_be(
if ignore_case:
text = text.lower()
not_expected = not_expected.lower()
if strip_spaces:
text = self._strip_spaces(text, strip_spaces)
not_expected = self._strip_spaces(not_expected, strip_spaces)
if collapse_spaces:
text = self._collapse_spaces(text)
not_expected = self._collapse_spaces(not_expected)
if text == not_expected:
if message is None:
message = f"The text of element '{locator}' was not supposed to be '{before_not_expected}'."
raise AssertionError(message)

def _strip_spaces(self, value, strip_spaces):
if not is_string(value):
return value
if not is_string(strip_spaces):
return value.strip() if strip_spaces else value
if strip_spaces.upper() == 'LEADING':
return value.lstrip()
if strip_spaces.upper() == 'TRAILING':
return value.rstrip()
return value.strip() if is_truthy(strip_spaces) else value

def _collapse_spaces(self, value):
return re.sub(r'\s+', ' ', value) if is_string(value) else value

@keyword
def get_element_attribute(
self, locator: Union[WebElement, str], attribute: str
Expand Down
22 changes: 22 additions & 0 deletions utest/test/keywords/test_keyword_arguments_element.py
Expand Up @@ -27,3 +27,25 @@ def test_element_text_should_be(element):
with pytest.raises(AssertionError) as error:
element.element_text_should_be(locator, "not text", "foobar")
assert "foobar" in str(error.value)

webelement.text = "text "
when(element).find_element(locator).thenReturn(webelement)
with pytest.raises(AssertionError) as error:
element.element_text_should_be(locator, "text", strip_spaces=False)
assert "should have been" in str(error.value)

with pytest.raises(AssertionError) as error:
element.element_text_should_be(locator, "text", strip_spaces="LEADING")
assert "should have been" in str(error.value)

webelement.text = " text"
when(element).find_element(locator).thenReturn(webelement)
with pytest.raises(AssertionError) as error:
element.element_text_should_be(locator, "text", strip_spaces="TRAILING")
assert "should have been" in str(error.value)

webelement.text = "testing is cool"
when(element).find_element(locator).thenReturn(webelement)
with pytest.raises(AssertionError) as error:
element.element_text_should_be(locator, "testing is cool", collapse_spaces=False)
assert "should have been" in str(error.value)