split selene.core into selene.web & selene.mobile
This is about keeping selene.core.Element & Co as "versatile general elements to work on all platforms", but extending it additionally with correspondent web and mobile versions
These commits were already made in context of this feature:
Oct 24, 2024 NEW: appium device support (POC) Oct 24, 2024 REFACTOR: device platform-processing to be more lazy
Jan 29, 2025 NEW: core to web + mobile split
- copy&paste Browser, Element, Collection into selene.web.*
core._browser.Browser(that will be now a "core general context" and should work for all platforms, that's why we don't need the following...):- remove:
execute_scriptsave_screenshotlast_screenshotsave_page_sourcelast_page_sourceclose_current_tabclear_local_storageclear_session_storage
- deprecate:
switch_to_next_tabswitch_to_previous_tabswitch_to_tabswitch_to
- remove:
Jan 30, 2025 NEW: core to web + mobile split
- extend web.Element with more web-specific commands
- element.shadow_root based on
weblement.shadow_root- wrapped as _SearchContext class object with only .element and .all methods
- collection.shadow_roots based on webelement.shadow_root
- element.frame_context
- element.shadow_root based on
Feb 01, 2025 NEW: core to web + mobile split
- extend web.Element with more web-specific commands
More commands among browser.element(selector).*
press_sequentially(text)select_all()drag_and_drop_to(target, _assert_location_changed=False)- with option to
.with(drag_and_drop_by_js=True).drag_and_drop_to(target)
- with option to
drag_and_drop_by_offset(x, y)drop_file(path)scroll_to_top()scroll_to_bottom()scroll_to_center()
Feb 03, 2025 NEW: command.paste, command.paste(text)
- the corresponding methods built into web.Element
Here goes the discussion happened in Selene chat.
Yasha, [31.01.2025 17:31]
💡 Hey everyone!
I’ve slowly started setting aside time to prepare for the next release again. And I’d like to consult with you a bit—especially with the more active and experienced among you. (I’ll still do everything my own way 😇, but your ideas will help me make a more informed decision…)
Big changes are coming!
We’ll try to ensure they remain backward compatible (so far, I don’t see any major issues—everything should work out fine).
These changes are more conceptual. As you may remember, I’ve been keeping Selene elements platform-agnostic for a long time. I didn’t add commands to elements if they worked only for mobile or only for web—such commands had to be explicitly called, for example:
.perform(command._long_press)
With Config, it’s a different story—it’s a collection of various options, and some of them can break mobile tests if enabled. That’s why we have to be careful and avoid enabling, for instance, JS-oriented options for mobile tests. That part will likely remain unchanged since restructuring it and creating separate configs for different platforms would be too complex for now.
The new approach to elements and the browser object
I’ve decided to expand the concept.
✅ For mobile testing, there will now be a separate object instead of browser—it will be device. It’s already available! If you want to try it, you can install Selene from the sources on GitHub. Live examples: https://github.com/automician/python-mobile-test-template
So, the elements obtained from device: • device.element(selector) and device.all(selector) will be mobile elements • They’ll have their own commands like long_press, tap (and later, we’ll add swipe, etc.).
✅ Web elements will also get new capabilities: • Additional commands like drag_and_drop, drop_file, etc. • Built-in support for shadow_root and frame_context—this will work out of the box for elements. • These elements will still be accessed via:
browser.element(selector) browser.all(selector)
What about cross-platform elements?
We will keep “general-purpose” elements for those writing cross-platform tests that need to work across all platforms.
The first open question—how should we access them? We need to come up with a good name.
Right now, I’m considering:
context.element(selector) context.all(selector)
The term context has been used in some libraries for this purpose, as it’s broader than browser or device.
However, there’s a small issue: • Context is actually something even broader… • If you think about it, Config already plays the role of context—it stores the entire setup for interacting with the driver, including the driver instance, options, and management logic. • If I were naming Config now, I might have called it Context, but it’s probably too late for that. • Also, in Playwright, context refers to a private browser session, which doesn’t quite align with our use case.
Alternative names?
Maybe view? Maybe page? But page might feel odd for mobile since mobile UI usually refers to a screen… which is why I’m leaning toward view, as it unites both page and screen.
What do you think? 🤔
🚨 The Second (Even More Important) Question 🚨
What should we do with:
from selene import Element, Collection
These classes already exist and currently represent general-purpose elements.
At the same time, when we import:
from selene import browser
the browser object will now be web-focused, providing only web.Element and web.Collection.
So the question is: Should we replace the current Element and Collection (imported from selene) with their expanded web versions, or should we keep them as general-purpose versions and require a different import for web-specific elements?
Two Possible Approaches:
Option A: • Element and Collection in from selene import ... remain cross-platform • Web-specific elements are imported separately
from selene import browser
from selene.web import Element, Collection
my_web_element: Element = browser.element('#some-id')
from selene import context, Element, Collection
my_cross_platform_element: Element = context.element('#some-id')
➡ This approach allows for a clean structure: ✅ selene.Element is the most generic version ✅ If needed, you can import specialized versions (web.Element, mobile.Element) ✅ Consistent and logically correct
import selene
my_cross_platform_element: selene.Element # The core, universal Selene element
➡ However, it might not be the most convenient for the majority of users.
Option B: • Element and Collection in from selene import ... become web-focused • Cross-platform elements require explicit imports
from selene import browser, Element, Collection
my_web_element: Element = browser.element('#some-id')
from selene import context
from selene.core import Element, Collection
my_cross_platform_element: Element = context.element('#some-id')
➡ This means that most users (who use Selene for web) will get expanded web elements by default. ✅ More convenient for the majority of users (web testers) ✅ No breaking changes for web testers—things just get better ✅ Mobile testers will only need a simple find & replace (browser → device)
⚠️ BUT: • Cross-platform testers will need to refactor their code more urgently.
Which One Is Better? 🤔
✅ Option A feels more conceptually correct—it keeps selene.Element as the base and allows explicit imports for extended versions. ✅ Option B is more practical for most users—since most people use Selene for web testing, it makes sense for Element to default to web.Element.
Final Thought:
If we prioritize "kind of cleaner" architecture, Option A is better. If we prioritize ease of transition for most users, Option B is better.
What would you choose? 😃
Aleksandr SanKolts, [31.01.2025 17:42]
context is not recommended, as it is widely used in behave (https://github.com/behave/behave) for many functions, and having to write import context as selene_context everywhere would be annoying. Maybe it’s better to play around with “client” instead?
Do we have any statistics on Selene usage for web/mobile/mobile+web? I think the decision should be based on that—let those with the rarest use cases be the ones who have to refactor the most. 😃
Yasha, [31.01.2025 17:59]
Oh, that’s a solid argument about the conflict with behave… client—hmm, actually looks pretty good!
There are no statistics… and I’m not sure how to collect them effectively, apart from just asking in this chat. :) But I think it wouldn’t be too different from my hypothesis: • Most users use Selene only for web. • A smaller group uses it for mobile or both web and mobile. • Almost no one bothers with true cross-platform tests (because it’s complicated and doesn’t always work out—usually, it’s easier to maintain separate test sets for each platform).
Here are results from the Poll in chat (48 votes):
I use selene...
- 79% only for web
- 2% only for mobile
- 11% for web and mobile (separate sets of tests)
- 2% cross-platform tests (same test can be run on web and mobile)
- 6% in some other way...
Volodymyr Datsenko, [31.01.2025 18:19]
mobile.element
web.element
Seems much clearer to me :)
Yasha, [31.01.2025 18:30]
I also considered such names… but something put me off. Wish I could remember what…
Maybe it’s the fact that Selenium already defines a WebElement type. Though, maybe it wouldn’t cause much confusion… or maybe it would.
Right now, in Selene, we have:
browser.element(selector).locate() # returns a WebElement
Which could lead to something like this:
submit_button: web.Element = web.element('#submit')
submit_web_element: WebElement = submit_button.locate()
# or:
submit_web_element: WebElement = web.element('#submit').locate()
Though, this would be quite rare… Usually, we don’t really need “pure” WebElements. Heh, not sure…
Maybe mobile and web are better suited as package names, where we collect all implementations for the respective platform. And for objects that act as the “root” for element searches, we should pick more specific names like browser, device, and so on… (client for a cross-platform object).