- 信息员预览基数改用本人销售额(原误用折算毛利润额,金额算错且口径自相矛盾) - 产品类别入参与维度值加存在性校验(拼错静默回退默认阈值 30% 会算错轨交工资) - submit 校验顺序前置查库(未注册 param_code 由 500 修正为 400) - 金额拒绝 NaN/Infinity(比较抛 InvalidOperation、计算抛溢出均穿透为 500) - version_no 并发冲突翻译为 400(对齐 user/role service 的 IntegrityError 处理) - 旧值留痕改取条目生效日时点的值(多未来批次下留痕链不再错位) - 脱敏红线:phone/mobile/id_card 键名整值抹除 + 手机号正则兼容分隔符写法 - 前端:撤回按钮与导出文件名改本地日期(UTC/本地混算)、维度行内精确「改」入口、 detailOf 补 catch、抽屉分页 size 生效、blob 错误读出真实 message - e2e 密码移除硬编码 fallback(缺失即报错退出);按钮文案同步「改」 - 全量回归:后端 406 + 集成 104 + 前端 type-check/build + e2e 7 步 全绿 Co-Authored-By: Claude Code <noreply@anthropic.com>
146 lines
6.3 KiB
Python
146 lines
6.3 KiB
Python
"""计提参数管理端到端测试(需要容器、后端、前端都在运行)。
|
||
|
||
覆盖链路(M1 验收):目录分组展示 → 修改参数入「待提交」→ 批次提交(立即
|
||
生效)→ 目录反映新值 → 版本记录可见 → 计算预览金标准复现(27 天 / 9.7‰ /
|
||
145.5 元)→ 值改回种子值恢复现场。
|
||
|
||
运行:``E2E_ADMIN_PASSWORD=... python e2e/param_management.py``
|
||
"""
|
||
|
||
import sys
|
||
|
||
sys.path.insert(0, __import__("os").path.dirname(__file__))
|
||
|
||
from playwright.sync_api import sync_playwright
|
||
|
||
from common import (
|
||
BASE_URL,
|
||
E2EFailure,
|
||
collect_console_errors,
|
||
expect_toast,
|
||
fail,
|
||
login,
|
||
wait_toast,
|
||
)
|
||
|
||
if hasattr(sys.stdout, "reconfigure"):
|
||
sys.stdout.reconfigure(encoding="utf-8")
|
||
|
||
PARAMS_URL = f"{BASE_URL}/system/params"
|
||
console_errors: list[str] = []
|
||
|
||
|
||
def step(title: str) -> None:
|
||
print(f"—— {title}")
|
||
|
||
|
||
def main() -> int:
|
||
failures: list[str] = []
|
||
with sync_playwright() as p:
|
||
browser = p.chromium.launch()
|
||
page = browser.new_page(viewport={"width": 1440, "height": 860})
|
||
errors = collect_console_errors(page, console_errors)
|
||
|
||
try:
|
||
admin_password = __import__("os").environ.get("E2E_ADMIN_PASSWORD")
|
||
if not admin_password:
|
||
print("✗ 缺少环境变量 E2E_ADMIN_PASSWORD(管理员密码不入库)")
|
||
return 1
|
||
login(page, "admin", admin_password)
|
||
page.goto(PARAMS_URL, wait_until="networkidle")
|
||
|
||
step("1. 目录分组展示")
|
||
if page.locator(".group-title", has_text="支付环节").count() == 0:
|
||
fail("目录分组", "未找到「支付环节」分组")
|
||
# 展开「支付环节」分组
|
||
page.locator(".el-collapse-item__header", has_text="支付环节").click()
|
||
page.wait_for_timeout(300)
|
||
|
||
step("2. 修改预付款比例 10 → 12(立即生效)")
|
||
row = page.locator(".param-table tbody tr", has_text="预付款计提比例").first
|
||
row.get_by_role("button", name="改", exact=True).click()
|
||
dialog = page.locator(".el-dialog")
|
||
dialog.locator("input").fill("12")
|
||
dialog.get_by_role("button", name="加入待提交").click()
|
||
if "待改为 12" not in page.content():
|
||
fail("待提交", "参数行未出现「待改为 12」标记")
|
||
|
||
step("3. 提交批次")
|
||
page.get_by_role("button", name="提交变更").click()
|
||
page.locator(".el-message-box").get_by_role("button", name="提交").click()
|
||
expect_toast(page, "已提交", "提交批次")
|
||
|
||
step("4. 目录反映新值")
|
||
page.wait_for_timeout(500)
|
||
row = page.locator(".param-table tbody tr", has_text="预付款计提比例").first
|
||
if "12" not in row.text_content():
|
||
fail("目录生效", "提交后目录未显示新值 12")
|
||
|
||
step("5. 版本记录可见")
|
||
page.get_by_role("button", name="版本管理").click()
|
||
page.wait_for_timeout(500)
|
||
first_version = page.locator(".el-drawer .el-table tbody tr").first.text_content()
|
||
if "P2026" not in first_version:
|
||
fail("版本记录", f"最新记录异常:{first_version}")
|
||
page.keyboard.press("Escape")
|
||
page.wait_for_timeout(300)
|
||
|
||
step("6. 恢复种子值 10")
|
||
row = page.locator(".param-table tbody tr", has_text="预付款计提比例").first
|
||
row.get_by_role("button", name="改", exact=True).click()
|
||
dialog = page.locator(".el-dialog")
|
||
dialog.locator("input").fill("10")
|
||
dialog.get_by_role("button", name="加入待提交").click()
|
||
page.get_by_role("button", name="提交变更").click()
|
||
page.locator(".el-message-box").get_by_role("button", name="提交").click()
|
||
wait_toast(page, "已提交")
|
||
page.wait_for_timeout(400)
|
||
|
||
step("7. 计算预览金标准(27 天 / 9.7‰ / 145.5)")
|
||
page.get_by_role("button", name="计算预览").click()
|
||
page.wait_for_timeout(600)
|
||
# 多个抽屉组件常驻 DOM(隐藏未销毁),按标题过滤出预览抽屉
|
||
drawer = page.locator(".el-drawer").filter(has_text="计算预览").last
|
||
# 岗位下拉默认 salesperson(v-model 初始值),无需操作
|
||
drawer.locator(".el-form-item", has_text="发货日").locator("input").click()
|
||
page.keyboard.type("2025-12-15")
|
||
page.keyboard.press("Enter")
|
||
drawer.locator(".el-form-item", has_text="回款到账日").locator("input").click()
|
||
page.keyboard.type("2026-01-10")
|
||
page.keyboard.press("Enter")
|
||
drawer.locator(".el-form-item", has_text="销售额").locator("input").fill("100000")
|
||
drawer.locator(".el-form-item", has_text="毛利润额").locator("input").fill("45000")
|
||
drawer.locator(".el-form-item", has_text="本笔回款").locator("input").fill("60000")
|
||
drawer.get_by_role("button", name="试 算").click()
|
||
page.wait_for_timeout(900)
|
||
result_text = drawer.locator(".preview-result").text_content()
|
||
for expected in ["27 天", "145.5", "97/10000"]:
|
||
if expected not in result_text:
|
||
fail("预览金标准", f"结果缺少 {expected}:{result_text[:200]}")
|
||
|
||
except E2EFailure as exc:
|
||
failures.append(str(exc))
|
||
page.screenshot(path="e2e/failure.png")
|
||
except Exception as exc: # noqa: BLE001
|
||
import traceback
|
||
traceback.print_exc()
|
||
failures.append(f"未预期异常:{exc}")
|
||
page.screenshot(path="e2e/failure.png")
|
||
finally:
|
||
browser.close()
|
||
|
||
if failures:
|
||
print(f"✗ {failures[0]}")
|
||
if console_errors:
|
||
print(f" 控制台错误(最近 3 条):{console_errors[-3:]}")
|
||
return 1
|
||
|
||
print("✓ 计提参数管理端到端:7 步全部通过(目录/待提交/提交/生效/版本/恢复/预览金标准)")
|
||
if console_errors:
|
||
print(f" (控制台非致命消息 {len(console_errors)} 条,见上方日志)")
|
||
return 0
|
||
|
||
|
||
if __name__ == "__main__":
|
||
raise SystemExit(main())
|