#
This is the latest development version
Some features documented on this page may not yet be available in the published stable version.
All = Collection
module-attribute
#
AllElements = Collection
module-attribute
#
R = TypeVar('R')
module-attribute
#
Collection
#
Bases: _WaitingConfiguredEntity
, Iterable[Element]
_locator = locator
instance-attribute
#
cached: Collection
property
#
even
property
#
A human-readable alias to [1::2], i.e. filtering collection to have only even elements
first: Element
property
#
A human-readable alias to .element(0) or [0]
odd
property
#
A human-readable alias to [::2], i.e. filtering collection to have only odd elements
second: Element
property
#
A human-readable alias to .element(1) or [1]
shadow_roots: Collection
property
#
all(selector)
#
Returns a collection of all elements found be selector inside each element of self
An alias to collection.collected(lambda its: its.all(selector))
.
Example#
Given html::
<table>
<tr class="row">
<td class="cell">A1</td><td class="cell">A2</td>
</tr>
<tr class="row">
<td class="cell">B1</td><td class="cell">B2</td>
</tr>
</table>
Then::
browser.all('.row').all('.cell')).should(have.texts('A1', 'A2', 'B1', 'B2'))
all_first(selector)
#
Returns a collection of each first element found be selector inside each element of self
An alias to collection.collected(lambda its: its.element(selector))
.
Not same as collection.all(selector).first
that is same as collection.first.element(selector)
Example#
Given html::
<table>
<tr class="row">
<td class="cell">A1</td><td class="cell">A2</td>
</tr>
<tr class="row">
<td class="cell">B1</td><td class="cell">B2</td>
</tr>
</table>
Then::
browser.all('.row').all_first('.cell')).should(have.texts('A1', 'B1'))
by(condition)
#
by_their(selector, condition)
#
Returns elements from collection that have inner/relative element,
found by selector
and matching condition
.
Is a shortcut for collection.by(lambda element: condition(element.element(selector))
.
Example (straightforward)#
GIVEN html elements somewhere in DOM:: .result .result-title .result-url .result-snippet
THEN::
browser.all('.result') .by_their('.result-title', have.text('Selene')) .should(have.size(3))
is similar to::
browser.all('.result') .by_their(lambda it: have.text(text)(it.element('.result-title'))) .should(have.size(3))
Example (PageObject)#
GIVEN html elements somewhere in DOM:: .result .result-title .result-url .result-snippet
AND::
results = browser.all('.result')
class Result:
def __init__(self, element):
self.element = element
self.title = self.element.element('.result-title')
self.url = self.element.element('.result-url')
# ...
THEN::
results.by_their(lambda it: Result(it).title, have.text(text)) .should(have.size(3))
is similar to::
results.by_their(lambda it: have.text(text)(Result(it).title)) .should(have.size(3))
collected(finder)
#
element(index)
#
element_by(condition)
#
element_by_its(selector, condition)
#
Returns element from collection that has inner/relative element
found by selector
and matching condition
.
Is a shortcut for collection.element_by(lambda its: condition(its.element(selector))
.
Example (straightforward)#
GIVEN html elements somewhere in DOM::
.result
.result-title
.result-url
.result-snippet
THEN::
browser.all('.result') .element_by_its('.result-title', have.text(text)) .element('.result-url').click()
... is a shortcut for::
browser.all('.result') .element_by(lambda its: have.text(text)(its.element('.result-title'))) .element('.result-url').click()
Example (PageObject)#
GIVEN html elements somewhere in DOM::
.result
.result-title
.result-url
.result-snippet
AND::
results = browser.all('.result')
class Result:
def __init__(self, element):
self.element = element
self.title = self.element.element('.result-title')
self.url = self.element.element('.result-url')
THEN::
Result(results.element_by_its(lambda it: Result(it).title, have.text(text))) .url.click()
is a shortcut for::
Result(results.element_by(lambda it: have.text(text)(Result(it).title))) .url.click()
# ...
filtered_by(condition)
#
from_(start)
#
locate()
#
sliced(start=None, stop=None, step=1)
#
to(stop)
#
with_(config=None, **config_as_kwargs)
#
Element
#
Bases: _LocatableEntity[WebElement]
, _WaitingConfiguredEntity
_actual_not_overlapped_webelement
property
#
cached: Element
property
#
frame_context: _FrameContext
property
#
A context manager to work with frames (iframes). Has an additional decorator to adapt context manager to step-methods when implementing a PageObject pattern. Partially serves as entity similar to Element allowing to find element or collection inside frame.
Technically it's a shortcut to _FrameContext(element)
and also is pretty similar to element.get(_FrameContext)
query.
Find more details in the _FrameContext docs.
shadow_root: _ElementsContext
property
#
wait: Wait[Element]
property
#
_actual_visible_webelement_and_maybe_its_cover(center_x_offset=0, center_y_offset=0)
#
_log_webelement_outer_html_for(element)
staticmethod
#
all(css_or_xpath_or_by)
#
clear()
#
Clears the text in a text-like field element.
Can be customized via config.wait_for_no_overlap_found_by_js
click(*, xoffset=0, yoffset=0)
#
Just a normal click with optional offset:)
By default, if not offset is asked, will wait till the element is not covered by any other element like overlays, because this is a pure Selenium WebDriver behavior.
If you start specifying offsets, then, if you still want to wait for no overlap, you should explicitly ask for it via setting to True the config.wait_for_no_overlap_found_by_js.
If you want to simulate a click via JS, by turning on the
config.click_by_js,
then unless #566 issue
is resolved, you can't wait for no overlap. After you can use
something like:
browser.element('#save').should(be.not_overlapped).with_(click_by_js=True).click()
context_click()
#
Context clicks (aka right-click to open a popup menu) on the element.
Can be customized via config.wait_for_no_overlap_found_by_js.
copy()
#
Sends «copy» OS-based keys shortcut.
See more at command.copy, that can be also applied on a "browser" level, without specifying the exact element to send shortcut to.
double_click()
#
Double clicks on the element.
Can be customized via config.wait_for_no_overlap_found_by_js.
drag_and_drop_by_offset(x, y)
#
Drags the element by the offset.
Currently, cannot be customized via config.drag_and_drop_by_js (wait for #568).
See more at command.drag_and_drop_by_offset.
drag_and_drop_to(target, /, *, _assert_location_changed=False)
#
Drags the element to the target element.
Can be customized via config.drag_and_drop_by_js. Though turning the config flag on will disable the _assert_location_changed feature (wait for #567).
See more at command.drag_and_drop_to. See also command.js.drag_and_drop_to.
drop_file(path)
#
Simulates via JS: drops file by absolute path to the element (self).
Usually is needed as a workaround for cases where there is no
input[type=file]
available to send_keys with path to the file.
Prefer the send_keys method
if possible. See also #569
See more at command.js.drop_file.
element(css_or_xpath_or_by)
#
execute_script(script_on_self, *arguments)
#
Executes JS script on self as webelement.
The script can use predefined parameters:
- element
and self
are aliases to this element handle, i.e. self.locate()
or self()
.
- arguments
are accessible from the script with same order and indexing as they are provided to the method
Examples:
browser.element('[id^=google_ads]').execute_script('element.remove()')
# OR
browser.element('[id^=google_ads]').execute_script('self.remove()')
'''
# are shortcuts to
browser.execute_script('arguments[0].remove()', browser.element('[id^=google_ads]')())
'''
browser.element('input').execute_script('element.value=arguments[0]', 'new value')
# OR
browser.element('input').execute_script('self.value=arguments[0]', 'new value')
'''
# are shortcuts to
browser.execute_script('arguments[0].value=arguments[1]', browser.element('input').locate(), 'new value')
'''
hover()
#
Hovers over the element.
Can be customized via config.wait_for_no_overlap_found_by_js.
locate()
#
paste(text=None)
#
Sends «paste» OS-based keys shortcut.
If text argument is provided, will copy it to clipboard before sending the keys shortuct.
See more at command.paste, that can be also applied on a "browser" level, without specifying the exact element to send shortcut to.
press(*keys)
#
Simulates pressing keys on the element. A human readable alternative to pure Selenium's send_keys method.
Can be customized via config.wait_for_no_overlap_found_by_js.
press_enter()
#
press_escape()
#
press_sequentially(text)
#
Presses each key (letter) in text sequentially to the element.
See more at command.press_sequentially.
press_tab()
#
s(css_or_xpath_or_by)
#
A JQuery-like alias (~ $) to Element.element(selector_or_by).
scroll_to_bottom()
#
Simulates via JS: scrolls to an element so the bottom of the element will be aligned to the bottom of the visible area of the scrollable ancestor.
See also command.scroll_into_view.
scroll_to_center()
#
Simulates via JS: scrolls to an element so the center of the element will be aligned to the center of the scrollable ancestor.
See also command.scroll_into_view.
scroll_to_top()
#
Simulates via JS: scrolls to an element so the top of the element will be aligned to the top of the visible area of the scrollable ancestor.
See also command.scroll_into_view.
select_all()
#
Sends «select all» keys shortcut as ctrl+a for Win/Linux or cmd+a for mac.
See more at command.select_all, that can be also applied on a "browser" level, without specifying the exact element to send shortcut to.
Has no "by_js" version so far (see #572)
send_keys(*value)
#
To be used for more low level operations like «uploading files», etc. To simulate normal input of keys by user when typing - consider using Element.type(self, text) that has additional customizaton to wait for the element to be not overlapped by other elements.
set(value)
#
Sounds similar to Element.set_value(self, value), but considered to be used in broader context. For example, a use can say «Set gender radio to Male» but will hardly say «Set gender radio to value Male». Now imagine, on your project you have custom html implementation of radio buttons, and want to teach selene to set such radio-button controls – you can do this via Element.set(self, value) method, after monkey-patching it according to your behavior;)
set_value(value)
#
ss(css_or_xpath_or_by)
#
A JQuery-like alias (~ $$) to Element.all(selector_or_by).
submit()
#
Submits a form-like element.
Can be customized via config.wait_for_no_overlap_found_by_js.
type(text)
#
Simulates typing text into a text-like field element. A human readable alternative to pure Selenium's send_keys method.
Will wait till the element is not covered by any other element like overlays, if config.wait_for_no_overlap_found_by_js is set to True.
with_(config=None, **config_as_kwargs)
#
_ElementsContext
#
Bases: _LocatableEntity[_SearchContext]
, _WaitingConfiguredEntity
An Element-like class that serves as pure context for search elements inside
via element(selector_or_by)
or all(selector_or_by)
methods
_FrameContext
#
A context manager to work with frames (iframes). Has an additional decorator to adapt context manager to step-methods when implementing a PageObject pattern.
Partially serves as entity similar to Element allowing to find element or collection inside frame and work with them with implicit automatic "switch into context" before any action and "switch out" after it. But this ability may reduce performance in case of "too much of actions" inside a frame. In such cases, it's better to use explicit context manager.
Note
There is a query.frame_context
alias to this class, because it can
be used as "pseudo-query": element.get(query.frame_context)
.
This context manager is already built into selene.web.Element
entity,
That's why in the majority of examples below
you will see element.frame_context
instead of _FrameContext(element)
or element.get(_FrameContext)
.
Laziness on query application#
On element.get(query.frame_context)
(or element.frame_context
)
it actually just wraps an element into context manager and so is lazy,
i.e. you can store result of such query into a variable
even before opening a browser and use it later.
Thus, unlike for other queries, there is no difference
between using the query directly as query.frame_context(element)
or via get
method as element.get(query.frame_context)
.
The "lazy result" of the query is also a "lazy search context"
similar to Element entity
– it allows to find elements or collections inside the frame
by using self.element(selector)
or self.all(selector)
methods.
This allows the easiest and most implicit way to work with frames in Selene
without bothering about switching to the frame and back:
Example: Using as "search context" with fully implicit frame management#
from selene import browser, command, have, query
...
# iframe = _FrameContext(browser.element('#editor-iframe'))
# OR:
# iframe = query.frame_context(browser.element('#editor-iframe'))
# OR:
# iframe = browser.element('#editor-iframe').get(_FrameContext)
# OR:
# iframe = browser.element('#editor-iframe').get(query.frame_context)
# OR:
iframe = browser.element('#editor-iframe').frame_context
iframe.all('strong').should(have.size(0))
iframe.element('.textarea').type('Hello, World!').perform(command.select_all)
browser.element('#toolbar').element('#bold').click()
iframe.all('strong').should(have.size(1))
Warning
But be aware that such syntax will force to switch to the frame and back for each command executed on element or collection of elements inside the frame. This might result in slower tests if you have a lot of commands to be executed all together inside the frame.
Tip
We recommend to stay
YAGNI
and use this "frame like an element context" syntax by default,
but when you notice performance drawbacks,
consider choosing an explicit way to work with frame context
as a context manager passed to with
statement
or as a decorator within
applied to step-methods of PageObject
as described below.
Laziness ends on with statement#
On passing the "lazy result" of the query to with
statement
it actually transforms from "lazy query" into "actual command",
that performs an action on the entity –
the action of switching to the element's frame
with the corresponding implicit waiting.
On exiting the with
statement it switches back to the default content,
without any additional implicit waiting.
This behavior might change in the future, and some waiting might be added.
Example: Straightforward usage of the frame context (in with statement):#
from selene import browser, query, command, have
toolbar = browser.element('.tox-toolbar__primary')
text_area_frame = browser.element('.tox-edit-area__iframe')
# the following var will only work if used after the switch to the frame ↙️
text_area = browser.element('#tinymce') # ❗️ inside the frame
browser.open('https://the-internet.herokuapp.com/iframe')
with text_area_frame.frame_context:
text_area.perform(command.select_all)
toolbar.element('[title=Bold]').click()
with text_area_frame.frame_context:
text_area.element('p').should(
have.js_property('innerHTML').value(
'<strong>Your content goes here.</strong>'
)
)
Example: Usage utilizing the lazy nature of the frame context (in with statement)#
from selene import browser, query, command, have
toolbar = browser.element('.tox-toolbar__primary')
text_area_frame = browser.element('.tox-edit-area__iframe')
text_area_frame_context = text_area_frame.frame_context # 💡↙️
# the following var will only work if used after the switch to the frame
text_area = browser.element('#tinymce') # ❗️ inside the frame
browser.open('https://the-internet.herokuapp.com/iframe')
with text_area_frame_context: # ⬅️
text_area.perform(command.select_all)
toolbar.element('[title=Bold]').click()
with text_area_frame_context: # ⬅️
text_area.element('p').should(
have.js_property('innerHTML').value(
'<strong>Your content goes here.</strong>'
)
)
Example: Usage utilizing the lazy nature of the query without get method:#
Since the query application is fully lazy
(laziness ends only on with
statement),
you can use it directly, without get
method:
from selene import browser, query, command, have
toolbar = browser.element('.tox-toolbar__primary')
text_area_frame = browser.element('.tox-edit-area__iframe')
# text_area_frame_context = _FrameContext(text_area_frame)
# OR:
text_area_frame_context = query.frame_context(text_area_frame) # 💡↙️
# the following var will only work if used after the switch to the frame
text_area = browser.element('#tinymce')
browser.open('https://the-internet.herokuapp.com/iframe')
with text_area_frame_context: # ⬅️
text_area.perform(command.select_all)
toolbar.element('[title=Bold]').click()
with text_area_frame_context: # ⬅️
text_area.element('p').should(
have.js_property('innerHTML').value(
'<strong>Your content goes here.</strong>'
)
)
Example: Nested with statements for nested frames#
from selene import browser, have, query, be
# GIVEN opened browser
browser.open('https://the-internet.herokuapp.com/nested_frames')
# WHEN
with browser.element('[name=frame-top]').frame_context:
with browser.element('[name=frame-middle]').frame_context:
browser.element(
'#content',
# THEN
).should(have.exact_text('MIDDLE'))
# AND
browser.element('[name=frame-right]').should(be.visible)
Example: Usage utilizing the within decorator for PageObjects:#
See example at within section.
_container = element
instance-attribute
#
within = decorator
class-attribute
instance-attribute
#
An alias to decorator
Example of usage:
from selene import browser, command, have, query
def teardown_function():
browser.quit()
class WYSIWYG:
toolbar = browser.element('.tox-toolbar__primary')
text_area_frame = browser.element('.tox-edit-area__iframe').frame_context # 💡⬇️
text_area = browser.element('#tinymce')
def open(self):
browser.open('https://the-internet.herokuapp.com/iframe')
return self
def set_bold(self):
self.toolbar.element('[title=Bold]').click()
return self
@text_area_frame.within # ⬅️
def should_have_text_html(self, text_html):
self.text_area.should(have.js_property('innerHTML').value(text_html))
return self
@text_area_frame.within # ⬅️
def select_all_text(self):
self.text_area.perform(command.select_all)
return self
@text_area_frame.within # ⬅️
def reset_to(self, text):
self.text_area.perform(command.select_all).type(text)
return self
def test_page_object_steps_within_frame_context():
wysiwyg = WYSIWYG().open()
wysiwyg.should_have_text_html(
'<p>Your content goes here.</p>',
).select_all_text().set_bold().should_have_text_html(
'<p><strong>Your content goes here.</strong></p>',
)
wysiwyg.reset_to('New content').should_have_text_html(
'<p><strong>New content</strong></p>',
)
all(selector)
#
Allows to search for all elements by selector inside the frame context with implicit switching to the frame and back for each method execution.
Is lazy, i.e. does not switch to the frame immediately on calling this method, and so can be stored in a variable and used later.
Parameters:
-
selector
(str | Tuple[str, str]
) –css or xpath as string or classic selenium tuple-like locator, e.g.
('css selector', '.some-class')
or(By.CSS_SELECTOR, '.some-class')
Warning
Same "potential performance drawbacks" warning is applied here as for element method.
decorator(func)
#
A decorator to mark a function as a step within context manager
See example of usage at within section.
element(selector)
#
Allows to search for a first element by selector inside the frame context with implicit switching to the frame and back for each method execution.
Is lazy, i.e. does not switch to the frame immediately on calling this method, and so can be stored in a variable and used later.
Parameters:
-
selector
(str | Tuple[str, str]
) –css or xpath as string or classic selenium tuple-like locator, e.g.
('css selector', '.some-class')
or(By.CSS_SELECTOR, '.some-class')
Warning
By adding implicit switching to the frame and back for each command executed on entity, it makes the usage of such entity slower in case of a lot of commands to be executed all together inside the frame.
It becomes especially important in case of nested frames.
In such cases, if you use
entity.get(query.frame_context)
over query.frame_context(entity)
or entity.frame_context
then try to keep turned on the option:
config._disable_wait_decorator_on_get_query
That will help to avoid re-switching at least on get
calls.
If you notice performance drawbacks, consider choosing an explicit way
to work with frame context as a context manager passed to with
statement.