PayrollManagementSystem/frontend/e2e/param_management.py
liuwenxin 6219698a39 test(system): M1 参数体系集成用例、e2e 脚本与文档更新
- 集成用例 26 项:岗位角色(CRUD/内置保护/权限)+ 参数管理(目录回溯/变更生命周期/值校验/预览金标准)
- 361 天分界断言按 Fraction 数值比较(4/1000 自动约分为 1/250,值相等)
- e2e param_management.py:7 步全通过(含预览金标准 27 天/9.7‰/145.5 元)
- 结果卡补「计提比例」精确分数行(对账透明)
- 三份 README 更新:接口职责/AI 摘要/M1 用例清单与运行记录/e2e 记录

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-10-13 01:05:07 +08:00

142 lines
6.1 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""计提参数管理端到端测试(需要容器、后端、前端都在运行)。
覆盖链路(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:
login(page, "admin", __import__("os").environ.get("E2E_ADMIN_PASSWORD", "E2ePwd@2026"))
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="修改").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="修改").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())