- cause : la garde de turnInto() faisait _BLOCK_TURN_TYPES.indexOf(type) sur
un tableau d'objets {id,name} → toujours -1 → retour immédiat après
l'ouverture du sous-menu, aucun changement de format
- correction : validation par id (_BLOCK_TURN_TYPES.some(t=>t.id===type))
- même fonction : convertir un texte en To-do / Toggle vidait le contenu
(exclusion par erreur) ; seuls les types sans champ texte (image, embed,
meeting, divider, table_of_contents, database, button, columns) le vident
- tests : tests/test_v7593_turn_into.py (4 tests, dont 1 comportemental node
qui exécute la vraie turnInto() extraite de la source)
- livraison : VERSION + app/main = 7.59.3, OpenAPI 525 chemins, CHANGELOG
83 lines
3.1 KiB
Python
83 lines
3.1 KiB
Python
"""7.59.3 — « Turn into » du menu contextuel : garde cassée + texte conservé."""
|
|
|
|
import json
|
|
import shutil
|
|
import subprocess
|
|
from pathlib import Path
|
|
|
|
import pytest
|
|
|
|
ROOT = Path(__file__).resolve().parent.parent
|
|
EDITOR_JS = ROOT / "static" / "js" / "page_editor_scripts.js"
|
|
SRC = EDITOR_JS.read_text(encoding="utf-8")
|
|
|
|
|
|
def _slice(start: str, end: str) -> str:
|
|
i = SRC.index(start)
|
|
j = SRC.index(end, i)
|
|
return SRC[i:j].rstrip()
|
|
|
|
|
|
def test_turn_into_guard_matches_objects_not_strings():
|
|
# BUG : indexOf() sur un tableau d'objets → toujours -1 → retour immédiat.
|
|
assert "_BLOCK_TURN_TYPES.indexOf(type)" not in SRC
|
|
assert "_BLOCK_TURN_TYPES.some(t=>t.id===type)" in SRC
|
|
|
|
|
|
def test_turn_into_menu_wiring():
|
|
# menu ⋮⋮ → « Turn into » → sous-menu → choix de type
|
|
assert 'data-bm-act="turn"' in SRC
|
|
assert "data-bm-act=\\\"turn-type\\\"" in SRC or 'data-bm-act="turn-type"' in SRC
|
|
assert "act==='turn-type'" in SRC
|
|
assert "_blockTurnMenuOpen(" in SRC
|
|
|
|
|
|
def test_turn_into_keeps_text_for_to_do_and_toggle():
|
|
# Convertir un texte en To-do / Toggle ne doit plus effacer le contenu.
|
|
line = [ln for ln in SRC.splitlines()
|
|
if ln.strip().startswith("turnInto(idx,type){")][0]
|
|
assert "type!=='to_do'&&type!=='toggle'" not in line
|
|
assert "if(keep&&['image','embed','meeting','divider'" in line
|
|
|
|
|
|
# ── Comportement réel : la méthode extraite de la source, exécutée sous node ─
|
|
|
|
def test_turn_into_converts_blocks_for_real():
|
|
node = shutil.which("node")
|
|
if not node:
|
|
pytest.skip("node absent : test comportemental turnInto ignoré")
|
|
types = _slice("const _BLOCK_TURN_TYPES=[", "];")
|
|
method = _slice("turnInto(idx,type){", "setBlockColor(idx,key,val){")
|
|
script = f"""
|
|
function _rtSync(){{}}
|
|
function _selClear(){{}}
|
|
{types}];
|
|
const E = {{
|
|
blocks: [{{id:'b1',type:'paragraph',content:'Bonjour'}}],
|
|
_blockTargets(i){{return [i];}},
|
|
sync(){{}}, pushHistory(){{}}, dirty:false,
|
|
autoSave(){{}}, render(){{}}, getEl(){{return null;}},
|
|
{method}
|
|
}};
|
|
E.turnInto(0,'heading_2');
|
|
const heading = {{type:E.blocks[0].type, content:E.blocks[0].content}};
|
|
E.turnInto(0,'to_do');
|
|
const to_do = {{type:E.blocks[0].type, content:E.blocks[0].content, checked:E.blocks[0].checked}};
|
|
E.turnInto(0,'button'); // type sans texte → contenu vidé
|
|
const button = {{type:E.blocks[0].type, content:E.blocks[0].content}};
|
|
console.log(JSON.stringify({{heading:heading, to_do:to_do, button:button}}));
|
|
"""
|
|
out = subprocess.run([node, "-e", script], capture_output=True, text=True,
|
|
timeout=30, encoding="utf-8")
|
|
assert out.returncode == 0, out.stderr
|
|
res = json.loads(out.stdout)
|
|
|
|
# 1) le changement de format a lieu (avant la correction : aucune conversion)
|
|
assert res["heading"] == {"type": "heading_2", "content": "Bonjour"}
|
|
|
|
# 2) To-do : texte conservé comme étiquette, case décochée
|
|
assert res["to_do"] == {"type": "to_do", "content": "Bonjour", "checked": False}
|
|
|
|
# 3) Button (type sans texte) → contenu vidé
|
|
assert res["button"] == {"type": "button", "content": ""}
|