Added
This is a bigger change that sets us up for things we want to do with better reporting and BDD functionality. There may be some breaking changes depending how you wrote your tests.
For example, the property of `Element.text` is now a function `Element.text()` and `.find()` no longer has an `at_least_one` parameter.
Make sure you run your tests after upgrading to catch errors like `str is not invocable`. They should be easy to fix.
**PyleniumShould**
The use case of checking that an element is NOT on the page or DOM was much more common than anticipated. I have changed how the `.find()` and `.find_xpath()` functions behave to help with this, but there are now three easy to use "should" commands as well.
* **`.not_find()`**
* **`.not_find_xpath()`**
* **`.not_contain()`**
python
example usage
py.should().not_find('hidden-element')
**Driver**
Having these as properties was actually messing people up as they used Pylenium. Because almost all of the commands are functions, it was common that someone would try `py.url()` or `py.title()` only to see the test fail saying that `str is not invocable`. Changing these to functions feels more natural.
* `.url` property changed to `.url()` function
* `.title` property changed to `.title()` function
**XPaths**
Removed the `.xpath()` function from _Pylenium_ and _Element_ and replaced with `get` and `find` options. The `.xpath()` function _could_ return an empty list, a single element, or a list of 2 or more elements. The flexibility was pretty "clever", but it was not intuitive to work with. Separating it into two distinct functions to match the CSS versions of `get()` and `.find()` made more sense.
* `.get_xpath()`
* `find_xpath()`
python
single element with xpath
py.get_xpath('//input[name="q"]')
list of elements with xpath
py.find_xpath('//li')
**Find Elements**
The `.find()` and `.find_xpath()` functions on the _Pylenium_ and _Element_ objects will now return an empty list if none are found rather than throwing an exception. Dealing with an empty list is easier and cleaner than having to handle an exception.
However, this is not the case If the timeout is set to `0` \(zero\). The next section goes into more detail.
**Immediate Poll with timeout=0**
There are times when you don't want to use an awesome wait and a timeout of 1 second isn't good enough. For all of the _Find Element_ commands, you can now set the timeout to `0` \(zero\) to poll the DOM immediately as if you were using Selenium with no wait.
> This will still return an `Element` or `Elements` object if found, but no _wait_ is used.
Let's take a look at the `.get()` signature:
python
def get(self, css: str, timeout: int = None) -> Element
* If `timeout=None` \(default\), the function will use the default `wait_time` in `pylenium.json` which is 10 seconds.
python
use `wait_time` in pylenium.json
py.get('button').click()
* If `timeout > 0`, override the default wait\_time.
python
shorten it to 3 seconds instead
py.get('button', timeout=3).click()
---or---
give it even more time
py.get('button', timeout=30).click()
* If timeout=0, poll the DOM immediately without any waiting.
python
no waiting, immediately poll the DOM
py.get('button', timeout=0).click()
**Element and Elements**
Changed some properties to functions for the same reasons as the props in Driver.
* `Elements.length` property changed to `Elements.length()` function
* `Element.tag_name` property changed to `Element.tag_name()` function
* `Element.text` property changed to `Element.text()` function
**ElementsShould**
_Pylenium_ and _Element_ have their own Should classes for expectations. Most of our assertions and checks are done against them, but there were enough use cases against the length of the Elements that I wanted to include them to make it easier. Now when you have a list of elements \(Elements\), you can use `.should()`:
* `be_empty()`
* `not_be_empty()`
* `have_length()`
* `be_greater_than()`
* `be_less_than()`