Skip to content

Commit

Permalink
NEW: be.present_in_dom and be.absent_in_dom instead...
Browse files Browse the repository at this point in the history
... deprecated:
- `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`
  • Loading branch information
yashaka committed Jun 15, 2024
1 parent 455d4d4 commit b14dd06
Show file tree
Hide file tree
Showing 6 changed files with 145 additions and 36 deletions.
11 changes: 11 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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']`
Expand Down
4 changes: 2 additions & 2 deletions selene/core/entity.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
40 changes: 36 additions & 4 deletions selene/core/match.py
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand All @@ -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(
Expand Down
31 changes: 22 additions & 9 deletions selene/support/conditions/be.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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.
"""
24 changes: 15 additions & 9 deletions selene/support/conditions/not_.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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 --- #

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand All @@ -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)
Expand All @@ -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

Expand Down Expand Up @@ -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(
'''
<!--<button id="absent">Press me</button>-->
<button id="hidden" style="display: none">Press me</button>
<button id="visible" style="display: block">Press me</button>
'''
)

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(
Expand Down

0 comments on commit b14dd06

Please sign in to comment.