Skip to main content

Persona DSL - Framework for implementing Screenplay pattern in Python tests

Project description

persona-dsl: фреймворк для автотестов на Python

persona-dsl — это библиотека для E2E-, API- и интеграционных тестов, построенная вокруг Screenplay-подхода и тесно связанная с runtime/discovery/tooling, которые использует TaaS.

Установка

pip install persona-dsl
python -m playwright install --with-deps

Базовая модель

Публичный слой строится вокруг:

  • Persona
  • top-level test_* сценариев в scenarios/**
  • directory-level __suite__.py
  • Ops
  • Step
  • CombinedStep
  • алиасов Action, Fact, Expectation, Goal
  • Page и Element

Skills и resources

Skill остаётся низкоуровневой capability-границей runtime: browser, api, db, kafka и другие интеграции. Тестовый сценарий по-прежнему получает только persona: Persona, а reusable domain-объекты поверх skills поднимаются через native resource-layer.

Базовое правило такое:

  • persona.skill(...) для прямого доступа к capability
  • persona.resource(...) для typed/reusable объектов проекта
  • lifecycle hooks для setup/cleanup orchestration

Ресурсы объявляются в support/resources/** или scenarios/**/support/resources/**:

from persona_dsl import Persona, define_resource


@define_resource("workspace.dashboard", scope="test")
def workspace_dashboard(persona: Persona):
    browser = persona.skill("browser")
    browser.page.goto("/dashboard")
    yield {"page": browser.page}

Использование в сценарии остаётся persona-centric:

from persona_dsl import Persona


def test_dashboard(persona: Persona) -> None:
    dashboard = persona.resource("workspace.dashboard")
    assert dashboard["page"] is not None

scope="test" очищается после attempt, scope="session" живёт до закрытия runtime session, а scope="worker" переиспользуется между сценариями внутри одного worker launch-а. Это покрывает основную полезную часть fixture-like поведения, но без fixture injection в сигнатуру сценария.

Инженерный контракт

В persona-dsl жёстко зафиксирован contract по длине файлов:

  • рабочая цель для production и verification модулей — держать файл в диапазоне 300-400 строк;
  • после 300 строк файл считается кандидатом на разбиение;
  • 500 строк — жёсткий предел;
  • всё, что временно не помещается в лимит, должно быть явно перечислено в scripts/file_length_policy.toml как tracked overflow-долг.

Проверка выполняется через:

make structure-policy

Это правило распространяется на src/persona_dsl/** и tests/**, включая TypeScript-часть runtime.

from __future__ import annotations

from persona_dsl import Persona, story, title
from persona_dsl.expectations.generic import IsEqualTo
from persona_dsl.ops.web import Click, CurrentPath, Fill, NavigateTo
from persona_dsl.pages import Button, Page, TextField


class LoginPage(Page):
    expected_path = "/login"

    username = TextField(name="username", accessible_name="Логин")
    password = TextField(name="password", accessible_name="Пароль")
    submit_button = Button(name="submit_button", accessible_name="Войти")


@story("Авторизация")
@title("Логин пользователя")
def test_login(persona: Persona) -> None:
    login_page = LoginPage()
    persona.parameter("env", persona.runtime.env)

    with persona.step("Авторизоваться под admin"):
        persona.make(
            NavigateTo(login_page),
            Fill(login_page.username, "admin"),
            Fill(login_page.password, "secret"),
            Click(login_page.submit_button),
        )
        current_path = persona.get(CurrentPath())
        persona.check(current_path, IsEqualTo("/dashboard"))

Страницы и элементы

Page наследуется от Element и добавляет:

  • expected_path
  • default_query_params
  • build_url(base_url=None)

Element поддерживает:

  • declarative class attrs
  • aria_ref
  • multi-strategy resolve
  • .using(...), .robust(), .resolve_or(...)
  • ElementList
  • Table и declarative table DSL

VirtualPage используется для динамической in-memory модели страницы.

Генерация page object'ов

PageGenerator и GeneratePageObject генерируют declarative page objects.

Для обычных generated страниц текущий контракт такой:

  • committed generated file не содержит def __init__(...)
  • не содержит self.add_element(...)
  • не содержит self.add_element_list(...)
  • хранит expected_path, snapshot/screenshot paths и aria_ref
  • для повторяющихся анонимных контролов может выпускать declarative group, доступную по индексу как page.otp_kod[0]
  • внутри таких групп item-level aria_ref может намеренно отсутствовать, чтобы resolve шёл через container scope и role + index
  • поддерживает merge/regeneration
  • использует footer-секции unresolved/archived diagnostics

CLI:

persona-page-gen --url http://localhost:8080 --output support/pages/home_page.py

Сгенерированный файл не считается исключением из структурного контракта. Если page object растёт, его нужно дробить:

  • выделять отдельные Page/Section/Table по доменным зонам экрана;
  • генерировать несколько page-файлов вместо одного монолита по всей странице;
  • выносить повторяющиеся блоки в переиспользуемые sections/components;
  • для schema/codegen разбивать входные XSD/API-пакеты по доменным границам, а не наращивать один огромный generated module.

Из сценария:

from persona_dsl import Persona
from persona_dsl.ops.web import GeneratePageObject, NavigateTo


def test_generate_home_page(persona: Persona) -> None:
    with persona.step("Открыть страницу и сгенерировать page object"):
        persona.make(NavigateTo("/"))
        persona.make(
            GeneratePageObject(
                class_name="HomePage",
                output_path="support/pages/home_page.py",
                wait_for_state="networkidle",
                sleep_before=1,
            )
        )

Таблицы

Актуальный table contract включает:

  • Column(...)
  • TableColumn
  • table.filters.*
  • row.elements.*
  • row.element(column)
  • row.value(column)
  • row.details
  • table.select_all_checkbox

Generator использует этот DSL и для обычных, и для сложных таблиц.

Конфигурация

Для новых native-проектов Persona authoring contract строится вокруг:

  • pyproject.toml
  • config/{env}.yaml
  • scenarios/
  • scenario_data/
  • support/

Минимальный pyproject.toml для native-проекта теперь фиксирует:

  • [project].name как project_id
  • [tool.persona].default_env
  • [tool.persona].default_role_id

Если проекту нужны default bindings для навыков, они задаются там же:

  • [tool.persona.skills.by_role.<role_id>] для role-specific overrides

persona run использует этот контракт как единственный source of truth для стартовых skill-profile bindings, а реальные настройки ролей и профилей по-прежнему берёт из config/{env}.yaml.

Основные команды:

persona run --project-root .
persona run --project-root . --include-tag smoke
persona run --project-root . --scenario-id checkout.matrix --variant-id guest
persona launch start --project-root . --max-workers 8
persona launch start --project-root . --scenario-id checkout.matrix --variant-id auth
persona launch list --project-root .
persona launch status --project-root .
persona launch workers --project-root . --launch-id <launch_id>
persona launch watch --project-root .
persona launch pause --project-root . --launch-id <launch_id>
persona launch resume --project-root . --launch-id <launch_id>
persona launch cancel --project-root . --launch-id <launch_id>
persona launch cancel-item --project-root . --launch-id <launch_id> --work-item-id <scenario_id>::<variant_id>
persona launch terminate --project-root . --launch-id <launch_id>
persona launch scale --project-root . --launch-id <launch_id> --max-workers 4
persona launch rerun-failed --project-root . --launch-id <launch_id> --max-workers 2
persona launch retry-stuck --project-root . --launch-id <launch_id> --max-workers 2
persona report info --project-root . --launch-id <launch_id>
persona report serve --project-root . --launch-id <launch_id>

persona run использует native discovery, canonical execution journal и изолированный Allure export adapter вне execution path. persona launch * позволяет запускать detached launch в фоне, читать realtime snapshot состояния, следить за journal.jsonl, смотреть worker pool, pause/resume dispatch, запрашивать graceful cancel, делать hard terminate, менять active worker limit и поднимать recovery launch по failed/stuck подмножеству. Для data-driven native-сценариев раннер также поддерживает фильтрацию по variant_id через --variant-id. Публичный execution-контракт для новых и мигрированных проектов строится вокруг native scenario_id, persona run, persona launch * и run_scenario в MCP.

Если нужен локальный генератор страниц или шаблонный проект, ориентируйтесь на example_template/templates/persona_project_starter.

Где смотреть дальше

Полная пользовательская карта Persona DSL живёт именно в starter template: там для каждого публичного capability указан конкретный test_*, соседний README и support-layer файл, включая lifecycle/retry, resources, browser/UI, service skills, tooling, local launch UX и report surface.

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

persona_dsl-2026.4.19rc156.tar.gz (464.3 kB view details)

Uploaded Source

Built Distribution

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

persona_dsl-2026.4.19rc156-py3-none-any.whl (590.3 kB view details)

Uploaded Python 3

File details

Details for the file persona_dsl-2026.4.19rc156.tar.gz.

File metadata

  • Download URL: persona_dsl-2026.4.19rc156.tar.gz
  • Upload date:
  • Size: 464.3 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.13

File hashes

Hashes for persona_dsl-2026.4.19rc156.tar.gz
Algorithm Hash digest
SHA256 ded956220946a59ccf8a74239c9827a27a55966bed2000a979f7979a3421cef0
MD5 8309fea2a2b292804b96e8fa6a917473
BLAKE2b-256 748e1471ee5e8d2d34513670f49acbfeaab9b37fa2eb18d5739a35a3a7e6eb1f

See more details on using hashes here.

File details

Details for the file persona_dsl-2026.4.19rc156-py3-none-any.whl.

File metadata

File hashes

Hashes for persona_dsl-2026.4.19rc156-py3-none-any.whl
Algorithm Hash digest
SHA256 318ccfacc46955163f1847e0fc67c0999f3e0d25a5fa582357005253874ba452
MD5 7b504738aae5d90d0b7365f7c2276693
BLAKE2b-256 7a5765f25a788c620ea21c83ada4c3ac5a0f85f84b9d0e9c3c6f564e458df42d

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