Audit complet de mise en forme — Bouton (3e élément du tableau)
Implémente toutes les options manquantes identifiées pour l'élément Bouton : typographie (gras/italique/transformation/police/taille/ espacement des lettres/couleur), icône SVG optionnelle avec position (avant/après le texte) et taille réglables — au-delà de l'Étiquette, qui n'a qu'une icône fixe —, tous les attributs de boîte partagés déjà créés pour Titre/Paragraphe/Image, et un effet visuel universel au survol/clic. Deux ajouts transversaux demandés pendant le test : un réglage "les 4 côtés de la bordure à la fois" dans le module de boîte partagé (bénéficie automatiquement à tous les éléments qui l'utilisent), et le glisser-déposer d'un élément du canevas vers une autre page via le panneau Pages (le mécanisme serveur existait déjà pour la pagination automatique, seule l'interaction manuelle manquait). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
9ad50c58b8
commit
8f879f6321
@@ -692,17 +692,136 @@ def test_image_box_style_targets_the_link_wrapper_when_no_caption(tmp_support_sl
|
||||
)
|
||||
|
||||
|
||||
def test_bouton_default_attributes_include_empty_attachment_fields(tmp_support_slug_cleanup: Any) -> None:
|
||||
def test_bouton_default_attributes_include_all_new_formatting_fields(tmp_support_slug_cleanup: Any) -> None:
|
||||
"""Audit du 26/09/2026 (réglages manquants — colonne "Bouton") : chaque
|
||||
nouveau champ doit exister avec une valeur "neutre" par défaut
|
||||
(comportement historique inchangé, voir _render_button)."""
|
||||
slug, page_id = _new_support(tmp_support_slug_cleanup)
|
||||
element_id = doc_engine.add_document_element(slug, "bouton", page_id=page_id)
|
||||
element = doc_engine.get_document_element(slug, element_id)
|
||||
assert element is not None
|
||||
assert element["attributes"] == {
|
||||
"label": "Bouton",
|
||||
"target": "",
|
||||
"attachment_stored_name": "",
|
||||
"attachment_filename": "",
|
||||
}
|
||||
attrs = element["attributes"]
|
||||
assert attrs["label"] == "Bouton"
|
||||
assert attrs["target"] == ""
|
||||
assert attrs["attachment_stored_name"] == ""
|
||||
assert attrs["attachment_filename"] == ""
|
||||
assert attrs["bold"] is False
|
||||
assert attrs["italic"] is False
|
||||
assert attrs["text_transform"] == "none"
|
||||
assert attrs["font_family"] == ""
|
||||
assert attrs["font_size"] == ""
|
||||
assert attrs["letter_spacing"] == ""
|
||||
assert attrs["text_color"] == ""
|
||||
assert attrs["svg_markup"] == ""
|
||||
assert attrs["icon_position"] == "before"
|
||||
assert attrs["icon_size"] == ""
|
||||
assert attrs["padding"] == ""
|
||||
assert attrs["align_self"] == "stretch"
|
||||
assert attrs["border"] == doc_engine_box_default_border()
|
||||
|
||||
html = doc_engine.render_document([element])
|
||||
assert html == (
|
||||
f'<button type="button" class="docButton" data-element-id="{element_id}" '
|
||||
f'data-kind="bouton"><span class="docButtonLabel">Bouton</span></button>'
|
||||
)
|
||||
|
||||
|
||||
def test_bouton_bold_and_italic_render_without_lowering_default_weight(tmp_support_slug_cleanup: Any) -> None:
|
||||
slug, page_id = _new_support(tmp_support_slug_cleanup)
|
||||
element_id = doc_engine.add_document_element(slug, "bouton", page_id=page_id)
|
||||
doc_engine.update_document_element_attributes(slug, element_id, {"label": "X", "bold": True, "italic": True})
|
||||
html = doc_engine.render_document(doc_engine.list_document_elements(slug, page_id))
|
||||
assert "font-weight:800;" in html
|
||||
assert "font-style:italic;" in html
|
||||
|
||||
|
||||
def test_bouton_typography_attributes_render_when_set(tmp_support_slug_cleanup: Any) -> None:
|
||||
slug, page_id = _new_support(tmp_support_slug_cleanup)
|
||||
element_id = doc_engine.add_document_element(slug, "bouton", page_id=page_id)
|
||||
doc_engine.update_document_element_attributes(
|
||||
slug,
|
||||
element_id,
|
||||
{
|
||||
"label": "X",
|
||||
"text_transform": "uppercase",
|
||||
"font_family": "Georgia, serif",
|
||||
"font_size": "18px",
|
||||
"letter_spacing": "0.05em",
|
||||
"text_color": "#ffffff",
|
||||
},
|
||||
)
|
||||
html = doc_engine.render_document(doc_engine.list_document_elements(slug, page_id))
|
||||
assert "text-transform:uppercase;" in html
|
||||
assert "font-family:Georgia, serif;" in html
|
||||
assert "font-size:18px;" in html
|
||||
assert "letter-spacing:0.05em;" in html
|
||||
assert "color:#ffffff;" in html
|
||||
|
||||
|
||||
def test_bouton_icon_renders_before_by_default_and_after_when_set(tmp_support_slug_cleanup: Any) -> None:
|
||||
slug, page_id = _new_support(tmp_support_slug_cleanup)
|
||||
element_id = doc_engine.add_document_element(slug, "bouton", page_id=page_id)
|
||||
svg = '<svg><circle cx="1" cy="1" r="1"/></svg>'
|
||||
doc_engine.update_document_element_attributes(slug, element_id, {"label": "X", "svg_markup": svg})
|
||||
html = doc_engine.render_document(doc_engine.list_document_elements(slug, page_id))
|
||||
assert html.index("docButtonIcon") < html.index("docButtonLabel")
|
||||
|
||||
doc_engine.update_document_element_attributes(
|
||||
slug, element_id, {"label": "X", "svg_markup": svg, "icon_position": "after"}
|
||||
)
|
||||
html = doc_engine.render_document(doc_engine.list_document_elements(slug, page_id))
|
||||
assert html.index("docButtonLabel") < html.index("docButtonIcon")
|
||||
|
||||
|
||||
def test_bouton_icon_size_sets_explicit_width_and_height(tmp_support_slug_cleanup: Any) -> None:
|
||||
slug, page_id = _new_support(tmp_support_slug_cleanup)
|
||||
element_id = doc_engine.add_document_element(slug, "bouton", page_id=page_id)
|
||||
doc_engine.update_document_element_attributes(
|
||||
slug, element_id, {"label": "X", "svg_markup": "<svg></svg>", "icon_size": "24px"}
|
||||
)
|
||||
html = doc_engine.render_document(doc_engine.list_document_elements(slug, page_id))
|
||||
assert 'style="width:24px; height:24px;"' in html
|
||||
|
||||
|
||||
def test_bouton_svg_markup_is_sanitized(tmp_support_slug_cleanup: Any) -> None:
|
||||
slug, page_id = _new_support(tmp_support_slug_cleanup)
|
||||
element_id = doc_engine.add_document_element(slug, "bouton", page_id=page_id)
|
||||
malicious = '<svg onload="alert(1)"><script>alert(2)</script></svg>'
|
||||
doc_engine.update_document_element_attributes(slug, element_id, {"label": "X", "svg_markup": malicious})
|
||||
html = doc_engine.render_document(doc_engine.list_document_elements(slug, page_id))
|
||||
assert "<script>" not in html
|
||||
assert "onload" not in html
|
||||
|
||||
|
||||
def test_bouton_box_style_attributes_render_via_shared_box_style(tmp_support_slug_cleanup: Any) -> None:
|
||||
slug, page_id = _new_support(tmp_support_slug_cleanup)
|
||||
element_id = doc_engine.add_document_element(slug, "bouton", page_id=page_id)
|
||||
border = doc_engine_box_default_border()
|
||||
border["bottom"] = {"style": "dashed", "width": "3px", "color": "#123456"}
|
||||
doc_engine.update_document_element_attributes(
|
||||
slug,
|
||||
element_id,
|
||||
{
|
||||
"label": "X",
|
||||
"padding": "12px 20px",
|
||||
"margin": "5px",
|
||||
"background_color": "#fafafa",
|
||||
"border_radius": "4px",
|
||||
"align_self": "center",
|
||||
"border": border,
|
||||
"box_shadow": "0 4px 12px rgba(0,0,0,.2)",
|
||||
"opacity": "0.9",
|
||||
},
|
||||
)
|
||||
html = doc_engine.render_document(doc_engine.list_document_elements(slug, page_id))
|
||||
assert "padding:12px 20px;" in html
|
||||
assert "margin:5px;" in html
|
||||
assert "background-color:#fafafa;" in html
|
||||
assert "border-radius:4px;" in html
|
||||
assert "align-self:center;" in html
|
||||
assert "border-bottom:3px dashed #123456;" in html
|
||||
assert "box-shadow:0 4px 12px rgba(0,0,0,.2);" in html
|
||||
assert "opacity:0.9;" in html
|
||||
|
||||
|
||||
def test_replace_document_content_rebuilds_pages_and_elements_from_seed(tmp_support_slug_cleanup: Any) -> None:
|
||||
|
||||
Reference in New Issue
Block a user