diff --git a/CHANGELOG.md b/CHANGELOG.md
index aa9b0430..20521a63 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -141,6 +141,17 @@ seems like currently we do raise, but cover with tests
### TODO: falsify WebDriverException when thrown inside by predicate?
+### Deprecated conditions
+
+- `be.present` in favor of `be.present_in_dom`
+- `be.not_.present` in favor of `be.not_.present_in_dom`
+- `be.absent` in favor of `be.absent_in_dom`
+- `be.not_.absent` in favor of `be.not_.absent_in_dom`
+
+### Added be.hidden_in_dom in addition to be.hidden
+
+Consider `be.hidden` as "hidden somewhere, maybe in DOM with "display:none", or even on frontend/backend, i.e. totally absent from the page". Then `be.hidden_in_dom` is stricter, and means "hidden in DOM, i.e. available in the page DOM, but not visible".
+
### Text related conditions now accepts int and floats as text item
`.have.exact_texts(1, 2.0, '3')` is now possible, and will be treated as `['1', '2.0', '3']`
diff --git a/selene/core/entity.py b/selene/core/entity.py
index e98863b8..9a47adff 100644
--- a/selene/core/entity.py
+++ b/selene/core/entity.py
@@ -153,11 +153,11 @@ def _log_webelement_outer_html_for(
) -> Callable[[TimeoutException], Exception]:
def log_webelement_outer_html(error: TimeoutException) -> Exception:
from selene.core import query
- from selene.core.match import present
+ from selene.core.match import present_in_dom
cached = element.cached
- if cached.matching(present):
+ if cached.matching(present_in_dom):
return TimeoutException(
f'{error.msg}\n'
f'Actual webelement: {query.outer_html(element)}' # type: ignore
diff --git a/selene/core/match.py b/selene/core/match.py
index 69ea416a..4c8b62aa 100644
--- a/selene/core/match.py
+++ b/selene/core/match.py
@@ -56,15 +56,47 @@
from selene.core.entity import Collection, Element
from selene.core._browser import Browser
-# TODO: consider renaming to present_in_dom
-present: Condition[Element] = Match(
+present_in_dom: Condition[Element] = Match(
'is present in DOM',
actual=lambda element: element.locate(),
by=lambda webelement: webelement is not None,
)
-# TODO: consider renaming to absent_in_dom
+absent_in_dom: Condition[Element] = Condition.as_not(present_in_dom, 'is absent in DOM')
+
+
+def __deprecated_is_present(element: Element) -> bool:
+ warnings.warn(
+ 'be.present is deprecated, use be.present_in_dom instead',
+ DeprecationWarning,
+ )
+ return element.locate() is not None
+
+
+present: Condition[Element] = Match(
+ 'is present in DOM',
+ by=__deprecated_is_present, # noqa
+)
+"""Deprecated 'is present' condition. Use present_in_dom instead. """
+
+
absent: Condition[Element] = Condition.as_not(present, 'is absent in DOM')
+"""Deprecated 'is absent' condition. Use absent_in_dom instead."""
+
+
+def __deprecated_is_existing(element: Element) -> bool:
+ warnings.warn(
+ 'be.existing is deprecated, use be.present_in_dom instead',
+ DeprecationWarning,
+ )
+ return element.locate() is not None
+
+
+existing: Condition[Element] = Match(
+ 'is present in DOM',
+ by=__deprecated_is_existing, # noqa
+)
+"""Deprecated 'is existing' condition. Use present_in_dom instead."""
visible: Condition[Element] = Match(
@@ -75,7 +107,7 @@
hidden: Condition[Element] = Condition.as_not(visible, 'is hidden')
-hidden_in_dom: Condition[Element] = present.and_(visible.not_)
+hidden_in_dom: Condition[Element] = present_in_dom.and_(visible.not_)
element_is_enabled: Condition[Element] = ElementCondition.raise_if_not(
diff --git a/selene/support/conditions/be.py b/selene/support/conditions/be.py
index f8927b62..9c53f707 100644
--- a/selene/support/conditions/be.py
+++ b/selene/support/conditions/be.py
@@ -19,22 +19,19 @@
# 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.
-
from selene.core import match
from selene.support.conditions import not_ as _not_
not_ = _not_
-visible = match.visible
-hidden = match.hidden
+present_in_dom = match.present_in_dom
+in_dom = match.present_in_dom # TODO: do we need both present_in_dom and in_dom?
+absent_in_dom = match.absent_in_dom
hidden_in_dom = match.hidden_in_dom
-selected = match.element_is_selected
-
-present = match.present
-in_dom = match.present # TODO: do we need both present and in_dom?
-existing = match.present # TODO: consider deprecating
+hidden = match.hidden
+visible = match.visible
-absent = match.absent
+selected = match.element_is_selected
enabled = match.element_is_enabled
disabled = match.element_is_disabled
@@ -47,3 +44,19 @@
# --- Deprecated --- #
empty = match.collection_is_empty
+
+
+present = match.present
+"""Deprecated 'is present' condition. Use
+[present_in_dom][selene.support.conditions.be.present_in_dom] instead.
+"""
+
+absent = match.absent
+"""Deprecated 'is absent' condition. Use
+[absent_in_dom][selene.support.conditions.not_.absent_in_dom] instead.
+"""
+
+existing = match.existing
+"""Deprecated 'is existing' condition. Use
+[present_in_dom][selene.support.conditions.be.present_in_dom] instead.
+"""
diff --git a/selene/support/conditions/not_.py b/selene/support/conditions/not_.py
index ea138d39..6bd20516 100644
--- a/selene/support/conditions/not_.py
+++ b/selene/support/conditions/not_.py
@@ -23,11 +23,9 @@
import warnings
from typing import Any, Iterable
-from typing_extensions import cast
-
from selene.core import match as _match
-# --- be.* conditions --- #
+# --- be.not_.* conditions --- #
from selene.core.condition import Condition
from selene.core.entity import Element, Collection
from selene.core._browser import Browser
@@ -39,19 +37,27 @@
hidden: Condition[Element] = _match.hidden.not_
hidden_in_dom: Condition[Element] = _match.hidden_in_dom.not_
-present: Condition[Element] = _match.present.not_
-in_dom: Condition[Element] = _match.present.not_
-# TODO: do we need both present and in_dom?
-# TODO: consider deprecating existing
-existing: Condition[Element] = _match.present.not_
+present_in_dom: Condition[Element] = _match.present_in_dom.not_
+absent_in_dom: Condition[Element] = _match.absent_in_dom.not_
+in_dom: Condition[Element] = _match.present_in_dom.not_
-absent: Condition[Element] = _match.absent.not_
enabled: Condition[Element] = _match.element_is_enabled.not_
disabled: Condition[Element] = _match.element_is_disabled.not_
blank: Condition[Element] = _match.element_is_blank.not_
+# --- be.not_.* DEPRECATED conditions --- #
+
+present: Condition[Element] = _match.present_in_dom.not_
+"""Deprecated 'is not present' condition. Use not_.present_in_dom instead."""
+
+existing: Condition[Element] = _match.present_in_dom.not_
+"""Deprecated 'is not existing' condition. Use not_.present_in_dom instead."""
+
+absent: Condition[Element] = _match.absent_in_dom.not_
+"""Deprecated 'is not absent' condition. Use not_.absent_in_dom instead."""
+
# --- have.* conditions --- #
diff --git a/tests/integration/condition__element__present_visible__plus_inversions__compared_test.py b/tests/integration/condition__element__present_visible__plus_inversions__compared_test.py
index 2edaed6d..16e73d0c 100644
--- a/tests/integration/condition__element__present_visible__plus_inversions__compared_test.py
+++ b/tests/integration/condition__element__present_visible__plus_inversions__compared_test.py
@@ -26,6 +26,9 @@
from tests.integration.helpers.givenpage import GivenPage
+# TODO: consider refactoring to parametrized test such type of tests
+
+
def test_should_be_hidden__passed_and_failed__compared_to_be_visible(session_browser):
browser = session_browser.with_(timeout=0.1)
GivenPage(session_browser.driver).opened_with_body(
@@ -42,19 +45,19 @@ def test_should_be_hidden__passed_and_failed__compared_to_be_visible(session_bro
# THEN
- absent.should(match.present.not_)
- absent.should(match.present.not_.not_.not_)
- absent.should(be.not_.present)
+ absent.should(match.present_in_dom.not_)
+ absent.should(match.present_in_dom.not_.not_.not_)
+ absent.should(be.not_.present_in_dom)
- absent.should(match.absent)
- absent.should(match.absent.not_.not_)
- absent.should(be.absent)
- hidden.should(match.present)
- hidden.should(be.present)
+ absent.should(match.absent_in_dom)
+ absent.should(match.absent_in_dom.not_.not_)
+ absent.should(be.absent_in_dom)
+ hidden.should(match.present_in_dom)
+ hidden.should(be.present_in_dom)
hidden.should(be.hidden_in_dom) # same ↙️
- hidden.should(be.present.and_(be.not_.visible))
+ hidden.should(be.present_in_dom.and_(be.not_.visible))
hidden.should(be.not_.visible)
- hidden.should(be.not_.absent) # TODO: rename to be.not_.absent_in_dom?
+ hidden.should(be.not_.absent_in_dom) # TODO: rename to be.not_.absent_in_dom?
absent.should(match.visible.not_)
absent.should(be.not_.visible)
@@ -66,8 +69,8 @@ def test_should_be_hidden__passed_and_failed__compared_to_be_visible(session_bro
visible.should(be.visible)
visible.should(be.not_.hidden)
visible.should(be.not_.hidden_in_dom)
- visible.should(be.present)
- visible.should(be.not_.absent)
+ visible.should(be.present_in_dom)
+ visible.should(be.not_.absent_in_dom)
# TODO: review and extend/finalize coverage below
@@ -135,6 +138,50 @@ def test_should_be_hidden__passed_and_failed__compared_to_be_visible(session_bro
) in str(error)
+def x_test_deprecated_should_be_absent__passed_and_failed__compared_(session_browser):
+ browser = session_browser.with_(timeout=0.1)
+ GivenPage(session_browser.driver).opened_with_body(
+ '''
+
+
+
+ '''
+ )
+
+ absent = browser.element("#absent")
+ hidden = browser.element("#hidden")
+ visible = browser.element("#visible")
+
+ # THEN
+
+ absent.should(match.present.not_)
+ absent.should(match.present.not_.not_.not_)
+ absent.should(be.not_.present)
+
+ absent.should(match.absent)
+ absent.should(match.absent.not_.not_)
+ absent.should(be.absent)
+ hidden.should(match.present)
+ hidden.should(be.present)
+ hidden.should(be.hidden_in_dom) # same ↙️
+ hidden.should(be.present.and_(be.not_.visible))
+ hidden.should(be.not_.visible)
+ hidden.should(be.not_.absent) # TODO: rename to be.not_.absent_in_dom?
+
+ absent.should(match.visible.not_)
+ absent.should(be.not_.visible)
+ absent.should(be.hidden) # TODO: should it fail?
+ absent.should(be.not_.hidden_in_dom)
+ absent.should(match.hidden_in_dom.not_)
+
+ visible.should(match.visible)
+ visible.should(be.visible)
+ visible.should(be.not_.hidden)
+ visible.should(be.not_.hidden_in_dom)
+ visible.should(be.present)
+ visible.should(be.not_.absent)
+
+
def test_action_on_element_found_relatively_from_hidden_element(session_browser):
browser = session_browser.with_(timeout=0.1)
GivenPage(session_browser.driver).opened_with_body(