"""HTML → 专业 Word(.docx) 转换器测试。 覆盖:表格转 Word 表格、标题分级、Markdown/AI 噪声剥离、style/svg 丢弃、 中文与产物可被 python-docx 重新打开(结构有效)。 """ from __future__ import annotations from io import BytesIO import pytest from services.docx_export import html_to_docx, docx_available pytestmark = pytest.mark.skipif(not docx_available(), reason="python-docx 未安装") _SAMPLE_HTML = """ T
Pharma K
专家系统
质量属性梳理报告
2026-06-07 00:56
37
分组
64
观测
各质量属性梳理

溶化时限符合限度。**这段含粗体**和 *斜体* 应被清理。

* 这是一个伪列表行

含量均匀度(接受值判定)
规格AV判定
20μg5.074符合
40μg3.418符合
""" def _open(data: bytes): from docx import Document return Document(BytesIO(data)) def test_returns_valid_docx_bytes(): data = html_to_docx(_SAMPLE_HTML) assert data and data[:2] == b"PK" # docx 是 zip,魔数 PK doc = _open(data) # 可被 python-docx 重新打开 assert doc is not None def test_tables_become_real_word_tables(): doc = _open(html_to_docx(_SAMPLE_HTML)) assert len(doc.tables) >= 1 cu = [t for t in doc.tables if t.rows and t.rows[0].cells[0].text == "规格"] assert cu, "含量均匀度表应转为 Word 表格且表头为规格" tbl = cu[0] assert tbl.rows[0].cells[1].text == "AV" assert tbl.cell(1, 0).text == "20μg" assert tbl.cell(1, 2).text == "符合" def test_markdown_and_ai_noise_stripped(): doc = _open(html_to_docx(_SAMPLE_HTML)) all_text = "\n".join(p.text for p in doc.paragraphs) assert "**" not in all_text and "*" not in all_text assert "这段含粗体" in all_text assert "斜体" in all_text def test_style_and_svg_dropped(): doc = _open(html_to_docx(_SAMPLE_HTML)) all_text = "\n".join(p.text for p in doc.paragraphs) assert "color:red" not in all_text assert "rect" not in all_text def test_headings_present(): doc = _open(html_to_docx(_SAMPLE_HTML)) texts = [p.text for p in doc.paragraphs] assert "Pharma K" in texts assert any("各质量属性梳理" in t for t in texts) def test_empty_html_returns_none(): assert html_to_docx("") is None def test_meta_void_tags_do_not_swallow_body(): """回归: 中的 void 元素 (无闭合)不得吞掉 (致空文档)。""" html = ( '' '' '' 'T' '
分节标题
' '

正文内容

' ) doc = _open(html_to_docx(html)) texts = [p.text for p in doc.paragraphs] assert any("分节标题" in t for t in texts) assert any("正文内容" in t for t in texts) # --------------------------------------------------------------------------- # adaptive-report-visualization 任务 12:内联 PNG → Word 图片 # --------------------------------------------------------------------------- def _real_png_datauri(): """用 ChartService 生成一张真实 PNG 的 data-uri(需 matplotlib)。""" pytest.importorskip("matplotlib") from services.chart_service import ChartService res = ChartService().grouped_bar(["A", "B"], [1.0, 2.0], title="t") assert res.ok return res.image_base64 def test_inline_png_embedded_as_word_picture(): png = _real_png_datauri() html = ( "
" "
图表化呈现
" f"
含量均匀度
" "
单位
199.19
" "
" ) doc = _open(html_to_docx(html)) # 图片被嵌入为 inline shape;配套数据表保留。 assert len(doc.inline_shapes) >= 1 assert len(doc.tables) >= 1 assert any("99.19" in c.text for t in doc.tables for r in t.rows for c in r.cells) def test_bad_data_uri_skipped_without_crash(): html = "

" data = html_to_docx(html) assert data and data[:2] == b"PK" # 不崩溃,仍产出有效 docx doc = _open(data) texts = "\n".join(p.text for p in doc.paragraphs) assert "前" in texts and "后" in texts