|
1 | 1 | import importlib |
2 | 2 | import json |
| 3 | +from pathlib import Path |
| 4 | + |
| 5 | +REPO_ROOT = Path(__file__).resolve().parent.parent |
| 6 | + |
| 7 | + |
| 8 | +def test_explainers_ui_js_stays_in_render_parity_with_build_explainers(): |
| 9 | + # assets/explainers-ui.js's renderMarkdown/parseTable is a client-side |
| 10 | + # port of scripts/build_explainers.py's render_markdown/split_row, but |
| 11 | + # nothing exercises it on a real explainer page, so it has silently |
| 12 | + # drifted before (#552, #553). Source-level guard (same idea as |
| 13 | + # test_js_parity's DOM-renderer checks) that the two fixes are present in |
| 14 | + # the JS too. |
| 15 | + js = (REPO_ROOT / "assets" / "explainers-ui.js").read_text(encoding="utf-8") |
| 16 | + |
| 17 | + # #553: +1 heading offset, capped at h6 |
| 18 | + assert "Math.min(headingMatch[1].length + 1, 6)" in js |
| 19 | + # #552: split table rows on unescaped "|" and unescape "\|" -> "|" |
| 20 | + assert r"/(?<!\\)\|/" in js |
| 21 | + assert r"replace(/\\\|/g, '|')" in js |
3 | 22 |
|
4 | 23 |
|
5 | 24 | def test_build_package_mirror_copies_data_and_markdown(tmp_path, monkeypatch): |
@@ -84,3 +103,33 @@ def test_parse_table_still_accepts_three_dash_separator_row(): |
84 | 103 | assert result is not None |
85 | 104 | headers, _body_rows, _next_index = result |
86 | 105 | assert headers == ["A", "B"] |
| 106 | + |
| 107 | + |
| 108 | +def test_parse_table_honors_escaped_pipe_inside_a_cell(): |
| 109 | + # A literal pipe in a cell must be written "\|" (GFM) and must not start a |
| 110 | + # new column; the "\" is stripped in the rendered cell. reject-inference.md |
| 111 | + # and base-rate-fallacy.md both hit this (#552). |
| 112 | + script = importlib.import_module("scripts.build_explainers") |
| 113 | + lines = [ |
| 114 | + "| Method | Formula |", |
| 115 | + "|---|---|", |
| 116 | + r"| IPW | w(X) = P(S = 1 \| X) |", |
| 117 | + ] |
| 118 | + |
| 119 | + headers, body_rows, _ = script.parse_table(lines, 0) |
| 120 | + |
| 121 | + assert headers == ["Method", "Formula"] |
| 122 | + assert body_rows == [["IPW", "w(X) = P(S = 1 | X)"]] |
| 123 | + |
| 124 | + |
| 125 | +def test_render_markdown_offsets_heading_levels_by_one(): |
| 126 | + # The explainer page's hero already renders a real <h1>, so the markdown |
| 127 | + # body's headings are shifted down one level (h1 -> h2, capped at h6). |
| 128 | + # assets/explainers-ui.js's renderMarkdown must match this (#553). |
| 129 | + script = importlib.import_module("scripts.build_explainers") |
| 130 | + |
| 131 | + html = script.render_markdown("# Top\n\n## Sub\n\n###### Deep\n", set()) |
| 132 | + |
| 133 | + assert '<h2 id="top">Top</h2>' in html |
| 134 | + assert '<h3 id="sub">Sub</h3>' in html |
| 135 | + assert '<h6 id="deep">Deep</h6>' in html # h6 + 1 stays h6, not h7 |
0 commit comments