Elemental¶
Elemental makes Selenium automation faster and easier.
- Adds common use-cases
Common use-cases missing from Selenium are built into Elemental. Get an input by its label or placeholder? Can do. Get a button by its text or type? Sure. Get the fourth element in a list? No problem.
- Automatic waiting
Elemental has built-in automatic waiting so that your automation is less flaky. It has a sensible default which can be overriden when necessary.
- The full power of Selenium
For complex operations which require the full power of the Selenium, Elemental gives you easy access to 100% of Selenium’s API.
- Terse, clean API
Write less code than you would if you were using Selenium directly. The Elemental API is terse and internally consistent while still being explicit and unambiguous.
The power of Elemental¶
import elemental
# Set up.
browser = elemental.Browser()
# Search PyPI for Elemental.
browser.visit("https://www.pypi.org")
browser.get_input(placeholder="Search projects").fill("elemental")
browser.get_button(type="submit").click()
# Click the first search result.
browser.get_element(partial_text="elemental").click()
# Confirm that Elemental's PyPI page was found.
assert browser.title == "elemental · PyPI"
# Tear down.
browser.quit()
Now dig in
Check out Elemental’s functionality or install it now and make working with Selenium faster and easier.
Functionality¶
Elemental’s functionality is grouped into 4 categories.
- Actions
Functions which perform an action.
For example: clicking a button or filling in an input field.
- Getters
Functions which get an element or elements.
For example: getting a button or div.
- States
Functions which get an element’s state.
For example: whether an element is displayed or selected.
- Values
Functions which get a value.
For example: the HTML of a page or the text contained in an element.
When you need more
For anything which Elemental can’t do and Selenium can, it’s easy to switch to raw Selenium.
First steps with Elemental¶
Step 2. Start the browser¶
Getting a browser to drive your automation is this easy:
>>> import elemental
>>> browser = elemental.Browser()
This will give you the default Firefox browser.
For information about configuring the default browser and using a custom browser, see the Browser reference.
Geckodriver required
Note that Mozilla’s geckodriver must be installed and available on PATH to use the default Selenium webdriver.
Step 3. Use the browser¶
Now do whatever you like with it. How about a web search?
>>> browser.visit("https://duckduckgo.com")
>>> placeholder = "Search the web without being tracked"
>>> browser.get_input(placeholder=placeholder).fill("python news")
>>> browser.get_input(id="search_button_homepage").click()
Enjoy your search results!
Behave + Elemental¶
Step 1. Create the browser fixture¶
Add the browser
fixture to Behave’s environment.py
file.
# features/environment.py
from behave import (
fixture,
use_fixture,
)
import elemental
@fixture
def browser(context):
# Create and yield the browser.
context.browser = elemental.Browser(headless=True)
yield context.browser
# Stop the browser after the tests have finished.
context.browser.quit()
def before_all(context):
use_fixture(browser, context)
Step 2. Use the fixture¶
Then use it in your step implementation files.
# features/steps/navigation.py
from behave import (
when,
then,
)
@when("I browse to PyPI")
def step_impl(context):
context.browser.visit("https://pypi.org")
@then("I see PyPI's title")
def step_impl(context):
assert context.browser.title == "PyPI · The Python Package Index"
Pytest + Elemental¶
Step 1. Create the browser fixture¶
Add the browser
session-scoped fixture to Pytest’s conftest.py
file.
# tests/conftest.py
import elemental
import pytest
@pytest.fixture(scope="session")
def browser():
# Create and yield the browser.
_browser = elemental.Browser(headless=True)
yield _browser
# Stop the browser after the tests have finished.
_browser.quit()
Step 2. Use the fixture¶
Then use it in your test files.
# tests/test_navigation.py
def test_pypi(browser):
browser.visit("https://pypi.org")
assert browser.title == "PyPI · The Python Package Index"
Actions¶
Action functions cause the driver to complete an action, either on an element or the browser.
These functions operate on an element or browser, and don’t return.
check¶
-
check
()¶
Checks a checkbox. Always leaves the checkbox in a ‘selected’ state, no matter whether it was checked or unchecked when the action was performed.
- Returns
None
- Example
>>> browser.get_element(id="my_checkbox").check()
click¶
-
click
()¶
Clicks the element.
- Returns
None
- Examples
>>> browser.get_button(id="my-button").click() >>> browser.get_element(link_text="Python Package Index (PyPI)").click()
fill¶
-
fill
(string)¶
Fills an input field with a string of text or filepath. Clears any existing input from the field prior to filling.
- Parameters
- string
str
The text or filepath as a string.
- Returns
None
- Examples
>>> browser.get_element(id="my_input_field").fill("my_string") >>> browser.get_input(label="Attach file").fill("my_filepath")
quit¶
-
quit
()¶
Quits the browser. Operates on a browser, not an element.
- Returns
None
- Example
>>> browser.quit()
screenshot¶
-
screenshot
(filepath)¶
Takes a screenshot of either the full browser or an element, and saves it to a given filepath.
- Parameters
- filepath
str
The full filepath, as a string.
- Returns
None
- Examples
>>> browser.get_element(id="screenshot").screenshot("element.png") >>> browser.screenshot("page.png")
select¶
-
select
()¶
Selects a radio button, select option, or checkbox element. Always leaves the target element in a selected state, no matter whether it was already selected.
- Returns
None
- Examples
>>> browser.get_element(id="my_radio_button").select() >>> browser.get_element(id="selector_id").get_element(text="option_text").select() >>> browser.get_element(id="selector_id").get_element(value="option_value").select()
Getters¶
Getters get an element.
They operate on an element or browser and return an element or list of elements.
Getters can be chained (see Chaining getters).
get_button¶
Gets a button by class, id, partial text, text or type.
- Parameters
- occurrence
int, optional
The occurrence to get. For instance, if multiple buttons on the page meet the requirements and the 3rd one is required, set this to 3.- wait
int, optional
The time to wait, in seconds, for the button to be found.- kwargs
One and only one keyword argument must be supplied. Allowed keys are: “class_name”, “id”, “partial_text”, “text”, “type”.
- Returns
element
- Examples
>>> browser.get_button(class_name="primary") >>> browser.get_button(id="my-button") >>> browser.get_button(partial_text="Save document") >>> browser.get_button(text="Save document now", wait=30) >>> browser.get_button(type="submit")
get_element¶
-
get_element
(occurrence=1, wait=5, **kwargs)¶
Gets any element.
- Parameters
- occurrence
int, optional
The occurrence to get. For instance, if multiple links on the page meet the requirements and the 3rd one is required, set this to 3.- wait
int, optional
The time to wait, in seconds, for the element to be found.- kwargs
One and only one keyword argument must be supplied. Allowed keys are: “class_name”, “css”, “id”, “link_text”, “name”, “partial_link_text”, “partial_text”, “tag”, “text”, “type”, “value”, “xpath”.
- Returns
element
- Examples
>>> browser.get_element(class_name="link") >>> browser.get_element(css="div.container p", wait=10) >>> browser.get_element(id="heading") >>> browser.get_element(link_text="Python Package Index (PyPI)") >>> browser.get_element(name="para-1") >>> browser.get_element(partial_link_text="PyPI") >>> browser.get_element(partial_text="Paragraph", occurrence=2) >>> browser.get_element(tag="a") >>> browser.get_element(text="Some text") >>> browser.get_element(type="button") >>> browser.get_element(value="Sometext") >>> browser.get_element(xpath="//*[@id='para-2']") >>> browser.get_element(tag="div").get_element(id="primary")
get_elements¶
-
get_elements
(min_elements=1, wait=5, **kwargs)¶
Gets a list of elements.
- Parameters
- min_elements
int, optional
The minimum number of elements which must be found to return before the wait time expires.- wait
int, optional
The time to wait, in seconds, for the elements to be found.- kwargs
One and only one keyword argument must be supplied. Allowed keys are: “class_name”, “css”, “id”, “link_text”, “name”, “partial_link_text”, “partial_text”, “tag”, “text”, “type”, “value”, “xpath”.
- Returns
list of elements
- Examples
>>> browser.get_elements(class_name="link") >>> browser.get_elements(css="div.container a") >>> browser.get_elements(id="heading") >>> browser.get_elements(link_text="Python.org") >>> browser.get_elements(name="para-1") >>> browser.get_elements(partial_link_text="Python") >>> browser.get_elements(partial_text="Paragraph") >>> browser.get_elements(tag="p", min_elements=5, wait=0) >>> browser.get_elements(text="Python.org") >>> browser.get_elements(type="button") >>> browser.get_elements(value="Sometext") >>> browser.get_elements(xpath="//*[@class='para']") >>> browser.get_element(class_name="container").get_elements(tag="p")
get_input¶
-
get_input
(occurrence=1, wait=5, **kwargs)¶
Gets an input field by class, id, label, or placeholder text.
- Parameters
- occurrence
int, optional
The occurrence to get. For instance, if multiple inputs on the page meet the requirements and the 3rd one is required, set this to 3.- wait
int, optional
The time to wait, in seconds, for the input field to be found.- kwargs:
One and only one keyword argument must be supplied. Allowed keys are: “class_name”, “id”, “label”, “placeholder”.
- Returns
element
- Examples
>>> browser.get_input(class_name="input", wait=0, occurrence=2) >>> browser.get_input(id="full-name") >>> browser.get_input(label="Full name") >>> browser.get_input(placeholder="Enter your full name")
Chaining getters¶
You can chain getters together to zero in on the element or list of elements you want. Note you cannot chain another getter after get_elements.
- Examples
>>> browser.get_element(id="my-form").get_button(type="submit") >>> browser.get_element(tag="div").get_element(id="primary") >>> browser.get_element(class_name="container").get_elements(tag="p") >>> browser.get_element(tag="form").get_input(label="Full name") >>> browser.get_element(tag="select").get_element(tag="option", occurrence=3)
States¶
States functions are used to determine whether an element has a state, such as whether it is displayed or selected.
These functions operate on an element, and return a boolean.
is_displayed¶
-
is_displayed
¶
Determines whether an element is displayed to the user.
- Returns
bool
True if displayed, False otherwise.- Examples
>>> browser.get_element(id="not-hiding").is_displayed True >>> browser.get_element(id="hiding").is_displayed False
Note
is_displayed
does not work on hidden select options.
Values¶
Values functions get the value of an element, or one of it’s attributes.
These functions operate on an element or browser, and return a string or boolean.
attribute¶
-
attribute
(attribute_name)¶
Gets the value of an attribute.
- Parameters
- attribute_name
str
The name of the attribute. For instance, “hidden”, or “class”.
- Returns
str
orbool
For boolean attributes like “hidden” a boolean is returned. For other attributes a string is returned.- Examples
>>> browser.get_element(id="hiding").attribute("hidden") True >>> browser.get_element(id="my_id").attribute("id") "my_id"
html¶
-
html
¶
Gets the html for an element or whole page.
- Returns
str
The html for the element or page, as a string.- Example
>>> browser.get_element(tag="p").html "<p>This is a paragraph.</p>"
text¶
-
text
¶
Gets the text of an element.
- Returns
str
The text of the element, as a string.- Example
>>> browser.get_element(tag="p").text "This is some text"
Browser¶
The Browser
class provides the browser which drives Elemental.
The Browser class¶
-
Browser
(selenium_webdriver=None, headless=False)¶
- Parameters
- selenium_webdriver
Selenium webdriver, optional
The webdriver being used to drive the browser. Default is a Firefox webdriver.- headless
bool, optional
Whether the default webdriver will run in headless mode. Has no effect if the default webdriver is not used. Default is False.
- Example: Default browser
import elemental browser = elemental.Browser() browser.visit("https://pypi.org/project/elemental/")
- Example: Headless default browser
import elemental browser = elemental.Browser(headless=True) browser.visit("https://pypi.org/project/elemental/")
Modifying the default browser¶
The Browser
class has a selenium_webelement
property which is the
underlying Selenium webdriver.
Use that to modify the default browser when necessary.
For example, to set window size of the default webdriver:
import elemental
browser = elemental.Browser(headless=True)
browser.selenium_webdriver.set_window_size(1920, 1080)
browser.visit("https://pypi.org/project/elemental/")
Bring-your-own browser¶
To use your own browser rather than the default browser, instantiate
Browser
with a Selenium WebDriver instance as the only argument.
For example:
import elemental
import selenium
from selenium.webdriver.firefox import options as firefox_options
options = firefox_options.Options()
options.headless = True
selenium_webdriver = selenium.webdriver.Firefox(
executable_path="geckodriver",
options=options,
)
browser = elemental.Browser(selenium_webdriver)
Raw Selenium¶
You can use Elemental and still access the full power of Selenium any time you need it.
Selenium webdriver¶
Every instance of Elemental’s Browser
class has a selenium_webdriver
property which provides an instance of Selenium’s WebDriver.
It can be used like this:
import elemental
browser = elemental.Browser()
browser.visit("https://pypi.org")
# Elemental doesn't provide a way to get cookies, so use the Selenium
# webdriver's get_cookies() method.
cookies = browser.selenium_webdriver.get_cookies()
print(cookies)
Selenium webelement¶
Every instance of Elemental’s Element
class has a selenium_webdriver
property which provides an instance of Selenium’s WebDriver.
Every instance of Elemental’s Element
class also has a
selenium_webelement
property which provides an instance of the Selenium
WebElement which corresponds to its HTML element.
It can be used like this:
import elemental
browser = elemental.Browser()
browser.visit("https://pypi.org")
logo = browser.get_element(class_name="site-header__logo")
# Elemental doesn't provide a way to get the element's size, so use the
# Selenium webelement's size property.
logo_size = logo.selenium_webelement.size
print(logo_size)
Contributions are welcome¶
Adding functionality is easy¶
The Elemental source code is simple, clean and well-organised.
Take a look at it and you’ll see what we mean!
The four main modules are actions.py
, getters.py
, states.py
and
values.py
. You can guess what sort of functionality each one contains.
As a result it’s easy to work with and add to.
Pull requests are encouraged¶
If Elemental lacks some functionality which you need, fork the repo and add it in.
Then send us a pull request.
We’re friendly and happy to work with you – no matter what your level of experience – to get your PR merged into Elemental and released promptly.
Source¶
The Elemental source is available under the MIT licence.
You can find it in the Elemental repository on Github.