fix(export): v4.7.3 tableaux + emojis en PDF/HTML
- Tableaux GFM rendus comme texte brut dans les exports HTML/PDF. Ajout d'un parseur de tableaux pipe (bloc 'table') + rendu <table> (thead/tbody, alignement gauche/centre/droite, bordures .ftable) dans blocks_to_html; blocks_to_markdown reconstruit un tableau pipe valide. - Emojis 'carrés noirs' en PDF: xhtml2pdf n'embarque que des polices de base sans glyphes emoji. Moteur PDF -> WeasyPrint (tables CSS + emojis couleur via pango + fonts-noto-color-emoji installes dans l'image). Repli automatique sur xhtml2pdf quand weasyprint n'a pas ses libs natives (dev Windows). - Dockerfile: libs weasyprint (pango/harfbuzz/gdk-pixbuf/shared-mime-info) + fonts-dejavu-core + fonts-noto-color-emoji. requirements: + weasyprint==69.0. - Verifie en reel sur README.md: HTML = <table class=ftable> (thead/th, center); PDF 10 pages, texte de table present, Noto-Color-Emoji embarque + pixels colores confirmes. 199/199 tests (4 nouveaux).
This commit is contained in:
@@ -3165,5 +3165,73 @@ def test_v472_binary_file_page_not_exported(client, monkeypatch, tmp_path):
|
||||
md = page_to_markdown(_load(pid), include_children=False)
|
||||
assert "# manual.pdf" in md
|
||||
assert "fake binary" not in md # never dump binary into markdown
|
||||
finally:
|
||||
_cleanup_src(pid, uid)
|
||||
|
||||
|
||||
_TABLE_MD = (
|
||||
"# Titre\n\n"
|
||||
"| ID | Nom | Score | Statut |\n"
|
||||
"|----|:---:|------:|--------|\n"
|
||||
"| 1 | Alice | 95.5 | ✅ Actif |\n"
|
||||
"| 2 | Bob | 87.2 | 🟡 En attente |\n"
|
||||
"| 3 | Charlie | 99.9 | ❌ Inactif |\n"
|
||||
)
|
||||
|
||||
|
||||
def test_v472_table_md_renders_real_html_table(client):
|
||||
"""A GFM pipe table becomes a real <table> (header + cells + alignment)."""
|
||||
from app.services.export import _page_blocks, blocks_to_html
|
||||
pid, uid = _make_src_page(raw_md=_TABLE_MD, title="Table Page")
|
||||
try:
|
||||
blocks = _page_blocks(_load(pid))
|
||||
tables = [b for b in blocks if b.get("type") == "table"]
|
||||
assert tables, "expected a parsed table block"
|
||||
t = tables[0]
|
||||
assert t["align"] == ["left", "center", "right", "left"]
|
||||
html = blocks_to_html(blocks)
|
||||
assert "<table" in html
|
||||
assert "<thead>" in html and "<th>" in html
|
||||
assert "<tbody>" in html and "<td>" in html
|
||||
assert 'text-align:center;' in html
|
||||
assert "Alice" in html and "✅ Actif" in html
|
||||
finally:
|
||||
_cleanup_src(pid, uid)
|
||||
|
||||
|
||||
def test_v472_table_md_standalone_html_has_table_css(client):
|
||||
"""Standalone HTML export embeds the table and its stylesheet class."""
|
||||
from app.services.export import page_to_standalone_html
|
||||
pid, uid = _make_src_page(raw_md=_TABLE_MD, title="Table Page")
|
||||
try:
|
||||
html = page_to_standalone_html(_load(pid), include_children=False)
|
||||
assert 'class="ftable"' in html
|
||||
assert "Alice" in html
|
||||
assert "Charlie" in html
|
||||
finally:
|
||||
_cleanup_src(pid, uid)
|
||||
|
||||
|
||||
def test_v472_table_markdown_roundtrip(client):
|
||||
"""A table block is re-emitted as a valid pipe table with a separator."""
|
||||
from app.services.export import _page_blocks, blocks_to_markdown
|
||||
pid, uid = _make_src_page(raw_md=_TABLE_MD, title="Table Page")
|
||||
try:
|
||||
md = blocks_to_markdown(_page_blocks(_load(pid)))
|
||||
assert "| ID | Nom | Score | Statut |" in md
|
||||
assert ":---:" in md and "---:" in md
|
||||
assert "| 3 | Charlie" in md
|
||||
finally:
|
||||
_cleanup_src(pid, uid)
|
||||
|
||||
|
||||
def test_v472_table_in_pdf(client, monkeypatch, tmp_path):
|
||||
"""PDF export of a markdown table page returns a valid PDF (any engine)."""
|
||||
from app.services.export import page_to_pdf_bytes
|
||||
pid, uid = _make_src_page(raw_md=_TABLE_MD, title="Table Page")
|
||||
try:
|
||||
pdf = page_to_pdf_bytes(_load(pid))
|
||||
assert pdf[:5] == b"%PDF-"
|
||||
assert len(pdf) > 1000
|
||||
finally:
|
||||
_cleanup_src(pid, uid)
|
||||
Reference in New Issue
Block a user