yashaka / selene

User-oriented Web UI browser tests in Python
https://yashaka.github.io/selene/
MIT License
676 stars 145 forks source link

use ... as placeholder in have.texts like collection conditions #528

Open yashaka opened 1 month ago

yashaka commented 1 month ago

Something like:

browser = session_browser.with_(timeout=0.25)
li = browser.all('li')
GivenPage(browser.driver).opened_with_body(
    '''
    <ul>Hello:
       <li>1</li>
       <li>2</li>
       <li>3</li>
       <li>4</li>
       <li>5</li>
       <li>6</li>
       <li>7</li>
       <li>8</li>
       <li>9</li>
       <li>X</li>
    </ul>
    '''
)
X = 'X'

# THEN
li.should(have.texts_like(..., 3, 4, ..., 7, 8, ...).where(one_or_more=...))
yashaka commented 1 month ago

List of conditions added (still marked as experimental with _ prefix):

Where:

Warning:

Examples of usage:

from selene import browser, have
...
# GivenPage(browser.driver).opened_with_body(
#     '''
#     <ul>Hello:
#         <li>1) One!!!</li>
#         <li>2) Two!!!</li>
#         <li>3) Three!!!</li>
#         <li>4) Four!!!</li>
#         <li>5) Five!!!</li>
#     </ul>
#     '''
# )

browser.all('li').should(have._exact_texts_like(
    '1) One!!!', '2) Two!!!', ..., ..., ...  # = exactly one
))
browser.all('li').should(have._texts_like(
    '\d\) One!+', '\d.*', ..., ..., ...
).with_regex)
browser.all('li').should(have._texts_like(
    '?) One*', '?) Two*', ..., ..., ...
).with_wildcards)
browser.all('li').should(have._texts_like(
    '_) One**', '_) Two*', ..., ..., ...
).where_wildcards(zero_or_more='**', exactly_one='_'))
browser.all('li').should(have._texts_like(
    'One', 'Two', ..., ..., ...  # matches each text by contains
))  # kind of "with implicit * wildcards" in the beginning and the end of each text

browser.all('li').should(have._texts_like(
    ..., ..., ..., 'Four', 'Five'
))
browser.all('li').should(have._texts_like(
    'One', ..., ..., 'Four', ...  # = exactly one
))

browser.all('li').should(have._texts_like(
    'One', 'Two', (..., )  # = one or more
))
browser.all('li').should(have._texts_like(
    [(..., )], 'One', 'Two', [(..., )]  # = ZERO or more ;)
))
browser.all('li').should(have._texts_like(
    [...], 'One', 'Two', 'Three', 'Four', [...]  # = zero or ONE ;)
))

# If you don't need so much "globs"...
# (here goes, actually, the 💡RECOMMENDED💡 way to use it in most cases...
# to keep things simpler for easier support and more explicit for readability)
# – you can use the simplest glob item with explicitly customized meaning:
browser.all('li').should(have._exact_texts_like(
    ..., 'One', 'Two', ...      # = zero OR MORE
).where(zero_or_more=...))  # – because the ... meaning was overridden
# Same works for other conditions that end with `_like`
browser.all('li').should(have._exact_texts_like(
    ..., '1) One!!!', '2) Two!!!', ...
).where(zero_or_more=...))
yashaka commented 1 week ago

Here are the critique of previous globs:

So, why not define default list globs as:

Examples of usage:

from selene import browser, have
...
# GivenPage(browser.driver).opened_with_body(
#     '''
#     <ul>Hello:
#         <li>1) One!!!</li>
#         <li>2) Two!!!</li>
#         <li>3) Three!!!</li>
#         <li>4) Four!!!</li>
#         <li>5) Five!!!</li>
#     </ul>
#     '''
# )

browser.all('li').should(have._exact_texts_like(
    '1) One!!!', '2) Two!!!', {...}, {...}, {...}  # = exactly one
))
browser.all('li').should(have._texts_like(
    '\d\) One!+', '\d.*', {...}, {...}, {...}
).with_regex)
browser.all('li').should(have._texts_like(
    '?) One*', '?) Two*', {...}, {...}, {...}
).with_wildcards)
browser.all('li').should(have._texts_like(
    '_) One**', '_) Two*', {...}, {...}, {...}
).where_wildcards(zero_or_more='**', exactly_one='_'))
browser.all('li').should(have._texts_like(
    'One', 'Two', {...}, {...}, {...}  # matches each text by contains
))  # kind of "with implicit * wildcards" in the beginning and the end of each text

browser.all('li').should(have._texts_like(
    {...}, {...}, {...}, 'Four', 'Five'
))
browser.all('li').should(have._texts_like(
    'One', {...}, {...}, 'Four', {...}  # = exactly one
))

browser.all('li').should(have._texts_like(
    'One', 'Two', ...  # = one or more
))
browser.all('li').should(have._texts_like(
    [...], 'One', 'Two', [...]  # = ZERO or more ;)
))
browser.all('li').should(have._texts_like(
    [{...}], 'One', 'Two', 'Three', 'Four', [{...}]  # = zero or ONE ;)
))

# If you don't need so much "globs"...
# (here goes, actually, the 💡RECOMMENDED💡 way to use it in most cases...
# to keep things simpler for easier support and more explicit for readability)
# – you can use the simplest glob item with explicitly customized meaning:
browser.all('li').should(have._exact_texts_like(
    ..., 'One', 'Two', ...      # = one OR MORE
).where(zero_or_more=...))  # – because the ... meaning was overridden
# Same works for other conditions that end with `_like`
browser.all('li').should(have._exact_texts_like(
    ..., '1) One!!!', '2) Two!!!', ...
).where(zero_or_more=...))