1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145
|
"""Build minimal test sites with sphinx_build_factory and test them with Playwright."""
from pathlib import Path
from typing import Callable
from urllib.parse import urljoin
import pytest
try:
from pathlib import UnsupportedOperation # added in Py 3.13
except ImportError:
UnsupportedOperation = NotImplementedError
# Using importorskip to ensure these tests are only loaded if Playwright is installed.
playwright = pytest.importorskip("playwright")
from playwright.sync_api import Page, expect # noqa: E402
repo_path = Path(__file__).parents[1]
test_sites_dir = repo_path / "docs" / "_build" / "html" / "playwright_tests"
def _is_overflowing(element):
"""Check if an element is being shortened via CSS due to text-overflow property.
We can't check the rendered text because we can't easily get that; all we can get
is the text as it exists in the DOM (prior to its truncation/elision). Thus we must
directly compare the rendered clientWidth to the scrollWidth required to display the
text.
"""
return element.evaluate("e => e.clientWidth < e.scrollWidth", element)
def _build_test_site(site_name: str, sphinx_build_factory: Callable) -> None:
"""Helper function for building simple test sites (with no `confoverrides`)."""
sphinx_build = sphinx_build_factory(site_name)
sphinx_build.build()
assert (sphinx_build.outdir / "index.html").exists(), sphinx_build.outdir.glob("*")
return sphinx_build.outdir
def _check_test_site(site_name: str, site_path: Path, test_func: Callable):
"""Make the built test site available to Playwright, then run `test_func` on it."""
test_sites_dir.mkdir(exist_ok=True)
symlink_path = test_sites_dir / site_name
try:
symlink_path.symlink_to(site_path, True)
except UnsupportedOperation:
pytest.xfail("filesystem doesn't support symlinking")
else:
test_func()
finally:
symlink_path.unlink()
test_sites_dir.rmdir()
def test_version_switcher_highlighting(page: Page, url_base: str) -> None:
"""
In sidebar and topbar - version switcher should apply highlight color to currently
selected version.
"""
page.goto(url=url_base)
# no need to include_hidden here ↓↓↓, we just need to get the active version name
button = page.get_by_role("button").filter(has_text="dev")
active_version_name = button.get_attribute("data-active-version-name")
# here we do include_hidden, so sidebar & topbar menus should each have a
# matching entry:
entries = page.get_by_role("option", include_hidden=True).filter(
has_text=active_version_name
)
assert entries.count() == 2
# make sure they're highlighted
for entry in entries.all():
light_mode = "rgb(10, 125, 145)" # pst-color-primary
# dark_mode = "rgb(63, 177, 197)"
expect(entry).to_have_css("color", light_mode)
def test_breadcrumb_expansion(page: Page, url_base: str) -> None:
"""Test breadcrumb text-overflow."""
# wide viewport width → no truncation
page.set_viewport_size({"width": 1440, "height": 720})
page.goto(urljoin(url_base, "community/topics/config.html"))
expect(page.get_by_label("Breadcrumb").get_by_role("list")).to_contain_text(
"Update Sphinx configuration during the build"
)
el = page.get_by_text("Update Sphinx configuration during the build").nth(1)
expect(el).to_have_css("overflow-x", "hidden")
expect(el).to_have_css("text-overflow", "ellipsis")
assert not _is_overflowing(el)
# narrow viewport width → truncation
page.set_viewport_size({"width": 150, "height": 720})
assert _is_overflowing(el)
def test_breadcrumbs_everywhere(
sphinx_build_factory: Callable, page: Page, url_base: str
) -> None:
"""Test breadcrumbs truncate properly when placed in various parts of the layout."""
site_name = "breadcrumbs"
site_path = _build_test_site(site_name, sphinx_build_factory=sphinx_build_factory)
def check_breadcrumb_truncation():
page.goto(
urljoin(url_base, f"playwright_tests/{site_name}/hansel/gretel/house.html")
)
# sidebar should overflow
text = "In the oven with my sister, so hot right now. Soooo. Hotttt."
el = page.locator("#main-content").get_by_text(text).last
assert _is_overflowing(el)
# footer containers never trigger ellipsis overflow because min-width is content
el = page.locator(".footer-items__center > .footer-item")
assert not _is_overflowing(el)
_check_test_site(site_name, site_path, check_breadcrumb_truncation)
def test_colors(sphinx_build_factory: Callable, page: Page, url_base: str) -> None:
"""Test that things get colored the way we expect them to.
Note: this is not comprehensive! Please feel free to add to this test by editing
`../sites/colors/index.rst` and adding more `expect` statements below.
"""
site_name = "colors"
site_path = _build_test_site(site_name, sphinx_build_factory=sphinx_build_factory)
def check_colors():
page.goto(urljoin(url_base, f"playwright_tests/{site_name}/index.html"))
primary_color = "rgb(10, 125, 145)"
hover_color = "rgb(128, 69, 229)"
spans = {
"text link": primary_color,
"cross reference link": primary_color,
"inline code": "rgb(145, 37, 131)",
"code link": "rgb(8, 93, 108)", # teal-600, AKA #085d6c
}
for text, color in spans.items():
el = page.get_by_text(text).first
expect(el).to_have_css("color", color)
if "link" in text:
el.hover()
expect(el).to_have_css("color", hover_color)
_check_test_site(site_name, site_path, check_colors)
|