test: add cover/frontmatter acceptance criteria validation tests (#473)
* test: add cover/frontmatter acceptance criteria validation tests Add tests verifying issue #358 acceptance criteria: - OG image template uses 1200x630 dimensions - Cover card uses 800x400 base with responsive srcsets (1600x800 2x) - Cover template only renders locally-hosted resources (no hotlinking) - Image registry exists at data/image-registry.json Closes #358 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix: address review comments Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Juan Manuel Servera committed
Jun 14, 2026 at 10:23 UTC
140edee654fa4a671c6632b42cca3ecec4df4579
1 file changed
+56
tests/test_article_visuals.py
+56
@@ -135,3 +135,59 @@ def test_article_visuals_css_is_responsive() -> None:
135
css = _read(ROOT / "assets/css/extended/article-visuals.css")
136
assert "@media (max-width: 768px)" in css
137
assert "aspect-ratio" in css # reserve space -> no CLS
138
+
139
+
140
+# -----------------------------------------------------------------------
141
+# Cover image pipeline validation (issue #358 acceptance criteria)
142
+# -----------------------------------------------------------------------
143
+
144
+
145
+def test_og_image_template_uses_1200x630() -> None:
146
+ """OG image must be resized to 1200x630 per issue #358 criterion 3."""
147
+ og = _read(ROOT / "layouts/partials/templates/opengraph.html")
148
+ assert "1200x630" in og, "OG template must resize to 1200x630"
149
+
150
+
151
+def test_cover_image_orchestrator_uses_800x400_with_srcset() -> None:
152
+ """Cover image orchestrator must emit responsive 800x400/1600x800 local cover variants."""
153
+ orchestrator = _read(VIS / "article-cover.html")
154
+ assert "800x400" in orchestrator, "Cover image flow must produce 800x400 base size"
155
+ assert "1600x800" in orchestrator, "Cover image flow must produce 1600x800 for 2x srcset"
156
+ assert "srcset" in orchestrator, "Cover image flow must use responsive srcset"
157
+
158
+
159
+def test_cover_only_renders_local_resources() -> None:
160
+ """Cover template must only render locally-hosted images (no hotlinking)."""
161
+ cover = _read(VIS / "article-cover.html")
162
+ assert "$page.Resources.GetMatch" in cover, "Cover lookup must resolve page-bundle resources"
163
+ assert "resources.Get" in cover, "Cover lookup must resolve global Hugo resources"
164
+ assert 'eq $candidate.ResourceType "image"' in cover, "Only Hugo image resources should render"
165
+ assert ".RelPermalink" in cover, "Rendered cover URLs must use local RelPermalink paths"
166
+ assert 'replaceRE `(?i)<img[^>]*>` ""' in cover, "Attribution must strip rendered img tags"
167
+
168
+
169
+def test_image_registry_exists_with_required_fields() -> None:
170
+ """data/image-registry.json must exist with required schema fields."""
171
+ import json
172
+
173
+ registry_path = ROOT / "data" / "image-registry.json"
174
+ schema_path = ROOT / "data" / "image-registry.schema.json"
175
+
176
+ assert registry_path.exists(), "Image registry must exist at data/image-registry.json"
177
+ assert schema_path.exists(), "Image registry schema must exist at data/image-registry.schema.json"
178
+
179
+ schema = json.loads(schema_path.read_text(encoding="utf-8"))
180
+ assert schema.get("type") == "object", "Image registry schema must define an object"
181
+ assert "images" in schema.get("required", []), "Image registry schema must require an images array"
182
+ images_schema = schema.get("properties", {}).get("images", {})
183
+ assert images_schema.get("type") == "array", "Image registry schema must define images as an array"
184
+ item_properties = images_schema.get("items", {}).get("properties", {})
185
+ required_fields = {"filename", "source_url", "license", "attribution", "added_by"}
186
+ assert required_fields.issubset(item_properties), (
187
+ f"Image registry schema missing required fields: {sorted(required_fields - set(item_properties))}"
188
+ )
189
+
190
+ data = json.loads(registry_path.read_text(encoding="utf-8"))
191
+ assert isinstance(data, dict), "Image registry must be a JSON object"
192
+ assert data.get("$schema") == "./image-registry.schema.json"
193
+ assert isinstance(data.get("images"), list), "Image registry must declare an images array"