fix: 适配 hash 路由登录页 (/#/login)

This commit is contained in:
xst
2026-07-15 10:55:08 +08:00
parent 7c5a4c5de7
commit 49eb9bcd2b
5 changed files with 34 additions and 26 deletions
+7 -8
View File
@@ -116,7 +116,9 @@ def ensure_login(web_config, page, config):
if auth_role == role:
# 验证登录态是否仍然有效
page.goto(base_url)
if "/login" not in page.url:
# Hash 路由模式下判断是否重定向到登录页
page.wait_for_timeout(2000) # 等 hash 路由完成
if "/#/login" not in page.url and "/login" not in page.url:
return # 登录态有效
# 登录态过期,给出明确指引
raise RuntimeError(
@@ -137,22 +139,19 @@ def ensure_login(web_config, page, config):
)
# ── skip_login: false,执行 UI 登录(可能有验证码,会失败) ──
page.goto(f"{base_url}/login")
page.goto(f"{base_url}/#/login")
page.get_by_placeholder("请输入用户名").fill(account["phone"])
page.get_by_placeholder("请输入密码").fill(account["password"])
page.get_by_role("button", name="登录").click()
# 如果有图形验证码,这里会超时
try:
page.wait_for_url(f"{base_url}/**", timeout=10_000)
except Exception:
# 等几秒让页面处理路由跳转
page.wait_for_timeout(3000)
if "/#/login" in page.url or "/login" in page.url:
raise RuntimeError(
"登录失败!可能存在图形验证码。\n"
"请改为手动登录生成 auth 文件: python tests/web/save_auth.py --role {role}"
)
return _ensure_login
def _load_auth_state(context_kwargs: dict, storage_dir: Path, browser: str) -> str | None:
"""尝试加载登录态,返回角色名或 None。"""
+1 -1
View File
@@ -46,7 +46,7 @@ class NavBar(BasePage):
def logout(self) -> None:
"""退出登录。"""
self.click_when_ready(self.logout_btn)
expect(self.page).to_have_url("**/login**", timeout=10_000)
expect(self.page).to_have_url("#/login", timeout=10_000)
def is_expanded(self) -> bool:
"""检查侧边栏是否展开。"""
+6 -4
View File
@@ -36,8 +36,10 @@ class LoginPage(BasePage):
self.click_when_ready(self.login_btn)
if expect_success:
# 等待登录成功后页面跳转
self.page.wait_for_url("**/admin/**", timeout=10_000)
# 等待登录成功后页面跳转hash 路由模式)
self.page.wait_for_timeout(3000)
assert "/#/login" not in self.page.url and "/login" not in self.page.url, \
"登录失败,仍在登录页"
else:
# 预期登录失败,停留在当前页
expect(self.page).to_have_url("**/login**", timeout=5_000)
@@ -48,5 +50,5 @@ class LoginPage(BasePage):
return self.error_tip.inner_text()
def is_on_login_page(self) -> bool:
"""检查是否仍在登录页。"""
return "/login" in self.page.url
"""检查是否仍在登录页(兼容 hash 路由)"""
return "/login" in self.page.url or "/#/login" in self.page.url
+4 -3
View File
@@ -71,7 +71,7 @@ def main():
sys.exit(1)
base_url = web_config["base_url"]
login_url = f"{base_url}/login"
login_url = f"{base_url}/#/login"
# ── 打开浏览器 ──
from playwright.sync_api import sync_playwright
@@ -98,7 +98,8 @@ def main():
# ── 等待用户手动完成验证码 + 登录 ──
try:
page.wait_for_url(f"{base_url}/**", timeout=300_000) # 5 分钟超时
# Hash 路由模式,用元素可见判断登录成功而不是 URL 变化
page.wait_for_selector(".ant-layout-sider, .sidebar, [class*='sider']", timeout=300_000)
except Exception:
print("\n⚠️ 等待超时(5 分钟)。可能原因:")
print(" 1. 未在浏览器中完成验证码登录")
@@ -109,7 +110,7 @@ def main():
sys.exit(1)
# ── 验证登录成功 ──
if "/login" in page.url:
if "/login" in page.url or "/#/login" in page.url:
print("\n❌ 登录失败,仍然停留在登录页。请检查账号密码。")
browser.close()
sys.exit(1)
+16 -10
View File
@@ -29,8 +29,10 @@ class TestLoginSmoke:
"""验证加载预登录态后可直接访问管理后台,无需重新登录。"""
ensure_login("super_admin")
page.goto(web_config["base_url"])
# 等 hash 路由完成
page.wait_for_timeout(2000)
# 已登录状态下不应重定向到登录页
assert "/login" not in page.url, (
assert "#/login" not in page.url and "/login" not in page.url, (
f"预登录态失效!仍然重定向到登录页。请运行: python tests/web/save_auth.py"
)
@@ -40,7 +42,8 @@ class TestLoginSmoke:
"""验证车队长预登录态有效。"""
ensure_login("team_leader")
page.goto(web_config["base_url"])
assert "/login" not in page.url
page.wait_for_timeout(2000)
assert "#/login" not in page.url and "/login" not in page.url
@pytest.mark.p0
@pytest.mark.smoke
@@ -62,29 +65,31 @@ class TestLoginPageDirect:
@pytest.mark.p1
def test_login_page_accessible(self, page: Page, web_config):
"""验证登录页可直接访问并正常渲染。"""
page.goto(f"{web_config['base_url']}/login")
page.goto(f"{web_config['base_url']}/#/login")
# 登录页应存在用户名输入框
assert page.get_by_placeholder("请输入用户名").is_visible()
@pytest.mark.p1
def test_login_page_elements(self, page: Page, web_config):
"""验证登录页所有关键元素存在。"""
page.goto(f"{web_config['base_url']}/login")
page.goto(f"{web_config['base_url']}/#/login")
assert page.get_by_placeholder("请输入用户名").is_visible()
assert page.get_by_placeholder("请输入密码").is_visible()
assert page.get_by_role("button", name="登录").is_visible()
@pytest.mark.p1
def test_double_login_session_redirect(self, page: Page, web_config, ensure_login):
"""验证已登录用户访问 /login 页自动重定向。"""
"""验证已登录用户访问登录页自动重定向。"""
ensure_login("super_admin")
page.goto(web_config["base_url"])
assert "/login" not in page.url
page.wait_for_timeout(2000)
assert "#/login" not in page.url and "/login" not in page.url
# 已登录状态再次访问 /login
page.goto(f"{web_config['base_url']}/login")
# 已登录状态再次访问登录页
page.goto(f"{web_config['base_url']}/#/login")
page.wait_for_timeout(2000)
# 应被重定向到后台
assert "/login" not in page.url, (
assert "#/login" not in page.url and "/login" not in page.url, (
f"已登录用户访问 /login 应被重定向,当前: {page.url}"
)
@@ -102,4 +107,5 @@ class TestLoginUI:
"""通过 UI 完成完整登录(需要手动关闭 skip_login)。"""
ensure_login("super_admin")
page.goto(web_config["base_url"])
assert "/login" not in page.url
page.wait_for_timeout(2000)
assert "#/login" not in page.url and "/login" not in page.url