Files
tick-stock-panel/backend/tests/test_analysis_menu_url_template.py
T
shy3130 01257c83ee feat(pages): 设置三页合一为「页面管理」+ 源码扩展删除/URL 嵌入页/源码导入
- 菜单设置/扩展页面/页面插件三个设置 tab 合并为「页面管理」(?tab=pages, 旧链接与 /analysis 重定向兼容)
- 源码扩展页(frontend/src/custom/<ns>/)支持界面内物理删除: 先自动备份 zip 到 data/backups/pages/(可下载)再删目录, 命名校验+防穿越, 产物部署无源码树 409
- 扩展页面新增 URL 嵌入模板: 仅填菜单名+网址生成 iframe 内嵌页, 复用看板外链安全约定(仅 http(s)/拒同源/sandbox 白名单/新窗口兜底)
- 页面插件新增源码导入: 上传 .tsx 或从本项目 custom/ 选择, 后端用自带 esbuild 编译+契约适配(component→mount, 独立 react 实例自挂 Provider/Router, 图标映射白名单), 产物即标准页面插件; 无工具链部署 409
2026-10-22 17:47:59 +08:00

60 lines
2.3 KiB
Python

"""url 嵌入型扩展页面: 模板绑定校验 (url 必填 http(s) / 数据型模板仍需 data_source)。"""
from __future__ import annotations
from pathlib import Path
from types import SimpleNamespace
from fastapi import FastAPI
from fastapi.testclient import TestClient
from app.api import analysis
def _client(tmp_path: Path) -> TestClient:
app = FastAPI()
app.include_router(analysis.router)
app.state.repo = SimpleNamespace(store=SimpleNamespace(data_dir=tmp_path))
return TestClient(app)
def _url_body(**overrides) -> dict:
body = {"label": "外部页面", "template": "url", "url": "https://example.com/embed"}
body.update(overrides)
return body
def test_url_template_roundtrip(tmp_path):
c = _client(tmp_path)
r = c.post("/api/analysis-menus/my_embed", json=_url_body())
assert r.status_code == 200, r.text
saved = c.get("/api/analysis-menus/my_embed").json()
assert saved["template"] == "url"
assert saved["url"] == "https://example.com/embed"
assert saved["label"] == "外部页面"
def test_url_template_rejects_missing_bad_and_long_urls(tmp_path):
c = _client(tmp_path)
assert c.post("/api/analysis-menus/a", json=_url_body(url=None)).status_code == 422
assert c.post("/api/analysis-menus/b", json=_url_body(url="javascript:alert(1)")).status_code == 422
assert c.post("/api/analysis-menus/d", json=_url_body(url="ftp://x/y")).status_code == 422
assert c.post("/api/analysis-menus/e", json=_url_body(url="https://x/" + "a" * 600)).status_code == 422
def test_data_templates_still_require_data_source(tmp_path):
c = _client(tmp_path)
body = {"label": "排行", "template": "ranking", "data_source": ""}
assert c.post("/api/analysis-menus/r1", json=body).status_code == 422
# 正常数据型保存不受影响
ok = c.post("/api/analysis-menus/r2", json={**body, "data_source": "ext_hy_ths"})
assert ok.status_code == 200
assert ok.json()["data_source"] == "ext_hy_ths"
def test_url_template_ignores_data_source(tmp_path):
"""url 模板不绑数据源: 缺省与传入都被接受, 保存值为空串。"""
c = _client(tmp_path)
r = c.post("/api/analysis-menus/u1", json=_url_body(data_source=""))
assert r.status_code == 200
assert r.json()["data_source"] == ""