138 lines
4.5 KiB
Python
138 lines
4.5 KiB
Python
#!/usr/bin/env python3
|
||
"""手动登录并保存浏览器登录态(cookies + localStorage)。
|
||
|
||
目的: 绕过图形验证码——人工完成一次验证码登录后,
|
||
cookies + localStorage 序列化到 JSON 文件,后续用例自动复用。
|
||
|
||
用法:
|
||
# 保存超级管理员的登录态(最常用)
|
||
python tests/web/save_auth.py
|
||
|
||
# 保存指定角色的登录态
|
||
python tests/web/save_auth.py --role team_leader
|
||
|
||
# 指定浏览器
|
||
python tests/web/save_auth.py --browser firefox
|
||
|
||
# 查看帮助
|
||
python tests/web/save_auth.py --help
|
||
|
||
生成的 auth 文件:
|
||
tests/web/auth/super_admin_chromium.json
|
||
tests/web/auth/team_leader_firefox.json
|
||
...
|
||
"""
|
||
|
||
import argparse
|
||
import sys
|
||
from pathlib import Path
|
||
|
||
# 确保 tests/ 在 Python path 中
|
||
sys.path.insert(0, str(Path(__file__).parent.parent.parent))
|
||
|
||
from tests.config.test_config import load_config
|
||
|
||
|
||
# 登录页的 URL 后缀
|
||
LOGIN_PATH = "/login"
|
||
|
||
# 登录后验证成功的 URL 关键字
|
||
SUCCESS_URL_KEYWORD = "/admin"
|
||
|
||
|
||
def main():
|
||
parser = argparse.ArgumentParser(
|
||
description="手动登录并保存浏览器登录态(绕过图形验证码)"
|
||
)
|
||
parser.add_argument(
|
||
"--role",
|
||
default="super_admin",
|
||
choices=["super_admin", "team_leader", "driver"],
|
||
help="登录角色(默认: super_admin)",
|
||
)
|
||
parser.add_argument(
|
||
"--browser",
|
||
default="chromium",
|
||
choices=["chromium", "firefox", "webkit"],
|
||
help="浏览器类型(默认: chromium)",
|
||
)
|
||
parser.add_argument(
|
||
"--headless",
|
||
action="store_true",
|
||
help="无头模式(开启后将无法手动输入验证码,仅用于测试已保存的登录态)",
|
||
)
|
||
args = parser.parse_args()
|
||
|
||
config = load_config()
|
||
web_config = config["web"]
|
||
account = config["accounts"].get(args.role)
|
||
if not account:
|
||
print(f"❌ 未知角色 '{args.role}',可用: {list(config['accounts'].keys())}")
|
||
sys.exit(1)
|
||
|
||
base_url = web_config["base_url"]
|
||
login_url = f"{base_url}/#/login"
|
||
|
||
# ── 打开浏览器 ──
|
||
from playwright.sync_api import sync_playwright
|
||
|
||
with sync_playwright() as p:
|
||
browser_launcher = getattr(p, args.browser)
|
||
browser = browser_launcher.launch(headless=args.headless)
|
||
context = browser.new_context(
|
||
viewport={"width": 1920, "height": 1080},
|
||
locale="zh-CN",
|
||
)
|
||
page = context.new_page()
|
||
|
||
# ── 导航到登录页 ──
|
||
print(f"\n🔗 打开登录页: {login_url}")
|
||
page.goto(login_url)
|
||
|
||
# ── 填入账号密码 ──
|
||
page.get_by_placeholder("请输入用户名").fill(account["phone"])
|
||
page.get_by_placeholder("请输入密码").fill(account["password"])
|
||
print(f"👤 已填入账号: {account['phone']}(角色: {args.role})")
|
||
print("📝 请在浏览器中手动完成验证码并点击登录...")
|
||
print(" (登录成功后脚本会自动检测并保存)\n")
|
||
|
||
# ── 等待用户手动完成验证码 + 登录 ──
|
||
try:
|
||
# Hash 路由模式,用元素可见判断登录成功而不是 URL 变化
|
||
page.wait_for_selector(".ant-layout-sider, .sidebar, [class*='sider']", timeout=300_000)
|
||
except Exception:
|
||
print("\n⚠️ 等待超时(5 分钟)。可能原因:")
|
||
print(" 1. 未在浏览器中完成验证码登录")
|
||
print(" 2. 账号密码错误")
|
||
print(" 3. 网络不可达")
|
||
print(" 请检查后重试。")
|
||
browser.close()
|
||
sys.exit(1)
|
||
|
||
# ── 验证登录成功 ──
|
||
if "/login" in page.url or "/#/login" in page.url:
|
||
print("\n❌ 登录失败,仍然停留在登录页。请检查账号密码。")
|
||
browser.close()
|
||
sys.exit(1)
|
||
|
||
print(f"✅ 登录成功!当前页面: {page.url}")
|
||
|
||
# ── 保存登录态 ──
|
||
auth_dir = Path(web_config.get("storage_state_dir", "tests/web/auth"))
|
||
auth_dir.mkdir(parents=True, exist_ok=True)
|
||
auth_file = auth_dir / f"{args.role}_{args.browser}.json"
|
||
|
||
context.storage_state(path=str(auth_file))
|
||
print(f"💾 登录态已保存到: {auth_file}")
|
||
|
||
browser.close()
|
||
|
||
print("\n🎉 完成!现在可以运行用例了:")
|
||
print(f" pytest tests/web/ -m p0")
|
||
print(f"\n登录态过期后重新运行即可:")
|
||
print(f" python tests/web/save_auth.py --role {args.role}")
|
||
|
||
|
||
if __name__ == "__main__":
|
||
main()
|