From 91a191da1f030677bcd921dea4008096dd7093f1 Mon Sep 17 00:00:00 2001 From: yashaka Date: Wed, 19 Jun 2024 17:30:53 +0300 Subject: [PATCH] REFACTOR: match.selected + ... + cover with tests + rename match.element_is_focused to js._active_element - left some TODOs, especially on falsy_exceptions case... --- selene/core/match.py | 21 ++- selene/support/conditions/not_.py | 4 + ...bled__plus_inversions_and_aliases_test.py} | 0 ...element__selected__plus_inversions_test.py | 167 ++++++++++++++++++ 4 files changed, 183 insertions(+), 9 deletions(-) rename tests/integration/{condition__element__enabled__plus_inversions_and_aliases.py => condition__element__enabled__plus_inversions_and_aliases_test.py} (100%) create mode 100644 tests/integration/condition__element__selected__plus_inversions_test.py diff --git a/selene/core/match.py b/selene/core/match.py index 20fd9e39..02d3a52d 100644 --- a/selene/core/match.py +++ b/selene/core/match.py @@ -57,6 +57,7 @@ from selene.core.entity import Collection, Element from selene.core._browser import Browser + present_in_dom: Condition[Element] = Match( 'is present in DOM', actual=lambda element: element.locate(), @@ -164,14 +165,16 @@ def __deprecated_is_existing(element: Element) -> bool: ) -# TODO: how will it work for mobile? – it will not work:) -element_is_focused: Condition[Element] = Match( - 'is focused', - by=lambda element: ( - element.locate() - == element.config.driver.execute_script('return document.activeElement') - ), -) +class js: + # todo: how will it work for mobile? – it will not work:) + # do we even need it? – inside js class? or maybe be multiplatform? + _active_element: Condition[Element] = Match( + 'has focus', + by=lambda element: ( + element.locate() + == element.config.driver.execute_script('return document.activeElement') + ), + ) class _ElementHasText(Condition[Element]): @@ -517,7 +520,7 @@ def _is_collection_empty(collection: Collection) -> bool: collection_is_empty: Condition[Collection] = CollectionCondition.raise_if_not( - 'is empty', _is_collection_empty + 'is empty', _is_collection_empty # noqa ) diff --git a/selene/support/conditions/not_.py b/selene/support/conditions/not_.py index 9a16bcc9..87d5e419 100644 --- a/selene/support/conditions/not_.py +++ b/selene/support/conditions/not_.py @@ -45,6 +45,10 @@ enabled: Condition[Element] = _match.enabled.not_ disabled: Condition[Element] = _match.disabled.not_ +selected: Condition[Element] = _match.selected.not_ + +# focused: Condition[Element] = _match.focused.not_ + blank: Condition[Element] = _match.element_is_blank.not_ # --- be.not_.* DEPRECATED conditions --- # diff --git a/tests/integration/condition__element__enabled__plus_inversions_and_aliases.py b/tests/integration/condition__element__enabled__plus_inversions_and_aliases_test.py similarity index 100% rename from tests/integration/condition__element__enabled__plus_inversions_and_aliases.py rename to tests/integration/condition__element__enabled__plus_inversions_and_aliases_test.py diff --git a/tests/integration/condition__element__selected__plus_inversions_test.py b/tests/integration/condition__element__selected__plus_inversions_test.py new file mode 100644 index 00000000..4a7e604f --- /dev/null +++ b/tests/integration/condition__element__selected__plus_inversions_test.py @@ -0,0 +1,167 @@ +# MIT License +# +# Copyright (c) 2015-2022 Iakiv Kramarenko +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +import pytest + +from selene import be +from selene.core import match +from selene.core.condition import Match +from tests.integration.helpers.givenpage import GivenPage + + +# todo: consider covering radio buttons too... + + +def test_should_be_selected__passed_and_failed(session_browser): + s = lambda selector: session_browser.with_(timeout=0.1).element(selector) + GivenPage(session_browser.driver).opened_with_body( + ''' + + + + + +

Just a comment

+ ''' + ) + + # THEN + + # selected? + # - visible & selected passes + s('#visible-selected').should(be.selected) + s('#visible-selected').should(be.selected.not_.not_) + # - visible & not selected fails with mismatch + try: + s('#visible').should(be.selected) + pytest.fail('expect mismatch') + except AssertionError as error: + assert ( + "browser.element(('css selector', '#visible')).is selected\n" + '\n' + 'Reason: ConditionMismatch: condition not matched\n' + 'Screenshot: ' + ) in str(error) + # - visible & non-selectable fails still just with mismatch + try: + s('p').should(be.selected) + pytest.fail('expect mismatch') + except AssertionError as error: + assert ( + "browser.element(('css selector', 'p')).is selected\n" + '\n' + 'Reason: ConditionMismatch: condition not matched\n' + 'Screenshot: ' + ) in str(error) + # - hidden & selected passes + s('#hidden-selected').should(be.selected) + # - hidden & not selected fails with mismatch + try: + s('#hidden').should(be.selected) + pytest.fail('expect mismatch') + except AssertionError as error: + assert ( + "browser.element(('css selector', '#hidden')).is selected\n" + '\n' + 'Reason: ConditionMismatch: condition not matched\n' + 'Screenshot: ' + ) in str(error) + # - absent fails with failure + try: + s('#absent').should(be.selected) + pytest.fail('expect failure') + except AssertionError as error: + assert ( + "browser.element(('css selector', '#absent')).is selected\n" + '\n' + 'Reason: ConditionMismatch: Message: no such element: Unable to locate ' + 'element: {"method":"css selector","selector":"#absent"}\n' + ' (Session info:' # ' chrome=126.0.6478.62); For documentation on this error, ' + # 'please visit: ' + # 'https://www.selenium.dev/documentation/webdriver/troubleshooting/errors#no-such-element-exception\n' + # ':\n' + # 'condition not matched\n' + ) in str(error) + + +def test_should_be_not_selected__passed_and_failed( + session_browser, +): + s = lambda selector: session_browser.with_(timeout=0.1).element(selector) + GivenPage(session_browser.driver).opened_with_body( + ''' + + + + + +

Just a comment

+ ''' + ) + + # THEN + + # not selected? + # - visible & selected fails with mismatch + try: + s('#visible-selected').should(be.not_.selected) + pytest.fail('expect mismatch') + except AssertionError as error: + assert ( + "browser.element(('css selector', '#visible-selected')).is not (selected)\n" + '\n' + 'Reason: ConditionMismatch: condition not matched\n' + 'Screenshot: ' + ) in str(error) + # - visible & not-selectable passes + s('p').should(match.selected.not_) + # - visible & not-selected passes + s('#visible').should(match.selected.not_) + s('#visible').should(be.not_.selected) + # - hidden & selected fails with mismatch + try: + s('#hidden-selected').should(be.not_.selected) + pytest.fail('expect mismatch') + except AssertionError as error: + assert ( + "browser.element(('css selector', '#hidden-selected')).is not (selected)\n" + '\n' + 'Reason: ConditionMismatch: condition not matched\n' + 'Screenshot: ' + ) in str(error) + # - hidden & not-selected passed + s('#hidden').should(be.not_.selected) + # - absent fails with failure + try: + s('#absent').should(be.not_.selected) + pytest.fail('expect failure') + except AssertionError as error: + assert ( + "browser.element(('css selector', '#absent')).is not (selected)\n" + '\n' + 'Reason: ConditionMismatch: Message: no such element: Unable to locate ' + 'element: {"method":"css selector","selector":"#absent"}\n' + ' (Session info:' # ' chrome=126.0.6478.62); For documentation on this error, ' + # 'please visit: ' + # 'https://www.selenium.dev/documentation/webdriver/troubleshooting/errors#no-such-element-exception\n' + # ':\n' + # 'condition not matched\n' + ) in str(error)