Skip to main content

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 of BaseConfig with a browser selector field and separate nested blocks chrome, firefox, edge, safari, undetected_chrome (all blocks coexist), plus a nested screencast block for step video recording.
  • BrowserType — enum: chrome, firefox, edge, safari, undetected-chrome. Per-OS availability is checked by OSUtils at browser startup (with an immediate failure on mismatch).
  • BaseElement and the typed subclasses Button, Input, CheckBox, Label with a full surface: click, text, get_attribute, wait_until_*, js_actions (lazily bound to the element).
  • BaseForm — page base class with title, current_url, element_factory (resolved via the composition root).
  • SeleniumServices — composition root (a dependency-injector container). Subclass it to add or replace any service.

Services

  • BrowserServiceWebDriver wrapper; parameters are taken from config.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 the CRITICAL log level.
  • SeleniumScreencastProvider — webm video recording (VP9 via imageio-ffmpeg) for steps at WITH_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


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

tquality_py_selenium-0.1.6.tar.gz (64.1 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

tquality_py_selenium-0.1.6-py3-none-any.whl (49.2 kB view details)

Uploaded Python 3

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

Hashes for tquality_py_selenium-0.1.6.tar.gz
Algorithm Hash digest
SHA256 ee217525e741693dc05f93bb99cc4f34270515e6fcf62a6093e0a03606b99dc3
MD5 31f7476c00e6eacf1a392f98c8460511
BLAKE2b-256 95dbbb9575bc039cbb9d1c3230307e4f496f223af53b7be202506977b7347ce1

See more details on using hashes here.

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

Hashes for tquality_py_selenium-0.1.6-py3-none-any.whl
Algorithm Hash digest
SHA256 dee327414e5a17ceb6564ad9c8fa4eadf3182c17cb789451b2e398bc068bfba4
MD5 233cf609dfd4c78db1d915cd5d27d403
BLAKE2b-256 78bcc698af3097c298ffdca92ab20be32ff684280ec739e8a1be809bb38dbd62

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page