Initial commit

This commit is contained in:
ThePetrovich 2026-08-17 22:42:04 +08:00
commit 97e799fd52
61 changed files with 2252 additions and 0 deletions

0
tests/__init__.py Normal file
View file

52
tests/settings.py Normal file
View file

@ -0,0 +1,52 @@
"""A minimal service, standing in for tdas/odms/ops."""
from pathlib import Path
SECRET_KEY = "test-only"
DEBUG = True
USE_TZ = True
USE_I18N = True
LANGUAGE_CODE = "en"
BASE_DIR = Path(__file__).resolve().parent
INSTALLED_APPS = [
"django.contrib.contenttypes",
"django.contrib.auth",
"django.contrib.sessions",
"django.contrib.messages",
"django.contrib.staticfiles",
"yksa_kit",
"yksa_web",
]
MIDDLEWARE = [
"django.contrib.sessions.middleware.SessionMiddleware",
"yksa_kit.middleware.UserTimezoneMiddleware",
"django.middleware.locale.LocaleMiddleware",
"django.middleware.common.CommonMiddleware",
"django.middleware.csrf.CsrfViewMiddleware",
"django.contrib.auth.middleware.AuthenticationMiddleware",
"django.contrib.messages.middleware.MessageMiddleware",
]
DATABASES = {"default": {"ENGINE": "django.db.backends.sqlite3", "NAME": ":memory:"}}
ROOT_URLCONF = "tests.urls"
STATIC_URL = "/static/"
TEMPLATES = [
{
"BACKEND": "django.template.backends.django.DjangoTemplates",
"DIRS": [BASE_DIR / "templates"],
"APP_DIRS": True,
"OPTIONS": {
"context_processors": [
"django.template.context_processors.request",
"django.contrib.auth.context_processors.auth",
"django.contrib.messages.context_processors.messages",
"yksa_kit.context_processors.ui_preferences",
],
},
},
]

12
tests/templates/base.html Normal file
View file

@ -0,0 +1,12 @@
{% extends "yksa/base.html" %}
{% load i18n %}
{% comment %}
The three-line base.html every service is expected to keep. If a service needs
more than blocks to fit the chrome, the chrome is wrong.
{% endcomment %}
{% block title %}{% trans "Test service" %}{% endblock title %}
{% block navbar_items %}
<li class="nav-item">
<a class="nav-link nav-full-height border border-top-0" href="/">{% trans "Home" %}</a>
</li>
{% endblock navbar_items %}

145
tests/test_ui_kit.py Normal file
View file

@ -0,0 +1,145 @@
"""The kit's snippets, the chrome, and the rules the estate agreed to.
This module used to be copied into every service. It lives here now; a service
keeps only the part that lists its own pages.
"""
from __future__ import annotations
import re
from pathlib import Path
import pytest
from django.template.loader import render_to_string
from django.test import Client
from yksa_web.states import STATES
ROOT = Path(__file__).resolve().parent.parent / "yksa_web"
TEMPLATES = sorted((ROOT / "templates").rglob("*.html"))
STYLESHEETS = [ROOT / "static" / "yksa" / "css" / "kit.css"]
# --- the chrome -------------------------------------------------------------
@pytest.mark.django_db
def test_the_shared_pages_render():
client = Client()
for url in ("/preferences/timezone/", "/privacy/", "/cookies/"):
assert client.get(url).status_code == 200, url
@pytest.mark.django_db
def test_the_navbar_and_footer_are_on_every_page():
"""Both are stated requirements, and both were hand-copied before this."""
html = Client().get("/privacy/").content.decode()
assert "custom-navbar" in html
assert "yksa/img/logo-full-en.svg" in html
assert 'href="/cookies/"' in html # footer link
assert "yksa/css/kit.css" in html
@pytest.mark.django_db
def test_the_service_cannot_reorder_the_chrome():
"""navbar, then main, then footer — a service that wants otherwise has to
stop extending the kit, which is the point."""
html = Client().get("/privacy/").content.decode()
assert html.index("<nav") < html.index("<main") < html.index("<footer")
# --- the snippets -----------------------------------------------------------
def test_state_carries_a_colour_an_icon_and_a_word():
"""Colour is never the only signal: the badge has to survive a colour-blind
reader and a greyscale print."""
html = render_to_string("yksa/ui/_state.html", {"state": "failed"})
assert "yksa-state-failed" in html
assert "bi-x-lg" in html
assert "failed" in html
def test_every_state_in_the_vocabulary_renders():
for name in STATES:
assert f"yksa-state-{name}" in render_to_string(
"yksa/ui/_state.html", {"state": name}
)
def test_an_unknown_state_still_renders():
"""A status the reader can see beats one that silently disappears."""
html = render_to_string("yksa/ui/_state.html", {"state": "nonsense"})
assert "yksa-state-unknown" in html
def test_chip_is_colourless():
"""A chip is a fact, not a status. If it needs a colour it is a state."""
html = render_to_string("yksa/ui/_chip.html", {"text": "v3"})
for variant in ("success", "danger", "warning", "primary"):
assert variant not in html
def test_page_title_is_always_h1_h3():
"""Pages cannot drift apart visually if none of them picks its own size."""
html = render_to_string("yksa/ui/_page_title.html", {"title": "Widgets"})
assert '<h1 class="h3' in html
def test_page_title_links_its_parent():
html = render_to_string("yksa/ui/_page_title.html", {
"title": "W-1", "parent": "Widgets", "parent_url": "/widgets/",
})
assert 'href="/widgets/"' in html
assert "W-1" in html
# --- the estate-wide rules --------------------------------------------------
@pytest.mark.parametrize("banned", ["fw-semibold", "fw-medium", "fw-light", "fw-bolder"])
def test_no_banned_font_weights_in_templates(banned):
"""Weights are 400 and 700. Hierarchy comes from weight, colour and size."""
assert [str(p) for p in TEMPLATES if banned in p.read_text(encoding="utf-8")] == []
@pytest.mark.parametrize("banned", [r"font-weight:\s*[56]00", r"letter-spacing"])
def test_no_banned_typography_in_css(banned):
"""The template rule was enforced and the CSS rule never was, which is how
main.css came to carry font-weight: 500."""
offenders = [
str(p) for p in STYLESHEETS
if re.search(banned, _without_comments(p.read_text(encoding="utf-8")))
]
assert offenders == []
def _without_comments(css: str) -> str:
return re.sub(r"/\*.*?\*/", "", css, flags=re.S)
def test_no_legacy_text_muted():
"""Deprecated in Bootstrap 5.3. Muted text is text-body-secondary."""
assert [str(p) for p in TEMPLATES if "text-muted" in p.read_text(encoding="utf-8")] == []
def test_no_display_classes():
"""`.display-*` is a marketing scale; headings take `.h1`-`.h6`."""
offenders = [
str(p) for p in TEMPLATES
if re.search(r"\bdisplay-[1-6]\b", p.read_text(encoding="utf-8"))
]
assert offenders == []
def test_no_django_comment_syntax():
"""`{# #}` breaks across edits and leaks into rendered output."""
assert [str(p) for p in TEMPLATES if "{#" in p.read_text(encoding="utf-8")] == []
def test_bootstrap_is_at_least_5_3():
"""text-body-secondary and --bs-*-bg-subtle arrived in 5.3. On 5.2.3 every
rule above passes and the page still renders wrong, which is what happened
across the estate before this package owned the bundle."""
bundle = ROOT / "static" / "yksa" / "css" / "bootstrap.min.css"
assert "--bs-success-bg-subtle" in bundle.read_text(encoding="utf-8")

6
tests/urls.py Normal file
View file

@ -0,0 +1,6 @@
from django.urls import include, path
urlpatterns = [
path("", include("yksa_kit.urls")),
path("i18n/", include("django.conf.urls.i18n")),
]