Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

adding basic tests w/ pytest regressions #227

Merged
merged 2 commits into from
Jul 20, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,10 @@ jobs:
export PATH="$HOME/miniconda/bin:$PATH"
sphinx-build -b html docs/ docs/_build/html -W --keep-going
# Run tests
- name: Run the tests
run: pytest

# Run local Lighthouse audit against built site
audit:

Expand Down
23 changes: 23 additions & 0 deletions docs/contributing.rst
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,7 @@ Steps to develop the theme
2. Install theme dependencies
3. Run development server
4. Build production assets
5. Install the testing infrastructure

.. Attention::

Expand Down Expand Up @@ -189,6 +190,28 @@ run:
yarn build:production


Install the test infrastructure
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

This theme uses ``pytest`` for its testing, with a lightweight fixture defined
in the ``test_build.py`` script that makes it easy to run a Sphinx build using
this theme and inspect the results.

In addition, we use `pytest-regressions <https://pytest-regressions.readthedocs.io/en/latest/>`_
to ensure that the HTML generated by the theme is what we'd expect. This module
provides a ``file_regression`` fixture that will check the contents of an object
against a reference file on disk. If the structure of the two differs, then the
test will fail. If we *expect* the structure to differ, then delete the file on
disk and run the test. A new file will be created, and subsequent tests will pass.

Install the testing dependencies with:

.. code-block:: bash

pip install pytest pytest-regressions

Then run the tests by calling ``pytest`` from the repository root.

Changing fonts
--------------

Expand Down
3 changes: 3 additions & 0 deletions docs/requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,6 @@ pandas
jupyter_sphinx
plotly
numpy
pytest
pytest-regressions
beautifulsoup4
20 changes: 20 additions & 0 deletions tests/sites/base/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Minimal makefile for Sphinx documentation
#

# You can set these variables from the command line, and also
# from the environment for the first two.
SPHINXOPTS ?=
SPHINXBUILD ?= sphinx-build
SOURCEDIR = .
BUILDDIR = _build

# Put it first so that "make" without argument is like "make help".
help:
@$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)

.PHONY: help Makefile

# Catch-all target: route all unknown targets to Sphinx using the new
# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
%: Makefile
@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
20 changes: 20 additions & 0 deletions tests/sites/base/conf.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# -- Project information -----------------------------------------------------

project = "PyData Tests"
copyright = "2020, Pydata community"
author = "Pydata community"

master_doc = "index"

# -- General configuration ---------------------------------------------------

# Add any Sphinx extension module names here, as strings. They can be
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
# ones.
extensions = []
html_theme = "pydata_sphinx_theme"
html_copy_source = True
html_sourcelink_suffix = ""

# Base options, we can add other key/vals later
html_theme_options = {}
10 changes: 10 additions & 0 deletions tests/sites/base/index.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
Index ``with code`` in title
============================

.. toctree::
:caption: My caption
:numbered:

page1
page2
section1/index
2 changes: 2 additions & 0 deletions tests/sites/base/page1.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Page 1
======
2 changes: 2 additions & 0 deletions tests/sites/base/page2.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Page 2
======
6 changes: 6 additions & 0 deletions tests/sites/base/section1/index.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
Section 1 index
===============
.. toctree::

page1
https://google.com
2 changes: 2 additions & 0 deletions tests/sites/base/section1/page1.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Section 1 page1
===============
70 changes: 70 additions & 0 deletions tests/test_build.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
from bs4 import BeautifulSoup
from pathlib import Path
from subprocess import run
from shutil import copytree, rmtree
import pytest


path_tests = Path(__file__).parent.resolve()
path_base = path_tests.joinpath("sites", "base")


@pytest.fixture(scope="session")
def sphinx_build(tmpdir_factory):
class SphinxBuild:
path_tmp = Path(tmpdir_factory.mktemp("build"))
path_docs = path_tmp.joinpath("testdocs")
path_build = path_docs.joinpath("_build")
path_html = path_build.joinpath("html")
path_pg_index = path_html.joinpath("index.html")
cmd_base = ["sphinx-build", ".", "_build/html", "-a", "-W"]

def copy(self, path=None):
"""Copy the specified book to our tests folder for building."""
if path is None:
path = path_base
if not self.path_docs.exists():
copytree(path, self.path_docs)

def build(self, cmd=None):
"""Build the test book"""
cmd = [] if cmd is None else cmd
run(self.cmd_base + cmd, cwd=self.path_docs, check=True)

def get(self, pagename):
path_page = self.path_html.joinpath(pagename)
if not path_page.exists():
raise ValueError(f"{path_page} does not exist")
return BeautifulSoup(path_page.read_text(), "html.parser")

def clean(self):
"""Clean the _build folder so files don't clash with new tests."""
rmtree(self.path_build)

return SphinxBuild()


def test_build_book(file_regression, sphinx_build):
"""Test building the base book template and config."""
sphinx_build.copy()

# Basic build with defaults
sphinx_build.build()
index_html = sphinx_build.get("index.html")
subpage_html = sphinx_build.get("section1/index.html")

# Navbar structure
navbar = index_html.select("div#navbar-menu")[0]
file_regression.check(navbar.prettify(), basename="navbar_ix", extension=".html")

# Sidebar structure
sidebar = index_html.select(".bd-sidebar")[0]
file_regression.check(sidebar.prettify(), basename="sidebar_ix", extension=".html")

# Sidebar subpage
sidebar = subpage_html.select(".bd-sidebar")[0]
file_regression.check(
sidebar.prettify(), basename="sidebar_subpage", extension=".html"
)

sphinx_build.clean()
21 changes: 21 additions & 0 deletions tests/test_build/navbar_ix.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<div class="col-lg-9 collapse navbar-collapse" id="navbar-menu">
<ul class="navbar-nav mr-auto" id="navbar-main-elements">
<li class="nav-item">
<a class="nav-link" href="page1.html">
Page 1
</a>
</li>
<li class="nav-item">
<a class="nav-link" href="page2.html">
Page 2
</a>
</li>
<li class="nav-item">
<a class="nav-link" href="section1/index.html">
Section 1 index
</a>
</li>
</ul>
<ul class="navbar-nav">
</ul>
</div>
13 changes: 13 additions & 0 deletions tests/test_build/sidebar_ix.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<div class="col-12 col-md-3 bd-sidebar">
<form action="search.html" class="bd-search d-flex align-items-center" method="get">
<i class="icon fas fa-search">
</i>
<input aria-label="Search the docs ..." autocomplete="off" class="form-control" id="search-input" name="q" placeholder="Search the docs ..." type="search"/>
</form>
<nav aria-label="Main navigation" class="bd-links" id="bd-docs-nav">
<div class="bd-toc-item active">
<ul class="nav bd-sidenav">
</ul>
</div>
</nav>
</div>
23 changes: 23 additions & 0 deletions tests/test_build/sidebar_subpage.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<div class="col-12 col-md-3 bd-sidebar">
<form action="../search.html" class="bd-search d-flex align-items-center" method="get">
<i class="icon fas fa-search">
</i>
<input aria-label="Search the docs ..." autocomplete="off" class="form-control" id="search-input" name="q" placeholder="Search the docs ..." type="search"/>
</form>
<nav aria-label="Main navigation" class="bd-links" id="bd-docs-nav">
<div class="bd-toc-item active">
<ul class="nav bd-sidenav">
<li class="">
<a href="page1.html">
Section 1 page1
</a>
</li>
<li class="">
<a href="https://google.com">
https://google.com
</a>
</li>
</ul>
</div>
</nav>
</div>