Commit 57cf814d authored by wenwen.tang's avatar wenwen.tang 😕

test(ui): ui_verify1-7 加 RENTOS_BASE 闸门并适配账期折叠,新增 ui_verify11

parent 9326844a
...@@ -4,9 +4,9 @@ ...@@ -4,9 +4,9 @@
==================================== ====================================
台账(房租车位费)→ 改单元格 → 增行 → 删行 → 搜索 → 电费手工录入 → 还原现场。 台账(房租车位费)→ 改单元格 → 增行 → 删行 → 搜索 → 电费手工录入 → 还原现场。
运行: 运行(该脚本会写数据,默认目标 8899 是【真实台账】,必须走沙箱):
python tools/ui_verify.py python tools/ui_verify_runner.py tools/ui_verify.py
RENTOS_BASE=http://127.0.0.1:8901 python tools/ui_verify.py RENTOS_ALLOW_REAL=1 python tools/ui_verify.py # 确需直连真实服务才这样用
覆盖的改造点: 覆盖的改造点:
* 只有一张台账「房租车位费」(旧的两张已退休) * 只有一张台账「房租车位费」(旧的两张已退休)
...@@ -21,7 +21,18 @@ warnings.filterwarnings("ignore") ...@@ -21,7 +21,18 @@ warnings.filterwarnings("ignore")
from playwright.sync_api import sync_playwright from playwright.sync_api import sync_playwright
BASE = os.environ.get("RENTOS_BASE", "http://127.0.0.1:8899") BASE = os.environ.get("RENTOS_BASE", "")
if not BASE:
# 该脚本会写数据;未注入 RENTOS_BASE 时默认目标 8899 是【真实台账】,
# 直连会污染权威数据(2026-10-13 曾误写入 17 个测试批次)。
# 正常路径:tools/ui_verify_runner.py(沙箱 + 注入 RENTOS_BASE)。
if os.environ.get("RENTOS_ALLOW_REAL") == "1":
BASE = "http://127.0.0.1:8899"
else:
_me = os.path.basename(__file__)
sys.exit("已阻止:%s 未设置 RENTOS_BASE(默认 8899 是【真实台账】)。\n"
" 沙箱运行: python tools/ui_verify_runner.py tools/%s\n"
" 确需打真实服务:RENTOS_ALLOW_REAL=1 python tools/%s" % (_me, _me, _me))
OUT = os.path.join(os.path.dirname(os.path.abspath(__file__)), "shots") OUT = os.path.join(os.path.dirname(os.path.abspath(__file__)), "shots")
os.makedirs(OUT, exist_ok=True) os.makedirs(OUT, exist_ok=True)
......
This diff is collapsed.
...@@ -2,19 +2,31 @@ ...@@ -2,19 +2,31 @@
""" """
界面验证:两张账单发送计划 / 免租期 / 台账锁定与二次确认 / 撤销 / 无「序号」列 界面验证:两张账单发送计划 / 免租期 / 台账锁定与二次确认 / 撤销 / 无「序号」列
运行: 运行(该脚本会写数据,默认目标 8899 是【真实台账】,必须走沙箱):
python tools/ui_verify2.py python tools/ui_verify_runner.py tools/ui_verify2.py
RENTOS_BASE=http://127.0.0.1:8901 python tools/ui_verify2.py RENTOS_ALLOW_REAL=1 python tools/ui_verify2.py # 确需直连真实服务才这样用
""" """
import json import json
import os import os
import re
import sys import sys
import warnings import warnings
warnings.filterwarnings("ignore") warnings.filterwarnings("ignore")
from playwright.sync_api import sync_playwright # noqa: E402 from playwright.sync_api import sync_playwright # noqa: E402
BASE = os.environ.get("RENTOS_BASE", "http://127.0.0.1:8899") BASE = os.environ.get("RENTOS_BASE", "")
if not BASE:
# 该脚本会写数据;未注入 RENTOS_BASE 时默认目标 8899 是【真实台账】,
# 直连会污染权威数据(2026-10-13 曾误写入 17 个测试批次)。
# 正常路径:tools/ui_verify_runner.py(沙箱 + 注入 RENTOS_BASE)。
if os.environ.get("RENTOS_ALLOW_REAL") == "1":
BASE = "http://127.0.0.1:8899"
else:
_me = os.path.basename(__file__)
sys.exit("已阻止:%s 未设置 RENTOS_BASE(默认 8899 是【真实台账】)。\n"
" 沙箱运行: python tools/ui_verify_runner.py tools/%s\n"
" 确需打真实服务:RENTOS_ALLOW_REAL=1 python tools/%s" % (_me, _me, _me))
OUT = os.path.join(os.path.dirname(os.path.abspath(__file__)), "shots2") OUT = os.path.join(os.path.dirname(os.path.abspath(__file__)), "shots2")
os.makedirs(OUT, exist_ok=True) os.makedirs(OUT, exist_ok=True)
...@@ -49,13 +61,14 @@ def main(): ...@@ -49,13 +61,14 @@ def main():
page.wait_for_url("**/admin.html") page.wait_for_url("**/admin.html")
page.wait_for_timeout(1200) page.wait_for_timeout(1200)
# ============================================ 1. 设置页:两张账单 # ============================================ 1. 设置页:只剩房租车位费
print("\n== 1. 设置页:两张账单发送计划 ==") print("\n== 1. 设置页:只配置「房租车位费」(电费已删) ==")
page.goto(f"{BASE}/admin.html#/settings") page.goto(f"{BASE}/admin.html#/settings")
page.wait_for_selector("#planRows tr[data-plan]", timeout=20000) page.wait_for_selector("#planRows tr[data-plan]", timeout=20000)
page.wait_for_timeout(800) page.wait_for_timeout(800)
rows = page.eval_on_selector_all("#planRows tr[data-plan]", "els=>els.map(e=>e.dataset.plan)") rows = page.eval_on_selector_all("#planRows tr[data-plan]", "els=>els.map(e=>e.dataset.plan)")
ck("两张账单计划各一行", rows == ["elec", "rent_parking"], str(rows)) ck("电费通知单已从定时发送设置里删掉,只剩房租车位费",
rows == ["rent_parking"], str(rows))
ck("退休的旧账单键已消失", ck("退休的旧账单键已消失",
"rent_summary_367" not in rows and "rent_contract_8f11f" not in rows, str(rows)) "rent_summary_367" not in rows and "rent_contract_8f11f" not in rows, str(rows))
for k in rows: for k in rows:
...@@ -71,24 +84,30 @@ def main(): ...@@ -71,24 +84,30 @@ def main():
ck(f"{k} 四个控件齐全", got["en"] and got["adv"] and got["tm"] and got["rf"], ck(f"{k} 四个控件齐全", got["en"] and got["adv"] and got["tm"] and got["rf"],
json.dumps(got, ensure_ascii=False)) json.dumps(got, ensure_ascii=False))
names = page.eval_on_selector_all("#planRows .bill-name", "e=>e.map(x=>x.innerText)") names = page.eval_on_selector_all("#planRows .bill-name", "e=>e.map(x=>x.innerText)")
ck("账单名称 = 电费 / 房租车位费", ck("账单名称只剩「房租车位费收费通知书」",
names == ["电费收费通知书", "房租车位费收费通知书"], str(names)) names == ["房租车位费收费通知书"], str(names))
ck("页面不再出现「三张账单」", ck("页面不再出现「三张账单」",
"三张账单" not in page.eval_on_selector("#page-settings", "e=>e.innerText")) "三张账单" not in page.eval_on_selector("#page-settings", "e=>e.innerText"))
ck("设置页不再重复展示「出租方 · 汇款公司」",
"汇款公司" not in page.eval_on_selector("#page-settings", "e=>e.innerText"))
page.screenshot(path=os.path.join(OUT, "S1-plans.png"), full_page=True) page.screenshot(path=os.path.join(OUT, "S1-plans.png"), full_page=True)
print("\n== 2. 免租期卡片 ==") print("\n== 2. 免租期卡片 ==")
rf = page.eval_on_selector("#rentfreeBox", "e=>e.innerText") rf = page.eval_on_selector("#rentfreeBox", "e=>e.innerText")
ck("免租期卡片列出两种免租类型", "首N月免租" in rf and "每年8-9月免租" in rf) ck("免租期卡片列出两种免租类型", "首N月免租" in rf and "每年8-9月免租" in rf)
ck("免租期列出 3 段(315室 / 302室 / 303室)", "共 3 段" in rf, rf.split("\n")[0][:80]) # 段数跟着台账走(不写死):801/802 登记「每年8-9月免租」后会按年展开
ck("免租期卡片给出「共 N 段」汇总",
re.search(r"共 \d+ 段", rf) is not None, rf.split("\n")[0][:80])
ck("免租期卡片列出真实台账里的免租房间",
all(u in rf for u in ("315室", "302室", "303室")), rf[:120])
ck("免租期表格有 302室", "302室" in rf and "2026-08-16" in rf) ck("免租期表格有 302室", "302室" in rf and "2026-08-16" in rf)
ck("免租期来源标注为房租车位费台账", "房租车位费" in rf or "台账" in rf) ck("免租期来源标注为房租车位费台账", "房租车位费" in rf or "台账" in rf)
page.screenshot(path=os.path.join(OUT, "S2-rentfree.png"), full_page=True) page.screenshot(path=os.path.join(OUT, "S2-rentfree.png"), full_page=True)
# 记下初始计划,最后原样还原(脚本不该改变现场配置) # 记下初始计划,最后原样还原(脚本不该改变现场配置)
adv = '#planRows tr[data-plan="elec"] input[data-f="advance_days"]' adv = '#planRows tr[data-plan="rent_parking"] input[data-f="advance_days"]'
tm = '#planRows tr[data-plan="elec"] input[data-f="send_time"]' tm = '#planRows tr[data-plan="rent_parking"] input[data-f="send_time"]'
en = '#planRows tr[data-plan="elec"] input[data-f="enabled"]' en = '#planRows tr[data-plan="rent_parking"] input[data-f="enabled"]'
init = {"master": page.input_value("#st-enabled"), "adv": page.input_value(adv), init = {"master": page.input_value("#st-enabled"), "adv": page.input_value(adv),
"tm": page.input_value(tm), "en": page.is_checked(en)} "tm": page.input_value(tm), "en": page.is_checked(en)}
...@@ -128,10 +147,10 @@ def main(): ...@@ -128,10 +147,10 @@ def main():
ck("确认后提前天数=7 已落盘", page.input_value(adv) == "7", page.input_value(adv)) ck("确认后提前天数=7 已落盘", page.input_value(adv) == "7", page.input_value(adv))
ck("确认后发送时点=07:30 已落盘", page.input_value(tm) == "07:30", page.input_value(tm)) ck("确认后发送时点=07:30 已落盘", page.input_value(tm) == "07:30", page.input_value(tm))
st_txt = page.eval_on_selector( st_txt = page.eval_on_selector(
'#planRows tr[data-plan="elec"] .plan-state', "e=>e.innerText") '#planRows tr[data-plan="rent_parking"] .plan-state', "e=>e.innerText")
ck("状态列给出运行状态(排期说明 / 暂无通知书 / 未启用)", ck("状态列给出运行状态(排期说明 / 未启用 / 无待发)",
("缴费期限" in st_txt) or ("还没有可发送的通知书" in st_txt) or ("未启用" in st_txt), ("推送日" in st_txt) or ("待出单" in st_txt) or ("未启用" in st_txt)
st_txt.replace("\n", " | ")[:110]) or ("无待发" in st_txt), st_txt.replace("\n", " | ")[:110])
page.screenshot(path=os.path.join(OUT, "S4-saved.png"), full_page=True) page.screenshot(path=os.path.join(OUT, "S4-saved.png"), full_page=True)
print("\n== 4b. 关闭总开关时不再排期 ==") print("\n== 4b. 关闭总开关时不再排期 ==")
...@@ -143,10 +162,10 @@ def main(): ...@@ -143,10 +162,10 @@ def main():
page.reload(wait_until="networkidle") page.reload(wait_until="networkidle")
page.wait_for_selector("#planRows tr[data-plan]", timeout=20000) page.wait_for_selector("#planRows tr[data-plan]", timeout=20000)
page.wait_for_timeout(600) page.wait_for_timeout(600)
ck("总开关关闭 → 两张账单状态均为 off", ck("总开关关闭 → 计划状态为「总开关关闭」",
page.eval_on_selector_all("#planRows tr[data-plan] .plan-state .l1", page.eval_on_selector_all("#planRows tr[data-plan] .plan-state .l1",
"e=>e.map(x=>x.innerText)") "e=>e.map(x=>x.innerText)")
== ["总开关关闭", "总开关关闭"], == ["总开关关闭"],
str(page.eval_on_selector_all("#planRows tr[data-plan] .plan-state .l1", str(page.eval_on_selector_all("#planRows tr[data-plan] .plan-state .l1",
"e=>e.map(x=>x.innerText)"))) "e=>e.map(x=>x.innerText)")))
......
...@@ -10,9 +10,9 @@ ...@@ -10,9 +10,9 @@
5. 「房租车位费」台账:8F/11F 付款周期 = 3 个月 5. 「房租车位费」台账:8F/11F 付款周期 = 3 个月
6. 全程页面无 JS 报错 6. 全程页面无 JS 报错
运行: 运行(该脚本会写数据,默认目标 8899 是【真实台账】,必须走沙箱):
python tools/ui_verify3.py # 默认 http://127.0.0.1:8899 python tools/ui_verify_runner.py tools/ui_verify3.py
RENTOS_BASE=http://127.0.0.1:8901 python tools/ui_verify3.py RENTOS_ALLOW_REAL=1 python tools/ui_verify3.py # 确需直连真实服务才这样用
""" """
import base64 import base64
import io import io
...@@ -24,7 +24,18 @@ sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding="utf-8") ...@@ -24,7 +24,18 @@ sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding="utf-8")
from playwright.sync_api import sync_playwright # noqa: E402 from playwright.sync_api import sync_playwright # noqa: E402
BASE = os.environ.get("RENTOS_BASE", "http://127.0.0.1:8899") BASE = os.environ.get("RENTOS_BASE", "")
if not BASE:
# 该脚本会写数据;未注入 RENTOS_BASE 时默认目标 8899 是【真实台账】,
# 直连会污染权威数据(2026-10-13 曾误写入 17 个测试批次)。
# 正常路径:tools/ui_verify_runner.py(沙箱 + 注入 RENTOS_BASE)。
if os.environ.get("RENTOS_ALLOW_REAL") == "1":
BASE = "http://127.0.0.1:8899"
else:
_me = os.path.basename(__file__)
sys.exit("已阻止:%s 未设置 RENTOS_BASE(默认 8899 是【真实台账】)。\n"
" 沙箱运行: python tools/ui_verify_runner.py tools/%s\n"
" 确需打真实服务:RENTOS_ALLOW_REAL=1 python tools/%s" % (_me, _me, _me))
USER, PWD = "admin", "1989@rent05" USER, PWD = "admin", "1989@rent05"
OUT = os.path.join(os.path.dirname(os.path.abspath(__file__)), "shots3") OUT = os.path.join(os.path.dirname(os.path.abspath(__file__)), "shots3")
PNG_B64 = ("iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8z8BQDwAEhQGA" PNG_B64 = ("iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8z8BQDwAEhQGA"
......
...@@ -6,14 +6,14 @@ ...@@ -6,14 +6,14 @@
1. 导航出现「公司管理」,深链 #/companies 可直达,共 5 项 1. 导航出现「公司管理」,深链 #/companies 可直达,共 5 项
2. 租客 / 往来单位名册:加载、类型标签、搜索过滤、录入、行内编辑改名、删除 2. 租客 / 往来单位名册:加载、类型标签、搜索过滤、录入、行内编辑改名、删除
3. 出租方 · 汇款公司:加载、引用单元数、录入、改名(提示会同步台账)、删除 3. 出租方 · 汇款公司:加载、引用单元数、录入、改名(提示会同步台账)、删除
4. 设置页不再有旧的「汇款公司」编辑卡片(只剩指引) 4. 设置页不再有旧的「汇款公司」编辑卡片,也不再重复展示(名单只在「公司管理」维护)
5. 选择场景接入:电费录入「单位名称 / 出租方」有候选并在填房间号时自动带出 5. 选择场景接入:电费录入「单位名称 / 出租方」有候选并在填房间号时自动带出
6. 台账「现租客」列编辑时挂上名册候选 6. 台账「现租客」列编辑时挂上名册候选
7. 全程页面无 JS 报错,且测试用完即清理(不留脏数据) 7. 全程页面无 JS 报错,且测试用完即清理(不留脏数据)
运行: 运行(该脚本会写数据,默认目标 8899 是【真实台账】,必须走沙箱):
python tools/ui_verify4.py # 默认 8899 python tools/ui_verify_runner.py tools/ui_verify4.py
RENTOS_BASE=http://127.0.0.1:8901 python tools/ui_verify4.py RENTOS_ALLOW_REAL=1 python tools/ui_verify4.py # 确需直连真实服务才这样用
""" """
import io import io
import os import os
...@@ -24,7 +24,18 @@ sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding="utf-8") ...@@ -24,7 +24,18 @@ sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding="utf-8")
from playwright.sync_api import sync_playwright # noqa: E402 from playwright.sync_api import sync_playwright # noqa: E402
BASE = os.environ.get("RENTOS_BASE", "http://127.0.0.1:8899") BASE = os.environ.get("RENTOS_BASE", "")
if not BASE:
# 该脚本会写数据;未注入 RENTOS_BASE 时默认目标 8899 是【真实台账】,
# 直连会污染权威数据(2026-10-13 曾误写入 17 个测试批次)。
# 正常路径:tools/ui_verify_runner.py(沙箱 + 注入 RENTOS_BASE)。
if os.environ.get("RENTOS_ALLOW_REAL") == "1":
BASE = "http://127.0.0.1:8899"
else:
_me = os.path.basename(__file__)
sys.exit("已阻止:%s 未设置 RENTOS_BASE(默认 8899 是【真实台账】)。\n"
" 沙箱运行: python tools/ui_verify_runner.py tools/%s\n"
" 确需打真实服务:RENTOS_ALLOW_REAL=1 python tools/%s" % (_me, _me, _me))
USER, PWD = "admin", "1989@rent05" USER, PWD = "admin", "1989@rent05"
OUT = os.path.join(os.path.dirname(os.path.abspath(__file__)), "shots4") OUT = os.path.join(os.path.dirname(os.path.abspath(__file__)), "shots4")
...@@ -278,7 +289,8 @@ def main(): ...@@ -278,7 +289,8 @@ def main():
ck("旧汇款公司编辑区已移除", ck("旧汇款公司编辑区已移除",
page.eval_on_selector_all("#ownersBox, #btn-save-owners, #btn-reset-owners", "e => e.length") == 0) page.eval_on_selector_all("#ownersBox, #btn-save-owners, #btn-reset-owners", "e => e.length") == 0)
txt = page.inner_text("#page-settings") txt = page.inner_text("#page-settings")
ck("留有指向公司管理的指引", "公司管理" in txt) ck("设置页不再重复展示「出租方 · 汇款公司」(已迁走,不留冗余指引)",
"汇款公司" not in txt, txt[:80].replace("\n", " "))
page.screenshot(path=os.path.join(OUT, "C4-settings.png"), full_page=True) page.screenshot(path=os.path.join(OUT, "C4-settings.png"), full_page=True)
# ============================================================ 5 # ============================================================ 5
......
...@@ -23,9 +23,9 @@ ...@@ -23,9 +23,9 @@
* 结束时逐格核对台账「账单起始日」与跑前一致,不一致就报 FAIL; * 结束时逐格核对台账「账单起始日」与跑前一致,不一致就报 FAIL;
* 本次生成的产物文件会被清理(批次 JSON 由删除步骤清掉)。 * 本次生成的产物文件会被清理(批次 JSON 由删除步骤清掉)。
运行: 运行(该脚本会写数据,默认目标 8899 是【真实台账】,必须走沙箱):
python tools/ui_verify5.py # 默认 8899 python tools/ui_verify_runner.py tools/ui_verify5.py
RENTOS_BASE=http://127.0.0.1:8901 python tools/ui_verify5.py RENTOS_ALLOW_REAL=1 python tools/ui_verify5.py # 确需直连真实服务才这样用
""" """
import io import io
import os import os
...@@ -37,7 +37,18 @@ sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding="utf-8") ...@@ -37,7 +37,18 @@ sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding="utf-8")
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
from playwright.sync_api import sync_playwright # noqa: E402 from playwright.sync_api import sync_playwright # noqa: E402
BASE = os.environ.get("RENTOS_BASE", "http://127.0.0.1:8899") BASE = os.environ.get("RENTOS_BASE", "")
if not BASE:
# 该脚本会写数据;未注入 RENTOS_BASE 时默认目标 8899 是【真实台账】,
# 直连会污染权威数据(2026-10-13 曾误写入 17 个测试批次)。
# 正常路径:tools/ui_verify_runner.py(沙箱 + 注入 RENTOS_BASE)。
if os.environ.get("RENTOS_ALLOW_REAL") == "1":
BASE = "http://127.0.0.1:8899"
else:
_me = os.path.basename(__file__)
sys.exit("已阻止:%s 未设置 RENTOS_BASE(默认 8899 是【真实台账】)。\n"
" 沙箱运行: python tools/ui_verify_runner.py tools/%s\n"
" 确需打真实服务:RENTOS_ALLOW_REAL=1 python tools/%s" % (_me, _me, _me))
OUT = os.environ.get("RENTOS_SHOTS", os.path.join(os.path.dirname(os.path.abspath(__file__)), OUT = os.environ.get("RENTOS_SHOTS", os.path.join(os.path.dirname(os.path.abspath(__file__)),
"..", "output", "ui_shots")) "..", "output", "ui_shots"))
USER, PWD = "admin", "1989@rent05" USER, PWD = "admin", "1989@rent05"
...@@ -275,14 +286,21 @@ def main(): ...@@ -275,14 +286,21 @@ def main():
# ============================================ 7. 批次台账 / 类别隔离 # ============================================ 7. 批次台账 / 类别隔离
print("\n7. 批次台账 · 类别隔离") print("\n7. 批次台账 · 类别隔离")
kinds = p.eval_on_selector_all("#rpBatchList tbody tr td:first-child", # 批次行默认按账期折叠;只展开仍折叠的分组(hash 导航不刷新页面,状态会延续)
js("""() => { document.querySelectorAll('#rpBatchList tbody.pgrp.collapsed tr.grp')
.forEach(tr => tr.click()); }""")
p.wait_for_timeout(500)
kinds = p.eval_on_selector_all("#rpBatchList tbody tr.prow td:first-child",
"e=>e.map(x=>x.innerText.trim())") "e=>e.map(x=>x.innerText.trim())")
ck("房租批次表的「账单」列标出「房租车位费」", ck("房租批次表的「账单」列标出「房租车位费」",
kinds and all(k == "房租车位费" for k in kinds), str(kinds[:3])) kinds and all(k == "房租车位费" for k in kinds), str(kinds[:3]))
p.goto(BASE + "/admin.html#/elec") p.goto(BASE + "/admin.html#/elec")
p.wait_for_selector("#eGrid", timeout=15000) p.wait_for_selector("#eGrid", timeout=15000)
p.wait_for_timeout(1800) p.wait_for_timeout(1800)
elec_ids = p.eval_on_selector_all("#batchList tbody tr td:nth-child(2)", js("""() => { document.querySelectorAll('#batchList tbody.pgrp.collapsed tr.grp')
.forEach(tr => tr.click()); }""")
p.wait_for_timeout(400)
elec_ids = p.eval_on_selector_all("#batchList tbody tr.prow td:nth-child(2)",
"e=>e.map(x=>x.innerText.trim())") "e=>e.map(x=>x.innerText.trim())")
ck("电费页的批次列表不含刚生成的房租批次", ck("电费页的批次列表不含刚生成的房租批次",
(created_batch or "x") not in elec_ids, str(elec_ids)) (created_batch or "x") not in elec_ids, str(elec_ids))
...@@ -292,6 +310,9 @@ def main(): ...@@ -292,6 +310,9 @@ def main():
p.goto(BASE + "/admin.html#/table/rent_parking") p.goto(BASE + "/admin.html#/table/rent_parking")
p.wait_for_selector("#rpWrap table", timeout=20000) p.wait_for_selector("#rpWrap table", timeout=20000)
p.wait_for_timeout(1200) p.wait_for_timeout(1200)
js("""() => { document.querySelectorAll('#rpBatchList tbody.pgrp.collapsed tr.grp')
.forEach(tr => tr.click()); }""")
p.wait_for_timeout(400)
if created_batch: if created_batch:
p.click('#rpBatchList button[data-open="%s"]' % created_batch) p.click('#rpBatchList button[data-open="%s"]' % created_batch)
p.wait_for_timeout(1500) p.wait_for_timeout(1500)
......
...@@ -15,7 +15,7 @@ ...@@ -15,7 +15,7 @@
* 只出 1 行单,跑完**必定删除该批次并回滚账期**(try/finally 兜底); * 只出 1 行单,跑完**必定删除该批次并回滚账期**(try/finally 兜底);
* 结束时核对台账 AC/AJ 与跑前一致。 * 结束时核对台账 AC/AJ 与跑前一致。
运行:python tools/ui_verify6.py (需先起服务) 运行:python tools/ui_verify_runner.py tools/ui_verify6.py (该脚本会写数据,沙箱隔离)
""" """
import io import io
import os import os
...@@ -25,7 +25,18 @@ sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding="utf-8") ...@@ -25,7 +25,18 @@ sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding="utf-8")
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
from playwright.sync_api import sync_playwright # noqa: E402 from playwright.sync_api import sync_playwright # noqa: E402
BASE = os.environ.get("RENTOS_BASE", "http://127.0.0.1:8899") BASE = os.environ.get("RENTOS_BASE", "")
if not BASE:
# 该脚本会写数据;未注入 RENTOS_BASE 时默认目标 8899 是【真实台账】,
# 直连会污染权威数据(2026-10-13 曾误写入 17 个测试批次)。
# 正常路径:tools/ui_verify_runner.py(沙箱 + 注入 RENTOS_BASE)。
if os.environ.get("RENTOS_ALLOW_REAL") == "1":
BASE = "http://127.0.0.1:8899"
else:
_me = os.path.basename(__file__)
sys.exit("已阻止:%s 未设置 RENTOS_BASE(默认 8899 是【真实台账】)。\n"
" 沙箱运行: python tools/ui_verify_runner.py tools/%s\n"
" 确需打真实服务:RENTOS_ALLOW_REAL=1 python tools/%s" % (_me, _me, _me))
OUT = os.environ.get("RENTOS_SHOTS", os.path.join(os.path.dirname(os.path.abspath(__file__)), OUT = os.environ.get("RENTOS_SHOTS", os.path.join(os.path.dirname(os.path.abspath(__file__)),
"..", "output", "ui_shots")) "..", "output", "ui_shots"))
USER, PWD = "admin", "1989@rent05" USER, PWD = "admin", "1989@rent05"
......
...@@ -247,6 +247,10 @@ def main(): ...@@ -247,6 +247,10 @@ def main():
_st, _bl = api_call("GET", "/api/batches?kind=elec") _st, _bl = api_call("GET", "/api/batches?kind=elec")
_elec = (_bl.get("batches") or []) _elec = (_bl.get("batches") or [])
if _elec: if _elec:
# 批次行默认按账期折叠;只展开仍折叠的分组
js("""() => { document.querySelectorAll('#batchList tbody.pgrp.collapsed tr.grp')
.forEach(tr => tr.click()); }""")
p.wait_for_timeout(500)
ck("guest 看得到电费批次的「删除」按钮", ck("guest 看得到电费批次的「删除」按钮",
p.eval_on_selector_all("#batchList tbody tr button[data-del]", p.eval_on_selector_all("#batchList tbody tr button[data-del]",
"es=>es.length>0 && es.every(b=>b.offsetParent!==null)")) "es=>es.length>0 && es.every(b=>b.offsetParent!==null)"))
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment