pytest-html

A pytest plugin that turns your test run into an interactive, shareable HTML report.

Tool
PyPI
v4.2.0
779stars
Mozilla Public License 2.0

Repository Health

Pre-computed score based on development activity, maintenance, community, maturity, and trend momentum.How we score it →
76/100Good
Development Activity76
Maintenance56
Community84
Maturity60
Momentum28

Technical Analysis

AI-assessed by reading the actual repository — architecture, code quality, innovation, and documentation.How we score it →
76/100Good
Architecture76
Code Quality78
Innovation58
Learning Curve90

pytest-html is the standard pytest plugin for generating rich HTML reports from a test run. It sits on top of pytest’s hook system and pytest-metadata to produce a single report file that lists every test outcome, its duration, and any captured logs, with sortable and filterable columns for result, test ID, and duration.

Beyond the default output, it exposes an ‘extras’ API and a set of pytest hooks that let teams attach screenshots, videos, JSON payloads, or arbitrary HTML to individual test results, customize the results table, redact sensitive environment variables, and produce self-contained single-file reports for easy sharing in CI artifacts or email.

What You Get

  • A single —html=report.html flag that produces a full interactive report with a summary, an environment table, and a sortable/filterable results table
  • An ‘extras’ API (pytest_html.extras) for attaching text, JSON, URLs, raw HTML, images, and video to individual test results, either via a fixture or a pytest_runtest_makereport hook
  • A —self-contained-html option that inlines CSS, JS, and assets into one file so the report survives CSP restrictions and is safe to email or archive
  • Public hooks (pytest_html_report_title, pytest_html_results_summary, pytest_html_results_table_header/row/html, pytest_html_duration_format) for customizing the title, summary text, table columns, and duration formatting
  • Query-string controls in the generated report itself (?collapsed=, ?visible=, ?sort=) for filtering and reordering results without regenerating the file
  • Optional streaming mode (generate_report_on_test) that writes the report incrementally as each test finishes instead of only at the end of the run

Common Use Cases

  • Publishing a browsable HTML report as a CI artifact (GitHub Actions, GitLab CI, Jenkins) so reviewers can inspect failures without re-running tests locally
  • Attaching failure screenshots or Selenium/Playwright artifacts to individual test rows via the extras API for visual debugging
  • Sharing a single self-contained report file with QA or stakeholders who don’t have access to the CI system or a terminal
  • Extending the results table with custom columns (e.g. a docstring-derived description column or a precise timestamp) via the results-table hooks for teams with reporting requirements beyond the defaults

Under The Hood

Architecture pytest-html registers as a pytest plugin via the pytest11 entry point declared in pyproject.toml, hooking pytest_addoption to expose CLI/INI flags and pytest_addhooks (src/pytest_html/plugin.py) to register its own hookspecs (src/pytest_html/hooks.py) for title, summary, table-row, and duration customization. Test outcomes accumulate in a ReportData object (src/pytest_html/report_data.py) that tracks per-test results, environment metadata, and summary counts as a JSON-serializable structure; at report time this data is handed to a Report or SelfContainedReport class (src/pytest_html/report.py, selfcontained_report.py), both subclassing a shared BaseReport (src/pytest_html/basereport.py) that renders a Jinja2 template and writes assets to disk (Report) or inlines them as base64 (SelfContainedReport). The split cleanly separates data collection (ReportData), rendering (BaseReport template logic), and asset-handling strategy (the two Report subclasses), so a new output mode could be added by subclassing BaseReport without touching the data-collection path.

Tech Stack The Python side targets 3.9+ and depends on jinja2 (templating), pytest>=7 (the host framework, consumed via its hook and fixture system), and pytest-metadata (which supplies the report’s Environment table). The frontend is a small vanilla-JS application (src/pytest_html/scripts/*.js — dom, filter, sort, storage, datamanager) compiled with Browserify into a single app.js bundle, styled from SCSS (src/layout/css/style.scss) compiled with Dart Sass into the shipped style.css. Packaging uses Hatchling with hatch-vcs for git-tag-based versioning and a custom build hook (scripts/npm.py) that runs the npm build (CSS/JS compilation) as part of the Python wheel build, unifying the two toolchains into one pip install step.

Code Quality The Python side has unit, integration, and end-to-end test suites under testing/ (test_unit.py, test_integration.py, test_e2e.py, plus a legacy suite), run through tox across supported Python versions and exercised in CI via .github/workflows/tests.yml. The JS side has its own Mocha/Chai/Sinon unit suite (testing/unittest.js) with nyc coverage and an ESLint config. Formatting and static checks are enforced through a comprehensive pre-commit configuration (black, pyproject-fmt, blacken-docs, trailing-whitespace/end-of-file checks, a branch-protection hook) plus a project-wide mypy configuration with several strict flags enabled (disallow_any_generics, no_implicit_optional, warn_unreachable). Public functions in extras.py carry full type hints. Overall this is a mature, CI-gated, dual-language codebase with deliberate lint/format automation rather than ad hoc discipline.

What Makes It Unique What sets pytest-html apart from generic test-report generators is its hook-based extensibility layered directly onto pytest’s own plugin architecture: rather than a fixed report format, it exposes pytest hookspecs that let other plugins or a project’s own conftest.py rewrite the results table, inject extra summary content, or reformat durations, and it ships a dedicated ‘extras’ content model (text/JSON/URL/HTML/image/video) that individual tests can attach to their own result inline. The self-contained single-file report mode, which inlines all assets to survive Content-Security-Policy restrictions, and the in-report query-string filtering/sorting controls are practical touches aimed specifically at making reports portable and reviewable outside of a CI dashboard, rather than just prettifying console output.

Join founders buildingwith open source

Opinionated takes, migration guides, cost-saving tips, and insights from the open source ecosystem.

Subscribe on Substack
Join 750+ subscribers

Search