"""7.59.2 — corrections : bouton ✕ de l'aide, « Insert below » qui perd le format, listes numérotées invisibles (agent + /numbered list).""" import json import shutil import subprocess from pathlib import Path import pytest ROOT = Path(__file__).resolve().parent.parent HELP_HTML = ROOT / "app" / "templates" / "help.html" HELP_JS = ROOT / "static" / "js" / "help.js" EDITOR_JS = ROOT / "static" / "js" / "page_editor_scripts.js" APP_CSS = ROOT / "static" / "css" / "app.css" SETTINGS_CSS = ROOT / "static" / "css" / "settings.css" # ── 1. Aide : fermeture en haut à droite (mobile compris) ─────────────────── def test_help_page_has_close_button(): html = HELP_HTML.read_text(encoding="utf-8") js = HELP_JS.read_text(encoding="utf-8") css = SETTINGS_CSS.read_text(encoding="utf-8") assert 'class="settings-close"' in html # bouton ✕ présent assert '@click="close()"' in html assert "close()" in js and "history.back()" in js # méthode réelle assert ".settings-close{" in css # style partagé (32/44px) assert "position:relative" in css.split(".settings-panel{")[1][:40] # ── 2. Insert below : on insère le MARKDOWN, pas le texte du HTML rendu ───── def test_ai_insert_below_keeps_source_markdown(): src = EDITOR_JS.read_text(encoding="utf-8") assert "self._md=String(text||'')" in src # source conservée assert "String(this._md||'').trim()||this._resultText()" in src # md d'abord assert src.count("this._md='';") >= 2 # close() + _err() # l'ancien chemin (texte extrait du DOM rendu) n'est plus que le repli assert "_resultText(){ const el=this.ROOT&&this.ROOT.querySelector('.aici-result')" in src # ── 3. Listes numérotées : numéros réellement affichés ────────────────────── def test_numbered_list_renders_its_number(): src = EDITOR_JS.read_text(encoding="utf-8") css = APP_CSS.read_text(encoding="utf-8") assert "let numAttr=''" in src and "data-num=" in src # rangée contiguë → rang assert ".block-numbered[data-num]::before" in css assert 'content: attr(data-num) ". "' in css # md2b accepte « 1. » et « 1) » (CommonMark) pour l'insertion agent assert r"/^\d+[.)] /" in src def test_slash_query_typed_in_block_is_synced_to_filter(): src = EDITOR_JS.read_text(encoding="utf-8") # « /numbered list » tapé dans le bloc → répercuté dans l'entrée du menu assert "SM._in.value=q" in src assert "SM.flt();" in src # ── md2b : test comportemental sur la source réelle (node) ────────────────── def _md2b_source() -> str: src = EDITOR_JS.read_text(encoding="utf-8") i = src.index("md2b(md){") j = src.index("return bl;},", i) + len("return bl;},") snippet = src[i:j].rstrip().rstrip(",") # « md2b(md){…} » return snippet def test_md2b_converts_numbered_lists_for_real(): node = shutil.which("node") if not node: pytest.skip("node absent : test comportemental md2b ignoré") md = ("# Titre\n" "1. premier\n" "2. second\n" "3) troisième\n" "- puce\n" "- [ ] à faire\n" "> citation\n") script = ( "function _tblIsData(){return false;}\n" "function _tblSplitLine(){return [];}\n" "const editor={mkB(t,c,e){const o={type:t,content:c||''};" "if(e)Object.assign(o,e);return o;},\n" f"{_md2b_source()}}};\n" f"console.log(JSON.stringify(editor.md2b({json.dumps(md)})));\n" ) out = subprocess.run([node, "-e", script], capture_output=True, text=True, timeout=30, encoding="utf-8") assert out.returncode == 0, out.stderr blocks = json.loads(out.stdout) assert [b["type"] for b in blocks] == [ "heading_1", "numbered_list", "numbered_list", "numbered_list", # 1. 2. 3) "bulleted_list", "to_do", "quote", ] assert [b["content"] for b in blocks[1:4]] == ["premier", "second", "troisième"]