Selenium integration for the tquality test automation framework, built on tquality-py-core.
Project description
tquality-py-selenium
Languages: English · Русский
Selenium integration built on top of tquality-py-core.
Components
SeleniumConfig— extension ofBaseConfigwith abrowserselector field and separate nested blockschrome,firefox,edge,safari,undetected_chrome(all blocks coexist), plus a nestedscreencastblock for step video recording.BrowserType— enum:chrome,firefox,edge,safari,undetected-chrome. Per-OS availability is checked byOSUtilsat browser startup (with an immediate failure on mismatch).BaseElementand the typed subclassesButton,Input,CheckBox,Labelwith a full surface:click,text,get_attribute,wait_until_*,js_actions(lazily bound to the element).BaseForm— page base class withtitle,current_url,element_factory(resolved via the composition root).SeleniumServices— composition root (adependency-injectorcontainer). Subclass it to add or replace any service.
Services
BrowserService—WebDriverwrapper; parameters are taken fromconfig.active_browser.Waiter,ElementWaiter— explicit waits at the page and element level.ElementFactory— element factory.JsActions+ElementJsActions— JavaScript actions on the page and on individual elements.CollectionFactory— Pydantic-model collection factory backed by the DOM (+DomField.css/xpath).SeleniumScreenshotProvider— screenshots for steps at theCRITICALlog level.SeleniumScreencastProvider— webm video recording (VP9 via imageio-ffmpeg) for steps atWITH_SCREENCAST.
Requirements
- Python 3.12+
- Installed browsers (for tests against a real driver).
Installation
The package is published to public PyPI. This is the recommended installation path for all consumers:
pip install tquality-py-selenium
Or in pyproject.toml:
dependencies = [
"tquality-py-selenium>=0.1.5",
]
Alternative: install from the GitHub mirror
For a source build (e.g., to verify a commit that has not yet been released), the package is also available by git tag from the public GitHub mirror:
dependencies = [
"tquality-py-selenium @ git+https://github.com/Tquality-ru/tquality-py-selenium.git@v0.1.5",
]
Direct git references require [tool.hatch.metadata] allow-direct-references = true on the consumer's side.
Quick start
# conftest.py
import pytest
from tquality_selenium import SeleniumServices
# Composition root. config_dir defaults to the directory of this file,
# so config.json5 next to conftest.py is picked up regardless of the
# current working directory.
SeleniumServices.setup()
@pytest.fixture(autouse=True)
def browser():
SeleniumServices.browser()
yield
SeleniumServices.browser().quit()
SeleniumServices.browser.reset()
SeleniumServices.logger.reset()
# pages/login_page.py
from tquality_selenium import BaseForm, By
class LoginPage(BaseForm):
def __init__(self) -> None:
self._username = self.element_factory.input(
By.id("username"), "Username",
)
self._password = self.element_factory.input(
By.id("password"), "Password",
)
self._submit = self.element_factory.button(
By.id("login-btn"), "Sign in",
)
super().__init__(unique_element=self._username, name="Login page")
def login(self, username: str, password: str) -> None:
self._username.type_text(username)
self._password.type_text(password)
self._submit.click()
// config.json5 — next to conftest.py
{
"$schema": "https://cdn.jsdelivr.net/gh/Tquality-ru/tquality-py-selenium@v0.1.4/schema/config.schema.json",
"base_url": "https://example.com",
"browser": "chrome",
"highlight_elements": true, // red outline during interactions
// All browsers are pre-configured — switching is a single line above.
"chrome": { "headless": true },
"firefox": { "headless": true },
"undetected_chrome": { "headless": false },
"screencast": {
"fps": 10,
"frame_interval": 0.1, // captures short UI states more often
},
}
Extending via subclasses of SeleniumServices
To add custom services, subclass SeleniumServices. The scope is
defined by the dependency-injector provider type (and where it is
reset in fixtures):
| Scope | Provider | Lifetime |
|---|---|---|
| global | providers.Singleton |
One instance per pytest process. |
| session | providers.ContextLocalSingleton + reset in a scope="session" fixture |
One instance per session, reset on exit. |
| test | providers.ContextLocalSingleton + reset in an autouse=True fixture |
A new instance per test. |
| transient | providers.Factory |
A fresh instance on every services.my_service() call. |
# my_project/services.py
from dependency_injector import providers
from tquality_selenium import SeleniumServices
from my_project.clients import ApiClient, CurrentUser, TempDirFactory
class ProjectServices(SeleniumServices):
# Global: one API client per process.
api_client = providers.Singleton(ApiClient)
# Session: data shared across all tests of a single run.
session_data = providers.ContextLocalSingleton(SessionData)
# Test: fresh state per test.
current_user = providers.ContextLocalSingleton(CurrentUser)
# Transient: a fresh instance on every access.
temp_dir = providers.Factory(TempDirFactory)
# Replacing an existing service (referencing the parent's config):
# browser = providers.ContextLocalSingleton(
# MyBrowserService, config=SeleniumServices.config,
# )
# conftest.py
import pytest
from my_project.services import ProjectServices
ProjectServices.setup()
@pytest.fixture(autouse=True)
def _reset_test_scoped_services():
"""Test-scoped ContextLocalSingleton instances are reset after each test."""
yield
ProjectServices.current_user.reset()
@pytest.fixture(scope="session", autouse=True)
def _reset_session_scoped_services():
"""Session-scoped ContextLocalSingleton instances are reset at the end of the pytest session."""
yield
ProjectServices.session_data.reset()
@pytest.fixture(autouse=True)
def browser():
ProjectServices.browser()
yield
ProjectServices.browser().quit()
ProjectServices.browser.reset()
ProjectServices.logger.reset()
Resolving a service by type, without referencing the provider name — useful inside elements and forms that don't see the concrete subclass:
from tquality_selenium import SeleniumServices
from my_project.clients import ApiClient
client = SeleniumServices.get_service(ApiClient)
get_service goes to the active composition root (the one whose
setup() was called last), so providers replaced in a subclass are
resolved transparently.
Step video recording
from tquality_selenium import LogLevel, step
def login():
with step("Sign in", level=LogLevel.WITH_SCREENCAST):
...
# An attached webm of the whole step is added to the allure report.
Capture runs in a background thread with contextvars.copy_context()
so a second WebDriver session is not opened. The frame-capture
strategy is BiDi → CDP → classic get_screenshot_as_png (with a
warning on fallback).
Development
See CONTRIBUTING.md.
Version history
See CHANGELOG.md.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file tquality_py_selenium-0.1.6.tar.gz.
File metadata
- Download URL: tquality_py_selenium-0.1.6.tar.gz
- Upload date:
- Size: 64.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.9.30 {"installer":{"name":"uv","version":"0.9.30","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Debian GNU/Linux","version":"12","id":"bookworm","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
ee217525e741693dc05f93bb99cc4f34270515e6fcf62a6093e0a03606b99dc3
|
|
| MD5 |
31f7476c00e6eacf1a392f98c8460511
|
|
| BLAKE2b-256 |
95dbbb9575bc039cbb9d1c3230307e4f496f223af53b7be202506977b7347ce1
|
File details
Details for the file tquality_py_selenium-0.1.6-py3-none-any.whl.
File metadata
- Download URL: tquality_py_selenium-0.1.6-py3-none-any.whl
- Upload date:
- Size: 49.2 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.9.30 {"installer":{"name":"uv","version":"0.9.30","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Debian GNU/Linux","version":"12","id":"bookworm","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
dee327414e5a17ceb6564ad9c8fa4eadf3182c17cb789451b2e398bc068bfba4
|
|
| MD5 |
233cf609dfd4c78db1d915cd5d27d403
|
|
| BLAKE2b-256 |
78bcc698af3097c298ffdca92ab20be32ff684280ec739e8a1be809bb38dbd62
|