fix: 修复多个关键问题
- 修复前端路由守卫:未登录时不显示提示,直接跳转登录页 - 修复API拦截器:401错误不显示提示,直接跳转 - 增强验证码显示:图片尺寸从120x40增加到200x80 - 增大验证码字体:从28号增加到48号 - 优化验证码字符:排除易混淆的0和1 - 减少干扰线:从5条减少到3条,添加背景色优化 - 增强登录API日志:添加详细的调试日志 - 增强验证码生成和验证日志 - 优化异常处理和错误追踪 影响文件: - src/router/index.ts - src/api/request.ts - app/services/auth_service.py - app/api/v1/auth.py - app/schemas/user.py 测试状态: - 前端构建通过 - 后端语法检查通过 - 验证码显示效果优化完成 Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
286
tests/conftest.py
Normal file
286
tests/conftest.py
Normal file
@@ -0,0 +1,286 @@
|
||||
"""
|
||||
测试配置和Fixtures
|
||||
"""
|
||||
import pytest
|
||||
from httpx import AsyncClient, ASGITransport
|
||||
from sqlalchemy.ext.asyncio import create_async_engine, AsyncSession, async_sessionmaker
|
||||
from sqlalchemy.pool import StaticPool
|
||||
from datetime import datetime
|
||||
from typing import AsyncGenerator
|
||||
|
||||
from app.main import app
|
||||
from app.db.base import Base
|
||||
from app.models.user import User, Role, UserRole, Permission
|
||||
from app.models.device_type import DeviceType, DeviceTypeField
|
||||
from app.core.security import get_password_hash, security_manager
|
||||
|
||||
|
||||
# 创建测试数据库引擎
|
||||
test_engine = create_async_engine(
|
||||
"sqlite+aiosqlite:///:memory:",
|
||||
connect_args={"check_same_thread": False},
|
||||
poolclass=StaticPool,
|
||||
)
|
||||
|
||||
# 创建测试会话工厂
|
||||
TestSessionLocal = async_sessionmaker(
|
||||
test_engine,
|
||||
class_=AsyncSession,
|
||||
expire_on_commit=False,
|
||||
autocommit=False,
|
||||
autoflush=False,
|
||||
)
|
||||
|
||||
|
||||
@pytest.fixture(scope="function")
|
||||
async def db_session():
|
||||
"""创建测试数据库会话"""
|
||||
async with test_engine.begin() as conn:
|
||||
await conn.run_sync(Base.metadata.create_all)
|
||||
|
||||
async with TestSessionLocal() as session:
|
||||
yield session
|
||||
await session.rollback()
|
||||
|
||||
async with test_engine.begin() as conn:
|
||||
await conn.run_sync(Base.metadata.drop_all)
|
||||
|
||||
|
||||
@pytest.fixture(scope="function")
|
||||
async def client(db_session):
|
||||
"""创建测试客户端"""
|
||||
from app.core.deps import get_db
|
||||
|
||||
async def override_get_db():
|
||||
yield db_session
|
||||
|
||||
app.dependency_overrides[get_db] = override_get_db
|
||||
|
||||
async with AsyncClient(
|
||||
transport=ASGITransport(app=app),
|
||||
base_url="http://test"
|
||||
) as ac:
|
||||
yield ac
|
||||
|
||||
app.dependency_overrides.clear()
|
||||
|
||||
|
||||
# ===== 用户相关Fixtures =====
|
||||
|
||||
@pytest.fixture
|
||||
async def test_password() -> str:
|
||||
"""测试密码"""
|
||||
return "Test123456"
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
async def test_user(db_session: AsyncSession, test_password: str) -> User:
|
||||
"""创建测试用户"""
|
||||
user = User(
|
||||
username="testuser",
|
||||
password_hash=get_password_hash(test_password),
|
||||
real_name="测试用户",
|
||||
email="test@example.com",
|
||||
phone="13800138000",
|
||||
status="active",
|
||||
is_admin=False
|
||||
)
|
||||
db_session.add(user)
|
||||
await db_session.flush()
|
||||
await db_session.refresh(user)
|
||||
return user
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
async def test_admin(db_session: AsyncSession, test_password: str) -> User:
|
||||
"""创建测试管理员"""
|
||||
admin = User(
|
||||
username="admin",
|
||||
password_hash=get_password_hash(test_password),
|
||||
real_name="系统管理员",
|
||||
email="admin@example.com",
|
||||
status="active",
|
||||
is_admin=True
|
||||
)
|
||||
db_session.add(admin)
|
||||
await db_session.flush()
|
||||
await db_session.refresh(admin)
|
||||
return admin
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
async def test_role(db_session: AsyncSession) -> Role:
|
||||
"""创建测试角色"""
|
||||
role = Role(
|
||||
role_name="测试角色",
|
||||
role_code="TEST_ROLE",
|
||||
description="用于测试的角色",
|
||||
status="active",
|
||||
sort_order=1
|
||||
)
|
||||
db_session.add(role)
|
||||
await db_session.flush()
|
||||
await db_session.refresh(role)
|
||||
return role
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
async def auth_headers(client: AsyncClient, test_user: User, test_password: str) -> dict:
|
||||
"""获取认证头"""
|
||||
# 登录获取token
|
||||
response = await client.post(
|
||||
"/api/v1/auth/login",
|
||||
json={
|
||||
"username": test_user.username,
|
||||
"password": test_password,
|
||||
"captcha": "1234",
|
||||
"captcha_key": "test-uuid"
|
||||
}
|
||||
)
|
||||
|
||||
if response.status_code == 200:
|
||||
token = response.json()["data"]["access_token"]
|
||||
return {"Authorization": f"Bearer {token}"}
|
||||
return {}
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
async def admin_headers(client: AsyncClient, test_admin: User, test_password: str) -> dict:
|
||||
"""获取管理员认证头"""
|
||||
response = await client.post(
|
||||
"/api/v1/auth/login",
|
||||
json={
|
||||
"username": test_admin.username,
|
||||
"password": test_password,
|
||||
"captcha": "1234",
|
||||
"captcha_key": "test-uuid"
|
||||
}
|
||||
)
|
||||
|
||||
if response.status_code == 200:
|
||||
token = response.json()["data"]["access_token"]
|
||||
return {"Authorization": f"Bearer {token}"}
|
||||
return {}
|
||||
|
||||
|
||||
# ===== 设备类型相关Fixtures =====
|
||||
|
||||
@pytest.fixture
|
||||
async def test_device_type(db_session: AsyncSession, test_admin: User) -> DeviceType:
|
||||
"""创建测试设备类型"""
|
||||
device_type = DeviceType(
|
||||
type_code="COMPUTER",
|
||||
type_name="计算机",
|
||||
category="IT设备",
|
||||
description="台式机、笔记本等",
|
||||
icon="computer",
|
||||
status="active",
|
||||
sort_order=1,
|
||||
created_by=test_admin.id
|
||||
)
|
||||
db_session.add(device_type)
|
||||
await db_session.flush()
|
||||
await db_session.refresh(device_type)
|
||||
return device_type
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
async def test_device_type_with_fields(
|
||||
db_session: AsyncSession,
|
||||
test_device_type: DeviceType,
|
||||
test_admin: User
|
||||
) -> DeviceType:
|
||||
"""创建带字段的测试设备类型"""
|
||||
fields = [
|
||||
DeviceTypeField(
|
||||
device_type_id=test_device_type.id,
|
||||
field_code="cpu",
|
||||
field_name="CPU型号",
|
||||
field_type="text",
|
||||
is_required=True,
|
||||
placeholder="例如: Intel i5-10400",
|
||||
validation_rules={"max_length": 100},
|
||||
sort_order=1,
|
||||
created_by=test_admin.id
|
||||
),
|
||||
DeviceTypeField(
|
||||
device_type_id=test_device_type.id,
|
||||
field_code="memory",
|
||||
field_name="内存容量",
|
||||
field_type="select",
|
||||
is_required=True,
|
||||
options=[
|
||||
{"label": "8GB", "value": "8"},
|
||||
{"label": "16GB", "value": "16"},
|
||||
{"label": "32GB", "value": "32"}
|
||||
],
|
||||
sort_order=2,
|
||||
created_by=test_admin.id
|
||||
),
|
||||
DeviceTypeField(
|
||||
device_type_id=test_device_type.id,
|
||||
field_code="disk",
|
||||
field_name="硬盘容量",
|
||||
field_type="text",
|
||||
is_required=False,
|
||||
placeholder="例如: 512GB SSD",
|
||||
sort_order=3,
|
||||
created_by=test_admin.id
|
||||
)
|
||||
]
|
||||
|
||||
for field in fields:
|
||||
db_session.add(field)
|
||||
|
||||
await db_session.flush()
|
||||
return test_device_type
|
||||
|
||||
|
||||
# ===== 辅助函数Fixtures =====
|
||||
|
||||
@pytest.fixture
|
||||
def sample_asset_data(test_device_type: DeviceType) -> dict:
|
||||
"""示例资产数据"""
|
||||
return {
|
||||
"asset_name": "测试资产",
|
||||
"device_type_id": test_device_type.id,
|
||||
"organization_id": 1,
|
||||
"model": "测试型号",
|
||||
"serial_number": f"SN{datetime.now().strftime('%Y%m%d%H%M%S')}",
|
||||
"purchase_date": "2024-01-15",
|
||||
"purchase_price": 5000.00,
|
||||
"warranty_period": 24,
|
||||
"location": "测试位置",
|
||||
"dynamic_attributes": {
|
||||
"cpu": "Intel i5-10400",
|
||||
"memory": "16",
|
||||
"disk": "512GB SSD"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def sample_device_type_data() -> dict:
|
||||
"""示例设备类型数据"""
|
||||
return {
|
||||
"type_code": "LAPTOP",
|
||||
"type_name": "笔记本电脑",
|
||||
"category": "IT设备",
|
||||
"description": "笔记本电脑类",
|
||||
"icon": "laptop",
|
||||
"sort_order": 1
|
||||
}
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def sample_field_data() -> dict:
|
||||
"""示例字段数据"""
|
||||
return {
|
||||
"field_code": "gpu",
|
||||
"field_name": "显卡型号",
|
||||
"field_type": "text",
|
||||
"is_required": False,
|
||||
"placeholder": "例如: GTX 1660Ti",
|
||||
"validation_rules": {"max_length": 100},
|
||||
"sort_order": 4
|
||||
}
|
||||
Reference in New Issue
Block a user