Pytest plugin for UReport — ships test results automatically
Project description
ureport-pytest-reporter
A pytest plugin that automatically ships test results to UReport after every test run. Zero code changes required in your tests — configure once and it hooks into pytest's lifecycle automatically.
Installation
pip install ureport-pytest-reporter
Quick Start
Add the following to your pytest.ini or pyproject.toml:
# pytest.ini
[pytest]
ureport_server_url = http://your-ureport-server:4100
ureport_api_token = your-api-token
ureport_product = MyProduct
ureport_type = E2E
# pyproject.toml
[tool.pytest.ini_options]
ureport_server_url = "http://your-ureport-server:4100"
ureport_api_token = "your-api-token"
ureport_product = "MyProduct"
ureport_type = "E2E"
That's it. Run pytest as normal — results are submitted to UReport at the end of the session.
Configuration Reference
Required
| Option | Env Variable | Description |
|---|---|---|
ureport_server_url |
UREPORT_SERVER_URL |
UReport server base URL |
ureport_api_token |
UREPORT_API_TOKEN |
API token from UReport → User Settings → API Token |
ureport_product |
UREPORT_PRODUCT |
Product name in UReport (groups tests across builds) |
ureport_type |
UREPORT_TYPE |
Build type: E2E, API, UI, or any custom string |
Build Metadata (Optional)
| Option | Env Variable | Default | Description |
|---|---|---|---|
ureport_build_number |
UREPORT_BUILD_NUMBER |
current timestamp | CI build / run number. Use your CI's build ID (e.g. $GITHUB_RUN_NUMBER) to correlate runs |
ureport_team |
UREPORT_TEAM |
— | Team name for organisational tracking |
ureport_browser |
UREPORT_BROWSER |
— | Browser name (e.g. CHROME, FIREFOX) |
ureport_device |
UREPORT_DEVICE |
— | Device name (e.g. DESKTOP-WINDOWS, MOBILE-PIXEL 5) |
ureport_platform |
UREPORT_PLATFORM |
auto-detected | OS platform (darwin, linux, win32) |
ureport_platform_version |
UREPORT_PLATFORM_VERSION |
auto-detected | OS release version |
ureport_stage |
UREPORT_STAGE |
— | Deployment stage (e.g. staging, prod) |
ureport_version |
UREPORT_VERSION |
— | Application version under test |
Behaviour (Optional)
| Option | Default | Description |
|---|---|---|
ureport_batch_size |
50 |
Number of tests per POST request to UReport |
ureport_include_steps |
true |
Send step-level detail (steps added via step()) |
ureport_include_screenshots |
true |
Embed screenshots as base64 in step payloads |
ureport_save_relations |
true |
Save test metadata (tags, components, teams) for cross-run tracking |
ureport_auto_detect_platform |
true |
Auto-detect platform and platform_version from the OS |
ureport_auto_token |
true |
Auto-derive a failure token (path/to/file.py:line) from the stack trace |
ureport_output_file |
— | Write the full submitted payload to this JSON file (useful for debugging) |
ureport_quick_info_markers |
— | Space-separated marker names stored as quick-info (execution-specific, never saved to relations) |
Environment Variables
All required and build metadata options can be set via environment variables. Environment variables take priority over ini options. This is the recommended approach for CI/CD pipelines:
export UREPORT_SERVER_URL=http://your-ureport-server:4100
export UREPORT_API_TOKEN=your-api-token
export UREPORT_PRODUCT=MyProduct
export UREPORT_TYPE=E2E
export UREPORT_BUILD_NUMBER=$GITHUB_RUN_NUMBER
export UREPORT_STAGE=staging
Adding Steps
Use the step() context manager to add named steps to your tests. Steps appear in UReport's step comparison view and can be nested.
from ureport_reporter import step
def test_user_checkout():
with step("Login"):
page.goto("/login")
page.fill("#email", "user@example.com")
page.fill("#password", "secret")
page.click("button[type=submit]")
with step("Add item to cart"):
page.click(".product-card:first-child .add-to-cart")
with step("Verify cart badge"): # nested step
assert page.locator(".cart-count").inner_text() == "1"
with step("Checkout"):
page.click(".checkout-btn")
page.fill("#card-number", "4242424242424242")
page.click("#pay-now")
assert page.locator(".order-confirmation").is_visible()
Steps are automatically routed to the correct section based on the pytest phase they run in:
- Steps inside fixtures with
autouse/setup scope →setupsection - Steps inside the test body →
bodysection - Steps inside teardown fixtures →
teardownsection
Attaching Files
Use attach() to attach screenshots, API responses, or any content to the current step (or directly to the test if no step is active).
from ureport_reporter import step, attach
def test_api_response():
with step("Call /api/users"):
response = requests.get("/api/users")
attach("response_body", body=response.content, content_type="application/json")
attach("request_curl", body=b"curl -X GET /api/users", content_type="text/x-curl")
assert response.status_code == 200
def test_ui_screenshot(page):
page.goto("/dashboard")
screenshot = page.screenshot()
attach("dashboard", body=screenshot, content_type="image/png")
Supported content types:
| Content-Type | Rendered in UReport as |
|---|---|
image/png, image/jpeg |
Screenshot thumbnail |
application/json |
Syntax-highlighted JSON |
application/xml, text/xml |
Syntax-highlighted XML |
text/x-curl |
Curl command |
text/plain |
Plain text |
You can also attach from a file path instead of bytes:
attach("report", path="/tmp/report.xml", content_type="application/xml")
Markers
Add metadata to tests using pytest markers. This metadata is saved to UReport and used for filtering, grouping, and cross-run tracking.
import pytest
@pytest.mark.ureport_uid("checkout-happy-path")
@pytest.mark.ureport_components("Cart", "Checkout", "Payment")
@pytest.mark.ureport_teams("frontend")
@pytest.mark.ureport_tags("@smoke", "@p1")
def test_checkout():
...
| Marker | Description |
|---|---|
@pytest.mark.ureport_uid("my-uid") |
Override the test's UID in UReport. Useful for stable identifiers across file renames |
@pytest.mark.ureport_components("A", "B") |
Component names this test covers |
@pytest.mark.ureport_teams("team-name") |
Team responsible for this test |
@pytest.mark.ureport_tags("@smoke", "@p1") |
Additional tags (native pytest marks like @pytest.mark.smoke are also captured automatically) |
Tags from Native pytest Marks
Any native pytest mark without arguments is automatically captured as a tag:
@pytest.mark.smoke # captured as @smoke
@pytest.mark.regression
def test_login():
...
Quick Info Markers
Quick info markers store execution-specific values (e.g. environment URL, run ID) that appear as copy-to-clipboard fields in UReport but are never saved to test relations.
Configure which markers are treated as quick info:
# pytest.ini
ureport_quick_info_markers = env build_url run_id
Then use them in tests:
@pytest.mark.env("staging")
@pytest.mark.build_url("https://ci.example.com/builds/123")
def test_something():
...
Using the ureport Fixture
Alternatively, use the built-in ureport fixture instead of importing step and attach directly:
def test_something(ureport):
with ureport.step("Do something"):
result = do_something()
ureport.attach("result", body=result.encode(), content_type="application/json")
assert result == "ok"
Retry Support
Works with pytest-rerunfailures out of the box. The final attempt's result is what gets submitted to UReport:
- Final attempt passes after retries →
RERUN_PASS - Final attempt fails after retries →
FAILwithis_rerun: true
# pytest.ini
addopts = --reruns 2 --reruns-delay 1
CI/CD Example
GitHub Actions
- name: Run tests
env:
UREPORT_SERVER_URL: ${{ secrets.UREPORT_SERVER_URL }}
UREPORT_API_TOKEN: ${{ secrets.UREPORT_API_TOKEN }}
UREPORT_PRODUCT: MyProduct
UREPORT_TYPE: E2E
UREPORT_BUILD_NUMBER: ${{ github.run_number }}
UREPORT_STAGE: ${{ github.ref == 'refs/heads/main' && 'prod' || 'staging' }}
run: pytest
GitLab CI
test:
variables:
UREPORT_SERVER_URL: "http://your-ureport-server:4100"
UREPORT_API_TOKEN: "$UREPORT_TOKEN"
UREPORT_PRODUCT: "MyProduct"
UREPORT_TYPE: "E2E"
UREPORT_BUILD_NUMBER: "$CI_PIPELINE_IID"
script:
- pytest
Debugging
Inspect the payload
Use ureport_output_file to dump the full payload to a JSON file after the run:
ureport_output_file = ureport-payload.json
Disable the reporter temporarily
Remove or comment out ureport_server_url (or unset UREPORT_SERVER_URL). If none of the four required fields are present, the plugin stays inactive and adds zero overhead.
Full Configuration Example
# pytest.ini
[pytest]
ureport_server_url = http://localhost:4100
ureport_api_token = abc123
ureport_product = MyProduct
ureport_type = E2E
ureport_build_number = 42
ureport_team = platform
ureport_browser = CHROME
ureport_stage = staging
ureport_version = 2.1.0
ureport_batch_size = 100
ureport_include_steps = true
ureport_include_screenshots = true
ureport_save_relations = true
ureport_auto_token = true
ureport_output_file = ureport-payload.json
ureport_quick_info_markers = env build_url
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 ureport_pytest_reporter-1.0.1.tar.gz.
File metadata
- Download URL: ureport_pytest_reporter-1.0.1.tar.gz
- Upload date:
- Size: 20.9 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.11.10
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
223e149670296809737204ace0c1c049fbcf1acc12a5d93fed803c41d5b8fe84
|
|
| MD5 |
3f20fa60d4d009a946c1250b0bec202f
|
|
| BLAKE2b-256 |
3850e40e85265bbf5b73a415a2a215f91a1ba040d054122678cd9937fd35088f
|
File details
Details for the file ureport_pytest_reporter-1.0.1-py3-none-any.whl.
File metadata
- Download URL: ureport_pytest_reporter-1.0.1-py3-none-any.whl
- Upload date:
- Size: 19.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.11.10
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e407cc81884d1f198be7756dc64cc8397ef6bcb07210d3aebd9ae5a092b982e1
|
|
| MD5 |
ddd2b238a83fc35bd717e9ba219b75cb
|
|
| BLAKE2b-256 |
e6b5ff6bea2afbeb85392a366415387c658f2571c23e720afce3a70ceda733ad
|