Metadata-Version: 2.5
Name: pytest-acereports
Version: 1.0.1
Summary: Ace Reports for pytest: one self-contained HTML report per run with logs, API calls, screenshots, retries and flaky tests. Zero setup.
Project-URL: Homepage, https://harshadlambate.github.io/AceReportsWebsite/
Project-URL: Live demo report, https://harshadlambate.github.io/AceReportsWebsite/demo.html
Project-URL: Issues, https://github.com/HarshadLambate/AceReportsWebsite/issues
Author: Harshad Lambate
License-File: LICENSE.md
License-File: NOTICE.md
Keywords: ace-reports,acereports,flaky-tests,html-report,playwright,pytest,pytest-bdd,pytest-plugin,reporting,selenium,test-automation,test-report,testing
Classifier: Development Status :: 5 - Production/Stable
Classifier: Framework :: Pytest
Classifier: Intended Audience :: Developers
Classifier: License :: Other/Proprietary License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Software Development :: Quality Assurance
Classifier: Topic :: Software Development :: Testing
Requires-Python: >=3.9
Requires-Dist: pytest>=7.0
Requires-Dist: python-liquid>=1.10
Provides-Extra: dev
Requires-Dist: build; extra == 'dev'
Requires-Dist: httpx; extra == 'dev'
Requires-Dist: playwright; extra == 'dev'
Requires-Dist: pytest-bdd; extra == 'dev'
Requires-Dist: pytest-rerunfailures; extra == 'dev'
Requires-Dist: pytest-xdist; extra == 'dev'
Requires-Dist: requests; extra == 'dev'
Requires-Dist: twine; extra == 'dev'
Description-Content-Type: text/markdown

# pytest-acereports

Zero-setup HTML reporting for pytest: one self-contained file per run with logs, API traffic,
screenshots, retries and flaky-test detection. The same report as Ace Reports for .NET.

**Website:** https://harshadlambate.github.io/AceReportsWebsite/ ·
**Live demo report:** https://harshadlambate.github.io/AceReportsWebsite/demo.html

## Setup

Install the package. That's all:

```
pip install pytest-acereports
```

The plugin registers itself with pytest. Run your tests as usual and the report is written to
`test-results/AceReport_<timestamp>.html` in your project's root folder; the path is printed at the
end of the run.

To turn reporting off: `pytest --no-acereports`, or `acereports = false` in `pytest.ini`.

## Configuration

Add this hook to a `conftest.py`. Ace Reports calls it before the first test runs:

```python
from acereports import ace

def pytest_acereports_configure(options):
    ace.suite_name("Checkout Regression")   # default: the name of the project folder
    ace.environment_name("UAT")             # see "Environment name" below
    ace.dark_theme()                        # or light_theme() / system_theme() (default)
    # ace.output_path("reports/report.html")
    # ace.capture_http_traffic(False)       # API capture is on by default
```

Or set the same things in `pytest.ini` (or `pyproject.toml` / `tox.ini`):

```ini
[pytest]
acereports_suite_name = Checkout Regression
acereports_environment = UAT
acereports_theme = dark
acereports_output = reports/report.html
acereports_capture_http = true
acereports_capture_logging = true
acereports_readable_names = true
```

`pytest --acereports-output=PATH` overrides the output path for one run.

### Environment name

Resolved in this order, first match wins:

1. `ace.environment_name("QA")`
2. the `ACEREPORTS_ENVIRONMENT` environment variable
3. `acereports_environment` in pytest.ini
4. `Local`

## Logging from a test

```python
from acereports import ace

ace.info("Submitting payment")
ace.pass_("Payment authorized")            # 'pass' is a Python keyword, hence the underscore
ace.fail("Refund was accepted but should have been rejected")   # logs only; use assert to fail
ace.debug("Skipping optional 3-D Secure step")
```

Each call attaches to whichever test is running. Records from Python's `logging` module are added to
the test's log as well. pytest's own `log_level` option decides what gets through, so set
`log_level = INFO` in pytest.ini to see INFO messages.

## Screenshots

A screenshot is taken automatically when a test fails, *before* fixtures are torn down, so the
browser is still open. Take your own at any point; each becomes its own tab in the report:

```python
ace.take_screenshot()                    # "Screenshot 1", "Screenshot 2", ...
ace.take_screenshot("After login")       # named tab
ace.take_screenshot("Cart page", image=png_bytes)   # an image you already have
```

Ace Reports finds the page by itself when the test uses a fixture whose name contains `page`,
`driver` or `browser`, such as pytest-playwright's `page`, or has such an attribute on its test
class. A browser created **inside** the test function has to be handed over once:

```python
page = browser.new_page()
ace.use_screenshot_source(page)          # Playwright Page, Selenium WebDriver, ...
```

Works with Playwright (sync API), Selenium, and anything with a `screenshot()` or
`get_screenshot_as_png()` method. With Playwright's async API, take the screenshot yourself and pass
it in with `image=await page.screenshot()`.

## API traffic

Every HTTP call made with **requests** or **httpx** (sync and async) is captured: method, URL,
request and response bodies, status, duration, and connection errors. It is shown per attempt in the
**API** tab. `Authorization`, `Proxy-Authorization`, `Cookie` and `Set-Cookie` headers are redacted.
Turn it off with `ace.capture_http_traffic(False)`.

## Categories

Markers are categories, from the test, its class and its module:

```python
pytestmark = pytest.mark.checkout          # every test in the file

@pytest.mark.smoke
@pytest.mark.category("UAT, Payments")     # names that are not valid identifiers
def test_pay():
    ...
```

Markers that steer pytest or a plugin (`parametrize`, `skip`, `xfail`, `flaky`, `usefixtures`, ...)
are not categories. A test with no category is filed under "Uncategorized".

## Retries and flaky tests

Retries come from [pytest-rerunfailures](https://pypi.org/project/pytest-rerunfailures/):

```python
@pytest.mark.flaky(reruns=3)
def test_checkout():
    ...
```

or `pytest --reruns 3` for every test. Each attempt keeps its own logs, API calls, error and
screenshots, shown as separate attempt tabs. A test is *retried* when it took more than one attempt,
and *flaky* when it ultimately passed after an earlier attempt failed.

## What is recorded

| pytest | Report |
| --- | --- |
| test function / method | one row; `test_create_post` is shown as "Create post" (set `acereports_readable_names = false` to keep the function name) |
| `@pytest.mark.parametrize` | one row per case; parameters listed as `name=value` |
| class, or module when there is no class | the "Test Group" column |
| markers | category tags (a test can have several) |
| setup or teardown errors | failed, with "Error in setup: ..." / "Error in teardown: ..." |
| `skip`, `skipif`, `xfail` | left out of the table; skipped tests are counted |
| `@pytest.mark.ace_name("Valid User Login")` | the name shown in the report (also works on `pytest.param(..., marks=...)`) |

## pytest-bdd

Gherkin scenarios run with [pytest-bdd](https://pypi.org/project/pytest-bdd/) are recorded with
their scenario title as the name, their feature as the group, their tags as categories and their
example row as arguments. Each step is a `GIVEN` / `WHEN` / `THEN` / `AND` / `BUT` line in the log;
a failing step carries its error, and the steps it prevented are listed as skipped. Nothing to
configure.

## Parallel runs

Works with [pytest-xdist](https://pypi.org/project/pytest-xdist/) (`pytest -n auto`): every worker's
results end up in one report.

## Requirements

Python 3.9+ and pytest 7.0+.

## License

Ace Reports is free to use under the
[PolyForm Perimeter License 1.0.1](https://polyformproject.org/licenses/perimeter/1.0.1).

Commercial terms (OEM, white-label, or a full buy-out) are available:
see the [website](https://harshadlambate.github.io/AceReportsWebsite/#faq).

Found it useful? [Buy me a coffee](https://buymeacoffee.com/lambate05p) ☕
