Files
flowdeck/tests/test_v7593_turn_into.py
T
bruno 033490c464
FlowDeck CI / lint (push) Successful in 2m16s
FlowDeck CI / test (push) Failing after 20m32s
FlowDeck CI / docker (push) Skipped
feat: menu contextuel de bloc refondu façon Notion — 10 actions, sous-menus et raccourcis (v7.61.0)
- panneau de gauche : recherche « Search actions... », section « Text », les
  10 actions dans l'ordre Notion (Turn into, Color, Copy link Alt+⇧+L,
  Duplicate Ctrl+D, Move to Ctrl+⇧+P, Delete Del, Comment Ctrl+⇧+M,
  Suggest edits Ctrl+⇧+Alt+X, Ask AI Ctrl+J, Skills) + pied métadonnées
  (auteur / heure de dernière édition / mots-caractères du bloc)
- panneau de droite au survol (fermeture différée) : Turn into avec ✓ du
  type actuel + Heading 1-4, listes, To-do, Toggle, Code, Quote, Callout,
  Block equation, Synced block, 2/3/4/5 columns (info-bulle « Create N
  columns of blocks ») ; Color avec Last used / Text color / Background
  color (10 couleurs nommées, ✓ courante, carré de couleur) ; Skills =
  compétences réelles de l'espace appliquées au bloc via l'IA
- turnInto(idx,type,cols) : crée N colonnes, sélecteur de source pour les
  blocs synchronisés ; setBlockColor mémorise la dernière couleur (Ctrl+⇧+H)
- nouvelles actions éditeur : commentBlock (sélection + tiroir), askAI
  (composeur sans effacer le bloc), suggestEdit / runSkill (IA, insertion
  sous le bloc), applyLastColor
- raccourcis : handler clavier dédié (Ctrl+J, Ctrl+⇧+H, Ctrl+⇧+M,
  Ctrl+⇧+Alt+X, Alt+⇧+L, Ctrl+⇧+P, Ctrl+D sans double, Del seulement avec le
  menu ouvert, Échap) — les entrées Copy/Cut/Paste du menu sont retirées
  (Ctrl+C/X/V conservés)
- styles : .bm-group, .bm-foot, .bm-check, .bm-current, .bm-dot, sous-menu
  60vh, recherche focalisée à l'ouverture
- tests : tests/test_v761_block_menu.py (9 tests, dont node : colonnes) +
  test_v7593 adapté ; suite complète 1362 passed / 0 failed, ruff 0, eslint 0
- livraison : VERSION + app/main = 7.61.0, OpenAPI 525 chemins, CHANGELOG
2026-10-07 23:09:21 -04:00

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 "_blockMenuItem('submenu','↩','Turn into',{sub:'turn'})" in SRC
assert "'turn-type'" in SRC # construit par _blockMenuItem
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": ""}