Skip to content

Commit 48b1c26

Browse files
committed
Add MkDocs visual catalog, generic preview shim, and tests with wider preview layout and git docs checks - 2026-02-22 17:21:06
1 parent 6902e89 commit 48b1c26

2 files changed

Lines changed: 115 additions & 0 deletions

File tree

CODING_AGENTS.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,3 +17,10 @@
1717
- Keep the project root lean. Prefer placing executable utilities under `tools/` (for example `tools/release/release.py`, `tools/git/git-save.sh`, `tools/git/git-push.sh`, `tools/support/bump_version.py`).
1818
- Do not add root-level wrapper scripts for tools unless explicitly requested.
1919
- Execute tools from their direct path under `tools/`.
20+
21+
## Commit Message Suggestions (Required)
22+
23+
- When the user asks for a commit message, provide plain text for direct paste into the terminal or UI text box.
24+
- Do not wrap commit message suggestions in quotes (`"`), backticks (`` ` ``), or code fences unless the user explicitly asks for that format.
25+
- Prefer detailed commit messages that describe the current change set clearly.
26+
- Avoid redundant wording and avoid repeating the exact prior commit message suggestion unless the diff is unchanged and the user explicitly asks to reuse it.

tests/test_build_visual_docs.py

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
from __future__ import annotations
2+
3+
import importlib.util
4+
import sys
5+
from pathlib import Path
6+
7+
8+
def _load_visual_docs_module():
9+
repo_root = Path(__file__).resolve().parents[1]
10+
script_path = repo_root / "tools" / "docs" / "build_visual_docs.py"
11+
spec = importlib.util.spec_from_file_location("repo_build_visual_docs", script_path)
12+
assert spec is not None and spec.loader is not None
13+
module = importlib.util.module_from_spec(spec)
14+
sys.modules[spec.name] = module
15+
spec.loader.exec_module(module)
16+
return module
17+
18+
19+
visual_docs = _load_visual_docs_module()
20+
21+
22+
def test_json_for_inline_script_escapes_script_end_tag() -> None:
23+
text = visual_docs._json_for_inline_script({"x": "</script><script>alert(1)</script>"})
24+
assert "</script>" not in text
25+
assert "<\\/script>" in text
26+
27+
28+
def test_build_example_markdown_skips_iframe_when_json_missing(tmp_path: Path) -> None:
29+
html_path = tmp_path / "sample.html"
30+
html_path.write_text("pm.visualizer.set('<div>x</div>', {});", encoding="utf-8")
31+
32+
example = visual_docs.VisualExample(
33+
key_rel=Path("PyPNM/SingleCapture/SpectrumAnalysis/GetCapture-FBC"),
34+
html_path=html_path,
35+
json_path=None,
36+
)
37+
md = visual_docs.build_example_markdown(
38+
example=example,
39+
repo_root=tmp_path,
40+
preview_rel_path=Path("/visual-previews/SingleCapture/SpectrumAnalysis/GetCapture-FBC.html"),
41+
)
42+
assert "Preview unavailable because no matching sample JSON fixture exists" in md
43+
assert "<iframe" not in md
44+
45+
46+
def test_build_preview_html_escapes_embedded_script_tags(tmp_path: Path) -> None:
47+
html_path = tmp_path / "vis.html"
48+
json_path = tmp_path / "vis.json"
49+
html_path.write_text(
50+
'pm.visualizer.set("<div><script src=\\"https://cdn.example/chart.js\\"></script></div>", {});',
51+
encoding="utf-8",
52+
)
53+
json_path.write_text('{"ok": true}', encoding="utf-8")
54+
55+
example = visual_docs.VisualExample(key_rel=Path("PyPNM/X/Test"), html_path=html_path, json_path=json_path)
56+
preview = visual_docs.build_preview_html(example, repo_root=tmp_path)
57+
58+
# Wrapper script tags remain, but embedded visual source must be escaped.
59+
assert "<\\/script>" in preview
60+
assert 'const visualSource =' in preview
61+
62+
63+
def test_main_generates_pages_and_check_is_clean(tmp_path: Path) -> None:
64+
repo_root = tmp_path
65+
visual_root = repo_root / "visual" / "PyPNM" / "DOCSIS-General"
66+
docs_root = repo_root / "docs"
67+
visual_root.mkdir(parents=True)
68+
docs_root.mkdir(parents=True)
69+
70+
(visual_root / "InterfaceStats.html").write_text(
71+
"pm.visualizer.set('<div>{{status}}</div>', {status: pm.response.json().status});",
72+
encoding="utf-8",
73+
)
74+
(visual_root / "InterfaceStats.json").write_text('{"status": 0}', encoding="utf-8")
75+
76+
rc_write = visual_docs.main(
77+
[
78+
"--repo-root",
79+
str(repo_root),
80+
"--visual-root",
81+
"visual",
82+
"--docs-root",
83+
"docs",
84+
]
85+
)
86+
assert rc_write == 0
87+
88+
generated_page = docs_root / "visual" / "DOCSIS-General" / "InterfaceStats.md"
89+
generated_preview = docs_root / "visual-previews" / "DOCSIS-General" / "InterfaceStats.html"
90+
generated_index = docs_root / "visual" / "index.md"
91+
92+
assert generated_page.exists()
93+
assert generated_preview.exists()
94+
assert generated_index.exists()
95+
assert '/visual-previews/DOCSIS-General/InterfaceStats.html' in generated_page.read_text(encoding="utf-8")
96+
97+
rc_check = visual_docs.main(
98+
[
99+
"--repo-root",
100+
str(repo_root),
101+
"--visual-root",
102+
"visual",
103+
"--docs-root",
104+
"docs",
105+
"--check",
106+
]
107+
)
108+
assert rc_check == 0

0 commit comments

Comments
 (0)