Repository: sphinx-doc/sphinx

Issue:
Reduce questions of sphinx-quickstart
### Problem
- At present, `sphinx-quickstart` asks many questions. it's not "quick" start.

#### Expected results
Make it simple.


Discussion:

Patch:
diff --git a/CHANGES b/CHANGES
index eebe32a30..b92d36b5d 100644
--- a/CHANGES
+++ b/CHANGES
@@ -59,6 +59,8 @@ Incompatible changes
   from LaTeX preamble now get overwritten.  Use ``\sphinxtableofcontentshook``
   to insert custom user definitions.  See :ref:`latex-macros`.
 * quickstart: Simplify generated ``conf.py``
+* #4148: quickstart: some questions are removed.  They are still able to specify
+  via command line options
 * websupport: unbundled from sphinx core. Please use sphinxcontrib-websupport
 * C++, the visibility of base classes is now always rendered as present in the
   input. That is, ``private`` is now shown, where it was ellided before.
@@ -66,7 +68,6 @@ Incompatible changes
   the text width and height, even if width and/or height option were used.
   (refs: #5956)
 * #4550: All tables and figures without ``align`` option are displayed to center
-* #4587: html: Output HTML5 by default
 
 Deprecated
 ----------
@@ -77,10 +78,6 @@ Deprecated
   ``EpubBuilder.build_container()``, ``EpubBuilder.bulid_content()``,
   ``EpubBuilder.build_toc()`` and ``EpubBuilder.build_epub()``
 * The arguments of ``Epub3Builder.build_navigation_doc()``
-* The config variables
-
-  - :confval:`html_experimental_html5_writer`
-
 * The ``encoding`` argument of ``autodoc.Documenter.get_doc()``,
   ``autodoc.DocstringSignatureMixin.get_doc()``,
   ``autodoc.DocstringSignatureMixin._find_signature()``, and
@@ -184,7 +181,6 @@ Features added
 * #4611: epub: Show warning for duplicated ToC entries
 * #1851: Allow to omit an argument for :rst:dir:`code-block` directive.  If
   omitted, it follows :rst:dir:`highlight` or :confval:`highlight_language`
-* #4587: html: Add :confval:`html4_writer` to use old HTML4 writer
 * #6016: HTML search: A placeholder for the search summary prevents search
   result links from changing their position when the search terminates.  This
   makes navigating search results easier.
diff --git a/doc/_themes/sphinx13/static/sphinx13.css b/doc/_themes/sphinx13/static/sphinx13.css
index 3dadf8168..235bfdcc4 100644
--- a/doc/_themes/sphinx13/static/sphinx13.css
+++ b/doc/_themes/sphinx13/static/sphinx13.css
@@ -388,29 +388,32 @@ div.admonition, div.warning {
     padding: 0;
 }
 
-div.admonition > p, div.warning > p {
+div.admonition p, div.warning p {
     margin: 0.5em 1em 0.5em 1em;
     padding: 0;
 }
 
-div.admonition > pre, div.warning > pre {
+div.admonition pre, div.warning pre {
     margin: 0.4em 1em 0.4em 1em;
 }
 
-div.admonition > p.admonition-title,
-div.warning > p.admonition-title {
-    margin-top: 0.5em;
+div.admonition p.admonition-title,
+div.warning p.admonition-title {
+    margin-top: 1em;
+    padding-top: 0.5em;
     font-weight: bold;
 }
 
 div.warning {
     border: 1px solid #940000;
+/*    background-color: #FFCCCF;*/
+}
+
+div.warning p.admonition-title {
 }
 
-div.admonition > ul,
-div.admonition > ol,
-div.warning > ul,
-div.warning > ol {
+div.admonition ul, div.admonition ol,
+div.warning ul, div.warning ol {
     margin: 0.1em 0.5em 0.5em 3em;
     padding: 0;
 }
diff --git a/doc/usage/configuration.rst b/doc/usage/configuration.rst
index f0db65aad..8b82147c1 100644
--- a/doc/usage/configuration.rst
+++ b/doc/usage/configuration.rst
@@ -1331,12 +1331,6 @@ that use Sphinx's HTMLWriter class.
 
    .. versionadded:: 1.6
 
-   .. deprecated:: 2.0
-
-.. confval:: html4_writer
-
-   Output is processed with HTML4 writer.  Default is ``False``.
-
 Options for Single HTML output
 -------------------------------
 
diff --git a/sphinx/builders/_epub_base.py b/sphinx/builders/_epub_base.py
index 00fa7187d..5f7a00e3c 100644
--- a/sphinx/builders/_epub_base.py
+++ b/sphinx/builders/_epub_base.py
@@ -134,6 +134,8 @@ class EpubBuilder(StandaloneHTMLBuilder):
     html_scaled_image_link = False
     # don't generate search index or include search page
     search = False
+    # use html5 translator by default
+    default_html5_translator = True
 
     coverpage_name = COVERPAGE_NAME
     toctree_template = TOCTREE_TEMPLATE
diff --git a/sphinx/builders/html.py b/sphinx/builders/html.py
index 8368b07db..09ba8d677 100644
--- a/sphinx/builders/html.py
+++ b/sphinx/builders/html.py
@@ -18,6 +18,7 @@
 from hashlib import md5
 from os import path
 
+import docutils
 from docutils import nodes
 from docutils.core import publish_parts
 from docutils.frontend import OptionParser
@@ -57,7 +58,7 @@
     from sphinx.domains import Domain, Index, IndexEntry  # NOQA
     from sphinx.util.tags import Tags  # NOQA
 
-# HTML5 Writer is avialable or not
+# Experimental HTML5 Writer
 if is_html5_writer_available():
     from sphinx.writers.html5 import HTML5Translator
     html5_ready = True
@@ -241,6 +242,8 @@ class StandaloneHTMLBuilder(Builder):
     search = True  # for things like HTML help and Apple help: suppress search
     use_index = False
     download_support = True  # enable download role
+    # use html5 translator by default
+    default_html5_translator = False
 
     imgpath = None          # type: str
     domain_indices = []     # type: List[Tuple[str, Type[Index], List[Tuple[str, List[IndexEntry]]], bool]]  # NOQA
@@ -282,6 +285,11 @@ def init(self):
 
         self.use_index = self.get_builder_config('use_index', 'html')
 
+        if self.config.html_experimental_html5_writer and not html5_ready:
+            logger.warning(__('html_experimental_html5_writer is set, but current version '
+                              'is old. Docutils\' version should be 0.13 or newer, but %s.'),
+                           docutils.__version__)
+
     def create_build_info(self):
         # type: () -> BuildInfo
         return BuildInfo(self.config, self.tags, ['html'])
@@ -366,10 +374,14 @@ def add_js_file(self, filename, **kwargs):
     @property
     def default_translator_class(self):  # type: ignore
         # type: () -> Type[nodes.NodeVisitor]
-        if not html5_ready or self.config.html4_writer:
-            return HTMLTranslator
-        else:
+        use_html5_writer = self.config.html_experimental_html5_writer
+        if use_html5_writer is None:
+            use_html5_writer = self.default_html5_translator
+
+        if use_html5_writer and html5_ready:
             return HTML5Translator
+        else:
+            return HTMLTranslator
 
     @property
     def math_renderer_name(self):
@@ -550,7 +562,7 @@ def prepare_writing(self, docnames):
             'parents': [],
             'logo': logo,
             'favicon': favicon,
-            'html5_doctype': html5_ready and not self.config.html4_writer
+            'html5_doctype': self.config.html_experimental_html5_writer and html5_ready,
         }
         if self.theme:
             self.globalcontext.update(
@@ -1428,9 +1440,9 @@ def setup(app):
     app.add_config_value('html_search_options', {}, 'html')
     app.add_config_value('html_search_scorer', '', None)
     app.add_config_value('html_scaled_image_link', True, 'html')
+    app.add_config_value('html_experimental_html5_writer', None, 'html')
     app.add_config_value('html_baseurl', '', 'html')
     app.add_config_value('html_math_renderer', None, 'env')
-    app.add_config_value('html4_writer', False, 'html')
 
     # event handlers
     app.connect('config-inited', convert_html_css_files)
diff --git a/sphinx/cmd/quickstart.py b/sphinx/cmd/quickstart.py
index 6639bf7e9..c8b1b4fdd 100644
--- a/sphinx/cmd/quickstart.py
+++ b/sphinx/cmd/quickstart.py
@@ -516,7 +516,7 @@ def get_parser():
     group = parser.add_argument_group(__('Structure options'))
     group.add_argument('--sep', action='store_true', default=None,
                        help=__('if specified, separate source and build dirs'))
-    group.add_argument('--dot', metavar='DOT',
+    group.add_argument('--dot', metavar='DOT', default='_',
                        help=__('replacement for dot in _templates etc.'))
 
     group = parser.add_argument_group(__('Project basic options'))
@@ -530,9 +530,9 @@ def get_parser():
                        help=__('release of project'))
     group.add_argument('-l', '--language', metavar='LANGUAGE', dest='language',
                        help=__('document language'))
-    group.add_argument('--suffix', metavar='SUFFIX',
+    group.add_argument('--suffix', metavar='SUFFIX', default='.rst',
                        help=__('source file suffix'))
-    group.add_argument('--master', metavar='MASTER',
+    group.add_argument('--master', metavar='MASTER', default='index',
                        help=__('master document name'))
     group.add_argument('--epub', action='store_true', default=False,
                        help=__('use epub'))
@@ -546,11 +546,11 @@ def get_parser():
                        action='append', help=__('enable arbitrary extensions'))
 
     group = parser.add_argument_group(__('Makefile and Batchfile creation'))
-    group.add_argument('--makefile', action='store_true', dest='makefile', default=None,
+    group.add_argument('--makefile', action='store_true', dest='makefile', default=True,
                        help=__('create makefile'))
     group.add_argument('--no-makefile', action='store_false', dest='makefile',
                        help=__('do not create makefile'))
-    group.add_argument('--batchfile', action='store_true', dest='batchfile', default=None,
+    group.add_argument('--batchfile', action='store_true', dest='batchfile', default=True,
                        help=__('create batchfile'))
     group.add_argument('--no-batchfile', action='store_false',
                        dest='batchfile',
@@ -592,6 +592,13 @@ def main(argv=sys.argv[1:]):
     # delete None or False value
     d = dict((k, v) for k, v in d.items() if v is not None)
 
+    # handle use of CSV-style extension values
+    d.setdefault('extensions', [])
+    for ext in d['extensions'][:]:
+        if ',' in ext:
+            d['extensions'].remove(ext)
+            d['extensions'].extend(ext.split(','))
+
     try:
         if 'quiet' in d:
             if not set(['project', 'author']).issubset(d):
@@ -621,13 +628,6 @@ def main(argv=sys.argv[1:]):
         print('[Interrupted.]')
         return 130  # 128 + SIGINT
 
-    # handle use of CSV-style extension values
-    d.setdefault('extensions', [])
-    for ext in d['extensions'][:]:
-        if ',' in ext:
-            d['extensions'].remove(ext)
-            d['extensions'].extend(ext.split(','))
-
     for variable in d.get('variables', []):
         try:
             name, value = variable.split('=')
diff --git a/sphinx/themes/basic/static/basic.css_t b/sphinx/themes/basic/static/basic.css_t
index ec30e8432..5bdd803eb 100644
--- a/sphinx/themes/basic/static/basic.css_t
+++ b/sphinx/themes/basic/static/basic.css_t
@@ -231,16 +231,6 @@ a.headerlink {
     visibility: hidden;
 }
 
-a.brackets:before,
-span.brackets > a:before{
-    content: "[";
-}
-
-a.brackets:after,
-span.brackets > a:after {
-    content: "]";
-}
-
 h1:hover > a.headerlink,
 h2:hover > a.headerlink,
 h3:hover > a.headerlink,
@@ -401,14 +391,6 @@ table.citation td {
     border-bottom: none;
 }
 
-td > p:first-child {
-    margin-top: 0px;
-}
-
-td > p:only-child {
-    margin-bottom: 0px;
-}
-
 /* -- figures --------------------------------------------------------------- */
 
 div.figure {
@@ -478,57 +460,11 @@ ol.upperroman {
     list-style: upper-roman;
 }
 
-li > p:first-child {
-    margin-top: 0px;
-}
-
-li > p:only-child {
-    margin-bottom: 0px;
-}
-
-dl.footnote > dt,
-dl.citation > dt {
-    float: left;
-}
-
-dl.footnote > dd,
-dl.citation > dd {
-    margin-bottom: 0em;
-}
-
-dl.footnote > dd:after,
-dl.citation > dd:after {
-    content: "";
-    clear: both;
-}
-
-dl.field-list {
-    display: flex;
-    flex-wrap: wrap;
-}
-
-dl.field-list > dt {
-    flex-basis: 20%;
-    font-weight: bold;
-    word-break: break-word;
-}
-
-dl.field-list > dt:after {
-    content: ":";
-}
-
-dl.field-list > dd {
-    flex-basis: 70%;
-    padding-left: 1em;
-    margin-left: 0em;
-    margin-bottom: 0em;
-}
-
 dl {
     margin-bottom: 15px;
 }
 
-dd > p:first-child {
+dd p {
     margin-top: 0px;
 }
 


Test patch:
diff --git a/tests/test_api_translator.py b/tests/test_api_translator.py
index 3e97cbc5a..7e2767681 100644
--- a/tests/test_api_translator.py
+++ b/tests/test_api_translator.py
@@ -12,8 +12,6 @@
 
 import pytest
 
-from sphinx.util import docutils
-
 
 @pytest.fixture(scope='module', autouse=True)
 def setup_module(rootdir):
@@ -28,10 +26,7 @@ def test_html_translator(app, status, warning):
     # no set_translator()
     translator_class = app.builder.get_translator_class()
     assert translator_class
-    if docutils.__version_info__ < (0, 13):
-        assert translator_class.__name__ == 'HTMLTranslator'
-    else:
-        assert translator_class.__name__ == 'HTML5Translator'
+    assert translator_class.__name__ == 'HTMLTranslator'
 
 
 @pytest.mark.sphinx('html', testroot='api-set-translator')
diff --git a/tests/test_build_html.py b/tests/test_build_html.py
index 77c86962e..514d0030c 100644
--- a/tests/test_build_html.py
+++ b/tests/test_build_html.py
@@ -10,7 +10,6 @@
 
 import os
 import re
-from hashlib import md5
 from itertools import cycle, chain
 
 import pytest
@@ -18,7 +17,6 @@
 
 from sphinx.errors import ConfigError
 from sphinx.testing.util import strip_escseq
-from sphinx.util import docutils
 from sphinx.util.inventory import InventoryFile
 
 
@@ -130,11 +128,6 @@ def test_html_warnings(app, warning):
         '--- Got:\n' + html_warnings
 
 
-@pytest.mark.sphinx('html', confoverrides={'html4_writer': True})
-def test_html4_output(app, status, warning):
-    app.build()
-
-
 @pytest.mark.parametrize("fname,expect", flat_dict({
     'images.html': [
         (".//img[@src='_images/img.png']", ''),
@@ -199,18 +192,18 @@ def test_html4_output(app, status, warning):
         # an option list
         (".//span[@class='option']", '--help'),
         # admonitions
-        (".//p[@class='admonition-title']", 'My Admonition'),
-        (".//div[@class='admonition note']/p", 'Note text.'),
-        (".//div[@class='admonition warning']/p", 'Warning text.'),
+        (".//p[@class='first admonition-title']", 'My Admonition'),
+        (".//p[@class='last']", 'Note text.'),
+        (".//p[@class='last']", 'Warning text.'),
         # inline markup
-        (".//li/p/strong", r'^command\\n$'),
-        (".//li/p/strong", r'^program\\n$'),
-        (".//li/p/em", r'^dfn\\n$'),
-        (".//li/p/kbd", r'^kbd\\n$'),
-        (".//li/p/span", 'File \N{TRIANGULAR BULLET} Close'),
-        (".//li/p/code/span[@class='pre']", '^a/$'),
-        (".//li/p/code/em/span[@class='pre']", '^varpart$'),
-        (".//li/p/code/em/span[@class='pre']", '^i$'),
+        (".//li/strong", r'^command\\n$'),
+        (".//li/strong", r'^program\\n$'),
+        (".//li/em", r'^dfn\\n$'),
+        (".//li/kbd", r'^kbd\\n$'),
+        (".//li/span", 'File \N{TRIANGULAR BULLET} Close'),
+        (".//li/code/span[@class='pre']", '^a/$'),
+        (".//li/code/em/span[@class='pre']", '^varpart$'),
+        (".//li/code/em/span[@class='pre']", '^i$'),
         (".//a[@href='https://www.python.org/dev/peps/pep-0008']"
          "[@class='pep reference external']/strong", 'PEP 8'),
         (".//a[@href='https://www.python.org/dev/peps/pep-0008']"
@@ -243,13 +236,13 @@ def test_html4_output(app, status, warning):
         (".//div[@class='versionchanged']/p",
          'Second paragraph of versionchanged'),
         # footnote reference
-        (".//a[@class='footnote-reference brackets']", r'1'),
+        (".//a[@class='footnote-reference']", r'\[1\]'),
         # created by reference lookup
         (".//a[@href='index.html#ref1']", ''),
         # ``seealso`` directive
-        (".//div/p[@class='admonition-title']", 'See also'),
+        (".//div/p[@class='first admonition-title']", 'See also'),
         # a ``hlist`` directive
-        (".//table[@class='hlist']/tbody/tr/td/ul/li/p", '^This$'),
+        (".//table[@class='hlist']/tbody/tr/td/ul/li", '^This$'),
         # a ``centered`` directive
         (".//p[@class='centered']/strong", 'LICENSE'),
         # a glossary
@@ -268,10 +261,10 @@ def test_html4_output(app, status, warning):
         # tests for numeric labels
         (".//a[@href='#id1'][@class='reference internal']/span", 'Testing various markup'),
         # tests for smartypants
-        (".//li/p", 'Smart “quotes” in English ‘text’.'),
-        (".//li/p", 'Smart — long and – short dashes.'),
-        (".//li/p", 'Ellipsis…'),
-        (".//li/p/code/span[@class='pre']", 'foo--"bar"...'),
+        (".//li", 'Smart “quotes” in English ‘text’.'),
+        (".//li", 'Smart — long and – short dashes.'),
+        (".//li", 'Ellipsis…'),
+        (".//li//code//span[@class='pre']", 'foo--"bar"...'),
         (".//p", 'Этот «абзац» должен использовать „русские“ кавычки.'),
         (".//p", 'Il dit : « C’est “super” ! »'),
     ],
@@ -301,24 +294,24 @@ def test_html4_output(app, status, warning):
         (".//li[@class='toctree-l1']/a[@href='markup.html']",
          'Testing various markup'),
         # test unknown field names
-        (".//dt[@class='field-odd']", 'Field_name'),
-        (".//dt[@class='field-even']", 'Field_name all lower'),
-        (".//dt[@class='field-odd']", 'FIELD_NAME'),
-        (".//dt[@class='field-even']", 'FIELD_NAME ALL CAPS'),
-        (".//dt[@class='field-odd']", 'Field_Name'),
-        (".//dt[@class='field-even']", 'Field_Name All Word Caps'),
-        (".//dt[@class='field-odd']", 'Field_name'),
-        (".//dt[@class='field-even']", 'Field_name First word cap'),
-        (".//dt[@class='field-odd']", 'FIELd_name'),
-        (".//dt[@class='field-even']", 'FIELd_name PARTial caps'),
+        (".//th[@class='field-name']", 'Field_name:'),
+        (".//th[@class='field-name']", 'Field_name all lower:'),
+        (".//th[@class='field-name']", 'FIELD_NAME:'),
+        (".//th[@class='field-name']", 'FIELD_NAME ALL CAPS:'),
+        (".//th[@class='field-name']", 'Field_Name:'),
+        (".//th[@class='field-name']", 'Field_Name All Word Caps:'),
+        (".//th[@class='field-name']", 'Field_name:'),
+        (".//th[@class='field-name']", 'Field_name First word cap:'),
+        (".//th[@class='field-name']", 'FIELd_name:'),
+        (".//th[@class='field-name']", 'FIELd_name PARTial caps:'),
         # custom sidebar
         (".//h4", 'Custom sidebar'),
         # docfields
-        (".//dd[@class='field-odd']/p/strong", '^moo$'),
-        (".//dd[@class='field-odd']/p/strong", tail_check(r'\(Moo\) .* Moo')),
-        (".//dd[@class='field-odd']/ul/li/p/strong", '^hour$'),
-        (".//dd[@class='field-odd']/ul/li/p/em", '^DuplicateType$'),
-        (".//dd[@class='field-odd']/ul/li/p/em", tail_check(r'.* Some parameter')),
+        (".//td[@class='field-body']/strong", '^moo$'),
+        (".//td[@class='field-body']/strong", tail_check(r'\(Moo\) .* Moo')),
+        (".//td[@class='field-body']/ul/li/strong", '^hour$'),
+        (".//td[@class='field-body']/ul/li/em", '^DuplicateType$'),
+        (".//td[@class='field-body']/ul/li/em", tail_check(r'.* Some parameter')),
         # others
         (".//a[@class='reference internal'][@href='#cmdoption-perl-arg-p']/code/span",
          'perl'),
@@ -347,17 +340,17 @@ def test_html4_output(app, status, warning):
     'index.html': [
         (".//meta[@name='hc'][@content='hcval']", ''),
         (".//meta[@name='hc_co'][@content='hcval_co']", ''),
-        (".//dt[@class='label']/span[@class='brackets']", r'Ref1'),
-        (".//dt[@class='label']", ''),
+        (".//td[@class='label']", r'\[Ref1\]'),
+        (".//td[@class='label']", ''),
         (".//li[@class='toctree-l1']/a", 'Testing various markup'),
         (".//li[@class='toctree-l2']/a", 'Inline markup'),
         (".//title", 'Sphinx <Tests>'),
         (".//div[@class='footer']", 'Georg Brandl & Team'),
         (".//a[@href='http://python.org/']"
          "[@class='reference external']", ''),
-        (".//li/p/a[@href='genindex.html']/span", 'Index'),
-        (".//li/p/a[@href='py-modindex.html']/span", 'Module Index'),
-        (".//li/p/a[@href='search.html']/span", 'Search Page'),
+        (".//li/a[@href='genindex.html']/span", 'Index'),
+        (".//li/a[@href='py-modindex.html']/span", 'Module Index'),
+        (".//li/a[@href='search.html']/span", 'Search Page'),
         # custom sidebar only for contents
         (".//h4", 'Contents sidebar'),
         # custom JavaScript
@@ -388,41 +381,37 @@ def test_html4_output(app, status, warning):
         (".//li/a", "double"),
     ],
     'footnote.html': [
-        (".//a[@class='footnote-reference brackets'][@href='#id9'][@id='id1']", r"1"),
-        (".//a[@class='footnote-reference brackets'][@href='#id10'][@id='id2']", r"2"),
-        (".//a[@class='footnote-reference brackets'][@href='#foo'][@id='id3']", r"3"),
+        (".//a[@class='footnote-reference'][@href='#id9'][@id='id1']", r"\[1\]"),
+        (".//a[@class='footnote-reference'][@href='#id10'][@id='id2']", r"\[2\]"),
+        (".//a[@class='footnote-reference'][@href='#foo'][@id='id3']", r"\[3\]"),
         (".//a[@class='reference internal'][@href='#bar'][@id='id4']", r"\[bar\]"),
         (".//a[@class='reference internal'][@href='#baz-qux'][@id='id5']", r"\[baz_qux\]"),
-        (".//a[@class='footnote-reference brackets'][@href='#id11'][@id='id6']", r"4"),
-        (".//a[@class='footnote-reference brackets'][@href='#id12'][@id='id7']", r"5"),
-        (".//a[@class='fn-backref'][@href='#id1']", r"1"),
-        (".//a[@class='fn-backref'][@href='#id2']", r"2"),
-        (".//a[@class='fn-backref'][@href='#id3']", r"3"),
-        (".//a[@class='fn-backref'][@href='#id4']", r"bar"),
-        (".//a[@class='fn-backref'][@href='#id5']", r"baz_qux"),
-        (".//a[@class='fn-backref'][@href='#id6']", r"4"),
-        (".//a[@class='fn-backref'][@href='#id7']", r"5"),
-        (".//a[@class='fn-backref'][@href='#id8']", r"6"),
+        (".//a[@class='footnote-reference'][@href='#id11'][@id='id6']", r"\[4\]"),
+        (".//a[@class='footnote-reference'][@href='#id12'][@id='id7']", r"\[5\]"),
+        (".//a[@class='fn-backref'][@href='#id1']", r"\[1\]"),
+        (".//a[@class='fn-backref'][@href='#id2']", r"\[2\]"),
+        (".//a[@class='fn-backref'][@href='#id3']", r"\[3\]"),
+        (".//a[@class='fn-backref'][@href='#id4']", r"\[bar\]"),
+        (".//a[@class='fn-backref'][@href='#id5']", r"\[baz_qux\]"),
+        (".//a[@class='fn-backref'][@href='#id6']", r"\[4\]"),
+        (".//a[@class='fn-backref'][@href='#id7']", r"\[5\]"),
+        (".//a[@class='fn-backref'][@href='#id8']", r"\[6\]"),
     ],
     'otherext.html': [
         (".//h1", "Generated section"),
         (".//a[@href='_sources/otherext.foo.txt']", ''),
     ]
 }))
-@pytest.mark.skipif(docutils.__version_info__ < (0, 13),
-                    reason='docutils-0.13 or above is required')
-@pytest.mark.sphinx('html', tags=['testtag'],
-                    confoverrides={'html_context.hckey_co': 'hcval_co'})
+@pytest.mark.sphinx('html', tags=['testtag'], confoverrides={
+    'html_context.hckey_co': 'hcval_co'})
 @pytest.mark.test_params(shared_result='test_build_html_output')
-def test_html5_output(app, cached_etree_parse, fname, expect):
+def test_html_output(app, cached_etree_parse, fname, expect):
     app.build()
-    print(app.outdir / fname)
     check_xpath(cached_etree_parse(app.outdir / fname), fname, *expect)
 
 
-@pytest.mark.skipif(docutils.__version_info__ < (0, 13),
-                    reason='docutils-0.13 or above is required')
-@pytest.mark.sphinx('html')
+@pytest.mark.sphinx('html', tags=['testtag'], confoverrides={
+    'html_context.hckey_co': 'hcval_co'})
 @pytest.mark.test_params(shared_result='test_build_html_output')
 def test_html_download(app):
     app.build()
@@ -446,29 +435,6 @@ def test_html_download(app):
     assert matched.group(1) == filename
 
 
-@pytest.mark.skipif(docutils.__version_info__ < (0, 13),
-                    reason='docutils-0.13 or above is required')
-@pytest.mark.sphinx('html', testroot='roles-download')
-def test_html_download_role(app, status, warning):
-    app.build()
-    digest = md5((app.srcdir / 'dummy.dat').encode()).hexdigest()
-    assert (app.outdir / '_downloads' / digest / 'dummy.dat').exists()
-
-    content = (app.outdir / 'index.html').text()
-    assert (('<li><p><a class="reference download internal" download="" '
-             'href="_downloads/%s/dummy.dat">'
-             '<code class="xref download docutils literal notranslate">'
-             '<span class="pre">dummy.dat</span></code></a></p></li>' % digest)
-            in content)
-    assert ('<li><p><code class="xref download docutils literal notranslate">'
-            '<span class="pre">not_found.dat</span></code></p></li>' in content)
-    assert ('<li><p><a class="reference download external" download="" '
-            'href="http://www.sphinx-doc.org/en/master/_static/sphinxheader.png">'
-            '<code class="xref download docutils literal notranslate">'
-            '<span class="pre">Sphinx</span> <span class="pre">logo</span>'
-            '</code></a></p></li>' in content)
-
-
 @pytest.mark.sphinx('html', testroot='build-html-translator')
 def test_html_translator(app):
     app.build()
@@ -507,8 +473,6 @@ def test_html_translator(app):
         (".//h1", '2.1.1. Baz A', True),
     ],
 }))
-@pytest.mark.skipif(docutils.__version_info__ < (0, 13),
-                    reason='docutils-0.13 or above is required')
 @pytest.mark.sphinx('html', testroot='tocdepth')
 @pytest.mark.test_params(shared_result='test_build_html_tocdepth')
 def test_tocdepth(app, cached_etree_parse, fname, expect):
@@ -544,8 +508,6 @@ def test_tocdepth(app, cached_etree_parse, fname, expect):
         (".//h4", '2.1.1. Baz A', True),
     ],
 }))
-@pytest.mark.skipif(docutils.__version_info__ < (0, 13),
-                    reason='docutils-0.13 or above is required')
 @pytest.mark.sphinx('singlehtml', testroot='tocdepth')
 @pytest.mark.test_params(shared_result='test_build_html_tocdepth')
 def test_tocdepth_singlehtml(app, cached_etree_parse, fname, expect):
@@ -570,16 +532,16 @@ def test_numfig_disabled_warn(app, warning):
         (".//table/caption/span[@class='caption-number']", None, True),
         (".//div[@class='code-block-caption']/"
          "span[@class='caption-number']", None, True),
-        (".//li/p/code/span", '^fig1$', True),
-        (".//li/p/code/span", '^Figure%s$', True),
-        (".//li/p/code/span", '^table-1$', True),
-        (".//li/p/code/span", '^Table:%s$', True),
-        (".//li/p/code/span", '^CODE_1$', True),
-        (".//li/p/code/span", '^Code-%s$', True),
-        (".//li/p/a/span", '^Section 1$', True),
-        (".//li/p/a/span", '^Section 2.1$', True),
-        (".//li/p/code/span", '^Fig.{number}$', True),
-        (".//li/p/a/span", '^Sect.1 Foo$', True),
+        (".//li/code/span", '^fig1$', True),
+        (".//li/code/span", '^Figure%s$', True),
+        (".//li/code/span", '^table-1$', True),
+        (".//li/code/span", '^Table:%s$', True),
+        (".//li/code/span", '^CODE_1$', True),
+        (".//li/code/span", '^Code-%s$', True),
+        (".//li/a/span", '^Section 1$', True),
+        (".//li/a/span", '^Section 2.1$', True),
+        (".//li/code/span", '^Fig.{number}$', True),
+        (".//li/a/span", '^Sect.1 Foo$', True),
     ],
     'foo.html': [
         (".//div[@class='figure align-center']/p[@class='caption']/"
@@ -603,8 +565,6 @@ def test_numfig_disabled_warn(app, warning):
          "span[@class='caption-number']", None, True),
     ],
 }))
-@pytest.mark.skipif(docutils.__version_info__ < (0, 13),
-                    reason='docutils-0.13 or above is required')
 @pytest.mark.sphinx('html', testroot='numfig')
 @pytest.mark.test_params(shared_result='test_build_html_numfig')
 def test_numfig_disabled(app, cached_etree_parse, fname, expect):
@@ -645,16 +605,16 @@ def test_numfig_without_numbered_toctree_warn(app, warning):
          "span[@class='caption-number']", '^Listing 9 $', True),
         (".//div[@class='code-block-caption']/"
          "span[@class='caption-number']", '^Listing 10 $', True),
-        (".//li/p/a/span", '^Fig. 9$', True),
-        (".//li/p/a/span", '^Figure6$', True),
-        (".//li/p/a/span", '^Table 9$', True),
-        (".//li/p/a/span", '^Table:6$', True),
-        (".//li/p/a/span", '^Listing 9$', True),
-        (".//li/p/a/span", '^Code-6$', True),
-        (".//li/p/code/span", '^foo$', True),
-        (".//li/p/code/span", '^bar_a$', True),
-        (".//li/p/a/span", '^Fig.9 should be Fig.1$', True),
-        (".//li/p/code/span", '^Sect.{number}$', True),
+        (".//li/a/span", '^Fig. 9$', True),
+        (".//li/a/span", '^Figure6$', True),
+        (".//li/a/span", '^Table 9$', True),
+        (".//li/a/span", '^Table:6$', True),
+        (".//li/a/span", '^Listing 9$', True),
+        (".//li/a/span", '^Code-6$', True),
+        (".//li/code/span", '^foo$', True),
+        (".//li/code/span", '^bar_a$', True),
+        (".//li/a/span", '^Fig.9 should be Fig.1$', True),
+        (".//li/code/span", '^Sect.{number}$', True),
     ],
     'foo.html': [
         (".//div[@class='figure align-center']/p[@class='caption']/"
@@ -711,8 +671,6 @@ def test_numfig_without_numbered_toctree_warn(app, warning):
          "span[@class='caption-number']", '^Listing 6 $', True),
     ],
 }))
-@pytest.mark.skipif(docutils.__version_info__ < (0, 13),
-                    reason='docutils-0.13 or above is required')
 @pytest.mark.sphinx(
     'html', testroot='numfig',
     srcdir='test_numfig_without_numbered_toctree',
@@ -753,16 +711,16 @@ def test_numfig_with_numbered_toctree_warn(app, warning):
          "span[@class='caption-number']", '^Listing 1 $', True),
         (".//div[@class='code-block-caption']/"
          "span[@class='caption-number']", '^Listing 2 $', True),
-        (".//li/p/a/span", '^Fig. 1$', True),
-        (".//li/p/a/span", '^Figure2.2$', True),
-        (".//li/p/a/span", '^Table 1$', True),
-        (".//li/p/a/span", '^Table:2.2$', True),
-        (".//li/p/a/span", '^Listing 1$', True),
-        (".//li/p/a/span", '^Code-2.2$', True),
-        (".//li/p/a/span", '^Section.1$', True),
-        (".//li/p/a/span", '^Section.2.1$', True),
-        (".//li/p/a/span", '^Fig.1 should be Fig.1$', True),
-        (".//li/p/a/span", '^Sect.1 Foo$', True),
+        (".//li/a/span", '^Fig. 1$', True),
+        (".//li/a/span", '^Figure2.2$', True),
+        (".//li/a/span", '^Table 1$', True),
+        (".//li/a/span", '^Table:2.2$', True),
+        (".//li/a/span", '^Listing 1$', True),
+        (".//li/a/span", '^Code-2.2$', True),
+        (".//li/a/span", '^Section.1$', True),
+        (".//li/a/span", '^Section.2.1$', True),
+        (".//li/a/span", '^Fig.1 should be Fig.1$', True),
+        (".//li/a/span", '^Sect.1 Foo$', True),
     ],
     'foo.html': [
         (".//div[@class='figure align-center']/p[@class='caption']/"
@@ -819,8 +777,6 @@ def test_numfig_with_numbered_toctree_warn(app, warning):
          "span[@class='caption-number']", '^Listing 2.2 $', True),
     ],
 }))
-@pytest.mark.skipif(docutils.__version_info__ < (0, 13),
-                    reason='docutils-0.13 or above is required')
 @pytest.mark.sphinx('html', testroot='numfig', confoverrides={'numfig': True})
 @pytest.mark.test_params(shared_result='test_build_html_numfig_on')
 def test_numfig_with_numbered_toctree(app, cached_etree_parse, fname, expect):
@@ -858,16 +814,16 @@ def test_numfig_with_prefix_warn(app, warning):
          "span[@class='caption-number']", '^Code-1 $', True),
         (".//div[@class='code-block-caption']/"
          "span[@class='caption-number']", '^Code-2 $', True),
-        (".//li/p/a/span", '^Figure:1$', True),
-        (".//li/p/a/span", '^Figure2.2$', True),
-        (".//li/p/a/span", '^Tab_1$', True),
-        (".//li/p/a/span", '^Table:2.2$', True),
-        (".//li/p/a/span", '^Code-1$', True),
-        (".//li/p/a/span", '^Code-2.2$', True),
-        (".//li/p/a/span", '^SECTION-1$', True),
-        (".//li/p/a/span", '^SECTION-2.1$', True),
-        (".//li/p/a/span", '^Fig.1 should be Fig.1$', True),
-        (".//li/p/a/span", '^Sect.1 Foo$', True),
+        (".//li/a/span", '^Figure:1$', True),
+        (".//li/a/span", '^Figure2.2$', True),
+        (".//li/a/span", '^Tab_1$', True),
+        (".//li/a/span", '^Table:2.2$', True),
+        (".//li/a/span", '^Code-1$', True),
+        (".//li/a/span", '^Code-2.2$', True),
+        (".//li/a/span", '^SECTION-1$', True),
+        (".//li/a/span", '^SECTION-2.1$', True),
+        (".//li/a/span", '^Fig.1 should be Fig.1$', True),
+        (".//li/a/span", '^Sect.1 Foo$', True),
     ],
     'foo.html': [
         (".//div[@class='figure align-center']/p[@class='caption']/"
@@ -924,22 +880,20 @@ def test_numfig_with_prefix_warn(app, warning):
          "span[@class='caption-number']", '^Code-2.2 $', True),
     ],
 }))
-@pytest.mark.skipif(docutils.__version_info__ < (0, 13),
-                    reason='docutils-0.13 or above is required')
-@pytest.mark.sphinx('html', testroot='numfig',
-                    confoverrides={'numfig': True,
-                                   'numfig_format': {'figure': 'Figure:%s',
-                                                     'table': 'Tab_%s',
-                                                     'code-block': 'Code-%s',
-                                                     'section': 'SECTION-%s'}})
+@pytest.mark.sphinx('html', testroot='numfig', confoverrides={
+    'numfig': True,
+    'numfig_format': {'figure': 'Figure:%s',
+                      'table': 'Tab_%s',
+                      'code-block': 'Code-%s',
+                      'section': 'SECTION-%s'}})
 @pytest.mark.test_params(shared_result='test_build_html_numfig_format_warn')
 def test_numfig_with_prefix(app, cached_etree_parse, fname, expect):
     app.build()
     check_xpath(cached_etree_parse(app.outdir / fname), fname, *expect)
 
 
-@pytest.mark.sphinx('html', testroot='numfig',
-                    confoverrides={'numfig': True, 'numfig_secnum_depth': 2})
+@pytest.mark.sphinx('html', testroot='numfig', confoverrides={
+    'numfig': True, 'numfig_secnum_depth': 2})
 @pytest.mark.test_params(shared_result='test_build_html_numfig_depth_2')
 def test_numfig_with_secnum_depth_warn(app, warning):
     app.build()
@@ -964,16 +918,16 @@ def test_numfig_with_secnum_depth_warn(app, warning):
          "span[@class='caption-number']", '^Listing 1 $', True),
         (".//div[@class='code-block-caption']/"
          "span[@class='caption-number']", '^Listing 2 $', True),
-        (".//li/p/a/span", '^Fig. 1$', True),
-        (".//li/p/a/span", '^Figure2.1.2$', True),
-        (".//li/p/a/span", '^Table 1$', True),
-        (".//li/p/a/span", '^Table:2.1.2$', True),
-        (".//li/p/a/span", '^Listing 1$', True),
-        (".//li/p/a/span", '^Code-2.1.2$', True),
-        (".//li/p/a/span", '^Section.1$', True),
-        (".//li/p/a/span", '^Section.2.1$', True),
-        (".//li/p/a/span", '^Fig.1 should be Fig.1$', True),
-        (".//li/p/a/span", '^Sect.1 Foo$', True),
+        (".//li/a/span", '^Fig. 1$', True),
+        (".//li/a/span", '^Figure2.1.2$', True),
+        (".//li/a/span", '^Table 1$', True),
+        (".//li/a/span", '^Table:2.1.2$', True),
+        (".//li/a/span", '^Listing 1$', True),
+        (".//li/a/span", '^Code-2.1.2$', True),
+        (".//li/a/span", '^Section.1$', True),
+        (".//li/a/span", '^Section.2.1$', True),
+        (".//li/a/span", '^Fig.1 should be Fig.1$', True),
+        (".//li/a/span", '^Sect.1 Foo$', True),
     ],
     'foo.html': [
         (".//div[@class='figure align-center']/p[@class='caption']/"
@@ -1030,11 +984,8 @@ def test_numfig_with_secnum_depth_warn(app, warning):
          "span[@class='caption-number']", '^Listing 2.1.2 $', True),
     ],
 }))
-@pytest.mark.skipif(docutils.__version_info__ < (0, 13),
-                    reason='docutils-0.13 or above is required')
-@pytest.mark.sphinx('html', testroot='numfig',
-                    confoverrides={'numfig': True,
-                                   'numfig_secnum_depth': 2})
+@pytest.mark.sphinx('html', testroot='numfig', confoverrides={
+    'numfig': True, 'numfig_secnum_depth': 2})
 @pytest.mark.test_params(shared_result='test_build_html_numfig_depth_2')
 def test_numfig_with_secnum_depth(app, cached_etree_parse, fname, expect):
     app.build()
@@ -1055,16 +1006,16 @@ def test_numfig_with_secnum_depth(app, cached_etree_parse, fname, expect):
          "span[@class='caption-number']", '^Listing 1 $', True),
         (".//div[@class='code-block-caption']/"
          "span[@class='caption-number']", '^Listing 2 $', True),
-        (".//li/p/a/span", '^Fig. 1$', True),
-        (".//li/p/a/span", '^Figure2.2$', True),
-        (".//li/p/a/span", '^Table 1$', True),
-        (".//li/p/a/span", '^Table:2.2$', True),
-        (".//li/p/a/span", '^Listing 1$', True),
-        (".//li/p/a/span", '^Code-2.2$', True),
-        (".//li/p/a/span", '^Section.1$', True),
-        (".//li/p/a/span", '^Section.2.1$', True),
-        (".//li/p/a/span", '^Fig.1 should be Fig.1$', True),
-        (".//li/p/a/span", '^Sect.1 Foo$', True),
+        (".//li/a/span", '^Fig. 1$', True),
+        (".//li/a/span", '^Figure2.2$', True),
+        (".//li/a/span", '^Table 1$', True),
+        (".//li/a/span", '^Table:2.2$', True),
+        (".//li/a/span", '^Listing 1$', True),
+        (".//li/a/span", '^Code-2.2$', True),
+        (".//li/a/span", '^Section.1$', True),
+        (".//li/a/span", '^Section.2.1$', True),
+        (".//li/a/span", '^Fig.1 should be Fig.1$', True),
+        (".//li/a/span", '^Sect.1 Foo$', True),
         (".//div[@class='figure align-center']/p[@class='caption']/"
          "span[@class='caption-number']", '^Fig. 1.1 $', True),
         (".//div[@class='figure align-center']/p[@class='caption']/"
@@ -1115,9 +1066,8 @@ def test_numfig_with_secnum_depth(app, cached_etree_parse, fname, expect):
          "span[@class='caption-number']", '^Listing 2.2 $', True),
     ],
 }))
-@pytest.mark.skipif(docutils.__version_info__ < (0, 13),
-                    reason='docutils-0.13 or above is required')
-@pytest.mark.sphinx('singlehtml', testroot='numfig', confoverrides={'numfig': True})
+@pytest.mark.sphinx('singlehtml', testroot='numfig', confoverrides={
+    'numfig': True})
 @pytest.mark.test_params(shared_result='test_build_html_numfig_on')
 def test_numfig_with_singlehtml(app, cached_etree_parse, fname, expect):
     app.build()
@@ -1134,17 +1084,17 @@ def test_numfig_with_singlehtml(app, cached_etree_parse, fname, expect):
          "/span[@class='caption-number']", "Fig. 3", True),
         (".//div//span[@class='caption-number']", "No.1 ", True),
         (".//div//span[@class='caption-number']", "No.2 ", True),
-        (".//li/p/a/span", 'Fig. 1', True),
-        (".//li/p/a/span", 'Fig. 2', True),
-        (".//li/p/a/span", 'Fig. 3', True),
-        (".//li/p/a/span", 'No.1', True),
-        (".//li/p/a/span", 'No.2', True),
+        (".//li/a/span", 'Fig. 1', True),
+        (".//li/a/span", 'Fig. 2', True),
+        (".//li/a/span", 'Fig. 3', True),
+        (".//li/a/span", 'No.1', True),
+        (".//li/a/span", 'No.2', True),
     ],
 }))
-@pytest.mark.skipif(docutils.__version_info__ < (0, 13),
-                    reason='docutils-0.13 or above is required')
-@pytest.mark.sphinx('html', testroot='add_enumerable_node',
-                    srcdir='test_enumerable_node')
+@pytest.mark.sphinx(
+    'html', testroot='add_enumerable_node',
+    srcdir='test_enumerable_node',
+)
 def test_enumerable_node(app, cached_etree_parse, fname, expect):
     app.build()
     check_xpath(cached_etree_parse(app.outdir / fname), fname, *expect)
diff --git a/tests/test_build_html5.py b/tests/test_build_html5.py
new file mode 100644
index 000000000..2c4ae517a
--- /dev/null
+++ b/tests/test_build_html5.py
@@ -0,0 +1,372 @@
+"""
+    test_build_html5
+    ~~~~~~~~~~~~~~~~
+
+    Test the HTML5 writer and check output against XPath.
+
+    This code is digest to reduce test running time.
+    Complete test code is here:
+
+    https://github.com/sphinx-doc/sphinx/pull/2805/files
+
+    :copyright: Copyright 2007-2019 by the Sphinx team, see AUTHORS.
+    :license: BSD, see LICENSE for details.
+"""
+
+import re
+from hashlib import md5
+
+import pytest
+from html5lib import HTMLParser
+from test_build_html import flat_dict, tail_check, check_xpath
+
+from sphinx.util import docutils
+from sphinx.util.docutils import is_html5_writer_available
+
+
+etree_cache = {}
+
+
+@pytest.mark.skipif(not is_html5_writer_available(), reason='HTML5 writer is not available')
+@pytest.fixture(scope='module')
+def cached_etree_parse():
+    def parse(fname):
+        if fname in etree_cache:
+            return etree_cache[fname]
+        with (fname).open('rb') as fp:
+            etree = HTMLParser(namespaceHTMLElements=False).parse(fp)
+            etree_cache.clear()
+            etree_cache[fname] = etree
+            return etree
+    yield parse
+    etree_cache.clear()
+
+
+@pytest.mark.skipif(not is_html5_writer_available(), reason='HTML5 writer is not available')
+@pytest.mark.parametrize("fname,expect", flat_dict({
+    'images.html': [
+        (".//img[@src='_images/img.png']", ''),
+        (".//img[@src='_images/img1.png']", ''),
+        (".//img[@src='_images/simg.png']", ''),
+        (".//img[@src='_images/svgimg.svg']", ''),
+        (".//a[@href='_sources/images.txt']", ''),
+    ],
+    'subdir/images.html': [
+        (".//img[@src='../_images/img1.png']", ''),
+        (".//img[@src='../_images/rimg.png']", ''),
+    ],
+    'subdir/includes.html': [
+        (".//a[@class='reference download internal']", ''),
+        (".//img[@src='../_images/img.png']", ''),
+        (".//p", 'This is an include file.'),
+        (".//pre/span", 'line 1'),
+        (".//pre/span", 'line 2'),
+    ],
+    'includes.html': [
+        (".//pre", 'Max Strauß'),
+        (".//a[@class='reference download internal']", ''),
+        (".//pre/span", '"quotes"'),
+        (".//pre/span", "'included'"),
+        (".//pre/span[@class='s2']", 'üöä'),
+        (".//div[@class='inc-pyobj1 highlight-text notranslate']//pre",
+         r'^class Foo:\n    pass\n\s*$'),
+        (".//div[@class='inc-pyobj2 highlight-text notranslate']//pre",
+         r'^    def baz\(\):\n        pass\n\s*$'),
+        (".//div[@class='inc-lines highlight-text notranslate']//pre",
+         r'^class Foo:\n    pass\nclass Bar:\n$'),
+        (".//div[@class='inc-startend highlight-text notranslate']//pre",
+         '^foo = "Including Unicode characters: üöä"\\n$'),
+        (".//div[@class='inc-preappend highlight-text notranslate']//pre",
+         r'(?m)^START CODE$'),
+        (".//div[@class='inc-pyobj-dedent highlight-python notranslate']//span",
+         r'def'),
+        (".//div[@class='inc-tab3 highlight-text notranslate']//pre",
+         r'-| |-'),
+        (".//div[@class='inc-tab8 highlight-python notranslate']//pre/span",
+         r'-|      |-'),
+    ],
+    'autodoc.html': [
+        (".//dt[@id='autodoc_target.Class']", ''),
+        (".//dt[@id='autodoc_target.function']/em", r'\*\*kwds'),
+        (".//dd/p", r'Return spam\.'),
+    ],
+    'extapi.html': [
+        (".//strong", 'from class: Bar'),
+    ],
+    'markup.html': [
+        (".//title", 'set by title directive'),
+        (".//p/em", 'Section author: Georg Brandl'),
+        (".//p/em", 'Module author: Georg Brandl'),
+        # created by the meta directive
+        (".//meta[@name='author'][@content='Me']", ''),
+        (".//meta[@name='keywords'][@content='docs, sphinx']", ''),
+        # a label created by ``.. _label:``
+        (".//div[@id='label']", ''),
+        # code with standard code blocks
+        (".//pre", '^some code$'),
+        # an option list
+        (".//span[@class='option']", '--help'),
+        # admonitions
+        (".//p[@class='admonition-title']", 'My Admonition'),
+        (".//div[@class='admonition note']/p", 'Note text.'),
+        (".//div[@class='admonition warning']/p", 'Warning text.'),
+        # inline markup
+        (".//li/p/strong", r'^command\\n$'),
+        (".//li/p/strong", r'^program\\n$'),
+        (".//li/p/em", r'^dfn\\n$'),
+        (".//li/p/kbd", r'^kbd\\n$'),
+        (".//li/p/span", 'File \N{TRIANGULAR BULLET} Close'),
+        (".//li/p/code/span[@class='pre']", '^a/$'),
+        (".//li/p/code/em/span[@class='pre']", '^varpart$'),
+        (".//li/p/code/em/span[@class='pre']", '^i$'),
+        (".//a[@href='https://www.python.org/dev/peps/pep-0008']"
+         "[@class='pep reference external']/strong", 'PEP 8'),
+        (".//a[@href='https://www.python.org/dev/peps/pep-0008']"
+         "[@class='pep reference external']/strong",
+         'Python Enhancement Proposal #8'),
+        (".//a[@href='https://tools.ietf.org/html/rfc1.html']"
+         "[@class='rfc reference external']/strong", 'RFC 1'),
+        (".//a[@href='https://tools.ietf.org/html/rfc1.html']"
+         "[@class='rfc reference external']/strong", 'Request for Comments #1'),
+        (".//a[@href='objects.html#envvar-HOME']"
+         "[@class='reference internal']/code/span[@class='pre']", 'HOME'),
+        (".//a[@href='#with']"
+         "[@class='reference internal']/code/span[@class='pre']", '^with$'),
+        (".//a[@href='#grammar-token-try-stmt']"
+         "[@class='reference internal']/code/span", '^statement$'),
+        (".//a[@href='#some-label'][@class='reference internal']/span", '^here$'),
+        (".//a[@href='#some-label'][@class='reference internal']/span", '^there$'),
+        (".//a[@href='subdir/includes.html']"
+         "[@class='reference internal']/span", 'Including in subdir'),
+        (".//a[@href='objects.html#cmdoption-python-c']"
+         "[@class='reference internal']/code/span[@class='pre']", '-c'),
+        # abbreviations
+        (".//abbr[@title='abbreviation']", '^abbr$'),
+        # version stuff
+        (".//div[@class='versionadded']/p/span", 'New in version 0.6: '),
+        (".//div[@class='versionadded']/p/span",
+         tail_check('First paragraph of versionadded')),
+        (".//div[@class='versionchanged']/p/span",
+         tail_check('First paragraph of versionchanged')),
+        (".//div[@class='versionchanged']/p",
+         'Second paragraph of versionchanged'),
+        # footnote reference
+        (".//a[@class='footnote-reference brackets']", r'1'),
+        # created by reference lookup
+        (".//a[@href='index.html#ref1']", ''),
+        # ``seealso`` directive
+        (".//div/p[@class='admonition-title']", 'See also'),
+        # a ``hlist`` directive
+        (".//table[@class='hlist']/tbody/tr/td/ul/li/p", '^This$'),
+        # a ``centered`` directive
+        (".//p[@class='centered']/strong", 'LICENSE'),
+        # a glossary
+        (".//dl/dt[@id='term-boson']", 'boson'),
+        # a production list
+        (".//pre/strong", 'try_stmt'),
+        (".//pre/a[@href='#grammar-token-try1-stmt']/code/span", 'try1_stmt'),
+        # tests for ``only`` directive
+        (".//p", 'A global substitution.'),
+        (".//p", 'In HTML.'),
+        (".//p", 'In both.'),
+        (".//p", 'Always present'),
+        # tests for ``any`` role
+        (".//a[@href='#with']/span", 'headings'),
+        (".//a[@href='objects.html#func_without_body']/code/span", 'objects'),
+        # tests for numeric labels
+        (".//a[@href='#id1'][@class='reference internal']/span", 'Testing various markup'),
+    ],
+    'objects.html': [
+        (".//dt[@id='mod.Cls.meth1']", ''),
+        (".//dt[@id='errmod.Error']", ''),
+        (".//dt/code", r'long\(parameter,\s* list\)'),
+        (".//dt/code", 'another one'),
+        (".//a[@href='#mod.Cls'][@class='reference internal']", ''),
+        (".//dl[@class='userdesc']", ''),
+        (".//dt[@id='userdesc-myobj']", ''),
+        (".//a[@href='#userdesc-myobj'][@class='reference internal']", ''),
+        # docfields
+        (".//a[@class='reference internal'][@href='#TimeInt']/em", 'TimeInt'),
+        (".//a[@class='reference internal'][@href='#Time']", 'Time'),
+        (".//a[@class='reference internal'][@href='#errmod.Error']/strong", 'Error'),
+        # C references
+        (".//span[@class='pre']", 'CFunction()'),
+        (".//a[@href='#c.Sphinx_DoSomething']", ''),
+        (".//a[@href='#c.SphinxStruct.member']", ''),
+        (".//a[@href='#c.SPHINX_USE_PYTHON']", ''),
+        (".//a[@href='#c.SphinxType']", ''),
+        (".//a[@href='#c.sphinx_global']", ''),
+        # test global TOC created by toctree()
+        (".//ul[@class='current']/li[@class='toctree-l1 current']/a[@href='#']",
+         'Testing object descriptions'),
+        (".//li[@class='toctree-l1']/a[@href='markup.html']",
+         'Testing various markup'),
+        # test unknown field names
+        (".//dt[@class='field-odd']", 'Field_name'),
+        (".//dt[@class='field-even']", 'Field_name all lower'),
+        (".//dt[@class='field-odd']", 'FIELD_NAME'),
+        (".//dt[@class='field-even']", 'FIELD_NAME ALL CAPS'),
+        (".//dt[@class='field-odd']", 'Field_Name'),
+        (".//dt[@class='field-even']", 'Field_Name All Word Caps'),
+        (".//dt[@class='field-odd']", 'Field_name'),
+        (".//dt[@class='field-even']", 'Field_name First word cap'),
+        (".//dt[@class='field-odd']", 'FIELd_name'),
+        (".//dt[@class='field-even']", 'FIELd_name PARTial caps'),
+        # custom sidebar
+        (".//h4", 'Custom sidebar'),
+        # docfields
+        (".//dd[@class='field-odd']/p/strong", '^moo$'),
+        (".//dd[@class='field-odd']/p/strong", tail_check(r'\(Moo\) .* Moo')),
+        (".//dd[@class='field-odd']/ul/li/p/strong", '^hour$'),
+        (".//dd[@class='field-odd']/ul/li/p/em", '^DuplicateType$'),
+        (".//dd[@class='field-odd']/ul/li/p/em", tail_check(r'.* Some parameter')),
+        # others
+        (".//a[@class='reference internal'][@href='#cmdoption-perl-arg-p']/code/span",
+         'perl'),
+        (".//a[@class='reference internal'][@href='#cmdoption-perl-arg-p']/code/span",
+         '\\+p'),
+        (".//a[@class='reference internal'][@href='#cmdoption-perl-objc']/code/span",
+         '--ObjC\\+\\+'),
+        (".//a[@class='reference internal'][@href='#cmdoption-perl-plugin-option']/code/span",
+         '--plugin.option'),
+        (".//a[@class='reference internal'][@href='#cmdoption-perl-arg-create-auth-token']"
+         "/code/span",
+         'create-auth-token'),
+        (".//a[@class='reference internal'][@href='#cmdoption-perl-arg-arg']/code/span",
+         'arg'),
+        (".//a[@class='reference internal'][@href='#cmdoption-hg-arg-commit']/code/span",
+         'hg'),
+        (".//a[@class='reference internal'][@href='#cmdoption-hg-arg-commit']/code/span",
+         'commit'),
+        (".//a[@class='reference internal'][@href='#cmdoption-git-commit-p']/code/span",
+         'git'),
+        (".//a[@class='reference internal'][@href='#cmdoption-git-commit-p']/code/span",
+         'commit'),
+        (".//a[@class='reference internal'][@href='#cmdoption-git-commit-p']/code/span",
+         '-p'),
+    ],
+    'index.html': [
+        (".//meta[@name='hc'][@content='hcval']", ''),
+        (".//meta[@name='hc_co'][@content='hcval_co']", ''),
+        (".//dt[@class='label']/span[@class='brackets']", r'Ref1'),
+        (".//dt[@class='label']", ''),
+        (".//li[@class='toctree-l1']/a", 'Testing various markup'),
+        (".//li[@class='toctree-l2']/a", 'Inline markup'),
+        (".//title", 'Sphinx <Tests>'),
+        (".//div[@class='footer']", 'Georg Brandl & Team'),
+        (".//a[@href='http://python.org/']"
+         "[@class='reference external']", ''),
+        (".//li/p/a[@href='genindex.html']/span", 'Index'),
+        (".//li/p/a[@href='py-modindex.html']/span", 'Module Index'),
+        (".//li/p/a[@href='search.html']/span", 'Search Page'),
+        # custom sidebar only for contents
+        (".//h4", 'Contents sidebar'),
+        # custom JavaScript
+        (".//script[@src='file://moo.js']", ''),
+        # URL in contents
+        (".//a[@class='reference external'][@href='http://sphinx-doc.org/']",
+         'http://sphinx-doc.org/'),
+        (".//a[@class='reference external'][@href='http://sphinx-doc.org/latest/']",
+         'Latest reference'),
+        # Indirect hyperlink targets across files
+        (".//a[@href='markup.html#some-label'][@class='reference internal']/span",
+         '^indirect hyperref$'),
+    ],
+    'bom.html': [
+        (".//title", " File with UTF-8 BOM"),
+    ],
+    'extensions.html': [
+        (".//a[@href='http://python.org/dev/']", "http://python.org/dev/"),
+        (".//a[@href='http://bugs.python.org/issue1000']", "issue 1000"),
+        (".//a[@href='http://bugs.python.org/issue1042']", "explicit caption"),
+    ],
+    'genindex.html': [
+        # index entries
+        (".//a/strong", "Main"),
+        (".//a/strong", "[1]"),
+        (".//a/strong", "Other"),
+        (".//a", "entry"),
+        (".//li/a", "double"),
+    ],
+    'footnote.html': [
+        (".//a[@class='footnote-reference brackets'][@href='#id9'][@id='id1']", r"1"),
+        (".//a[@class='footnote-reference brackets'][@href='#id10'][@id='id2']", r"2"),
+        (".//a[@class='footnote-reference brackets'][@href='#foo'][@id='id3']", r"3"),
+        (".//a[@class='reference internal'][@href='#bar'][@id='id4']", r"\[bar\]"),
+        (".//a[@class='reference internal'][@href='#baz-qux'][@id='id5']", r"\[baz_qux\]"),
+        (".//a[@class='footnote-reference brackets'][@href='#id11'][@id='id6']", r"4"),
+        (".//a[@class='footnote-reference brackets'][@href='#id12'][@id='id7']", r"5"),
+        (".//a[@class='fn-backref'][@href='#id1']", r"1"),
+        (".//a[@class='fn-backref'][@href='#id2']", r"2"),
+        (".//a[@class='fn-backref'][@href='#id3']", r"3"),
+        (".//a[@class='fn-backref'][@href='#id4']", r"bar"),
+        (".//a[@class='fn-backref'][@href='#id5']", r"baz_qux"),
+        (".//a[@class='fn-backref'][@href='#id6']", r"4"),
+        (".//a[@class='fn-backref'][@href='#id7']", r"5"),
+        (".//a[@class='fn-backref'][@href='#id8']", r"6"),
+    ],
+    'otherext.html': [
+        (".//h1", "Generated section"),
+        (".//a[@href='_sources/otherext.foo.txt']", ''),
+    ]
+}))
+@pytest.mark.sphinx('html', tags=['testtag'], confoverrides={
+    'html_context.hckey_co': 'hcval_co',
+    'html_experimental_html5_writer': True})
+@pytest.mark.test_params(shared_result='test_build_html5_output')
+def test_html5_output(app, cached_etree_parse, fname, expect):
+    app.build()
+    print(app.outdir / fname)
+    check_xpath(cached_etree_parse(app.outdir / fname), fname, *expect)
+
+
+@pytest.mark.skipif(docutils.__version_info__ < (0, 13),
+                    reason='docutils-0.13 or above is required')
+@pytest.mark.sphinx('html', tags=['testtag'], confoverrides={
+    'html_context.hckey_co': 'hcval_co',
+    'html_experimental_html5_writer': True})
+@pytest.mark.test_params(shared_result='test_build_html_output')
+def test_html_download(app):
+    app.build()
+
+    # subdir/includes.html
+    result = (app.outdir / 'subdir' / 'includes.html').text()
+    pattern = ('<a class="reference download internal" download="" '
+               'href="../(_downloads/.*/img.png)">')
+    matched = re.search(pattern, result)
+    assert matched
+    assert (app.outdir / matched.group(1)).exists()
+    filename = matched.group(1)
+
+    # includes.html
+    result = (app.outdir / 'includes.html').text()
+    pattern = ('<a class="reference download internal" download="" '
+               'href="(_downloads/.*/img.png)">')
+    matched = re.search(pattern, result)
+    assert matched
+    assert (app.outdir / matched.group(1)).exists()
+    assert matched.group(1) == filename
+
+
+@pytest.mark.skipif(docutils.__version_info__ < (0, 13),
+                    reason='docutils-0.13 or above is required')
+@pytest.mark.sphinx('html', testroot='roles-download',
+                    confoverrides={'html_experimental_html5_writer': True})
+def test_html_download_role(app, status, warning):
+    app.build()
+    digest = md5((app.srcdir / 'dummy.dat').encode()).hexdigest()
+    assert (app.outdir / '_downloads' / digest / 'dummy.dat').exists()
+
+    content = (app.outdir / 'index.html').text()
+    assert (('<li><p><a class="reference download internal" download="" '
+             'href="_downloads/%s/dummy.dat">'
+             '<code class="xref download docutils literal notranslate">'
+             '<span class="pre">dummy.dat</span></code></a></p></li>' % digest)
+            in content)
+    assert ('<li><p><code class="xref download docutils literal notranslate">'
+            '<span class="pre">not_found.dat</span></code></p></li>' in content)
+    assert ('<li><p><a class="reference download external" download="" '
+            'href="http://www.sphinx-doc.org/en/master/_static/sphinxheader.png">'
+            '<code class="xref download docutils literal notranslate">'
+            '<span class="pre">Sphinx</span> <span class="pre">logo</span>'
+            '</code></a></p></li>' in content)
diff --git a/tests/test_domain_cpp.py b/tests/test_domain_cpp.py
index 4d7d3e592..fe5e37f23 100644
--- a/tests/test_domain_cpp.py
+++ b/tests/test_domain_cpp.py
@@ -17,7 +17,6 @@
 from sphinx import addnodes
 from sphinx.domains.cpp import DefinitionParser, DefinitionError, NoOldIdError
 from sphinx.domains.cpp import Symbol, _max_id, _id_prefix
-from sphinx.util import docutils
 
 
 def parse(name, string):
@@ -735,14 +734,12 @@ def test_build_domain_cpp_misuse_of_roles(app, status, warning):
     # TODO: properly check for the warnings we expect
 
 
-@pytest.mark.skipif(docutils.__version_info__ < (0, 13),
-                    reason='docutils-0.13 or above is required')
 @pytest.mark.sphinx(testroot='domain-cpp', confoverrides={'add_function_parentheses': True})
 def test_build_domain_cpp_with_add_function_parentheses_is_True(app, status, warning):
     app.builder.build_all()
 
     def check(spec, text, file):
-        pattern = '<li><p>%s<a .*?><code .*?><span .*?>%s</span></code></a></p></li>' % spec
+        pattern = '<li>%s<a .*?><code .*?><span .*?>%s</span></code></a></li>' % spec
         res = re.search(pattern, text)
         if not res:
             print("Pattern\n\t%s\nnot found in %s" % (pattern, file))
@@ -778,14 +775,13 @@ def check(spec, text, file):
         check(s, t, f)
 
 
-@pytest.mark.skipif(docutils.__version_info__ < (0, 13),
-                    reason='docutils-0.13 or above is required')
-@pytest.mark.sphinx(testroot='domain-cpp', confoverrides={'add_function_parentheses': False})
+@pytest.mark.sphinx(testroot='domain-cpp', confoverrides={
+    'add_function_parentheses': False})
 def test_build_domain_cpp_with_add_function_parentheses_is_False(app, status, warning):
     app.builder.build_all()
 
     def check(spec, text, file):
-        pattern = '<li><p>%s<a .*?><code .*?><span .*?>%s</span></code></a></p></li>' % spec
+        pattern = '<li>%s<a .*?><code .*?><span .*?>%s</span></code></a></li>' % spec
         res = re.search(pattern, text)
         if not res:
             print("Pattern\n\t%s\nnot found in %s" % (pattern, file))
diff --git a/tests/test_ext_autosectionlabel.py b/tests/test_ext_autosectionlabel.py
index 9a139a687..0b4d355a8 100644
--- a/tests/test_ext_autosectionlabel.py
+++ b/tests/test_ext_autosectionlabel.py
@@ -12,43 +12,37 @@
 
 import pytest
 
-from sphinx.util import docutils
 
-
-@pytest.mark.skipif(docutils.__version_info__ < (0, 13),
-                    reason='docutils-0.13 or above is required')
 @pytest.mark.sphinx('html', testroot='ext-autosectionlabel')
 def test_autosectionlabel_html(app, status, warning):
     app.builder.build_all()
 
     content = (app.outdir / 'index.html').text()
-    html = ('<li><p><a class="reference internal" href="#introduce-of-sphinx">'
-            '<span class=".*?">Introduce of Sphinx</span></a></p></li>')
+    html = ('<li><a class="reference internal" href="#introduce-of-sphinx">'
+            '<span class=".*?">Introduce of Sphinx</span></a></li>')
     assert re.search(html, content, re.S)
 
-    html = ('<li><p><a class="reference internal" href="#installation">'
-            '<span class="std std-ref">Installation</span></a></p></li>')
+    html = ('<li><a class="reference internal" href="#installation">'
+            '<span class="std std-ref">Installation</span></a></li>')
     assert re.search(html, content, re.S)
 
-    html = ('<li><p><a class="reference internal" href="#for-windows-users">'
-            '<span class="std std-ref">For Windows users</span></a></p></li>')
+    html = ('<li><a class="reference internal" href="#for-windows-users">'
+            '<span class="std std-ref">For Windows users</span></a></li>')
     assert re.search(html, content, re.S)
 
-    html = ('<li><p><a class="reference internal" href="#for-unix-users">'
-            '<span class="std std-ref">For UNIX users</span></a></p></li>')
+    html = ('<li><a class="reference internal" href="#for-unix-users">'
+            '<span class="std std-ref">For UNIX users</span></a></li>')
     assert re.search(html, content, re.S)
 
     # for smart_quotes (refs: #4027)
-    html = ('<li><p><a class="reference internal" '
+    html = ('<li><a class="reference internal" '
             'href="#this-one-s-got-an-apostrophe">'
             '<span class="std std-ref">This one’s got an apostrophe'
-            '</span></a></p></li>')
+            '</span></a></li>')
     assert re.search(html, content, re.S)
 
 
 # Re-use test definition from above, just change the test root directory
-@pytest.mark.skipif(docutils.__version_info__ < (0, 13),
-                    reason='docutils-0.13 or above is required')
 @pytest.mark.sphinx('html', testroot='ext-autosectionlabel-prefix-document')
 def test_autosectionlabel_prefix_document_html(app, status, warning):
     return test_autosectionlabel_html(app, status, warning)
diff --git a/tests/test_ext_todo.py b/tests/test_ext_todo.py
index 2ce7ac95e..a6e258347 100644
--- a/tests/test_ext_todo.py
+++ b/tests/test_ext_todo.py
@@ -12,11 +12,7 @@
 
 import pytest
 
-from sphinx.util import docutils
 
-
-@pytest.mark.skipif(docutils.__version_info__ < (0, 13),
-                    reason='docutils-0.13 or above is required')
 @pytest.mark.sphinx('html', testroot='ext-todo', freshenv=True,
                     confoverrides={'todo_include_todos': True, 'todo_emit_warnings': True})
 def test_todo(app, status, warning):
@@ -30,22 +26,22 @@ def on_todo_defined(app, node):
 
     # check todolist
     content = (app.outdir / 'index.html').text()
-    html = ('<p class="admonition-title">Todo</p>\n'
-            '<p>todo in foo</p>')
+    html = ('<p class="first admonition-title">Todo</p>\n'
+            '<p class="last">todo in foo</p>')
     assert re.search(html, content, re.S)
 
-    html = ('<p class="admonition-title">Todo</p>\n'
-            '<p>todo in bar</p>')
+    html = ('<p class="first admonition-title">Todo</p>\n'
+            '<p class="last">todo in bar</p>')
     assert re.search(html, content, re.S)
 
     # check todo
     content = (app.outdir / 'foo.html').text()
-    html = ('<p class="admonition-title">Todo</p>\n'
-            '<p>todo in foo</p>')
+    html = ('<p class="first admonition-title">Todo</p>\n'
+            '<p class="last">todo in foo</p>')
     assert re.search(html, content, re.S)
 
-    html = ('<p class="admonition-title">Todo</p>\n'
-            '<p>todo in param field</p>')
+    html = ('<p class="first admonition-title">Todo</p>\n'
+            '<p class="last">todo in param field</p>')
     assert re.search(html, content, re.S)
 
     # check emitted warnings
@@ -72,18 +68,18 @@ def on_todo_defined(app, node):
 
     # check todolist
     content = (app.outdir / 'index.html').text()
-    html = ('<p class="admonition-title">Todo</p>\n'
-            '<p>todo in foo</p>')
+    html = ('<p class="first admonition-title">Todo</p>\n'
+            '<p class="last">todo in foo</p>')
     assert not re.search(html, content, re.S)
 
-    html = ('<p class="admonition-title">Todo</p>\n'
-            '<p>todo in bar</p>')
+    html = ('<p class="first admonition-title">Todo</p>\n'
+            '<p class="last">todo in bar</p>')
     assert not re.search(html, content, re.S)
 
     # check todo
     content = (app.outdir / 'foo.html').text()
-    html = ('<p class="admonition-title">Todo</p>\n'
-            '<p>todo in foo</p>')
+    html = ('<p class="first admonition-title">Todo</p>\n'
+            '<p class="last">todo in foo</p>')
     assert not re.search(html, content, re.S)
 
     # check emitted warnings