Files
ewoooc/tests/test_chart_fallback_contract.py
ogt 911393190d
Some checks failed
CD Pipeline / deploy (push) Has been cancelled
fix(analytics): enforce trustworthy chart rendering
2026-07-16 15:55:22 +08:00

128 lines
6.1 KiB
Python

from pathlib import Path
ROOT = Path(__file__).resolve().parents[1]
def test_daily_sales_canvas_is_primary_and_fallback_is_opt_in():
css = (ROOT / "web/static/css/page-daily-sales.css").read_text(encoding="utf-8")
script = (ROOT / "web/static/js/page-daily-sales.js").read_text(encoding="utf-8")
assert ".chart-container.has-html-chart canvas" not in css
assert ".chart-container.chart-fallback-active canvas" in css
assert ".chart-container.chart-empty-active canvas" in css
assert ".chart-container:not(.chart-fallback-active) .chart-fallback-list" in css
assert "node.content && node.content.textContent" in script
assert "chart-empty-active" in script
assert "Math.abs(Number(value)) > 1e-9" in script
render_body = script.split("function renderAllCharts()", 1)[1].split("function bootCharts()", 1)[0]
assert "renderHtmlChartFallbacks();" not in render_body
assert "catch(error =>" in script
assert "renderHtmlChartFallbacks();" in script.split("catch(error =>", 1)[1]
def test_growth_analysis_canvas_is_primary_and_fallback_is_opt_in():
css = (ROOT / "web/static/css/page-growth-bem.css").read_text(encoding="utf-8")
script = (ROOT / "web/static/js/page-growth.js").read_text(encoding="utf-8")
assert ".ga-chart-card__body.has-html-chart canvas" not in css
assert ".ga-chart-card__body.chart-fallback-active canvas" in css
assert ".ga-chart-card__body.chart-empty-active canvas" in css
assert ".ga-chart-card__body:not(.chart-fallback-active) .ga-chart-snapshot" in css
assert "node.content && node.content.textContent" in script
assert "chart-empty-active" in script
assert "Math.abs(Number(value)) > 1e-9" in script
render_body = script.split("function renderCharts()", 1)[1].split("function bootCharts()", 1)[0]
assert "renderHtmlChartFallbacks();" not in render_body
assert "catch(error =>" in script
assert "renderHtmlChartFallbacks();" in script.split("catch(error =>", 1)[1]
def test_chart_theme_has_cdn_timeout_and_fallback_sources():
script = (ROOT / "web/static/js" / "analysis-chart-theme.js").read_text(encoding="utf-8")
assert "CHART_LOAD_TIMEOUT_MS" in script
assert "Chart.js 載入逾時" in script
assert "cdn.jsdelivr.net/npm/chart.js@4.4.6" in script
assert "unpkg.com/chart.js@4.4.6" in script
assert "cdnjs.cloudflare.com/ajax/libs/Chart.js/4.4.6" in script
assert "!Array.isArray(ds.backgroundColor)" in script
assert "!Array.isArray(ds.borderColor)" in script
assert script.index("...originalScale") < script.index("border: { color: theme.faint")
assert "callback: v => formatNumber(v)" not in script
assert "autoSkip: true" in script
def test_sales_chart_runtime_guard_rejects_axis_only_canvases():
script = (ROOT / "scripts" / "check_sales_charts_runtime.js").read_text(encoding="utf-8")
assert "nonZeroPoints" in script
assert "colorPixels" in script
assert "has no colored chart marks" in script
assert "has no non-zero dataset values" in script
def test_all_analysis_pages_have_runtime_chart_integrity_contracts():
script = (ROOT / "scripts" / "check_analysis_chart_integrity.js").read_text(encoding="utf-8")
for route in (
"/daily_sales?month=2026-04",
"/growth_analysis?start_month=2026-04&end_month=2026-04",
"/sales_analysis?start_date=2026-04-01&end_date=2026-04-30",
"/monthly_summary_analysis?start_month=2026-04&end_month=2026-04",
):
assert route in script
for viewport in ("1440, height: 1000", "1024, height: 900", "390, height: 844"):
assert viewport in script
assert "loading overlay remains visible" in script
assert "has no colored chart marks" in script
assert "extreme percent values are not bounded with traceable markers" in script
assert "single point is not visibly emphasized" in script
assert "hides drawable payload behind an empty state" in script
assert "analysis tab lost the active period" in script
assert "rendered numeric indexes instead of product labels" in script
assert "contains labels outside the selected April period" in script
assert "explicitEmpty" in script
def test_analysis_chart_failure_states_are_explicit_and_bounded():
sales = (ROOT / "web/static/js/page-sales-analysis.js").read_text(encoding="utf-8")
daily = (ROOT / "web/static/js/page-daily-sales.js").read_text(encoding="utf-8")
growth = (ROOT / "web/static/js/page-growth.js").read_text(encoding="utf-8")
monthly = (ROOT / "web/static/js/page-monthly-summary.js").read_text(encoding="utf-8")
assert "document.documentElement.dataset.salesCharts = 'ready'" in sales
assert "series.chart_values" in sales
assert "renderChartEmpty(bcgEl" in sales
assert "renderChartEmpty(hmEl" in sales
assert "originalValue" in daily
assert "clippedCount" in daily
assert "function dateAxis(element)" in daily
assert "overlapping date ticks" in (ROOT / "scripts/check_analysis_chart_integrity.js").read_text(encoding="utf-8")
assert "beginAtZero: true" in growth
assert "pointRadiusFor" in growth
assert "REQUEST_TIMEOUT_MS" in monthly
assert "activeFetchController.abort()" in monthly
assert "const refreshForViewport = () => {" in monthly
assert "const refreshForViewport = () => fetchData()" not in monthly
assert "dataset.monthlyCharts = 'ready'" in monthly
assert "safeHtmlText(p.value[3])" in monthly
assert "safeHtmlText(ps[0].name)" in monthly
def test_analysis_tables_use_local_traditional_chinese_language_contract():
helper = (ROOT / "web/static/js/datatables-zh-hant.js").read_text(encoding="utf-8")
assert "window.EwoooCDataTableLanguage" in helper
assert "沒有符合條件的資料" in helper
assets = [
ROOT / "web/static/js/page-daily-sales.js",
ROOT / "web/static/js/page-sales-analysis.js",
ROOT / "web/static/js/page-monthly-summary.js",
ROOT / "templates/abc_analysis_detail.html",
]
for asset in assets:
source = asset.read_text(encoding="utf-8")
assert "cdn.datatables.net/plug-ins" not in source
assert "EwoooCDataTableLanguage()" in source