"""Style metadata in the .xlsx viewer (#153 A15): bold, colors, number formats, merged ranges and freeze panes — plus the endpoint wiring.""" from __future__ import annotations from pathlib import Path import pytest openpyxl = pytest.importorskip("openpyxl") VAULT = "TestVault" @pytest.fixture def styled_book(test_vault_dir: str) -> str: """A workbook with a bold red-font header, a filled cell, a merge and a freeze.""" from openpyxl.styles import Font, PatternFill path = Path(test_vault_dir) / "styles.xlsx" wb = openpyxl.Workbook() ws = wb.active ws.title = "Data" ws["A1"] = "En-tête" ws["A1"].font = Font(bold=True, italic=True, color="FFCC0000") ws["B1"] = "Total" ws["B1"].fill = PatternFill("solid", fgColor="FFFFEE99") ws["B2"] = 1234.5 ws["B2"].number_format = "#,##0.00" ws["C3"] = "fusionnée" ws.merge_cells("C3:D3") ws["C3"].value = "fusionnée" ws.freeze_panes = "A2" wb.save(path) return str(path) class TestStyleReading: def test_bold_italic_and_font_color(self, styled_book): from backend.xlsx_reader import read_sheet_styles styles = read_sheet_styles(Path(styled_book), "Data") a1 = styles["A1"] assert "font-weight:600" in a1["style"] assert "font-style:italic" in a1["style"] assert a1["style"].startswith("color:#cc0000") def test_background_fill_is_read(self, styled_book): from backend.xlsx_reader import read_sheet_styles styles = read_sheet_styles(Path(styled_book), "Data") assert "background:#ffee99" in styles["B1"]["style"] def test_number_format_is_signalled(self, styled_book): from backend.xlsx_reader import read_sheet_styles styles = read_sheet_styles(Path(styled_book), "Data") assert "font-family" in styles["B2"]["style"] def test_plain_cell_has_no_entry(self, styled_book): from backend.xlsx_reader import read_sheet_styles styles = read_sheet_styles(Path(styled_book), "Data") assert "A2" not in styles # untouched cell def test_merges_and_freeze(self, styled_book): from backend.xlsx_reader import read_sheet_freeze, read_sheet_merges assert read_sheet_merges(Path(styled_book), "Data") == ["C3:D3"] assert read_sheet_freeze(Path(styled_book), "Data") == "A2" def test_unknown_sheet_yields_empty(self, styled_book): from backend.xlsx_reader import read_sheet_styles assert read_sheet_styles(Path(styled_book), "Nope") == {} def test_broken_file_yields_empty(self, test_vault_dir): from backend.xlsx_reader import read_sheet_styles bad = Path(test_vault_dir) / "broken-styles.xlsx" bad.write_bytes(b"not a zip") assert read_sheet_styles(bad, "Data") == {} class TestEndpointWiring: def test_read_response_carries_styles_merges_freeze(self, client, styled_book): resp = client.get(f"/api/file/{VAULT}", params={"path": "styles.xlsx"}) assert resp.status_code == 200 sheet = resp.json()["xlsx_sheets"][0] assert sheet["styles"]["A1"].startswith("color:#cc0000") assert sheet["aligns"] == {} or isinstance(sheet["aligns"], dict) assert sheet["merges"] == ["C3:D3"] assert sheet["freeze"] == "A2" def test_rendered_html_carries_the_inline_style(self, client, styled_book): resp = client.get(f"/api/file/{VAULT}", params={"path": "styles.xlsx"}) html = resp.json()["xlsx_sheets"][0]["html"] assert 'data-cell="A1" style="' in html assert "font-weight:600" in html