Files
FTC25009/scripts/verify_dense_cargo_space_plan.py

141 lines
6.2 KiB
Python

import os
from pathlib import Path
from urllib.parse import urlparse
from playwright.sync_api import sync_playwright
FRONTEND_URL = "http://localhost"
BACKEND_URL = os.environ.get("DENSE_PLAN_BACKEND_URL", "http://127.0.0.1:8080")
TEST_USERNAME = os.environ.get("DENSE_PLAN_USERNAME")
TEST_PASSWORD = os.environ.get("DENSE_PLAN_PASSWORD")
SCREENSHOT_PATH = Path(
os.environ.get(
"DENSE_PLAN_SCREENSHOT",
r"C:\Users\13623\.codex\visualizations\2026\07\14\019f5e36-a2f0-7751-86cc-3d8ac317f956\dense-cargo-space-plan.png",
)
)
if not TEST_USERNAME or not TEST_PASSWORD:
raise RuntimeError("请通过 DENSE_PLAN_USERNAME 和 DENSE_PLAN_PASSWORD 提供测试账号")
def choose_warehouse(page, warehouse_name):
warehouse_field = page.locator(".el-form-item").filter(has_text="仓库").first
warehouse_field.locator(".el-select").click()
page.locator(".el-select-dropdown:visible .el-select-dropdown__item").filter(
has_text=warehouse_name
).click()
def assert_no_internal_overflow(page):
for selector in (".dense-map__viewport", ".dense-grid"):
metrics = page.locator(selector).evaluate(
"node => ({ scrollWidth: node.scrollWidth, clientWidth: node.clientWidth, "
"scrollHeight: node.scrollHeight, clientHeight: node.clientHeight })"
)
assert metrics["scrollWidth"] <= metrics["clientWidth"] + 1, (selector, metrics)
assert metrics["scrollHeight"] <= metrics["clientHeight"] + 1, (selector, metrics)
with sync_playwright() as playwright:
browser = playwright.chromium.launch(
headless=True,
executable_path=r"C:\Program Files\Google\Chrome\Application\chrome.exe",
)
context = browser.new_context(viewport={"width": 1500, "height": 1050})
page = context.new_page()
console_errors = []
page.on("console", lambda message: console_errors.append(message.text) if message.type == "error" else None)
login_response = page.request.post(
f"{BACKEND_URL}/login",
data={"username": TEST_USERNAME, "password": TEST_PASSWORD, "code": "", "uuid": ""},
)
login_data = login_response.json()
assert login_data.get("code") == 200, login_data
token = login_data["token"]
context.add_cookies(
[{"name": "Admin-Token", "value": token, "url": FRONTEND_URL}]
)
def route_backend(route):
request = route.request
parsed = urlparse(request.url)
backend_path = parsed.path.removeprefix("/dev-api")
target_url = f"{BACKEND_URL}{backend_path}"
if parsed.query:
target_url += f"?{parsed.query}"
response = page.request.fetch(
target_url,
method=request.method,
headers=request.headers,
data=request.post_data,
)
route.fulfill(response=response)
page.route("**/dev-api/**", route_backend)
page.goto(f"{FRONTEND_URL}/kpi/planKpi")
page.wait_for_load_state("networkidle")
choose_warehouse(page, "密集库")
dense_map = page.get_by_test_id("dense-cargo-space-map")
dense_map.wait_for(state="visible")
page.wait_for_function(
"document.querySelectorAll('[data-testid=dense-location]').length === 259"
)
floor_one_count = page.get_by_test_id("dense-location").count()
mother_count = page.locator('[data-testid="dense-location"][data-status="9"]').count()
lift_count = page.locator('[data-testid="dense-location"][data-status="7"]').count()
conveyor_count = page.locator('[data-testid="dense-location"][data-status="8"]').count()
charging_count = page.locator('[data-testid="dense-location"][data-status="10"]').count()
assert (floor_one_count, mother_count, lift_count, conveyor_count, charging_count) == (259, 49, 2, 2, 1)
assert page.get_by_text("充电桩", exact=True).count() >= 1
assert page.locator(".axis-label--column").count() == 24
assert page.locator(".axis-label--column", has_text="25").count() == 0
assert page.locator(".search-box").get_by_test_id("floor-switch").count() == 1
assert page.locator(".search-box").get_by_test_id("dense-refresh").count() == 1
assert page.get_by_text("密集库模式:按层展示完整平面坐标", exact=True).count() == 0
assert page.get_by_text("密集库货位平面图", exact=True).count() == 0
assert_no_internal_overflow(page)
assert page.locator('[data-testid="dense-location"][data-platoon="7"][data-column="13"]').count() == 1
assert page.locator('[data-testid="dense-location"][data-platoon="1"][data-column="13"]').count() == 1
assert page.locator('[data-testid="dense-location"][data-platoon="13"][data-column="13"]').count() == 1
page.locator('[data-testid="dense-location"][data-platoon="1"][data-column="1"]').click()
assert page.get_by_text("货区 A", exact=True).count() == 1
assert page.get_by_text("区域 Z01", exact=True).count() == 0
page.get_by_test_id("floor-switch").get_by_text("2层", exact=True).click()
page.wait_for_function(
"Array.from(document.querySelectorAll('[data-testid=dense-location]')).every(node => node.textContent.trim().endsWith('02'))"
)
floor_two_count = page.get_by_test_id("dense-location").count()
assert floor_two_count == 259
assert page.locator('[data-testid="dense-location"][data-status="10"]').count() == 1
page.set_viewport_size({"width": 1280, "height": 800})
page.wait_for_timeout(300)
assert_no_internal_overflow(page)
SCREENSHOT_PATH.parent.mkdir(parents=True, exist_ok=True)
dense_map.screenshot(path=str(SCREENSHOT_PATH))
choose_warehouse(page, "托盘库1")
page.locator(".chart-container--normal").wait_for(state="visible")
page.locator(".chart-container--normal canvas").first.wait_for(state="visible")
assert page.get_by_test_id("dense-cargo-space-map").count() == 0
relevant_errors = [
error for error in console_errors
if "favicon" not in error.lower() and "sockjs" not in error.lower()
]
assert not relevant_errors, relevant_errors
print(
"dense-plan-ok "
f"floor1={floor_one_count} floor2={floor_two_count} "
f"mother={mother_count} lift={lift_count} conveyor={conveyor_count} charging={charging_count} "
"legacy-chart=visible console-errors=0"
)
browser.close()