- aide : bouton ✕ en haut à droite du panneau (classe partagée settings-close, 44 px mobile) + helpInit.close() (retour en arrière, sinon /workspaces) ; .settings-panel en position:relative pour ancrer hamburger + ✕ au panneau - éditeur « Insert below » (/Write with AI) : insère le markdown source conservé à la génération (AIC._md) au lieu du texte extrait du HTML rendu (_resultText() reste seulement en repli) → titres/listes/gras conservés - listes numérotées : aucun numéro n'était affiché (CSS = retrait seul) ; le rang des blocs numbered_list contigus est calculé au rendu (data-num) et rendu via content: attr(data-num) — /numbered list et l'insertion agent affichent 1, 2, 3 - md2b : cases à cocher - [ ] / - [x] testées avant la branche des puces (aligné sur paste2b) + séparateur 1) accepté (CommonMark) - menu slash : requête tapée dans le bloc (/numbered list) répercutée dans le filtre du menu quand le focus n'a pas rejoint l'entrée - tests : tests/test_v7592_ui_fixes.py (5 tests, dont 1 comportemental node qui exécute le vrai md2b) ; ruff I001 préexistant sur test_agent.py - livraison : VERSION + app/main = 7.59.2, OpenAPI 525 chemins, CHANGELOG
101 lines
4.1 KiB
Python
101 lines
4.1 KiB
Python
"""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"]
|