Files
libretro/tests/test_site_r5_css.py
T
Abdessamad Derraz 89c6a151ae fix: one page grid, shorter stacked rows
Search box, column and table of contents are placed from one grid
width on every page. Long code in table cells breaks to fit, stacked
rows drop to one line per cell, and the button, search marker, choice
list and crumb spacing are aligned with the rest.
2026-10-24 00:53:08 +02:00

114 lines
5.8 KiB
Python

"""Round 5 theme: the stylesheet fixes of package 1, read from its source.
Each test fails on the stylesheet as it was before the fix: detection tables
whose last column sat past the page at 1440 px, a header search box, title
and "On this page" that moved 12 px between a guide and a console page,
stacked rows 136 px tall for four short cells, a line 4 px under a button,
a heading touching its first line, the browser's own choice list, and a
crumb separator free to end a line alone.
"""
from __future__ import annotations
import re
import unittest
from tests.test_site_r2_css import CSS_PATH, _blocks, _strip_comments, _theme_tokens
STACK = ".sl-markdown-content table[data-rb-stack] td"
def _block(css: str, selector: str) -> str:
bodies = [b for s, b in _blocks(css) if s == selector]
if not bodies:
raise AssertionError(f"no block {selector}")
return "".join(bodies)
def _declarations(body: str) -> dict[str, str]:
return {k.strip(): v.strip() for k, v in re.findall(r"([\w-]+)\s*:\s*([^;]+);", body)}
class ThemeStylesheetRound5(unittest.TestCase):
@classmethod
def setUpClass(cls) -> None:
cls.css = _strip_comments(CSS_PATH.read_text(encoding="utf-8"))
# 1.1
def test_long_code_in_a_cell_breaks_to_fit_its_column(self):
self.assertIn("overflow-wrap: anywhere",
_block(self.css, ".sl-markdown-content table td code:not(.rb-short)"))
last = _block(self.css, ".sl-markdown-content table:not([data-rb-stack='kv']) "
"td:last-child:not(:first-child):has(code:not(.rb-short))")
self.assertIn("min-width: 9rem", last)
# A flag or a short name in a cell still never splits.
self.assertIn("white-space: pre", _block(self.css, ".sl-markdown-content :not(pre) > code.rb-short"))
# 1.2
def test_one_grid_for_every_page(self):
self.assertEqual(_theme_tokens(self.css, ":root").get("--rb-grid-width"), "54rem")
self.assertIn("--sl-content-width: var(--rb-grid-width)",
_block(self.css, "body:has(.rb-sys-file, .rb-file-entry)"))
# The header places its search box from the grid, not the page's column.
self.assertIn("--sl-content-width: var(--rb-grid-width)",
_block(self.css, ":root[data-has-sidebar] header.header"))
toc = _block(self.css, ":root[data-has-sidebar] .right-sidebar-container")
pane = _block(self.css, ":root[data-has-sidebar] .main-pane")
for body in (toc, pane):
self.assertIn("var(--rb-grid-width)", body)
self.assertNotIn("var(--sl-content-width)", body)
# Every column starts on the grid's edge, the narrow one included.
self.assertIn("--sl-content-margin-inline: max(0rem, 100% - var(--rb-grid-width)) auto", pane)
# The pane rule covers pages with and without "On this page" alike.
self.assertFalse([s for s, _ in _blocks(self.css) if s.endswith(":not([data-has-toc]) .main-pane")])
# 1.3
def test_stacked_rows_are_short(self):
cell = _declarations(_block(self.css, STACK))
self.assertEqual(cell["font-size"], "0.875rem")
self.assertEqual(cell["line-height"], "1.35")
label = _declarations(_block(self.css, STACK + "::before"))
self.assertEqual(label["width"], "max-content")
self.assertEqual(label["min-width"], "6.5rem")
self.assertEqual(label["max-width"], "9rem")
self.assertEqual(label["font-size"], "0.8125rem")
# Values start in the column of the shortest label: the label's
# negative margin is the cell's left padding.
indent = cell["padding"].split()[3]
self.assertEqual(label["margin"].split()[3], f"-{indent}")
self.assertEqual(indent, "7.1rem")
self.assertIn("padding: 0.3rem 0", _block(self.css, ".sl-markdown-content table[data-rb-stack] tr"))
# A two-column list keeps body text.
self.assertIn("font-size: 1rem", _block(self.css, ".sl-markdown-content table[data-rb-stack='kv'] td"))
# 1.5
def test_spacing_after_a_button_and_a_search_marker(self):
self.assertIn("margin-top: 1rem",
_block(self.css, ".sl-markdown-content :is(.rb-button, p:has(> .rb-button)) + p"))
self.assertIn("margin-top: var(--sl-content-gap-y)",
_block(self.css, ".sl-markdown-content span[data-pagefind-meta]:empty + :is(p, ul, ol, table, div)"))
def test_choice_list_matches_the_filter_box(self):
select = _declarations(_block(self.css, ".sl-markdown-content :is(.rb-file-lookup, .rb-picker) select,\n"
".sl-markdown-content select"))
box = _declarations(_block(self.css, ".rb-table-filter input"))
for prop in ("border", "border-radius", "min-height"):
with self.subTest(prop=prop):
self.assertEqual(select[prop], box[prop])
self.assertEqual(select["appearance"], "none")
self.assertIn("var(--rb-select-arrow)", select["background"])
dark = _theme_tokens(self.css, ":root")["--rb-select-arrow"]
light = _theme_tokens(self.css, ":root[data-theme='light']")["--rb-select-arrow"]
# The arrow is drawn in each theme's secondary text colour.
for arrow, tokens in ((dark, _theme_tokens(self.css, ":root")),
(light, _theme_tokens(self.css, ":root[data-theme='light']"))):
colour = tokens["--rb-text-secondary"].lstrip("#")
self.assertIn(f"%23{colour}", arrow)
def test_crumb_separator_stays_with_its_label(self):
self.assertIn("white-space: nowrap", _block(self.css, ".rb-breadcrumbs li"))
self.assertIn("white-space: normal", _block(self.css, ".rb-breadcrumbs li > :is(a, span)"))
if __name__ == "__main__":
unittest.main()