dodil/erp-platform

src/erp_platform/scenarios/__init__.py

"""scenarios — SAP-grade end-to-end scenarios, written ONCE, run two ways: in process (the whole composition,
seconds, with the clock and failures under control) and live (a real deployment, as real people).

A scenario is a plain Python function over a run context, with its Given / When / Then written as words a
functional consultant reads in the report, and its steps going ONLY through the composition's doors — HTTP
routes, MCP tools, public links. Never a table write: a scenario that wrote rows would test the rows, not the
product, and could not run live.

    from decimal import Decimal
    from erp_platform.scenarios import Catalogue

    CAT = Catalogue("orders", compose=HERE / "compose.yaml", roles=HERE / "roles.yaml",
                    ticks=["POST /orders/tick"], tick_as="ticker", clock="orders")

    @CAT.scenario("SC-OR-02", "an order placed on Friday is due 09:00 London time three working days later",
                  stories=["OR-03"], tags=["clock"], personas=["clerk"])
    def due_across_dst(s):
        s.given("it is Friday 23 October 2026, 10:00 in London — British Summer Time ends on Sunday")
        s.clock.set("2026-10-23T10:00 Europe/London")
        s.when("a clerk places an order")
        r = s.as_("clerk").post("/orders/orders", {"order_id": s.key("O"), "customer": "Acme", "lines": [...]})
        s.then("it is due Wednesday 09:00 GMT, which is 09:00Z — not 08:00Z")
        r.ok().field("due_at", "2026-10-28T09:00:00Z").field("total", Decimal("99.99"))

WHY PYTHON, NOT YAML. Scenarios carry values forward (the id step 1 made is what step 4 approves), poll
("eventually"), run things at once and reach for helpers; a YAML DSL would grow its own expression language
for each of those, and be worse at all of them. The consultant's view is not lost: the s.given / s.when /
s.then sentences and every request are what the Markdown report prints, in order, under the scenario's id and
story references — the catalogue reads as the spec it came from (module.yaml tests: SC-<MODULE>-nn).

Modules: core (the DSL, responses and assertions), personas (role catalogue, live credentials), inprocess
(runner + failure injection), live (runner), probes (generated permission / idempotency / mass-assignment
tests), report (console, JUnit, Markdown), gateway (a local issuer + gateway stand-in), cli (`erp-scenarios`).
"""
from erp_platform.scenarios.core import (Actor, Catalogue, Response, Responses, Result, Run, Runner, Scenario,
                                         ScenarioFailed, Skip)
from erp_platform.scenarios.personas import RoleCatalogue
from erp_platform.scenarios.probes import Rows

__all__ = ["Actor", "Catalogue", "Response", "Responses", "Result", "RoleCatalogue", "Rows", "Run", "Runner",
           "Scenario", "ScenarioFailed", "Skip"]