"""Tests for heading and paragraph renderers — verify the EFFECT (text + style land).""" import zipfile import xml.etree.ElementTree as ET from pathlib import Path from docx import Document from bs4 import BeautifulSoup from md2doc import STYLES, _render_heading, _render_paragraph W_NS = "http://schemas.openxmlformats.org/wordprocessingml/2006/main" def get_doc_xml(doc): tmp = Path(__file__).parent / "_tmp_render.docx" doc.save(tmp) try: with zipfile.ZipFile(tmp) as z: return ET.fromstring(z.read("word/document.xml")) finally: tmp.unlink() def test_render_h1_uses_heading1_style_and_text(): doc = Document() style = STYLES["elegant"] node = BeautifulSoup("

My Title

", "html.parser").find("h1") _render_heading(doc, node, level=1, style=style) root = get_doc_xml(doc) pStyles = [p.text for p in root.iter(f"{{{W_NS}}}pStyle")] assert "Heading1" in pStyles texts = [t.text for t in root.iter(f"{{{W_NS}}}t")] assert "My Title" in texts def test_render_h1_has_bottom_border(): doc = Document() style = STYLES["elegant"] node = BeautifulSoup("

Title

", "html.parser").find("h1") _render_heading(doc, node, level=1, style=style) root = get_doc_xml(doc) bottoms = list(root.iter(f"{{{W_NS}}}bottom")) assert len(bottoms) >= 1, "h1 should have bottom border" def test_render_h1_applies_style_heading_color(): """Heading color should come from STYLES[style]['heading_color'].""" doc = Document() style = STYLES["report"] node = BeautifulSoup("

Title

", "html.parser").find("h1") _render_heading(doc, node, level=1, style=style) root = get_doc_xml(doc) colors = [c.get(f"{{{W_NS}}}val") for c in root.iter(f"{{{W_NS}}}color")] assert "1e3a8a" in colors, f"expected heading color 1e3a8a from 'report' style, got {colors}" def test_render_heading_applies_keep_with_next(): """COMMON['keep_with_next_headings'] should set paragraph_format.keep_with_next=True.""" doc = Document() style = STYLES["elegant"] node = BeautifulSoup("

Section

", "html.parser").find("h2") _render_heading(doc, node, level=2, style=style) root = get_doc_xml(doc) keep_next = list(root.iter(f"{{{W_NS}}}keepNext")) assert len(keep_next) >= 1, "expected w:keepNext for heading" def test_render_h2_no_bottom_border(): """Only h1 gets border; h2/h3/h4 don't.""" doc = Document() style = STYLES["elegant"] node = BeautifulSoup("

Subtitle

", "html.parser").find("h2") _render_heading(doc, node, level=2, style=style) root = get_doc_xml(doc) bottoms = list(root.iter(f"{{{W_NS}}}bottom")) assert len(bottoms) == 0 def test_render_paragraph_emits_text(): doc = Document() style = STYLES["elegant"] node = BeautifulSoup("

Hello world

", "html.parser").find("p") _render_paragraph(doc, node, style=style) root = get_doc_xml(doc) texts = [t.text for t in root.iter(f"{{{W_NS}}}t")] assert "Hello world" in texts def test_render_paragraph_handles_bold_inline(): doc = Document() style = STYLES["elegant"] node = BeautifulSoup("

This is bold text

", "html.parser").find("p") _render_paragraph(doc, node, style=style) root = get_doc_xml(doc) b_el = list(root.iter(f"{{{W_NS}}}b")) assert len(b_el) >= 1 def test_render_paragraph_handles_inline_code_with_shading(): """Inline should have monospace font AND run-level shading.""" doc = Document() style = STYLES["elegant"] node = BeautifulSoup("

See foo() here

", "html.parser").find("p") _render_paragraph(doc, node, style=style) root = get_doc_xml(doc) rPr_list = list(root.iter(f"{{{W_NS}}}rPr")) shd_in_runs = [r.find(f"{{{W_NS}}}shd") for r in rPr_list if r.find(f"{{{W_NS}}}shd") is not None] assert len(shd_in_runs) >= 1, "expected w:shd inside a w:rPr for inline code"