selene icon indicating copy to clipboard operation
selene copied to clipboard

alias for collection.collected(lambda element: element.element(selector)) ?

Open yashaka opened this issue 3 years ago • 7 comments

given

 <table>
  <tr>
    <td>A1</td><td>A2</td>
  </tr>
  <tr>
    <td>B1</td><td>B2</td>
  </tr>
</table> 

now we can:

  • browser.all('tr').collected(lambda its: its.all('td')).should(have.texts('A1', 'A2', 'B1', 'B2'))
  • browser.all('tr').collected(lambda its: its.element('td')).should(have.texts('A1', 'B1'))

This issue is about choosing aliases for .collected(lambda its: its.all('td')) and .collected(lambda its: its.element('td')), what names would fit? ... Taking into account that we already have:

  • browser.element('tr').should(have.text('A1 A2')
  • browser.all('tr').should(have.text('A1 A2 B1 B2')
  • browser.element('tr').element('td').should(have.text('A1')
  • s('tr').element('td').should(have.text('A1')
  • s('tr').s('td').should(have.text('A1')
    • here, the second, i.e. «inner» s(selector) - is kind of planned to be deprecated, but we might change the direction and keep it:)
  • s('tr').ss('td').should(have.text('A1', 'A2')
    • same thing about deprecating «inner» ss(selector)
  • browser.element('tr').all('td').first.should(have.text('A1'))
  • browser.all('tr').by(have.text('A')).should(have.text('A1 A2'))
  • browser.all('tr').by(have.text('2')).first.should(have.text('A1 A2'))
  • browser.all('tr').by(have.text('B')).first.should(have.text('B1 B2'))
  • browser.all('tr').element_by(have.text('B')).should(have.text('B1 B2'))
    • see also #448 that tells that we might have instead: browser.all('tr').first_by(have.text('B')).should(have.text('B1 B2'))

Probably there are no questions to :

  • browser.all('tr').all('td').should(have.texts('A1', 'A2', 'B1', 'B2'))

It's just awesome:)

It also allows something as sexy as:

  • browser.all('tr').all('td').odd.should(have.texts('A1', 'B1'))
  • browser.all('tr').all('td').even.should(have.texts('A2', 'B2'))

BUT...

  • browser.all('tr').HERE_IS_NOT_SO_OBVIOUS('td').should(have.texts('A1', 'B1'))

Let's meditate on it...

yashaka avatar Sep 27 '22 15:09 yashaka

OPTION 1.1

  • browser.all('tr').all('td').should(have.texts('A1', 'A2', 'B1', 'B2'))
  • browser.all('tr').element('td').should(have.texts('A1', 'B1'))

Thoughts:

  • ++ it's consistent with element.element(selector)
    • i.e. both accept selector, hence, both named with element
    • but is it obvious and natural to guess...
      • - that collection.element(selector) will return collection not element?
        • that rows.element('.cell') will return all first cells from each row, not just first cell?
        • that browser.all('.row').element('.cell') will return all first cells ... ?
        • that ss('.row').element('.cell') will return all first cells ... ?
        • that ss('.row').s('.cell') will return all first cells ... ?
  • + it's kind of a bit consistent with collection.collected(lambda its: its.element(selector))
    • - but without emphasize on «collecting»
  • - it's inconsistent with the fact that all other commands with «term» return single element not a collection, like:
    • browser.element('tr').should(have.text('A1 A2')
    • browser.element('tr').element('td').should(have.text('A1')
    • browser.all('tr').element_by(have.text('B')).should(have.text('B1 B2'))
      • but it may be deprecated in favor of... (see #448): browser.all('tr').first_by(have.text('B')).should(have.text('B1 B2'))

yashaka avatar Sep 27 '22 16:09 yashaka

or with s/ss style...

OPTION 1.2

  • ss('tr').ss('td').should(have.texts('A1', 'A2', 'B1', 'B2'))
  • ss('tr').s('td').should(have.texts('A1', 'B1'))

Thoughts:

  • probably will go together with 1.1 if we don't deprecate «inner» s and ss on element
  • collection.s is pretty similar to collection.element, but a bit less questinable in context of "naturality", because s/ss are nevertheless not so natural when speaking about real web users...:)... hence, this is nevertheless a special shortcut to remember so we can just get used to it...
    • +- yet, it has similar pros and cons...

yashaka avatar Sep 27 '22 16:09 yashaka

OPTION 2

  • browser.all('tr').all('td').should(have.texts('A1', 'A2', 'B1', 'B2'))
  • browser.all('tr').all_first('td').should(have.texts('A1', 'B1'))

Thoughts:

  • ++ it's kind of «named according to what it does» :)
  • ++ and by including «all» term we clearly see that the collection will be returned, not a single element
  • +- it's kind of inconsistent with browser.element(selector) and element.element(selector)
    • ... for some reason we don't have browser.first(selector) and element.first(selector)
  • it looks consistent with collection.first ...
    • -- but it may lead to confusion when comparing to collection.all(selector).first:
      • they are not the same:
        • browser.all('tr').all('td').first.should(have.texts('A1'))
        • browser.all('tr').all_first('td').should(have.texts('A1', 'B1'))
          • but isn't it obvious that they are not the same? 🤔
      • while these will be same (if we add .first_by alias, see #448):
        • browser.all('tr').by(have.text('2')).first.should(have.text('A1 A2'))
        • browser.all('tr').first_by(have.text('2')).should(have.texts('A1 A2'))

yashaka avatar Sep 27 '22 16:09 yashaka

or just keep thinks not concise but straightforward? kind of following YAGNI and KISS...

OPTION 0.1

  • browser.all('tr').collected(lambda its: its.all('td')).should(have.texts('A1', 'A2', 'B1', 'B2'))
  • browser.all('tr').collected(lambda its: its.element('td')).should(have.texts('A1', 'B1'))

yashaka avatar Sep 27 '22 16:09 yashaka

Or maybe a bit more concise with extra helpers (to be added) inside already existing query.py:

OPTION 0.2

  • browser.all('tr').collected(query.all('td')).should(have.texts('A1', 'A2', 'B1', 'B2'))
  • browser.all('tr').collected(query.element('td')).should(have.texts('A1', 'B1'))

yashaka avatar Sep 27 '22 16:09 yashaka

And this one I would add just for myself as big lover of FP's map & reduce:D

OPTION 0.3.1

  • browser.all('tr').__map__(query.all('td')).should(have.texts('A1', 'A2', 'B1', 'B2'))
  • browser.all('tr').__map__(query.element('td')).should(have.texts('A1', 'B1'))

OR

OPTION 0.3.2

  • browser.all('tr').__map__(lambda its: its.all('td')).should(have.texts('A1', 'A2', 'B1', 'B2'))
  • browser.all('tr').__map__(lambda its: its.element('td')).should(have.texts('A1', 'B1'))

Thoughts:

  • keeping it underscored/dangled to emphasize it's technical nature...
  • + «map» is actually very good name, because here we do the same as normal python map function does...
  • - just this map function is already pretty low level, that does not fit very well with "Selene is user oriented wrapper" :D

yashaka avatar Sep 27 '22 16:09 yashaka

For now I have stopped on OPTION 2

  • browser.all('tr').all('td').should(have.texts('A1', 'A2', 'B1', 'B2'))
  • browser.all('tr').all_first('td').should(have.texts('A1', 'B1'))

Let's definitely forget about OPTION 1.1

  • browser.all('tr').all('td').should(have.texts('A1', 'A2', 'B1', 'B2'))
  • browser.all('tr').element('td').should(have.texts('A1', 'B1'))

Other options as aliases might be still considered... but maybe after release 2.0

yashaka avatar Oct 04 '22 16:10 yashaka