""" 用户生命周期UAT测试 - 模拟真实业务场景 """ import pytest import time from playwright.async_api import async_playwright, Page from httpx import AsyncClient from config.settings import settings @pytest.mark.uat @pytest.mark.user_lifecycle class TestUserLifecycleUAT: """用户生命周期UAT测试""" @pytest.fixture async def browser(self): """浏览器fixture""" async with async_playwright() as p: browser = await p.chromium.launch(headless=True) yield browser await browser.close() @pytest.fixture async def context(self, browser): """浏览器上下文fixture""" context = await browser.new_context() yield context await context.close() @pytest.fixture async def page(self, context): """页面fixture""" page = await context.new_page() page.set_default_timeout(30000) yield page await page.close() @pytest.fixture async def authenticated_client(self): """已认证的HTTP客户端""" async with AsyncClient(base_url=settings.API_BASE_URL) as client: response = await client.post( "/api/auth/login", json={ "username": settings.TEST_USERNAME, "password": settings.TEST_PASSWORD } ) assert response.status_code == 200 token = response.json().get("token") client.headers.update({"Authorization": f"Bearer {token}"}) yield client @pytest.mark.asyncio async def test_uat_user_registration_and_login(self, page, authenticated_client): """UAT: 用户注册和登录流程""" timestamp = int(time.time() * 1000) username = f"uat_user_{timestamp}" email = f"uat_{timestamp}@example.com" password = "Test123!@#" # 步骤1: 通过API创建用户 response = await authenticated_client.post( "/api/users", json={ "username": username, "password": password, "email": email, "phone": "13800138000", "status": 1 } ) assert response.status_code == 201, f"创建用户失败: {response.text}" user_id = response.json()["id"] try: # 步骤2: 通过前端登录 await page.goto("http://localhost:3002/login") await page.wait_for_load_state("networkidle") await page.fill('input[placeholder="请输入用户名"]', username) await page.fill('input[placeholder="请输入密码"]', password) await page.click('button[type="submit"]') await page.wait_for_url("**/") await page.wait_for_load_state("networkidle") # 步骤3: 验证登录成功 title = await page.title() assert "首页" in title or "Dashboard" in title, "登录后未跳转到首页" # 步骤4: 验证用户信息显示 user_info = await page.query_selector('.user-info') assert user_info is not None, "用户信息元素未找到" finally: # 清理 await authenticated_client.delete(f"/api/users/{user_id}") @pytest.mark.asyncio async def test_uat_user_profile_update(self, page, authenticated_client): """UAT: 用户资料更新流程""" timestamp = int(time.time() * 1000) username = f"uat_profile_{timestamp}" email = f"uat_profile_{timestamp}@example.com" # 步骤1: 创建测试用户 response = await authenticated_client.post( "/api/users", json={ "username": username, "password": "Test123!@#", "email": email, "phone": "13800138000", "status": 1 } ) assert response.status_code == 201 user_id = response.json()["id"] try: # 步骤2: 登录 await page.goto("http://localhost:3002/login") await page.fill('input[placeholder="请输入用户名"]', username) await page.fill('input[placeholder="请输入密码"]', "Test123!@#") await page.click('button[type="submit"]') await page.wait_for_url("**/") # 步骤3: 访问用户资料页面 await page.click('text=用户管理') await page.wait_for_url("**/users") # 步骤4: 编辑用户 await page.click('text=编辑') await page.wait_for_load_state("networkidle") # 步骤5: 更新资料 await page.fill('input[placeholder=""]', '测试用户昵称') await page.fill('input[placeholder=""]', '13900139000') await page.click('button:has-text("确定")') await page.wait_for_load_state("networkidle") # 步骤6: 验证更新 page_content = await page.content() assert "测试用户昵称" in page_content finally: await authenticated_client.delete(f"/api/users/{user_id}") @pytest.mark.asyncio async def test_uat_user_status_change(self, page, authenticated_client): """UAT: 用户状态变更流程""" timestamp = int(time.time() * 1000) username = f"uat_status_{timestamp}" # 创建用户 response = await authenticated_client.post( "/api/users", json={ "username": username, "password": "Test123!@#", "email": f"uat_status_{timestamp}@example.com", "status": 1 } ) assert response.status_code == 201 user_id = response.json()["id"] try: # 登录并禁用用户 await page.goto("http://localhost:3002/login") await page.fill('input[placeholder="请输入用户名"]', username) await page.fill('input[placeholder="请输入密码"]', "Test123!@#") await page.click('button[type="submit"]') await page.wait_for_url("**/") # 尝试禁用用户 await page.click('text=用户管理') await page.wait_for_url("**/users") # 禁用用户 await page.click('button:has-text("禁用")') await page.click('button:has-text("确定")') await page.wait_for_load_state("networkidle") # 验证状态变更 page_content = await page.content() assert "禁用" in page_content finally: await authenticated_client.delete(f"/api/users/{user_id}") @pytest.mark.asyncio async def test_uat_user_delete(self, page, authenticated_client): """UAT: 用户删除流程""" timestamp = int(time.time() * 1000) username = f"uat_delete_{timestamp}" # 创建用户 response = await authenticated_client.post( "/api/users", json={ "username": username, "password": "Test123!@#", "email": f"uat_delete_{timestamp}@example.com", "status": 1 } ) assert response.status_code == 201 user_id = response.json()["id"] # 登录并删除用户 await page.goto("http://localhost:3002/login") await page.fill('input[placeholder="请输入用户名"]', username) await page.fill('input[placeholder="请输入密码"]', "Test123!@#") await page.click('button[type="submit"]') await page.wait_for_url("**/") await page.click('text=用户管理') await page.wait_for_url("**/users") await page.click('button:has-text("删除")') await page.click('button:has-text("确定")') await page.wait_for_load_state("networkidle") # 验证删除 page_content = await page.content() assert username not in page_content @pytest.mark.uat @pytest.mark.role_workflow class TestRoleWorkflowUAT: """角色工作流UAT测试""" @pytest.fixture async def browser(self): async with async_playwright() as p: browser = await p.chromium.launch(headless=True) yield browser await browser.close() @pytest.fixture async def context(self, browser): context = await browser.new_context() yield context await context.close() @pytest.fixture async def page(self, context): page = await context.new_page() page.set_default_timeout(30000) yield page await page.close() @pytest.fixture async def authenticated_client(self): async with AsyncClient(base_url=settings.API_BASE_URL) as client: response = await client.post( "/api/auth/login", json={ "username": settings.TEST_USERNAME, "password": settings.TEST_PASSWORD } ) assert response.status_code == 200 token = response.json().get("token") client.headers.update({"Authorization": f"Bearer {token}"}) yield client @pytest.mark.asyncio async def test_uat_role_assignment(self, page, authenticated_client): """UAT: 角色分配流程""" timestamp = int(time.time() * 1000) username = f"uat_role_user_{timestamp}" role_name = f"UAT_Role_{timestamp}" # 创建角色 role_response = await authenticated_client.post( "/api/roles", json={ "roleName": role_name, "roleKey": f"uat_role_{timestamp}", "roleSort": 1, "status": 1 } ) assert role_response.status_code == 201 role_id = role_response.json()["id"] try: # 创建用户 user_response = await authenticated_client.post( "/api/users", json={ "username": username, "password": "Test123!@#", "email": f"uat_role_user_{timestamp}@example.com", "status": 1 } ) assert user_response.status_code == 201 user_id = user_response.json()["id"] # 登录并分配角色 await page.goto("http://localhost:3002/login") await page.fill('input[placeholder="请输入用户名"]', username) await page.fill('input[placeholder="请输入密码"]', "Test123!@#") await page.click('button[type="submit"]') await page.wait_for_url("**/") await page.click('text=用户管理') await page.wait_for_url("**/users") # 分配角色 await page.click('text=分配角色') await page.wait_for_load_state("networkidle") # 选择角色 await page.click(f'text={role_name}') await page.click('button:has-text("确定")') await page.wait_for_load_state("networkidle") # 验证角色分配 user_info = await authenticated_client.get(f"/api/users/{user_id}") assert user_info.status_code == 200 user_data = user_info.json() assert user_data["roleId"] == role_id finally: await authenticated_client.delete(f"/api/users/{user_id}") await authenticated_client.delete(f"/api/roles/{role_id}") @pytest.mark.asyncio async def test_uat_role_permission_management(self, page, authenticated_client): """UAT: 角色权限管理流程""" timestamp = int(time.time() * 1000) role_name = f"UAT_Permission_Role_{timestamp}" # 创建角色 role_response = await authenticated_client.post( "/api/roles", json={ "roleName": role_name, "roleKey": f"uat_perm_role_{timestamp}", "roleSort": 1, "status": 1 } ) assert role_response.status_code == 201 role_id = role_response.json()["id"] try: # 登录并访问角色管理 await page.goto("http://localhost:3002/login") await page.fill('input[placeholder="请输入用户名"]', settings.TEST_USERNAME) await page.fill('input[placeholder="请输入密码"]', settings.TEST_PASSWORD) await page.click('button[type="submit"]') await page.wait_for_url("**/") await page.click('text=角色管理') await page.wait_for_url("**/roles") # 编辑角色权限 await page.click('text=编辑') await page.wait_for_load_state("networkidle") # 更新角色信息 await page.fill('input[placeholder=""]', f"{role_name}_updated") await page.click('button:has-text("确定")') await page.wait_for_load_state("networkidle") # 验证更新 roles_response = await authenticated_client.get("/api/roles") roles = roles_response.json() role_exists = any(r['roleName'] == f"{role_name}_updated" for r in roles) assert role_exists finally: await authenticated_client.delete(f"/api/roles/{role_id}") @pytest.mark.uat @pytest.mark.config_workflow class TestConfigWorkflowUAT: """配置工作流UAT测试""" @pytest.fixture async def browser(self): async with async_playwright() as p: browser = await p.chromium.launch(headless=True) yield browser await browser.close() @pytest.fixture async def context(self, browser): context = await browser.new_context() yield context await context.close() @pytest.fixture async def page(self, context): page = await context.new_page() page.set_default_timeout(30000) yield page await page.close() @pytest.fixture async def authenticated_client(self): async with AsyncClient(base_url=settings.API_BASE_URL) as client: response = await client.post( "/api/auth/login", json={ "username": settings.TEST_USERNAME, "password": settings.TEST_PASSWORD } ) assert response.status_code == 200 token = response.json().get("token") client.headers.update({"Authorization": f"Bearer {token}"}) yield client @pytest.mark.asyncio async def test_uat_system_config_update(self, page, authenticated_client): """UAT: 系统配置更新流程""" timestamp = int(time.time() * 1000) # 登录并访问系统配置 await page.goto("http://localhost:3002/login") await page.fill('input[placeholder="请输入用户名"]', settings.TEST_USERNAME) await page.fill('input[placeholder="请输入密码"]', settings.TEST_PASSWORD) await page.click('button[type="submit"]') await page.wait_for_url("**/") await page.click('text=系统配置') await page.wait_for_url("**/config") await page.wait_for_load_state("networkidle") # 编辑配置 await page.click('text=编辑') await page.wait_for_load_state("networkidle") # 更新配置 await page.fill('input[placeholder=""]', f"Test_Config_{timestamp}") await page.fill('textarea[placeholder=""]', '测试配置内容') await page.click('button:has-text("确定")') await page.wait_for_load_state("networkidle") # 验证更新 config_response = await authenticated_client.get("/api/config") assert config_response.status_code == 200 @pytest.mark.uat @pytest.mark.data_dict_workflow class TestDataDictWorkflowUAT: """数据字典工作流UAT测试""" @pytest.fixture async def browser(self): async with async_playwright() as p: browser = await p.chromium.launch(headless=True) yield browser await browser.close() @pytest.fixture async def context(self, browser): context = await browser.new_context() yield context await context.close() @pytest.fixture async def page(self, context): page = await context.new_page() page.set_default_timeout(30000) yield page await page.close() @pytest.fixture async def authenticated_client(self): async with AsyncClient(base_url=settings.API_BASE_URL) as client: response = await client.post( "/api/auth/login", json={ "username": settings.TEST_USERNAME, "password": settings.TEST_PASSWORD } ) assert response.status_code == 200 token = response.json().get("token") client.headers.update({"Authorization": f"Bearer {token}"}) yield client @pytest.mark.asyncio async def test_uat_dict_type_management(self, page, authenticated_client): """UAT: 字典类型管理流程""" timestamp = int(time.time() * 1000) dict_type = f"UAT_DICT_{timestamp}" # 登录并访问字典管理 await page.goto("http://localhost:3002/login") await page.fill('input[placeholder="请输入用户名"]', settings.TEST_USERNAME) await page.fill('input[placeholder="请输入密码"]', settings.TEST_PASSWORD) await page.click('button[type="submit"]') await page.wait_for_url("**/") await page.click('text=字典管理') await page.wait_for_url("**/dicts") await page.wait_for_load_state("networkidle") # 创建字典类型 await page.click('text=新增字典') await page.wait_for_load_state("networkidle") await page.fill('input[placeholder=""]', dict_type) await page.fill('input[placeholder=""]', f"uat_dict_{timestamp}") await page.fill('textarea[placeholder=""]', '测试字典类型') await page.click('button:has-text("确定")') await page.wait_for_load_state("networkidle") # 验证创建 dicts_response = await authenticated_client.get("/api/dict/types") assert dicts_response.status_code == 200 dicts = dicts_response.json() dict_exists = any(d['type'] == dict_type for d in dicts) assert dict_exists @pytest.mark.asyncio async def test_uat_dict_data_management(self, page, authenticated_client): """UAT: 字典数据管理流程""" timestamp = int(time.time() * 1000) # 登录并访问字典管理 await page.goto("http://localhost:3002/login") await page.fill('input[placeholder="请输入用户名"]', settings.TEST_USERNAME) await page.fill('input[placeholder="请输入密码"]', settings.TEST_PASSWORD) await page.click('button[type="submit"]') await page.wait_for_url("**/") await page.click('text=字典管理') await page.wait_for_url("**/dicts") await page.wait_for_load_state("networkidle") # 查看字典数据 await page.click('text=查看') await page.wait_for_load_state("networkidle") # 验证字典数据列表 page_content = await page.content() assert "字典数据" in page_content or "code" in page_content.lower() @pytest.mark.uat @pytest.mark.audit_workflow class TestAuditWorkflowUAT: """审计工作流UAT测试""" @pytest.fixture async def browser(self): async with async_playwright() as p: browser = await p.chromium.launch(headless=True) yield browser await browser.close() @pytest.fixture async def context(self, browser): context = await browser.new_context() yield context await context.close() @pytest.fixture async def page(self, context): page = await context.new_page() page.set_default_timeout(30000) yield page await page.close() @pytest.fixture async def authenticated_client(self): async with AsyncClient(base_url=settings.API_BASE_URL) as client: response = await client.post( "/api/auth/login", json={ "username": settings.TEST_USERNAME, "password": settings.TEST_PASSWORD } ) assert response.status_code == 200 token = response.json().get("token") client.headers.update({"Authorization": f"Bearer {token}"}) yield client @pytest.mark.asyncio async def test_uat_operation_log_audit(self, page, authenticated_client): """UAT: 操作日志审计流程""" timestamp = int(time.time() * 1000) # 登录并访问操作日志 await page.goto("http://localhost:3002/login") await page.fill('input[placeholder="请输入用户名"]', settings.TEST_USERNAME) await page.fill('input[placeholder="请输入密码"]', settings.TEST_PASSWORD) await page.click('button[type="submit"]') await page.wait_for_url("**/") await page.click('text=操作日志') await page.wait_for_url("**/operation-logs") await page.wait_for_load_state("networkidle") # 验证操作日志列表 await page.wait_for_selector('.el-card', timeout=10000) # 通过API验证 logs_response = await authenticated_client.get("/api/audit/operation-logs") assert logs_response.status_code == 200 logs = logs_response.json() assert len(logs) > 0, "操作日志为空" @pytest.mark.asyncio async def test_uat_login_log_audit(self, page, authenticated_client): """UAT: 登录日志审计流程""" # 登录并访问登录日志 await page.goto("http://localhost:3002/login") await page.fill('input[placeholder="请输入用户名"]', settings.TEST_USERNAME) await page.fill('input[placeholder="请输入密码"]', settings.TEST_PASSWORD) await page.click('button[type="submit"]') await page.wait_for_url("**/") await page.click('text=登录日志') await page.wait_for_url("**/login-logs") await page.wait_for_load_state("networkidle") # 验证登录日志列表 await page.wait_for_selector('.el-card', timeout=10000) # 通过API验证 login_logs_response = await authenticated_client.get("/api/audit/login-logs") assert login_logs_response.status_code == 200 login_logs = login_logs_response.json() assert len(login_logs) > 0, "登录日志为空" @pytest.mark.uat @pytest.mark.comprehensive_workflow class TestComprehensiveWorkflowUAT: """综合业务流程UAT测试""" @pytest.fixture async def browser(self): async with async_playwright() as p: browser = await p.chromium.launch(headless=True) yield browser await browser.close() @pytest.fixture async def context(self, browser): context = await browser.new_context() yield context await context.close() @pytest.fixture async def page(self, context): page = await context.new_page() page.set_default_timeout(30000) yield page await page.close() @pytest.fixture async def authenticated_client(self): async with AsyncClient(base_url=settings.API_BASE_URL) as client: response = await client.post( "/api/auth/login", json={ "username": settings.TEST_USERNAME, "password": settings.TEST_PASSWORD } ) assert response.status_code == 200 token = response.json().get("token") client.headers.update({"Authorization": f"Bearer {token}"}) yield client @pytest.mark.asyncio async def test_uat_complete_business_workflow(self, page, authenticated_client): """UAT: 完整业务流程测试""" timestamp = int(time.time() * 1000) # 步骤1: 用户注册 username = f"uat_complete_{timestamp}" response = await authenticated_client.post( "/api/users", json={ "username": username, "password": "Test123!@#", "email": f"uat_complete_{timestamp}@example.com", "phone": "13800138000", "status": 1 } ) assert response.status_code == 201 user_id = response.json()["id"] try: # 步骤2: 用户登录 await page.goto("http://localhost:3002/login") await page.fill('input[placeholder="请输入用户名"]', username) await page.fill('input[placeholder="请输入密码"]', "Test123!@#") await page.click('button[type="submit"]') await page.wait_for_url("**/") # 步骤3: 浏览用户管理 await page.click('text=用户管理') await page.wait_for_url("**/users") # 步骤4: 浏览角色管理 await page.click('text=角色管理') await page.wait_for_url("**/roles") # 步骤5: 浏览系统配置 await page.click('text=系统配置') await page.wait_for_url("**/config") # 步骤6: 浏览字典管理 await page.click('text=字典管理') await page.wait_for_url("**/dicts") # 步骤7: 浏览通知管理 await page.click('text=通知管理') await page.wait_for_url("**/notices") # 步骤8: 浏览文件管理 await page.click('text=文件管理') await page.wait_for_url("**/files") # 步骤9: 浏览审计日志 await page.click('text=操作日志') await page.wait_for_url("**/operation-logs") # 步骤10: 登出 await page.click('text=退出登录') await page.wait_for_url("**/login") finally: await authenticated_client.delete(f"/api/users/{user_id}")