Go to file
Gleb Nikonorov 817d04df58
Move documentation to read the docs (#402)
* first pass at moving docs to read the docs

* migrate to readthedocs

* Fix broken development link in README

* Use better build command and some stylistic touchups

* Add development section on writing docs

* undo changes to documentation not in readthedocs
2020-12-09 13:21:28 +00:00
.github Move documentation to read the docs (#402) 2020-12-09 13:21:28 +00:00
docs Move documentation to read the docs (#402) 2020-12-09 13:21:28 +00:00
src Remove pkg_resources (#396) 2020-12-04 15:54:50 +00:00
testing Stop attaching test reruns to final test report entries (#387) 2020-11-30 21:40:18 -05:00
.coveragerc Disable codecov PR comments (#382) 2020-11-27 12:29:42 +00:00
.eslintrc.json Add ESLint to project (#367) 2020-11-12 12:34:57 +00:00
.gitignore Move documentation to read the docs (#402) 2020-12-09 13:21:28 +00:00
.pre-commit-config.yaml Use scss (#385) 2020-12-01 00:34:39 -05:00
CHANGES.rst Update release date for latest version (#394) 2020-12-03 21:44:40 -05:00
Gruntfile.js Add JavaScript tests (#73) 2016-10-06 15:14:09 +01:00
LICENSE Add LICENSE 2015-05-08 16:14:01 +01:00
Pipfile Use pre-commit to streamline development (#229) 2019-08-12 20:11:52 +02:00
README.rst Fix readme typos (#398) 2020-12-03 14:25:57 +00:00
codecov.yml Disable codecov PR comments (#382) 2020-11-27 12:29:42 +00:00
development.rst Use scss (#385) 2020-12-01 00:34:39 -05:00
package.json Use scss (#385) 2020-12-01 00:34:39 -05:00
pyproject.toml Remove pkg_resources (#396) 2020-12-04 15:54:50 +00:00
setup.cfg Add support for py39 (#345) 2020-10-17 17:49:07 +01:00
setup.py Move sources to `src` dir (#384) 2020-11-27 15:14:03 +00:00
tox.ini Move documentation to read the docs (#402) 2020-12-09 13:21:28 +00:00

README.rst

pytest-html
===========

pytest-html is a plugin for `pytest <http://pytest.org>`_ that generates a
HTML report for the test results.

.. image:: https://img.shields.io/badge/license-MPL%202.0-blue.svg
   :target: https://github.com/pytest-dev/pytest-html/blob/master/LICENSE
   :alt: License
.. image:: https://img.shields.io/pypi/v/pytest-html.svg
   :target: https://pypi.python.org/pypi/pytest-html/
   :alt: PyPI
.. image:: https://img.shields.io/conda/vn/conda-forge/pytest-html.svg
   :target: https://anaconda.org/conda-forge/pytest-html
   :alt: Conda Forge
.. image:: https://github.com/pytest-dev/pytest-html/workflows/gh/badge.svg
   :target: https://github.com/pytest-dev/pytest-html/actions
   :alt: CI
.. image:: https://img.shields.io/requires/github/pytest-dev/pytest-html.svg
   :target: https://requires.io/github/pytest-dev/pytest-html/requirements/?branch=master
   :alt: Requirements
.. image:: https://codecov.io/gh/pytest-dev/pytest-html/branch/master/graph/badge.svg?token=Y0myNKkdbi
   :target: https://codecov.io/gh/pytest-dev/pytest-html
   :alt: Codecov

Requirements
------------

You will need the following prerequisites in order to use pytest-html:

- Python 3.6+ or PyPy3

Installation
------------

To install pytest-html:

.. code-block:: bash

  $ pip install pytest-html

Then run your tests with:

.. code-block:: bash

  $ pytest --html=report.html

ANSI codes
----------

Note that ANSI code support depends on the
`ansi2html <https://pypi.python.org/pypi/ansi2html/>`_ package. Due to the use
of a less permissive license, this package is not included as a dependency. If
you have this package installed, then ANSI codes will be converted to HTML in
your report.

Creating a self-contained report
--------------------------------

In order to respect the `Content Security Policy (CSP)
<https://developer.mozilla.org/docs/Web/Security/CSP>`_,
several assets such as CSS and images are stored separately by default.
You can alternatively create a self-contained report, which can be more
convenient when sharing your results. This can be done in the following way:

.. code-block:: bash

   $ pytest --html=report.html --self-contained-html

Images added as files or links are going to be linked as external resources,
meaning that the standalone report HTML-file may not display these images
as expected.

The plugin will issue a warning when adding files or links to the standalone report.

Enhancing reports
-----------------

Appearance
~~~~~~~~~~

Custom CSS (Cascasding Style Sheets) can be passed on the command line using
the :code:`--css` option. These will be applied in the order specified, and can
be used to change the appearance of the report.

.. code-block:: bash

  $ pytest --html=report.html --css=highcontrast.css --css=accessible.css

Report Title
~~~~~~~~~~~~

By default report title will be the filename of the report, you can edit it by using the :code:`pytest_html_report_title` hook:

.. code-block:: python

   def pytest_html_report_title(report):
       report.title = "My very own title!"

Environment
~~~~~~~~~~~

The *Environment* section is provided by the `pytest-metadata
<https://pypi.python.org/pypi/pytest-metadata/>`_ plugin, and can be accessed
via the :code:`pytest_configure` hook:

.. code-block:: python

  def pytest_configure(config):
      config._metadata["foo"] = "bar"

The generated table will be sorted alphabetically unless the metadata is a
:code:`collections.OrderedDict`.

Additional summary information
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

You can edit the *Summary* section by using the :code:`pytest_html_results_summary` hook:

.. code-block:: python

   from py.xml import html


   def pytest_html_results_summary(prefix, summary, postfix):
       prefix.extend([html.p("foo: bar")])

Extra content
~~~~~~~~~~~~~

You can add details to the HTML reports by creating an 'extra' list on the
report object. Here are the types of extra content that can be added:

==========  ============================================
Type        Example
==========  ============================================
Raw HTML    ``extra.html('<div>Additional HTML</div>')``
`JSON`_     ``extra.json({'name': 'pytest'})``
Plain text  ``extra.text('Add some simple Text')``
URL         ``extra.url('http://www.example.com/')``
Image       ``extra.image(image, mime_type='image/gif', extension='gif')``
Image       ``extra.image('/path/to/file.png')``
Image       ``extra.image('http://some_image.png')``
==========  ============================================

**Note**: When adding an image from file, the path can be either absolute
or relative.

**Note**: When using ``--self-contained-html``, images added as files or links
may not work as expected, see section `Creating a self-contained report`_ for
more info.

There are also convenient types for several image formats:

============  ====================
Image format  Example
============  ====================
PNG           ``extra.png(image)``
JPEG          ``extra.jpg(image)``
SVG           ``extra.svg(image)``
============  ====================

The following example adds the various types of extras using a
:code:`pytest_runtest_makereport` hook, which can be implemented in a plugin or
conftest.py file:

.. code-block:: python

  import pytest


  @pytest.hookimpl(hookwrapper=True)
  def pytest_runtest_makereport(item, call):
      pytest_html = item.config.pluginmanager.getplugin("html")
      outcome = yield
      report = outcome.get_result()
      extra = getattr(report, "extra", [])
      if report.when == "call":
          # always add url to report
          extra.append(pytest_html.extras.url("http://www.example.com/"))
          xfail = hasattr(report, "wasxfail")
          if (report.skipped and xfail) or (report.failed and not xfail):
              # only add additional html on failure
              extra.append(pytest_html.extras.html("<div>Additional HTML</div>"))
          report.extra = extra

You can also specify the :code:`name` argument for all types other than :code:`html` which will change the title of the
created hyper link:

.. code-block:: python

    extra.append(pytest_html.extras.text("some string", name="Different title"))

It is also possible to use the fixture :code:`extra` to add content directly
in a test function without implementing hooks. These will generally end up
before any extras added by plugins.

.. code-block:: python

   from pytest_html import extras


   def test_extra(extra):
       extra.append(extras.text("some string"))


Modifying the results table
~~~~~~~~~~~~~~~~~~~~~~~~~~~

You can modify the columns by implementing custom hooks for the header and
rows. The following example :code:`conftest.py` adds a description column with
the test function docstring, adds a sortable time column, and removes the links
column:

.. code-block:: python

  from datetime import datetime
  from py.xml import html
  import pytest


  def pytest_html_results_table_header(cells):
      cells.insert(2, html.th("Description"))
      cells.insert(1, html.th("Time", class_="sortable time", col="time"))
      cells.pop()


  def pytest_html_results_table_row(report, cells):
      cells.insert(2, html.td(report.description))
      cells.insert(1, html.td(datetime.utcnow(), class_="col-time"))
      cells.pop()


  @pytest.hookimpl(hookwrapper=True)
  def pytest_runtest_makereport(item, call):
      outcome = yield
      report = outcome.get_result()
      report.description = str(item.function.__doc__)

You can also remove results by implementing the
:code:`pytest_html_results_table_row` hook and removing all cells. The
following example removes all passed results from the report:

.. code-block:: python

  def pytest_html_results_table_row(report, cells):
      if report.passed:
          del cells[:]

The log output and additional HTML can be modified by implementing the
:code:`pytest_html_results_html` hook. The following example replaces all
additional HTML and log output with a notice that the log is empty:

.. code-block:: python

  from py.xml import html


  def pytest_html_results_table_html(report, data):
      if report.passed:
          del data[:]
          data.append(html.div("No log output captured.", class_="empty log"))

Display options
---------------

By default, all rows in the **Results** table will be expanded except those that have :code:`Passed`.

This behavior can be customized either with a query parameter: :code:`?collapsed=Passed,XFailed,Skipped`
or by setting the :code:`render_collapsed` in a configuration file (pytest.ini, setup.cfg, etc).

.. code-block:: ini

  [pytest]
  render_collapsed = True

**NOTE:** Setting :code:`render_collapsed` will, unlike the query parameter, affect all statuses.

The formatting of the timestamp used in the :code:`Durations` column can be modified by setting :code:`duration_formatter`
on the :code:`report` attribute. All `time.strftime`_ formatting directives are supported. In addition, it is possible
to supply :code:`%f` to get duration milliseconds. If this value is not set, the values in the :code:`Durations` column are
displayed in :code:`%S.%f` format where :code:`%S` is the total number of seconds a test ran for.

Below is an example of a :code:`conftest.py` file setting :code:`duration_formatter`:

.. code-block:: python

   import pytest


   @pytest.hookimpl(hookwrapper=True)
   def pytest_runtest_makereport(item, call):
       outcome = yield
       report = outcome.get_result()
       setattr(report, "duration_formatter", "%H:%M:%S.%f")

**NOTE**: Milliseconds are always displayed with a precision of 2

Screenshots
-----------

.. image:: https://cloud.githubusercontent.com/assets/122800/11952194/62daa964-a88e-11e5-9745-2aa5b714c8bb.png
   :target: https://cloud.githubusercontent.com/assets/122800/11951695/f371b926-a88a-11e5-91c2-499166776bd3.png
   :alt: Enhanced HTML report

Contributing
------------

We welcome contributions.

To learn more, see `Development <https://github.com/pytest-dev/pytest-html/blob/master/development.rst>`_

Resources
---------

- `Release Notes <http://github.com/pytest-dev/pytest-html/blob/master/CHANGES.rst>`_
- `Issue Tracker <http://github.com/pytest-dev/pytest-html/issues>`_
- `Code <http://github.com/pytest-dev/pytest-html/>`_


.. _JSON: http://json.org/
.. _time.strftime: https://docs.python.org/3/library/time.html#time.strftime